You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
12 KiB
292 lines
12 KiB
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)
|
|
group_stage_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(default=1)
|
|
prioritize_club_members = models.BooleanField()
|
|
qualified_per_group_stage = models.IntegerField(default=0)
|
|
teams_per_group_stage = models.IntegerField(default=0)
|
|
entry_fee = models.FloatField(default=20.0, null=True, blank=True)
|
|
payment = models.IntegerField(default=TournamentPayment.FREE, choices=TournamentPayment.choices, null=True, blank=True)
|
|
is_deleted = models.BooleanField(default=False)
|
|
is_canceled = models.BooleanField(default=False)
|
|
additional_estimation_duration = models.IntegerField(default=0)
|
|
|
|
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():
|
|
group_stages = self.live_group_stages()
|
|
matches = self.group_stages_matches()
|
|
else:
|
|
# last_started_match = self.first_unfinished_match()
|
|
current_round = self.round_to_show()
|
|
previous_round = self.round_for_index(current_round.index + 1)
|
|
|
|
if previous_round:
|
|
matches.extend(current_round.get_matches_recursive(True))
|
|
matches.extend(previous_round.get_matches_recursive(True))
|
|
else:
|
|
matches.extend(current_round.all_matches(True))
|
|
group_stages = self.live_group_stages()
|
|
|
|
return matches, group_stages
|
|
|
|
def all_matches(self, hide_empty_matches):
|
|
matches = []
|
|
for round in self.round_set.all():
|
|
matches.extend(round.all_matches(hide_empty_matches))
|
|
for group_stage in self.groupstage_set.all():
|
|
matches.extend(group_stage.match_set.all())
|
|
|
|
if hide_empty_matches:
|
|
matches = [m for m in matches if m.should_appear()]
|
|
|
|
return matches
|
|
|
|
def group_stage_matches(self):
|
|
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:
|
|
matches = self.group_stage_matches()
|
|
running_group_stage_matches = [m for m in matches if m.end_date is None]
|
|
return len(running_group_stage_matches) > 0
|
|
else:
|
|
return False
|
|
|
|
def first_unfinished_match(self):
|
|
matches = [m for m in self.all_matches(False) if m.start_date and m.end_date is None]
|
|
matches.sort(key=lambda m: m.start_date)
|
|
if matches:
|
|
return matches[0]
|
|
else:
|
|
return None
|
|
|
|
def round_to_show(self):
|
|
last_started_match = self.first_unfinished_match()
|
|
if last_started_match:
|
|
current_round = last_started_match.round.root_round()
|
|
if current_round:
|
|
return current_round
|
|
main_rounds = list(self.round_set.filter(parent=None).all())
|
|
main_rounds.sort(key=lambda r: r.index)
|
|
if main_rounds:
|
|
return main_rounds[0]
|
|
else:
|
|
return None
|
|
|
|
def last_started_match(self):
|
|
matches = [m for m in self.all_matches(False) 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,
|
|
}
|
|
|