1. вернул обратно в код создание учетки из базы, и прогон парсеров через базу
This commit is contained in:
147
app.py
147
app.py
@@ -1,5 +1,5 @@
|
|||||||
from fastapi import FastAPI, Form, Request, Query, Body, HTTPException, WebSocket, WebSocketDisconnect
|
from fastapi import FastAPI, Form, Request, Query, HTTPException, WebSocket, WebSocketDisconnect
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime
|
||||||
from fastapi.responses import (
|
from fastapi.responses import (
|
||||||
HTMLResponse,
|
HTMLResponse,
|
||||||
RedirectResponse,
|
RedirectResponse,
|
||||||
@@ -10,15 +10,21 @@ from fastapi.responses import (
|
|||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from collections import defaultdict
|
from typing import List, Dict
|
||||||
from typing import List, Optional, Dict, Any
|
|
||||||
import json
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import io
|
import io
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
from urllib.parse import quote
|
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 (
|
from repositories.match_formation_repository import (
|
||||||
get_match_formations,
|
get_match_formations,
|
||||||
replace_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 repositories.auth_repository import get_user_by_username
|
||||||
from services.auth_service import (
|
from services.auth_service import (
|
||||||
create_auth_session,
|
create_auth_session,
|
||||||
|
hash_password,
|
||||||
verify_password,
|
verify_password,
|
||||||
get_current_user_from_request,
|
get_current_user_from_request,
|
||||||
build_not_authenticated_response,
|
build_not_authenticated_response,
|
||||||
@@ -1661,3 +1668,133 @@ def info_page(request: Request):
|
|||||||
request=request,
|
request=request,
|
||||||
context={}
|
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()
|
||||||
Reference in New Issue
Block a user