first commit
This commit is contained in:
460
repositories/match_lineup_repository.py
Normal file
460
repositories/match_lineup_repository.py
Normal file
@@ -0,0 +1,460 @@
|
||||
from db import get_connection
|
||||
from repositories.match_view_repository import get_match_lineups_grouped
|
||||
from repositories.match_coach_repository import get_match_coaches_grouped
|
||||
|
||||
|
||||
def replace_match_lineups(match_id: int, rows: list[dict]) -> None:
|
||||
delete_query = "DELETE FROM match_lineups WHERE match_id = %s;"
|
||||
insert_query = """
|
||||
INSERT INTO match_lineups (
|
||||
match_id,
|
||||
team_id,
|
||||
player_id,
|
||||
player_name,
|
||||
number,
|
||||
position,
|
||||
is_captain,
|
||||
lineup_type,
|
||||
source,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW());
|
||||
"""
|
||||
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(delete_query, (match_id,))
|
||||
for row in rows:
|
||||
cur.execute(
|
||||
insert_query,
|
||||
(
|
||||
row["match_id"],
|
||||
row["team_id"],
|
||||
row.get("player_id"),
|
||||
row["player_name"],
|
||||
row.get("number"),
|
||||
row.get("position"),
|
||||
row.get("is_captain"),
|
||||
row["lineup_type"],
|
||||
row.get("source", "parser"),
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
except Exception:
|
||||
conn.rollback()
|
||||
raise
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def _player_to_editor_dict(p: dict) -> dict:
|
||||
return {
|
||||
"player_id": p.get("player_id"),
|
||||
"player_name": p.get("player_name")
|
||||
or f"{p.get('last_name', '')} {p.get('first_name', '')}".strip(),
|
||||
"last_name": p.get("last_name", "") or p.get("player_name", "") or "",
|
||||
"first_name": p.get("first_name", "") or "",
|
||||
"number": str(p.get("number", "") or ""),
|
||||
"position": p.get("position", "") or "",
|
||||
"is_captain": bool(p.get("is_captain")),
|
||||
}
|
||||
|
||||
|
||||
def _coach_to_editor_dict(c: dict) -> dict:
|
||||
return {
|
||||
"coach_id": c.get("coach_id"),
|
||||
"coach_name": c.get("coach_name", "") or "",
|
||||
"role": c.get("role", "") or "",
|
||||
}
|
||||
|
||||
|
||||
def get_match_lineup_for_editor(
|
||||
match_id: int,
|
||||
home_team_id: int,
|
||||
away_team_id: int,
|
||||
) -> dict:
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT
|
||||
mlp.side,
|
||||
mlp.role,
|
||||
mlp.sort_order,
|
||||
p.id AS player_id,
|
||||
COALESCE(p.full_name, TRIM(COALESCE(p.last_name, '') || ' ' || COALESCE(p.first_name, ''))) AS player_name,
|
||||
COALESCE(p.last_name, '') AS last_name,
|
||||
COALESCE(p.first_name, '') AS first_name,
|
||||
COALESCE(mlp.number::text, '') AS number,
|
||||
COALESCE(mlp.position, '') AS position,
|
||||
COALESCE(mlp.is_captain, FALSE) AS is_captain
|
||||
FROM match_lineup_players mlp
|
||||
JOIN players p
|
||||
ON p.id = mlp.player_id
|
||||
WHERE mlp.match_id = %s
|
||||
ORDER BY mlp.side, mlp.role, mlp.sort_order, mlp.id
|
||||
""",
|
||||
(match_id,),
|
||||
)
|
||||
player_rows = cur.fetchall()
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT
|
||||
mc.side,
|
||||
mc.sort_order,
|
||||
c.id AS coach_id,
|
||||
COALESCE(c.player, '') AS coach_name,
|
||||
COALESCE(mc.role, c.amplua, '') AS role
|
||||
FROM match_coaches mc
|
||||
JOIN coaches c
|
||||
ON c.id = mc.coach_id
|
||||
WHERE mc.match_id = %s
|
||||
ORDER BY mc.side, mc.sort_order, mc.id
|
||||
""",
|
||||
(match_id,),
|
||||
)
|
||||
coach_rows = cur.fetchall()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
result = {
|
||||
"home_starting": [],
|
||||
"home_bench": [],
|
||||
"away_starting": [],
|
||||
"away_bench": [],
|
||||
"home_coaches": [],
|
||||
"away_coaches": [],
|
||||
}
|
||||
|
||||
# Если редактор уже сохранял состав — берём игроков из новой таблицы
|
||||
if player_rows:
|
||||
for row in player_rows:
|
||||
player = {
|
||||
"player_id": row[3],
|
||||
"player_name": row[4] or "",
|
||||
"last_name": row[5] or "",
|
||||
"first_name": row[6] or "",
|
||||
"number": row[7] or "",
|
||||
"position": row[8] or "",
|
||||
"is_captain": bool(row[9]),
|
||||
}
|
||||
|
||||
side = row[0]
|
||||
role = row[1]
|
||||
|
||||
if side == "home" and role == "starting":
|
||||
result["home_starting"].append(player)
|
||||
elif side == "home" and role == "bench":
|
||||
result["home_bench"].append(player)
|
||||
elif side == "away" and role == "starting":
|
||||
result["away_starting"].append(player)
|
||||
elif side == "away" and role == "bench":
|
||||
result["away_bench"].append(player)
|
||||
else:
|
||||
# Иначе берём загруженный с сайта состав из старой таблицы
|
||||
lineups = get_match_lineups_grouped(
|
||||
match_id=match_id,
|
||||
home_team_id=home_team_id,
|
||||
away_team_id=away_team_id,
|
||||
)
|
||||
|
||||
result["home_starting"] = [
|
||||
_player_to_editor_dict(p) for p in lineups.get("home_starting", [])
|
||||
]
|
||||
result["home_bench"] = [
|
||||
_player_to_editor_dict(p) for p in lineups.get("home_bench", [])
|
||||
]
|
||||
result["away_starting"] = [
|
||||
_player_to_editor_dict(p) for p in lineups.get("away_starting", [])
|
||||
]
|
||||
result["away_bench"] = [
|
||||
_player_to_editor_dict(p) for p in lineups.get("away_bench", [])
|
||||
]
|
||||
|
||||
# Тренеров берём из match_coaches, если они уже есть
|
||||
if coach_rows:
|
||||
for row in coach_rows:
|
||||
coach = {
|
||||
"coach_id": row[2],
|
||||
"coach_name": row[3] or "",
|
||||
"role": row[4] or "",
|
||||
}
|
||||
|
||||
side = row[0]
|
||||
if side == "home":
|
||||
result["home_coaches"].append(coach)
|
||||
elif side == "away":
|
||||
result["away_coaches"].append(coach)
|
||||
else:
|
||||
coaches = get_match_coaches_grouped(
|
||||
match_id=match_id,
|
||||
home_team_id=home_team_id,
|
||||
away_team_id=away_team_id,
|
||||
)
|
||||
|
||||
result["home_coaches"] = [
|
||||
_coach_to_editor_dict(c) for c in coaches.get("home", [])
|
||||
]
|
||||
result["away_coaches"] = [
|
||||
_coach_to_editor_dict(c) for c in coaches.get("away", [])
|
||||
]
|
||||
|
||||
return result
|
||||
|
||||
def get_match_lineup_for_vmix(
|
||||
match_id: int,
|
||||
home_team_id: int,
|
||||
away_team_id: int,
|
||||
) -> dict:
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
# Сначала пробуем взять ручную версию из редактора
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT
|
||||
mlp.side,
|
||||
mlp.role,
|
||||
mlp.sort_order,
|
||||
p.id AS player_id,
|
||||
COALESCE(
|
||||
p.full_name,
|
||||
TRIM(COALESCE(p.last_name, '') || ' ' || COALESCE(p.first_name, ''))
|
||||
) AS player_name,
|
||||
COALESCE(p.last_name, '') AS last_name,
|
||||
COALESCE(p.first_name, '') AS first_name,
|
||||
COALESCE(mlp.number::text, '') AS number,
|
||||
COALESCE(mlp.position, '') AS position,
|
||||
COALESCE(mlp.is_captain, FALSE) AS is_captain,
|
||||
COALESCE(p.position, '') AS pos
|
||||
FROM match_lineup_players mlp
|
||||
JOIN players p
|
||||
ON p.id = mlp.player_id
|
||||
WHERE mlp.match_id = %s
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN LOWER(COALESCE(p.position, '')) IN ('вр', 'вр.', 'gk', 'goalkeeper', 'вратарь') THEN 0
|
||||
ELSE 1
|
||||
END,
|
||||
CASE
|
||||
WHEN COALESCE(p.number::text, '') ~ '^[0-9]+$' THEN p.number::integer
|
||||
ELSE 999
|
||||
END,
|
||||
COALESCE(p.last_name, ''),
|
||||
COALESCE(p.first_name, ''),
|
||||
p.id
|
||||
""",
|
||||
(match_id,),
|
||||
)
|
||||
player_rows = cur.fetchall()
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT
|
||||
mc.side,
|
||||
mc.sort_order,
|
||||
c.id AS coach_id,
|
||||
COALESCE(c.player, '') AS coach_name,
|
||||
COALESCE(mc.role, c.amplua, '') AS role
|
||||
FROM match_coaches mc
|
||||
JOIN coaches c
|
||||
ON c.id = mc.coach_id
|
||||
WHERE mc.match_id = %s
|
||||
ORDER BY mc.side, mc.sort_order, mc.id
|
||||
""",
|
||||
(match_id,),
|
||||
)
|
||||
coach_rows = cur.fetchall()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
result = {
|
||||
"home_starting": [],
|
||||
"home_bench": [],
|
||||
"away_starting": [],
|
||||
"away_bench": [],
|
||||
"home_coaches": [],
|
||||
"away_coaches": [],
|
||||
}
|
||||
|
||||
# 1. Если есть ручной состав — берём его
|
||||
if player_rows:
|
||||
for row in player_rows:
|
||||
player = {
|
||||
"player_id": row[3],
|
||||
"player_name": row[4] or "",
|
||||
"last_name": row[5] or "",
|
||||
"first_name": row[6] or "",
|
||||
"number": row[7] or "",
|
||||
"position": row[8] or "",
|
||||
"is_captain": bool(row[9]),
|
||||
"pos": row[10] or "",
|
||||
}
|
||||
|
||||
side = row[0]
|
||||
role = row[1]
|
||||
|
||||
if side == "home" and role == "starting":
|
||||
result["home_starting"].append(player)
|
||||
elif side == "home" and role == "bench":
|
||||
result["home_bench"].append(player)
|
||||
elif side == "away" and role == "starting":
|
||||
result["away_starting"].append(player)
|
||||
elif side == "away" and role == "bench":
|
||||
result["away_bench"].append(player)
|
||||
|
||||
else:
|
||||
# 2. Иначе — fallback на сайт
|
||||
lineups = get_match_lineups_grouped(
|
||||
match_id=match_id,
|
||||
home_team_id=home_team_id,
|
||||
away_team_id=away_team_id,
|
||||
)
|
||||
|
||||
result["home_starting"] = lineups.get("home_starting", [])
|
||||
result["home_bench"] = lineups.get("home_bench", [])
|
||||
result["away_starting"] = lineups.get("away_starting", [])
|
||||
result["away_bench"] = lineups.get("away_bench", [])
|
||||
|
||||
if coach_rows:
|
||||
for row in coach_rows:
|
||||
coach = {
|
||||
"coach_id": row[2],
|
||||
"coach_name": row[3] or "",
|
||||
"role": row[4] or "",
|
||||
}
|
||||
|
||||
if row[0] == "home":
|
||||
result["home_coaches"].append(coach)
|
||||
elif row[0] == "away":
|
||||
result["away_coaches"].append(coach)
|
||||
else:
|
||||
coaches = get_match_coaches_grouped(
|
||||
match_id=match_id,
|
||||
home_team_id=home_team_id,
|
||||
away_team_id=away_team_id,
|
||||
)
|
||||
result["home_coaches"] = coaches.get("home", [])
|
||||
result["away_coaches"] = coaches.get("away", [])
|
||||
|
||||
return result
|
||||
|
||||
def save_match_lineup_for_editor(
|
||||
match_id: int,
|
||||
home_team_id: int,
|
||||
away_team_id: int,
|
||||
home_starting: list[dict],
|
||||
home_bench: list[dict],
|
||||
away_starting: list[dict],
|
||||
away_bench: list[dict],
|
||||
home_coaches: list[dict],
|
||||
away_coaches: list[dict],
|
||||
) -> None:
|
||||
def is_goalkeeper(position: str) -> bool:
|
||||
if not position:
|
||||
return False
|
||||
return str(position).strip().lower() in {
|
||||
"вр", "вр.", "вратарь", "gk", "goalkeeper"
|
||||
}
|
||||
|
||||
def safe_number(value) -> int:
|
||||
try:
|
||||
return int(str(value).strip())
|
||||
except Exception:
|
||||
return 9999
|
||||
|
||||
def lineup_sort_key(player: dict):
|
||||
return (
|
||||
0 if is_goalkeeper(player.get("position", "")) else 1,
|
||||
safe_number(player.get("number")),
|
||||
(player.get("last_name") or player.get("player_name") or "").lower(),
|
||||
(player.get("first_name") or "").lower(),
|
||||
player.get("player_id") or 0,
|
||||
)
|
||||
|
||||
# Пересортировка перед сохранением
|
||||
home_starting = sorted(home_starting, key=lineup_sort_key)
|
||||
home_bench = sorted(home_bench, key=lineup_sort_key)
|
||||
away_starting = sorted(away_starting, key=lineup_sort_key)
|
||||
away_bench = sorted(away_bench, key=lineup_sort_key)
|
||||
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"DELETE FROM match_lineup_players WHERE match_id = %s",
|
||||
(match_id,),
|
||||
)
|
||||
cur.execute(
|
||||
"DELETE FROM match_coaches WHERE match_id = %s",
|
||||
(match_id,),
|
||||
)
|
||||
|
||||
def insert_players(side: str, role: str, players: list[dict]) -> None:
|
||||
for sort_order, p in enumerate(players, start=1):
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO match_lineup_players (
|
||||
match_id,
|
||||
side,
|
||||
role,
|
||||
sort_order,
|
||||
player_id,
|
||||
number,
|
||||
position,
|
||||
is_captain
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
""",
|
||||
(
|
||||
match_id,
|
||||
side,
|
||||
role,
|
||||
sort_order,
|
||||
p.get("player_id"),
|
||||
p.get("number", "") or None,
|
||||
p.get("position", "") or None,
|
||||
bool(p.get("is_captain")),
|
||||
),
|
||||
)
|
||||
|
||||
def insert_coaches(side: str, coaches: list[dict]) -> None:
|
||||
for sort_order, c in enumerate(coaches, start=1):
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO match_coaches (
|
||||
match_id,
|
||||
side,
|
||||
sort_order,
|
||||
coach_id,
|
||||
role
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
""",
|
||||
(
|
||||
match_id,
|
||||
side,
|
||||
sort_order,
|
||||
c.get("coach_id"),
|
||||
c.get("role", "") or None,
|
||||
),
|
||||
)
|
||||
|
||||
insert_players("home", "starting", home_starting)
|
||||
insert_players("home", "bench", home_bench)
|
||||
insert_players("away", "starting", away_starting)
|
||||
insert_players("away", "bench", away_bench)
|
||||
|
||||
insert_coaches("home", home_coaches)
|
||||
insert_coaches("away", away_coaches)
|
||||
|
||||
conn.commit()
|
||||
except Exception:
|
||||
conn.rollback()
|
||||
raise
|
||||
finally:
|
||||
conn.close()
|
||||
Reference in New Issue
Block a user