2.0.0-rc2: Achievements Refactored & Admin improved.
This commit is contained in:
+71
-14
@@ -1,15 +1,27 @@
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, session, flash, jsonify
|
||||
from flask import (
|
||||
Blueprint,
|
||||
flash,
|
||||
jsonify,
|
||||
redirect,
|
||||
render_template,
|
||||
request,
|
||||
session,
|
||||
url_for,
|
||||
)
|
||||
from web.config import Config
|
||||
from web.auth import admin_required
|
||||
from web.auth import admin_required, csrf_protected, validate_csrf
|
||||
from web.database import query_db
|
||||
from web.services.admin_service import AdminService
|
||||
from web.services.etl_service import EtlService
|
||||
import hmac
|
||||
import time
|
||||
|
||||
bp = Blueprint('admin', __name__, url_prefix='/admin')
|
||||
|
||||
@bp.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
validate_csrf()
|
||||
token = request.form.get('token') or ''
|
||||
if hmac.compare_digest(token, Config.ADMIN_TOKEN):
|
||||
session['is_admin'] = True
|
||||
@@ -26,7 +38,10 @@ def logout():
|
||||
@bp.route('/')
|
||||
@admin_required
|
||||
def dashboard():
|
||||
return render_template('admin/dashboard.html')
|
||||
return render_template(
|
||||
'admin/dashboard.html',
|
||||
**AdminService.get_overview(),
|
||||
)
|
||||
|
||||
@bp.route('/data-integrity')
|
||||
@admin_required
|
||||
@@ -40,6 +55,7 @@ def data_integrity():
|
||||
|
||||
@bp.route('/trigger_etl', methods=['POST'])
|
||||
@admin_required
|
||||
@csrf_protected
|
||||
def trigger_etl():
|
||||
from database.job_store import JobStore
|
||||
|
||||
@@ -68,6 +84,7 @@ def import_match():
|
||||
|
||||
store = JobStore(Config.DB_WEB_PATH)
|
||||
if request.method == 'POST':
|
||||
validate_csrf()
|
||||
upload = request.files.get('capture')
|
||||
if not upload or not upload.filename:
|
||||
flash('请选择 iframe_network.json 文件。', 'error')
|
||||
@@ -91,7 +108,7 @@ def import_match():
|
||||
'success',
|
||||
)
|
||||
return redirect(url_for(
|
||||
'admin.import_match',
|
||||
'admin.jobs',
|
||||
job_id=prepared['job_id'],
|
||||
))
|
||||
except (DuplicateMatchError, ImportValidationError) as exc:
|
||||
@@ -106,14 +123,34 @@ def import_match():
|
||||
)
|
||||
flash(f'启动导入失败:{exc}', 'error')
|
||||
|
||||
selected_job = None
|
||||
selected_job_id = request.args.get('job_id', type=int)
|
||||
if selected_job_id:
|
||||
selected_job = store.get_job(selected_job_id)
|
||||
return render_template(
|
||||
'admin/import_match.html',
|
||||
jobs=store.list_jobs(30),
|
||||
selected_job=selected_job,
|
||||
jobs=store.list_jobs(5),
|
||||
)
|
||||
|
||||
|
||||
@bp.route('/jobs')
|
||||
@admin_required
|
||||
def jobs():
|
||||
from database.job_store import JobStore
|
||||
|
||||
status = request.args.get('status') or None
|
||||
job_type = request.args.get('type') or None
|
||||
selected_job_id = request.args.get('job_id', type=int)
|
||||
data = AdminService.get_jobs(status, job_type)
|
||||
data['selected_job'] = (
|
||||
JobStore(Config.DB_WEB_PATH).get_job(selected_job_id)
|
||||
if selected_job_id else None
|
||||
)
|
||||
return render_template('admin/jobs.html', **data)
|
||||
|
||||
|
||||
@bp.route('/system')
|
||||
@admin_required
|
||||
def system():
|
||||
return render_template(
|
||||
'admin/system.html',
|
||||
**AdminService.get_system_status(),
|
||||
)
|
||||
|
||||
|
||||
@@ -133,9 +170,14 @@ def sql_runner():
|
||||
result = None
|
||||
error = None
|
||||
query = ""
|
||||
db_name = "l2"
|
||||
db_name = request.args.get('db_name', 'l2')
|
||||
if db_name not in {'l2', 'l3', 'web'}:
|
||||
db_name = 'l2'
|
||||
duration_ms = None
|
||||
row_count = None
|
||||
|
||||
if request.method == 'POST':
|
||||
validate_csrf()
|
||||
query = (request.form.get('query') or '').strip()
|
||||
db_name = request.form.get('db_name', 'l2')
|
||||
|
||||
@@ -151,8 +193,10 @@ def sql_runner():
|
||||
query = statement
|
||||
if 'LIMIT' not in statement.upper():
|
||||
query = f"{statement} LIMIT 50"
|
||||
|
||||
started = time.perf_counter()
|
||||
rows = query_db(db_name, query)
|
||||
duration_ms = (time.perf_counter() - started) * 1000
|
||||
row_count = len(rows)
|
||||
if rows:
|
||||
columns = rows[0].keys()
|
||||
result = {'columns': columns, 'rows': rows}
|
||||
@@ -160,5 +204,18 @@ def sql_runner():
|
||||
result = {'columns': [], 'rows': []}
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
|
||||
return render_template('admin/sql.html', result=result, error=error, query=query, db_name=db_name)
|
||||
|
||||
try:
|
||||
catalog = AdminService.get_database_catalog(db_name)
|
||||
except ValueError:
|
||||
catalog = []
|
||||
return render_template(
|
||||
'admin/sql.html',
|
||||
result=result,
|
||||
error=error,
|
||||
query=query,
|
||||
db_name=db_name,
|
||||
catalog=catalog,
|
||||
duration_ms=duration_ms,
|
||||
row_count=row_count,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user