from django.db import models from . import Event, TournamentPayment, FederalMatchCategory, FederalCategory, FederalLevelCategory, FederalAgeCategory import uuid from django.utils import timezone, formats class Tournament(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) event = models.ForeignKey(Event, blank=True, null=True, on_delete=models.CASCADE) name = models.CharField(max_length=200, null=True, blank=True) start_date = models.DateTimeField() end_date = models.DateTimeField(null=True, blank=True) creation_date = models.DateTimeField() is_private = models.BooleanField(default=False) # format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) group_stage_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) loser_round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) bracket_sort_mode = models.IntegerField(default=0) group_stage_count = models.IntegerField(default=0) rank_source_date = models.DateTimeField(null=True, blank=True) day_duration = models.IntegerField(default=0) team_count = models.IntegerField(default=0) team_sorting = models.IntegerField(default=0) federal_category = models.IntegerField(default=FederalCategory.MEN, choices=FederalCategory.choices) # optional ? federal_level_category = models.IntegerField(default=FederalLevelCategory.P100, choices=FederalLevelCategory.choices) federal_age_category = models.IntegerField(default=FederalAgeCategory.SENIOR, choices=FederalAgeCategory.choices) group_stage_court_count = models.IntegerField(null=True, blank=True) seed_count = models.IntegerField(default=0) closed_registration_date = models.DateTimeField(null=True, blank=True) group_stage_additional_qualified = models.IntegerField(default=0) court_count = models.IntegerField(null=True, blank=True) prioritize_club_members = models.BooleanField() qualified_per_group_stage = models.IntegerField(default=0) teams_per_group_stage = models.IntegerField(default=0) payment = models.IntegerField(default=TournamentPayment.FREE, choices=TournamentPayment.choices, null=True, blank=True) def __str__(self): if self.name: return self.name else: return self.display_name() def display_name(self): if self.name: return self.name else: return f"{self.level()} {self.category()}" def level(self): return self.get_federal_level_category_display() def category(self): return self.get_federal_category_display() def formatted_start_date(self): return self.start_date.strftime("%d/%m/%y") def in_progress(self): return self.end_date is None def team_summons(self): summons = [] for team_registration in self.teamregistration_set.all(): if team_registration.is_valid_for_summon(): next_match = team_registration.next_match() if next_match: names = team_registration.team_names() stage = next_match.stage_name() weight = team_registration.weight() summon = TeamSummon(names, next_match.start_date, weight, stage, team_registration.logo) summons.append(summon) summons.sort(key=lambda s: s.weight) return summons def match_groups(self, broadcasted, group_stage_id, round_id): match_groups = [] if group_stage_id: group_stage = self.groupstage_set.filter(id=group_stage_id).first() match_groups.append(self.group_stage_match_group(group_stage, broadcasted, hide_empty_matches=False)) elif round_id: round = self.round_set.filter(id=round_id).first() match_groups = self.round_match_groups(round, broadcasted, hide_empty_matches=False) else: match_groups = self.all_groups(broadcasted) return match_groups def all_groups(self, broadcasted): groups = [] for round in self.round_set.filter(parent=None).all().order_by('index'): groups.extend(self.round_match_groups(round, broadcasted, hide_empty_matches=True)) for group_stage in self.groupstage_set.all(): group = self.group_stage_match_group(group_stage, broadcasted, hide_empty_matches=True) if group: groups.append(group) return groups def group_stage_match_group(self, group_stage, broadcasted, hide_empty_matches): matches = group_stage.match_set.all() if hide_empty_matches: matches = [m for m in matches if m.should_appear()] if matches: return self.create_match_group(group_stage.name(), matches, broadcasted) else: return None def round_match_groups(self, round, broadcasted, hide_empty_matches): groups = [] matches = round.match_set.order_by('index').all() if hide_empty_matches: matches = [m for m in matches if m.should_appear()] if matches: group = self.create_match_group(round.name(), round.match_set.all(), broadcasted) groups.append(group) ranking_matches = round.ranking_matches(hide_empty_matches) if len(ranking_matches) > 0: group = self.create_match_group('Matchs de classement', ranking_matches, broadcasted) groups.append(group) return groups def create_match_group(self, name, matches, broadcasted): matches = list(matches) # if not broadcasted: # matches = [m for m in matches if m.should_appear()] matches.sort(key=lambda m: m.index) live_matches = [match.live_match() for match in matches] 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) return [gs.live_group_stages() for gs in group_stages] def broadcast_content(self): matches, group_stages = self.broadcasted_matches_and_group_stages() group_stages_dicts = [gs.to_dict() for gs in group_stages] # if now is before the first match, we want to show the summons + group stage or first matches if timezone.now() < self.start_date: team_summons_dicts = [summon.to_dict() for summon in self.team_summons()] if group_stages: return { 'matches': [], 'group_stages': group_stages_dicts, 'summons': team_summons_dicts, } else: live_matches_dicts = [match.live_match().to_dict() for match in matches] return { 'matches': live_matches_dicts, 'group_stages': [], 'summons': team_summons_dicts, } else: # we want to display the broadcasted content live_matches_dicts = [match.live_match().to_dict() for match in matches] return { 'matches': live_matches_dicts, 'group_stages': group_stages_dicts, 'summons': [], } def broadcasted_matches_and_group_stages(self): matches = [] group_stages = [] if self.group_stages_running(): matches = self.group_stages_matches() else: last_started_match = self.first_unfinished_match() current_round = last_started_match.round previous_round = self.round_for_index(current_round.index + 1) if previous_round: matches.extend(current_round.get_matches_recursive(False)) matches.extend(previous_round.get_matches_recursive(False)) else: matches.extend(current_round.all_matches()) group_stages = self.live_group_stages() return matches, group_stages def all_matches(self): matches = [] for round in self.round_set.all(): matches.extend(round.all_matches()) for group_stage in self.groupstage_set.all(): matches.extend(group_stage.match_set.all()) return matches def group_stages_running(self): if len(self.groupstage_set.all()) > 0: running_group_stage_matches = Match.objects.filter(group_stage__is_null=False, end_date=None) return len(running_group_stage_matches) > 0 else: return False def first_unfinished_match(self): matches = [m for m in self.all_matches() if m.start_date and m.end_date is None] matches.sort(key=lambda m: m.start_date) return matches[0] def last_started_match(self): matches = [m for m in self.all_matches() if m.start_date] matches.sort(key=lambda m: m.start_date, reverse=True) return matches[0] def round_for_index(self, index): return self.round_set.filter(index=index,parent=None).first() def group_stages_matches(self): matches = [] for group_stage in self.groupstage_set.all(): matches.extend(group_stage.match_set.all()) matches = [m for m in matches if m.should_appear()] matches.sort(key=lambda m: m.start_date, reverse=True) return matches class MatchGroup: def __init__(self, name, matches): self.name = name self.matches = matches def add_match(self, match): self.matches.append(match) def add_matches(self, matches): self.matches = matches class TeamSummon: def __init__(self, names, date, weight, stage, image): self.names = names self.date = date self.weight = weight self.stage = stage self.image = image def formatted_date(self): if self.date: timezoned_datetime = timezone.localtime(self.date) return formats.date_format(timezoned_datetime, format='H:i') else: return None def to_dict(self): return { "names": self.names, "date": self.formatted_date(), "weight": self.weight, "stage": self.stage, "image": self.image, }