From e301af9fa346168f3e3ab0f528deb7a28b9f7369 Mon Sep 17 00:00:00 2001 From: Fruktus Date: Fri, 15 May 2026 18:41:09 +0200 Subject: [PATCH] feat: add tournament helpers - tz-aoe, pairwise and getting tournament by name --- server/src/QRServer/common/utils.py | 38 ++++++++++++++++++++++++----- server/src/QRServer/db/connector.py | 26 +++++++++++++++++++- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/server/src/QRServer/common/utils.py b/server/src/QRServer/common/utils.py index 4056bddd..d1263a8d 100644 --- a/server/src/QRServer/common/utils.py +++ b/server/src/QRServer/common/utils.py @@ -1,7 +1,16 @@ import hashlib -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone import secrets import string +from itertools import zip_longest + + +def tz_aoe() -> timezone: + """ + Returns: + 'Anywhere on Earth' timezone + """ + return timezone(timedelta(hours=-12), name='AOE') def is_guest(username: str, password: str) -> bool: @@ -17,9 +26,9 @@ def is_guest(username: str, password: str) -> bool: def make_month_dates(month: int, year: int) -> tuple[datetime, datetime]: """ - Returns: - a tuple consisting of the first day of the given month and year, and \ - the first day of the next month (incrementing year if needed) + Returns: + a tuple consisting of the first day of the given month and year, and \ + the first day of the next month (incrementing year if needed) """ return \ datetime(year, month, 1, tzinfo=timezone.utc), \ @@ -36,8 +45,8 @@ def generate_random_password(length: int) -> str: def make_month_dates_range(start_date: datetime, end_date: datetime) -> list[datetime]: """ - Returns: - a list of datetimes for each month (with day = 1) between the start_date and end_date (both inclusive) + Returns: + a list of datetimes for each month (with day = 1) between the start_date and end_date (both inclusive) """ if start_date > end_date: return [] @@ -76,3 +85,20 @@ def calculate_new_ratings(winner_rating: int, loser_rating: int, k_factor: int = new_loser_rating = loser_rating + k_factor * (0 - expected_score_2) return (round(new_winner_rating), round(new_loser_rating)) + + +def pairwise(seq: list[any])-> list[tuple[any, any]]: + """ + Group elements from a sequence into consecutive pairs. + + Elements are taken two at a time in order: + [a, b, c, d] -> [(a, b), (c, d)] + + If the sequence contains an odd number of elements, the final pair + is padded with `None`: + [a, b, c] -> [(a, b), (c, None)] + + Returns: + A list of 2-tuples containing consecutive elements from `seq`. + """ + return list(zip_longest(seq[::2], seq[1::2])) diff --git a/server/src/QRServer/db/connector.py b/server/src/QRServer/db/connector.py index d091acde..4b427b0e 100644 --- a/server/src/QRServer/db/connector.py +++ b/server/src/QRServer/db/connector.py @@ -658,7 +658,7 @@ async def remove_participant(self, tournament_id, user_id) -> bool: await self.conn.commit() return bool(c.rowcount) - async def add_duel(self, tournament_id: str, duel_idx: int, active_until: datetime, + async def add_duel(self, tournament_id: str, duel_idx: int, active_until: datetime | None, user1_id: str | None, user2_id: str | None) -> bool: """ Returns: @@ -677,9 +677,33 @@ async def add_duel(self, tournament_id: str, duel_idx: int, active_until: dateti ( tournament_id, duel_idx, + int(active_until.timestamp()) if active_until else None, + user1_id, + user2_id, + ) + ) + await self.conn.commit() + return bool(c.rowcount) + + async def update_duel(self, tournament_id: str, duel_idx: int, active_until: datetime, + user1_id: str | None, user2_id: str | None) -> bool: + """ + Returns: + bool: True if succesfully updated the duel + """ + c = await self.conn.cursor() + await c.execute( + "update tournament_duels" + " set active_until = ?," + " user1_id = ?," + " user2_id = ?" + " where tournament_id = ? and duel_idx = ?", + ( int(active_until.timestamp()), user1_id, user2_id, + tournament_id, + duel_idx, ) ) await self.conn.commit()