implement registering and unregistering from tournament

This commit is contained in:
David Rodenkirchen 2026-02-03 13:20:07 +01:00
parent fffb607b16
commit caacd8bbc1
4 changed files with 75 additions and 56 deletions

View File

@ -43,16 +43,28 @@ class TournamentDetailsPage(Component):
self.loading = True self.loading = True
if not self.user: if not self.user:
return return
self.is_success = True
self.message = f"Erfolgreich angemeldet!" # ToDo: Hook into Tournament Service try:
await self.session[TournamentService].register_user_for_tournament(self.user.user_id, self.tournament.id)
self.is_success = True
self.message = f"Erfolgreich angemeldet!"
except Exception as e:
self.is_success = False
self.message = f"Fehler: {e}"
self.loading = False self.loading = False
async def unregister_pressed(self) -> None: async def unregister_pressed(self) -> None:
self.loading = True self.loading = True
if not self.user: if not self.user:
return return
self.is_success = True
self.message = f"Erfolgreich abgemeldet!" # ToDo: Hook into Tournament Service try:
await self.session[TournamentService].unregister_user_from_tournament(self.user.user_id, self.tournament.id)
self.is_success = True
self.message = f"Erfolgreich abgemeldet!"
except Exception as e:
self.is_success = False
self.message = f"Fehler: {e}"
self.loading = False self.loading = False
async def tree_button_clicked(self) -> None: async def tree_button_clicked(self) -> None:

View File

@ -931,3 +931,37 @@ class DatabaseService:
tournaments.append(current_tournament) tournaments.append(current_tournament)
return tournaments return tournaments
async def add_participant_to_tournament(self, participant: Participant, tournament: Tournament) -> None:
async with self._connection_pool.acquire() as conn:
async with conn.cursor(aiomysql.Cursor) as cursor:
try:
await cursor.execute(
"INSERT INTO tournament_participants (tournament_id, user_id, participant_type) VALUES (%s, %s, %s);",
(tournament.id, participant.id, participant.participant_type.name)
)
await conn.commit()
except aiomysql.InterfaceError:
pool_init_result = await self.init_db_pool()
if not pool_init_result:
raise NoDatabaseConnectionError
return await self.add_participant_to_tournament(participant, tournament)
except Exception as e:
logger.warning(f"Error adding participant to tournament: {e}")
async def remove_participant_from_tournament(self, participant: Participant, tournament: Tournament) -> None:
async with self._connection_pool.acquire() as conn:
async with conn.cursor(aiomysql.Cursor) as cursor:
try:
await cursor.execute(
"DELETE FROM tournament_participants WHERE (tournament_id = %s AND user_id = %s);",
(tournament.id, participant.id)
)
await conn.commit()
except aiomysql.InterfaceError:
pool_init_result = await self.init_db_pool()
if not pool_init_result:
raise NoDatabaseConnectionError
return await self.remove_participant_from_tournament(participant, tournament)
except Exception as e:
logger.warning(f"Error removing participant from tournament: {e}")

View File

@ -1,76 +1,45 @@
from asyncio import sleep
from datetime import datetime
from typing import Optional from typing import Optional
from src.ezgg_lan_manager.services.DatabaseService import DatabaseService from src.ezgg_lan_manager.services.DatabaseService import DatabaseService
from src.ezgg_lan_manager.services.UserService import UserService from src.ezgg_lan_manager.services.UserService import UserService
from src.ezgg_lan_manager.types.Participant import Participant from src.ezgg_lan_manager.types.Participant import Participant
from src.ezgg_lan_manager.types.Tournament import Tournament from src.ezgg_lan_manager.types.Tournament import Tournament
from src.ezgg_lan_manager.types.TournamentBase import GameTitle, TournamentFormat, TournamentStatus, ParticipantType from src.ezgg_lan_manager.types.TournamentBase import ParticipantType, TournamentError
DEV_LOREM_IPSUM = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Dieses LAN-Turnier bringt Spieler aus verschiedenen Regionen zusammen, um gemeinsam spannende Matches zu erleben. Tastaturen klappern, Monitore leuchten und die Stimmung ist von Anfang an von Vorfreude und Ehrgeiz geprägt.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. In intensiven Partien zählen Strategie, Reaktion und Teamarbeit. Zwischen den Spielen wird gefachsimpelt, gelacht und neue Kontakte entstehen, während Server stabil laufen und das Netzwerk dauerhaft gefordert ist.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Wenn die Finalspiele beginnen, steigt die Spannung spürbar. Am Ende bleiben faire Wettkämpfe, gemeinsame Erinnerungen und das Gefühl, Teil einer starken Community gewesen zu sein.
"""
class TournamentService: class TournamentService:
def __init__(self, db_service: DatabaseService, user_service: UserService) -> None: def __init__(self, db_service: DatabaseService, user_service: UserService) -> None:
self._db_service = db_service self._db_service = db_service
self._user_service = user_service self._user_service = user_service
# Crude cache mechanism. If performance suffers, maybe implement a queue with Single-Owner-Pattern or a Lock
self._cache: dict[int, Tournament] = {} self._cache: dict[int, Tournament] = {}
self._cache_dirty: bool = True # Setting this flag invokes cache update on next read self._cache_dirty: bool = True # Setting this flag invokes cache update on next read
# This overrides the database access and is meant for easy development.
# Set to None before merging back into main.
self._dev_data = [
Tournament(
1,
"Rocket League 3vs3",
DEV_LOREM_IPSUM,
GameTitle(
"Rocket League",
"Rocket League is a high-powered hybrid of arcade-style soccer and vehicular mayhem with easy-to-understand controls and fluid, physics-driven competition.",
"https://steamcommunity.com/app/252950",
"rl.png"
),
TournamentFormat.SINGLE_ELIMINATION_BO_3,
datetime(2026, 5, 8, 18, 0, 0),
TournamentStatus.OPEN,
[Participant(30, ParticipantType.PLAYER)],
None,
[],
8
),
Tournament(
2,
"Worms Armageddon 1vs1",
DEV_LOREM_IPSUM,
GameTitle(
"Worms Armageddon",
"2D turn-based artillery strategy game.",
"https://store.steampowered.com/app/217200/Worms_Armageddon/",
"worms.png"
),
TournamentFormat.SINGLE_ELIMINATION_BO_1,
datetime(2026, 5, 8, 18, 30, 0),
TournamentStatus.CLOSED,
[],
None,
[],
16
)
]
async def _update_cache(self) -> None: async def _update_cache(self) -> None:
tournaments = await self._db_service.get_all_tournaments() tournaments = await self._db_service.get_all_tournaments()
for tournament in tournaments: for tournament in tournaments:
self._cache[tournament.id] = tournament self._cache[tournament.id] = tournament
self._cache_dirty = False self._cache_dirty = False
async def register_user_for_tournament(self, user_id: int, tournament_id: int) -> None:
tournament = await self.get_tournament_by_id(tournament_id)
if not tournament:
raise TournamentError(f"No tournament with ID {tournament_id} was found")
participant = Participant(id_=user_id, participant_type=ParticipantType.PLAYER)
tournament.add_participant(participant)
await self._db_service.add_participant_to_tournament(participant, tournament)
self._cache_dirty = True
async def unregister_user_from_tournament(self, user_id: int, tournament_id: int) -> None:
tournament = await self.get_tournament_by_id(tournament_id)
if not tournament:
raise TournamentError(f"No tournament with ID {tournament_id} was found")
participant = next(filter(lambda p: p.id == user_id, tournament.participants), None)
if participant is not None:
tournament.remove_participant(participant)
await self._db_service.remove_participant_from_tournament(participant, tournament)
self._cache_dirty = True
async def get_tournaments(self) -> list[Tournament]: async def get_tournaments(self) -> list[Tournament]:
if self._cache_dirty: if self._cache_dirty:

View File

@ -90,6 +90,10 @@ class Tournament:
raise TournamentError(f"Participant with ID {participant.id} already registered for tournament") raise TournamentError(f"Participant with ID {participant.id} already registered for tournament")
self._participants.append(participant) self._participants.append(participant)
def remove_participant(self, participant: Participant) -> None:
if participant.id not in (p.id for p in self._participants):
raise TournamentError(f"Participant with ID {participant.id} not registered for tournament")
self._participants.remove(participant)
def match_has_ended_callback(self, match: Match) -> None: def match_has_ended_callback(self, match: Match) -> None:
if self._matches is None: if self._matches is None: