добавил кнопки парсинга в редактировании базы для админов

This commit is contained in:
2026-04-23 11:24:47 +03:00
parent a7597f943c
commit 23300a4a37
2 changed files with 152 additions and 7 deletions

60
app.py
View File

@@ -16,6 +16,8 @@ import json
from pathlib import Path from pathlib import Path
import io import io
import asyncio import asyncio
import contextlib
import traceback
import time import time
from urllib.parse import quote from urllib.parse import quote
@@ -26,6 +28,9 @@ from repositories.match_formation_repository import (
) )
from parsers.parser_game import run_parser_game 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 repositories.match_session_repository import ( from repositories.match_session_repository import (
create_match_session, create_match_session,
get_match_session_by_token, get_match_session_by_token,
@@ -725,17 +730,68 @@ def close_session(session_token: str):
return RedirectResponse(url="/admin/matches", status_code=303) return RedirectResponse(url="/admin/matches", status_code=303)
@app.get("/admin/db", response_class=HTMLResponse) def render_admin_db_index(request: Request, parser_output: str | None = None, parser_name: str | None = None, parser_success: bool | None = None):
def admin_db_index(request: Request):
return templates.TemplateResponse( return templates.TemplateResponse(
name="admin_db_index.html", name="admin_db_index.html",
request=request, request=request,
context={ context={
"current_user": getattr(request.state, "current_user", None), "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.get("/admin/db/players", response_class=HTMLResponse) @app.get("/admin/db/players", response_class=HTMLResponse)
def admin_db_players(request: Request, q: str = Query(default="")): def admin_db_players(request: Request, q: str = Query(default="")):
# denied = require_role(request, {"admin"}) # denied = require_role(request, {"admin"})

View File

@@ -13,6 +13,10 @@
--muted: #9aa4b2; --muted: #9aa4b2;
--accent: #4f8cff; --accent: #4f8cff;
--accent-hover: #3e78e6; --accent-hover: #3e78e6;
--success-bg: rgba(46, 204, 113, 0.12);
--success-border: rgba(46, 204, 113, 0.35);
--danger-bg: rgba(255, 99, 99, 0.12);
--danger-border: rgba(255, 99, 99, 0.35);
--shadow: 0 10px 30px rgba(0, 0, 0, 0.35); --shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
--radius: 16px; --radius: 16px;
} }
@@ -46,15 +50,24 @@
margin-bottom: 18px; margin-bottom: 18px;
} }
.tabs { .tabs,
.parser-actions {
display: flex; display: flex;
gap: 12px; gap: 12px;
flex-wrap: wrap; flex-wrap: wrap;
} }
.tab-link { .parser-actions {
margin-top: 18px;
padding-top: 18px;
border-top: 1px solid var(--border);
}
.tab-link,
.action-btn {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center;
min-height: 42px; min-height: 42px;
padding: 0 16px; padding: 0 16px;
border-radius: 999px; border-radius: 999px;
@@ -63,13 +76,58 @@
color: var(--text); color: var(--text);
text-decoration: none; text-decoration: none;
font-weight: 600; font-weight: 600;
cursor: pointer;
font-size: 14px;
} }
.tab-link:hover { .tab-link:hover,
.action-btn:hover {
background: var(--accent); background: var(--accent);
border-color: var(--accent); border-color: var(--accent);
color: white; color: white;
} }
.action-form {
margin: 0;
}
.log-block {
margin-top: 20px;
border: 1px solid var(--border);
border-radius: 14px;
padding: 16px;
background: var(--panel-2);
}
.log-block.success {
background: var(--success-bg);
border-color: var(--success-border);
}
.log-block.error {
background: var(--danger-bg);
border-color: var(--danger-border);
}
.log-title {
font-size: 18px;
font-weight: 700;
margin-bottom: 10px;
}
.log-status {
color: var(--muted);
margin-bottom: 10px;
}
.log-output {
margin: 0;
white-space: pre-wrap;
word-break: break-word;
font-family: Consolas, Monaco, monospace;
font-size: 13px;
line-height: 1.5;
}
</style> </style>
</head> </head>
<body> <body>
@@ -79,13 +137,44 @@
<div class="tabs"> <div class="tabs">
<a class="tab-link" href="/admin/db/players">Игроки</a> <a class="tab-link" href="/admin/db/players">Игроки</a>
<a class="tab-link" href="/admin/db/referees">Судьи</a> <a class="tab-link" href="/admin/db/referees">Судьи</a>
<a class="tab-link" href="/admin/db/teams">Команды</a> <a class="tab-link" href="/admin/db/teams">Команды</a>
<a class="tab-link" href="/admin/db/coaches">Тренеры</a> <a class="tab-link" href="/admin/db/coaches">Тренеры</a>
<a class="tab-link" href="/admin/db/stadiums">Стадионы</a> <a class="tab-link" href="/admin/db/stadiums">Стадионы</a>
<a class="tab-link" href="/admin/matches">Назад к матчам</a> <a class="tab-link" href="/admin/matches">Назад к матчам</a>
</div> </div>
<div class="parser-actions">
<form method="post" action="/admin/db/run-parser" class="action-form">
<input type="hidden" name="parser_name" value="players">
<button type="submit" class="action-btn">Заграбить игроков</button>
</form>
<form method="post" action="/admin/db/run-parser" class="action-form">
<input type="hidden" name="parser_name" value="schedule">
<button type="submit" class="action-btn">Заграбить расписание</button>
</form>
<form method="post" action="/admin/db/run-parser" class="action-form">
<input type="hidden" name="parser_name" value="standings">
<button type="submit" class="action-btn">Заграбить турнирку</button>
</form>
</div>
{% if parser_output %}
<div class="log-block {% if parser_success %}success{% else %}error{% endif %}">
<div class="log-title">Итог парсинга{% if parser_name %}: {{ parser_name }}{% endif %}</div>
<div class="log-status">
Статус:
{% if parser_success %}
успешно
{% else %}
ошибка
{% endif %}
</div>
<pre class="log-output">{{ parser_output }}</pre>
</div>
{% endif %}
</div> </div>
</div> </div>
</body> </body>