добавил возможность администраторам создавать игроков, тренеров и судей вручную

This commit is contained in:
2026-08-04 10:49:03 +03:00
parent 2c2d9b9a7c
commit adea3a8bd6
10 changed files with 891 additions and 3 deletions

186
app.py
View File

@@ -75,6 +75,7 @@ from repositories.player_repository import (
update_player_admin,
update_player_photo_enabled,
ensure_player_photo_enabled_column,
create_player_admin,
)
from repositories.referee_repository import (
@@ -82,6 +83,7 @@ from repositories.referee_repository import (
get_referee_by_id,
update_referee_admin,
get_all_referees,
create_referee_admin,
# replace_match_referees,
)
@@ -91,6 +93,7 @@ from repositories.coach_repository import (
search_coaches_for_admin,
get_coach_by_id,
update_coach_admin,
create_coach_admin,
)
from repositories.stadium_repository import (
@@ -103,6 +106,7 @@ from repositories.team_repository import (
search_teams_for_admin,
get_team_by_id,
update_team_admin,
list_teams_for_admin_select,
)
from repositories.match_event_repository import (
@@ -894,6 +898,188 @@ def close_session(session_token: str):
def _admin_create_optional_int(value, field_title: str, minimum: int = 0) -> int | None:
text = str(value or "").strip()
if not text:
return None
try:
number = int(text)
except ValueError as exc:
raise ValueError(f"Поле «{field_title}» должно быть целым числом.") from exc
if number < minimum:
raise ValueError(f"Поле «{field_title}» не может быть меньше {minimum}.")
return number
def _admin_create_required_int(value, field_title: str, minimum: int = 0) -> int:
number = _admin_create_optional_int(value, field_title, minimum)
if number is None:
raise ValueError(f"Заполните поле «{field_title}».")
return number
def _render_admin_entity_create(
request: Request,
entity_type: str = "player",
error: str | None = None,
created_id: int | None = None,
form_values: dict | None = None,
status_code: int = 200,
):
allowed_entities = {"player", "coach", "referee"}
entity_type = entity_type if entity_type in allowed_entities else "player"
try:
teams = list_teams_for_admin_select()
except Exception:
teams = []
return templates.TemplateResponse(
name="admin_db_create.html",
request=request,
context={
"entity_type": entity_type,
"teams": teams,
"error": error,
"created_id": created_id,
"form_values": form_values or {},
},
status_code=status_code,
)
@app.get("/admin/db/create", response_class=HTMLResponse)
def admin_db_create_page(
request: Request,
entity: str = Query(default="player"),
created_id: int | None = Query(default=None),
):
denied = require_role(request, {"admin"})
if denied:
return denied
return _render_admin_entity_create(
request=request,
entity_type=entity,
created_id=created_id,
)
@app.post("/admin/db/create", response_class=HTMLResponse)
async def admin_db_create_submit(request: Request):
denied = require_role(request, {"admin"})
if denied:
return denied
form = await request.form()
values = {key: str(value) for key, value in form.items()}
entity_type = values.get("entity_type", "player").strip().lower()
if entity_type not in {"player", "coach", "referee"}:
entity_type = "player"
try:
full_name = values.get("full_name", "").strip()
if not full_name:
raise ValueError("Заполните поле «Полное имя / ФИО».")
external_id = values.get("external_id", "").strip()
first_name = values.get("first_name", "").strip()
last_name = values.get("last_name", "").strip()
is_active = "is_active" in form
if entity_type == "player":
team_id = _admin_create_required_int(values.get("team_id"), "Команда", 1)
position = values.get("position", "").strip()
if not position:
raise ValueError("Выберите или укажите амплуа игрока.")
created_id = create_player_admin(
team_id=team_id,
full_name=full_name,
first_name=first_name,
last_name=last_name,
external_id=external_id,
number=values.get("number", ""),
position=position,
birth_date=values.get("birth_date", ""),
photo=values.get("photo", ""),
video=values.get("video", ""),
height_cm=_admin_create_optional_int(values.get("height_cm"), "Рост", 1),
weight_kg=_admin_create_optional_int(values.get("weight_kg"), "Вес", 1),
games=_admin_create_optional_int(values.get("games"), "Игры", 0) or 0,
goals=_admin_create_optional_int(values.get("goals"), "Голы", 0) or 0,
penaltys=_admin_create_optional_int(values.get("penaltys"), "Голы с пенальти", 0) or 0,
assists=_admin_create_optional_int(values.get("assists"), "Передачи", 0) or 0,
yellows=_admin_create_optional_int(values.get("yellows"), "Жёлтые карточки", 0) or 0,
reds=_admin_create_optional_int(values.get("reds"), "Красные карточки", 0) or 0,
is_active=is_active,
photo_enabled="photo_enabled" in form,
)
redirect_url = f"/admin/db/create?entity=player&created_id={created_id}"
elif entity_type == "coach":
team_id = _admin_create_required_int(values.get("team_id"), "Команда", 1)
role = values.get("role", "").strip()
if not role:
raise ValueError("Заполните должность / амплуа тренера.")
created_id = create_coach_admin(
team_id=team_id,
full_name=full_name,
first_name=first_name,
last_name=last_name,
external_id=external_id,
birth_date=values.get("birth_date", ""),
role=role,
is_active=is_active,
)
redirect_url = f"/admin/db/create?entity=coach&created_id={created_id}"
else:
created_id = create_referee_admin(
full_name=full_name,
first_name=first_name,
last_name=last_name,
middle_name=values.get("middle_name", ""),
city=values.get("city", ""),
external_id=external_id,
is_active=is_active,
)
redirect_url = f"/admin/db/create?entity=referee&created_id={created_id}"
log_action(
request,
action="admin_db_entity_created",
entity_type=entity_type,
entity_id=created_id,
details={"full_name": full_name, "external_id": external_id},
)
return RedirectResponse(url=redirect_url, status_code=303)
except ValueError as exc:
return _render_admin_entity_create(
request=request,
entity_type=entity_type,
error=str(exc),
form_values=values,
status_code=400,
)
except Exception as exc:
traceback.print_exc()
error_text = "Не удалось создать запись."
if "duplicate key" in str(exc).lower() or "unique constraint" in str(exc).lower():
error_text += " Запись с таким External ID уже существует."
else:
error_text += f" Ошибка базы данных: {str(exc)}"
return _render_admin_entity_create(
request=request,
entity_type=entity_type,
error=error_text,
form_values=values,
status_code=500,
)
@app.get("/admin/db/players", response_class=HTMLResponse)
def admin_db_players(
request: Request,