diff --git a/tournaments/models/group_stage.py b/tournaments/models/group_stage.py index c64d384..6f0a0dc 100644 --- a/tournaments/models/group_stage.py +++ b/tournaments/models/group_stage.py @@ -1,3 +1,4 @@ +from asyncio.streams import StreamReaderProtocol from django.db import models from . import Tournament, FederalMatchCategory import uuid @@ -23,7 +24,11 @@ class GroupStage(models.Model): if self.name: return self.name else: - return f"Poule {self.index + 1}" + if self.step == 0: + return f"Poule {self.index + 1}" + else: + return f"Poule {self.index + 1} - " + f"Phase {self.step + 1}" + def next_match(self, player_registration): matches = self.matches_for_registration(player_registration).filter(end_date__isnull=False).order_by('start_date') @@ -34,16 +39,26 @@ class GroupStage(models.Model): return [ts.match for ts in team_scores] # map(lambda ts: ts.match, team_scores) def live_group_stages(self): - lgs = LiveGroupStage(self.display_name()) + lgs = LiveGroupStage(self.display_name(), self.step, self.index) gs_teams = {} - # init all teams - for team_registration in self.teamregistration_set.all(): - if team_registration in gs_teams: - team = gs_teams[team_registration] - else: - team = GroupStageTeam(team_registration) - gs_teams[team_registration] = team + if self.step == 0: + # init all teams + for team_registration in self.teamregistration_set.all(): + if team_registration in gs_teams: + team = gs_teams[team_registration] + else: + team = GroupStageTeam(team_registration) + gs_teams[team_registration] = team + else: + previous = self.tournament.get_previous_live_group_stages(self.step - 1) + for gs in previous: + team_registration = gs.teams[self.index].team_registration + if team_registration in gs_teams: + team = gs_teams[team_registration] + else: + team = GroupStageTeam(team_registration) + gs_teams[team_registration] = team # compute matches for match in self.match_set.all(): @@ -109,12 +124,17 @@ class GroupStage(models.Model): return True return False + def is_completed(self): + return not self.match_set.filter(end_date__isnull=True).exists() + class LiveGroupStage: - def __init__(self, title): + def __init__(self, title, step, index): self.title = title self.teams = [] self.start = None self.end = None + self.step = step + self.index = index def add_match(self, match): if self.start and match.start_date and match.start_date < self.start: @@ -153,6 +173,7 @@ class GroupStageTeam: self.losses = 0 self.diff = 0 self.weight = team_registration.weight + self.team_registration = team_registration def wins_losses(self): return f"{self.wins}/{self.losses}" diff --git a/tournaments/models/tournament.py b/tournaments/models/tournament.py index a2999de..1a0d3a5 100644 --- a/tournaments/models/tournament.py +++ b/tournaments/models/tournament.py @@ -401,7 +401,8 @@ class Tournament(models.Model): for round in self.round_set.filter(parent=None, group_stage_loser_bracket=True).all().order_by('index'): groups.extend(self.round_match_groups(round, broadcasted, hide_empty_matches=True)) - for group_stage in self.groupstage_set.all().order_by('index'): + ordered = sorted(self.get_computed_group_stage(), key=lambda s: (-s.step, s.index)) + for group_stage in ordered: group = self.group_stage_match_group(group_stage, broadcasted, hide_empty_matches=True) if group: groups.append(group) @@ -455,10 +456,47 @@ class Tournament(models.Model): return MatchGroup(name, live_matches) def live_group_stages(self): - group_stages = list(self.groupstage_set.all()) - group_stages.sort(key=lambda gs: gs.index) + group_stages = self.get_computed_group_stage() return [gs.live_group_stages() for gs in group_stages] + def get_computed_group_stage(self): + # Get all group stages and sort by step (descending) and index (ascending) + group_stages = self.groupstage_set.all().order_by('-step', 'index') + + # List to collect live group stages from finished steps + filtered = [] + + for group_stage in group_stages: + if group_stage.step > 0: + # Check the previous step's group stages + previous_step_group_stages = self.groupstage_set.filter(step=group_stage.step - 1) + + # Check if all previous step group stages are completed + if all(gs.is_completed() for gs in previous_step_group_stages): + filtered.append(group_stage) + else: + # Always include step 0 + filtered.append(group_stage) + + return filtered + + def get_previous_live_group_stages(self, step): + previous_step_group_stages = self.groupstage_set.filter(step=step).order_by('index') + return [gs.live_group_stages() for gs in previous_step_group_stages] + + def last_group_stage_step(self): + live_group_stages = self.get_computed_group_stage() + + # Filter to find the last running step + last_running_step = max(gs.step for gs in live_group_stages) if live_group_stages else None + + if last_running_step is not None: + # Get only group stages from the last running step + group_stages_last_step = [gs for gs in live_group_stages if gs.step == last_running_step] + return group_stages_last_step + else: + return [] + def broadcast_content(self): matches, group_stages = self.broadcasted_matches_and_group_stages() @@ -514,7 +552,7 @@ class Tournament(models.Model): group_stages = [] if len(self.groupstage_set.all()) > 0 and self.no_bracket_match_has_started(): - group_stages = self.live_group_stages() + group_stages = [gs.live_group_stages() for gs in self.last_group_stage_step()] matches = self.broadcasted_group_stages_matches() first_round = self.first_round() if first_round and self.has_all_group_stages_started(): @@ -535,7 +573,7 @@ class Tournament(models.Model): matches.extend(previous_round.get_matches_recursive(True)) else: matches.extend(current_round.all_matches(True)) - group_stages = self.live_group_stages() + group_stages = [gs.live_group_stages() for gs in self.last_group_stage_step()] return matches, group_stages @@ -626,7 +664,7 @@ class Tournament(models.Model): return matches def elected_broadcast_group_stages(self): - group_stages = list(self.groupstage_set.all()) + group_stages = list(self.last_group_stage_step()) started = [gs for gs in group_stages if gs.starts_soon()] if len(started) > 0: return started diff --git a/tournaments/templates/tournaments/group_stages.html b/tournaments/templates/tournaments/group_stages.html index 468b0fb..ae084d7 100644 --- a/tournaments/templates/tournaments/group_stages.html +++ b/tournaments/templates/tournaments/group_stages.html @@ -10,11 +10,15 @@ {% include 'tournaments/navigation_tournament.html' %} + {% for step in unique_steps %}
{% for group_stage in group_stages %} - {% include 'tournaments/group_stage_cell.html' %} + {% if group_stage.step == step %} + {% include 'tournaments/group_stage_cell.html' %} + {% endif %} {% endfor %}
+ {% endfor %} {% endblock %} diff --git a/tournaments/views.py b/tournaments/views.py index 59f71c0..d6bb001 100644 --- a/tournaments/views.py +++ b/tournaments/views.py @@ -146,7 +146,8 @@ def tournament(request, tournament_id): rounds = list(tournament.round_set.filter(group_stage_loser_bracket=True)) rounds.extend(bracket_rounds) - group_stages = tournament.groupstage_set.order_by('index') + #group_stages = tournament.groupstage_set.order_by('index') + group_stages = sorted(tournament.get_computed_group_stage(), key=lambda s: (s.step, s.index)) #print(len(match_groups)) #print(len(rounds)) @@ -256,9 +257,12 @@ def tournament_matches_json(request, tournament_id): def tournament_group_stages(request, tournament_id): tournament = get_object_or_404(Tournament, pk=tournament_id) live_group_stages = list(tournament.live_group_stages()) + unique_steps = sorted(set(gs.step for gs in live_group_stages), reverse=True) + return render(request, 'tournaments/group_stages.html', { 'tournament': tournament, 'group_stages': live_group_stages, + 'unique_steps': unique_steps, }) def tournament_broadcasted_group_stages(request, tournament_id): @@ -272,8 +276,10 @@ def tournament_broadcasted_group_stages(request, tournament_id): def tournament_live_group_stage_json(request, tournament_id): tournament = get_object_or_404(Tournament, pk=tournament_id) - gs_dicts = [gs.to_dict() for gs in tournament.live_group_stages()] - # group_stages = tournament.live_group_stages() + # Get all live group stages and filter for the last running step + live_group_stages = [gs.live_group_stages() for gs in tournament.last_group_stage_step()] + + gs_dicts = [gs.to_dict() for gs in live_group_stages] data = json.dumps(gs_dicts) return HttpResponse(data, content_type='application/json')