first commit

This commit is contained in:
2026-04-20 11:56:11 +03:00
commit 8d80fadb56
103 changed files with 19756 additions and 0 deletions

View File

@@ -0,0 +1,373 @@
from db import get_connection
from repositories.team_repository import get_team_id_by_external_id
def normalize_birth_date_for_input(value) -> str:
if not value:
return ""
text = str(value).strip()
if not text:
return ""
# Уже нормальный формат для input[type=date]
if len(text) == 10 and text[4] == "-" and text[7] == "-":
return text
# Формат ДД.ММ.ГГГГ -> YYYY-MM-DD
if len(text) == 10 and text[2] == "." and text[5] == ".":
dd, mm, yyyy = text.split(".")
return f"{yyyy}-{mm}-{dd}"
return ""
def upsert_player(
external_id: str,
team_external_id: str,
player: str,
lastname: str = "",
name: str = "",
number: str = "",
pos: str = "",
amplua: str = "",
born: str = "",
games: int = 0,
goals: int = 0,
penaltys: int = 0,
assists: int = 0,
yellows: int = 0,
reds: int = 0,
is_active: bool = True,
) -> None:
team_id = get_team_id_by_external_id(str(team_external_id).strip())
if team_id is None:
raise ValueError(f"Team not found by external_id: {team_external_id}")
query = """
INSERT INTO players (
external_id,
team_id,
full_name,
first_name,
last_name,
number,
position,
is_active,
pos,
amplua,
born,
games,
goals,
penaltys,
assists,
yellows,
reds,
created_at,
updated_at
)
VALUES (
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
NOW(), NOW()
)
ON CONFLICT (external_id)
DO UPDATE SET
team_id = EXCLUDED.team_id,
full_name = EXCLUDED.full_name,
first_name = EXCLUDED.first_name,
last_name = EXCLUDED.last_name,
number = EXCLUDED.number,
position = EXCLUDED.position,
is_active = EXCLUDED.is_active,
pos = EXCLUDED.pos,
amplua = EXCLUDED.amplua,
born = EXCLUDED.born,
games = EXCLUDED.games,
goals = EXCLUDED.goals,
penaltys = EXCLUDED.penaltys,
assists = EXCLUDED.assists,
yellows = EXCLUDED.yellows,
reds = EXCLUDED.reds,
updated_at = NOW();
"""
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(
query,
(
str(external_id).strip(),
team_id,
player.strip(),
name.strip(),
lastname.strip(),
str(number).strip(),
amplua.strip(),
is_active,
pos.strip(),
amplua.strip(),
born.strip(),
games,
goals,
penaltys,
assists,
yellows,
reds,
),
)
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()
def get_match_by_external_id(external_id: str):
query = """
SELECT id, external_id, home_team_id, away_team_id
FROM matches
WHERE external_id = %s
LIMIT 1;
"""
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(query, (str(external_id).strip(),))
return cur.fetchone()
finally:
conn.close()
def mark_match_parsed(external_id: str) -> None:
query = """
UPDATE matches
SET parsed = TRUE,
parse_error = NULL,
updated_at = NOW()
WHERE external_id = %s;
"""
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(query, (str(external_id).strip(),))
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()
def mark_match_parse_error(external_id: str, error_text: str) -> None:
query = """
UPDATE matches
SET parsed = FALSE,
parse_error = %s,
updated_at = NOW()
WHERE external_id = %s;
"""
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(query, (str(error_text)[:2000], str(external_id).strip()))
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()
def get_player_id_by_name_and_team(full_name: str, team_id: int) -> int | None:
query = """
SELECT id
FROM players
WHERE team_id = %s
AND LOWER(full_name) = LOWER(%s)
LIMIT 1;
"""
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(query, (team_id, full_name.strip()))
row = cur.fetchone()
return row[0] if row else None
finally:
conn.close()
def get_player_id_by_external_id(external_id: str) -> int | None:
query = """
SELECT id
FROM players
WHERE external_id = %s
LIMIT 1;
"""
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(query, (str(external_id).strip(),))
row = cur.fetchone()
return row[0] if row else None
finally:
conn.close()
from db import get_connection
def search_players_for_admin(q: str = "") -> list[dict]:
conn = get_connection()
try:
with conn.cursor() as cur:
if q.strip():
pattern = f"%{q.strip()}%"
cur.execute(
"""
SELECT
p.id,
p.full_name,
p.first_name,
p.last_name,
p.external_id,
p.position
FROM players p
WHERE
p.full_name ILIKE %s
OR p.first_name ILIKE %s
OR p.last_name ILIKE %s
OR COALESCE(p.external_id, '') ILIKE %s
ORDER BY p.full_name ASC, p.id ASC
LIMIT 200
""",
(pattern, pattern, pattern, pattern),
)
else:
cur.execute(
"""
SELECT
p.id,
p.full_name,
p.first_name,
p.last_name,
p.external_id,
p.position
FROM players p
ORDER BY p.id DESC
LIMIT 200
"""
)
rows = cur.fetchall()
return [
{
"id": row[0],
"full_name": row[1] or "",
"first_name": row[2] or "",
"last_name": row[3] or "",
"external_id": row[4] or "",
"position": row[5] or "",
}
for row in rows
]
finally:
conn.close()
def get_player_by_id(player_id: int) -> dict | None:
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(
"""
SELECT
p.id,
p.full_name,
p.first_name,
p.last_name,
p.external_id,
p.position,
p.born,
p.photo,
p.video
FROM players p
WHERE p.id = %s
LIMIT 1
""",
(player_id,),
)
row = cur.fetchone()
if not row:
return None
return {
"id": row[0],
"full_name": row[1] or "",
"first_name": row[2] or "",
"last_name": row[3] or "",
"external_id": row[4] or "",
"position": row[5] or "",
"birth_date": normalize_birth_date_for_input(row[6]),
"photo": row[7] or "",
"video": row[8] or "",
}
finally:
conn.close()
def update_player_admin(
player_id: int,
full_name: str = "",
first_name: str = "",
last_name: str = "",
external_id: str = "",
position: str = "",
birth_date: str = "",
photo: str = "",
video: str = "",
) -> None:
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(
"""
UPDATE players
SET
full_name = %s,
first_name = %s,
last_name = %s,
external_id = NULLIF(%s, ''),
position = %s,
born = NULLIF(%s, '')::date,
photo = NULLIF(%s, ''),
video = NULLIF(%s, '')
WHERE id = %s
""",
(
full_name.strip(),
first_name.strip(),
last_name.strip(),
external_id.strip(),
position.strip(),
birth_date.strip(),
photo.strip(),
video.strip(),
player_id,
),
)
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()