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,178 @@
from db import get_connection
def create_match_clock_table() -> None:
query = """
CREATE TABLE IF NOT EXISTS match_clocks (
match_id BIGINT PRIMARY KEY REFERENCES matches(id) ON DELETE CASCADE,
current_period VARCHAR(10) NOT NULL DEFAULT '1H',
timer_running BOOLEAN NOT NULL DEFAULT FALSE,
accumulated_seconds INTEGER NOT NULL DEFAULT 0,
period_started_at TIMESTAMP NULL,
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
"""
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(query)
conn.commit()
finally:
conn.close()
def ensure_match_clock(match_id: int) -> None:
query = """
INSERT INTO match_clocks (match_id, current_period, timer_running, accumulated_seconds, period_started_at, updated_at)
VALUES (%s, '1H', FALSE, 0, NULL, NOW())
ON CONFLICT (match_id) DO NOTHING;
"""
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(query, (match_id,))
conn.commit()
finally:
conn.close()
def get_match_clock(match_id: int) -> dict:
ensure_match_clock(match_id)
query = """
SELECT
match_id,
current_period,
timer_running,
accumulated_seconds,
period_started_at,
CASE
WHEN timer_running = TRUE AND period_started_at IS NOT NULL
THEN accumulated_seconds + FLOOR(EXTRACT(EPOCH FROM (NOW() - period_started_at)))::INT
ELSE accumulated_seconds
END AS current_seconds
FROM match_clocks
WHERE match_id = %s;
"""
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(query, (match_id,))
row = cur.fetchone()
finally:
conn.close()
return {
"match_id": row[0],
"current_period": row[1],
"timer_running": bool(row[2]),
"accumulated_seconds": row[3] or 0,
"period_started_at": row[4].isoformat() if row[4] else None,
"current_seconds": row[5] or 0,
}
def update_match_clock(match_id: int, action: str, seconds: int | None = None) -> dict:
ensure_match_clock(match_id)
conn = get_connection()
try:
with conn.cursor() as cur:
if action == "start_1h":
cur.execute(
"""
UPDATE match_clocks
SET current_period = '1H', timer_running = TRUE, accumulated_seconds = 0,
period_started_at = NOW(), updated_at = NOW()
WHERE match_id = %s;
""",
(match_id,),
)
elif action == "pause":
cur.execute(
"""
UPDATE match_clocks
SET accumulated_seconds = CASE
WHEN timer_running = TRUE AND period_started_at IS NOT NULL
THEN accumulated_seconds + FLOOR(EXTRACT(EPOCH FROM (NOW() - period_started_at)))::INT
ELSE accumulated_seconds
END,
timer_running = FALSE,
period_started_at = NULL,
updated_at = NOW()
WHERE match_id = %s;
""",
(match_id,),
)
elif action == "halftime":
cur.execute(
"""
UPDATE match_clocks
SET accumulated_seconds = CASE
WHEN timer_running = TRUE AND period_started_at IS NOT NULL
THEN accumulated_seconds + FLOOR(EXTRACT(EPOCH FROM (NOW() - period_started_at)))::INT
ELSE accumulated_seconds
END,
current_period = 'HT',
timer_running = FALSE,
period_started_at = NULL,
updated_at = NOW()
WHERE match_id = %s;
""",
(match_id,),
)
elif action == "start_2h":
cur.execute(
"""
UPDATE match_clocks
SET current_period = '2H', timer_running = TRUE,
accumulated_seconds = CASE WHEN accumulated_seconds < 2700 THEN 2700 ELSE accumulated_seconds END,
period_started_at = NOW(),
updated_at = NOW()
WHERE match_id = %s;
""",
(match_id,),
)
elif action == "finish":
cur.execute(
"""
UPDATE match_clocks
SET accumulated_seconds = CASE
WHEN timer_running = TRUE AND period_started_at IS NOT NULL
THEN accumulated_seconds + FLOOR(EXTRACT(EPOCH FROM (NOW() - period_started_at)))::INT
ELSE accumulated_seconds
END,
current_period = 'FT',
timer_running = FALSE,
period_started_at = NULL,
updated_at = NOW()
WHERE match_id = %s;
""",
(match_id,),
)
elif action == "set_time":
if seconds is None or not isinstance(seconds, int) or seconds < 0:
raise ValueError("invalid_seconds")
cur.execute(
"""
UPDATE match_clocks
SET accumulated_seconds = %s,
period_started_at = CASE WHEN timer_running THEN NOW() ELSE NULL END,
updated_at = NOW()
WHERE match_id = %s;
""",
(seconds, match_id),
)
else:
raise ValueError("invalid_clock_action")
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()
return get_match_clock(match_id)