diff --git a/app.py b/app.py index 492f5e3..30be8e3 100644 --- a/app.py +++ b/app.py @@ -90,6 +90,7 @@ from repositories.match_event_repository import ( from repositories.auth_repository import get_user_by_username from services.auth_service import ( create_auth_session, + hash_password, verify_password, get_current_user_from_request, build_not_authenticated_response, @@ -730,7 +731,14 @@ def close_session(session_token: str): return RedirectResponse(url="/admin/matches", status_code=303) -def render_admin_db_index(request: Request, parser_output: str | None = None, parser_name: str | None = None, parser_success: bool | None = None): +def render_admin_db_index( + request: Request, + parser_output: str | None = None, + parser_name: str | None = None, + parser_success: bool | None = None, + account_output: str | None = None, + account_success: bool | None = None, +): return templates.TemplateResponse( name="admin_db_index.html", request=request, @@ -739,6 +747,8 @@ def render_admin_db_index(request: Request, parser_output: str | None = None, pa "parser_output": parser_output, "parser_name": parser_name, "parser_success": parser_success, + "account_output": account_output, + "account_success": account_success, }, ) @@ -792,6 +802,107 @@ def admin_db_run_parser(request: Request, parser_name: str = Form(...)): ) +@app.post("/admin/db/create-account", response_class=HTMLResponse) +def admin_db_create_account( + request: Request, + username: str = Form(...), + password: str = Form(...), + role: str = Form(default="operator"), +): + current_user = getattr(request.state, "current_user", None) + if not current_user or current_user.get("role") != "admin": + return RedirectResponse(url="/login", status_code=303) + + username = username.strip() + password = password.strip() + role = (role or "operator").strip().lower() + + if not username: + return render_admin_db_index( + request, + account_output="Логин обязателен.", + account_success=False, + ) + + if not password: + return render_admin_db_index( + request, + account_output="Пароль обязателен.", + account_success=False, + ) + + if role not in {"admin", "operator"}: + return render_admin_db_index( + request, + account_output="Роль должна быть admin или operator.", + account_success=False, + ) + + password_hash = hash_password(password) + conn = get_connection() + success = True + messages: list[str] = [] + + try: + with conn: + with conn.cursor() as cur: + try: + cur.execute( + """ + INSERT INTO admin_users (username, password_hash, role, is_active) + VALUES (%s, %s, %s, TRUE) + ON CONFLICT (username) DO NOTHING + RETURNING id; + """, + (username, password_hash, role), + ) + except Exception: + conn.rollback() + with conn: + with conn.cursor() as fallback_cur: + fallback_cur.execute( + """ + INSERT INTO admin_users (username, password_hash, is_active) + VALUES (%s, %s, TRUE) + ON CONFLICT (username) DO NOTHING + RETURNING id; + """, + (username, password_hash), + ) + row = fallback_cur.fetchone() + if row: + messages.append(f"Пользователь создан: {username} (id={row[0]})") + messages.append("Примечание: колонка role в БД не найдена, роль не сохранена.") + else: + success = False + messages.append(f"Пользователь '{username}' уже существует.") + return render_admin_db_index( + request, + account_output="\n".join(messages), + account_success=success, + ) + + row = cur.fetchone() + if row: + messages.append(f"Пользователь создан: {username} (id={row[0]})") + messages.append(f"Роль: {role}") + else: + success = False + messages.append(f"Пользователь '{username}' уже существует.") + except Exception: + success = False + messages.append("Ошибка при создании аккаунта:") + messages.append(traceback.format_exc()) + finally: + conn.close() + + return render_admin_db_index( + request, + account_output="\n".join(messages).strip(), + account_success=success, + ) + + @app.get("/admin/db/players", response_class=HTMLResponse) def admin_db_players(request: Request, q: str = Query(default="")): # denied = require_role(request, {"admin"}) diff --git a/templates/admin_db_index.html b/templates/admin_db_index.html index 4143b25..63b56a1 100644 --- a/templates/admin_db_index.html +++ b/templates/admin_db_index.html @@ -11,8 +11,8 @@ --border: #2b3240; --text: #e8ecf3; --muted: #9aa4b2; - --accent: #28c76f; - --accent-hover: #20b15f; + --accent: #00c773; + --accent-hover: #00a861; --success-bg: rgba(46, 204, 113, 0.12); --success-border: rgba(46, 204, 113, 0.35); --danger-bg: rgba(255, 99, 99, 0.12); @@ -162,7 +162,7 @@ width: min(90vw, 560px); padding: 28px 24px; border-radius: 18px; - border: 1px solid rgba(0, 255, 136, 0.35); + border: 1px solid rgba(0, 255, 136, 0.30); background: rgba(12, 17, 26, 0.88); box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45); text-align: center; @@ -172,7 +172,7 @@ .matrix-title { font-size: 28px; font-weight: 700; - color: #d8ffe9; + color: #dfffee; margin-bottom: 12px; } @@ -215,6 +215,32 @@ +
{{ parser_output }}
{{ account_output }}
+