добавил возможность администраторам создавать игроков, тренеров и судей вручную
This commit is contained in:
186
app.py
186
app.py
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user