1. вернул обратно в код создание учетки из базы, и прогон парсеров через базу

This commit is contained in:
2026-04-24 14:45:39 +03:00
parent 312a006312
commit 6c50e7e2fe

149
app.py
View File

@@ -1,5 +1,5 @@
from fastapi import FastAPI, Form, Request, Query, Body, HTTPException, WebSocket, WebSocketDisconnect
from datetime import datetime, timezone
from fastapi import FastAPI, Form, Request, Query, HTTPException, WebSocket, WebSocketDisconnect
from datetime import datetime
from fastapi.responses import (
HTMLResponse,
RedirectResponse,
@@ -10,15 +10,21 @@ from fastapi.responses import (
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel, Field
from collections import defaultdict
from typing import List, Optional, Dict, Any
import json
from typing import List, Dict
from pathlib import Path
import io
import asyncio
import time
from urllib.parse import quote
import traceback
import contextlib
from parsers.parser_game import run_parser_game
from parsers.parser_players import run_parser_players
from parsers.parser_schedule import run_parser_schedule
from parsers.parser_standings import run_parser_standings
from db import get_connection
from repositories.match_formation_repository import (
get_match_formations,
replace_match_formations,
@@ -85,6 +91,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,
@@ -1660,4 +1667,134 @@ def info_page(request: Request):
name="info.html",
request=request,
context={}
)
)
def render_admin_db_index(request: Request, parser_output: str | None = None, parser_name: str | None = None, parser_success: bool | None = None):
return templates.TemplateResponse(
name="admin_db_index.html",
request=request,
context={
"current_user": getattr(request.state, "current_user", None),
"parser_output": parser_output,
"parser_name": parser_name,
"parser_success": parser_success,
},
)
@app.get("/admin/db", response_class=HTMLResponse)
def admin_db_index(request: Request):
return render_admin_db_index(request)
@app.post("/admin/db/run-parser", response_class=HTMLResponse)
def admin_db_run_parser(request: Request, parser_name: str = Form(...)):
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)
parser_map = {
"players": ("Игроки", run_parser_players),
"schedule": ("Расписание", run_parser_schedule),
"standings": ("Турнирка", run_parser_standings),
}
parser_meta = parser_map.get(parser_name)
if not parser_meta:
return render_admin_db_index(
request,
parser_output="Неизвестный парсер.",
parser_name=parser_name,
parser_success=False,
)
title, parser_func = parser_meta
buffer = io.StringIO()
success = True
with contextlib.redirect_stdout(buffer), contextlib.redirect_stderr(buffer):
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Запуск парсера: {title}")
try:
parser_func()
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Парсер завершён успешно")
except Exception:
success = False
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Ошибка при выполнении парсера")
print(traceback.format_exc())
output = buffer.getvalue().strip() or "Парсер не вернул сообщений."
return render_admin_db_index(
request,
parser_output=output,
parser_name=title,
parser_success=success,
)
@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()
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 len(password) < 6:
return render_admin_db_index(request, account_output="Пароль должен быть не короче 6 символов.", 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()
try:
with conn.cursor() as cur:
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),
)
row = cur.fetchone()
conn.commit()
if row:
return render_admin_db_index(
request,
account_output=f"Пользователь создан: {username} (id={row[0]})\nРоль: {role}",
account_success=True,
)
return render_admin_db_index(
request,
account_output=f"Пользователь '{username}' уже существует.",
account_success=False,
)
except Exception:
conn.rollback()
return render_admin_db_index(
request,
account_output="Ошибка при создании аккаунта:\n" + traceback.format_exc(),
account_success=False,
)
finally:
conn.close()