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.
447 lines
18 KiB
447 lines
18 KiB
from os import WEXITED, preadv
|
|
from django.db import models
|
|
from django.contrib.auth.models import AbstractUser
|
|
from django.conf import settings
|
|
import uuid
|
|
import os
|
|
from django.utils import timezone
|
|
|
|
from django.utils.encoding import Promise
|
|
|
|
import tournaments
|
|
|
|
class FederalCategory(models.IntegerChoices):
|
|
MEN = 0, 'Men'
|
|
WOMEN = 1, 'Women'
|
|
MIXED = 2, 'Mixed'
|
|
|
|
class FederalLevelCategory(models.IntegerChoices):
|
|
P25 = 25, 'P25'
|
|
P100 = 100, 'P100'
|
|
P250 = 250, 'P250'
|
|
P500 = 500, 'P500'
|
|
P1000 = 1000, 'P1000'
|
|
P1500 = 1500, 'P1500'
|
|
P2000 = 2000, 'P2000'
|
|
|
|
class FederalAgeCategory(models.IntegerChoices):
|
|
A11_12 = 120, 'A11_12'
|
|
A13_14 = 140, 'A13_14'
|
|
A15_16 = 160, 'A15_16'
|
|
A17_18 = 180, 'A17_18'
|
|
SENIOR = 200, 'SENIOR'
|
|
A45 = 450, 'A45'
|
|
A55 = 550, 'A55'
|
|
|
|
class FederalMatchCategory(models.IntegerChoices):
|
|
TWO_SETS = 0, 'Two sets'
|
|
TWO_SETS_SUPER_TIE = 1, 'Two sets super tie'
|
|
TWO_SETS_FOUR_GAME = 2, 'Two sets of four games'
|
|
NINE_GAMES = 3, 'Nine games'
|
|
SUPER_TIE = 4, 'Super Tie-Break'
|
|
MEGA_TIE = 5, 'Mega Tie-Break'
|
|
TWO_SETS_DECISIVE_POINT = 6, 'Two Sets with decisive point'
|
|
TWO_SETS_DECISIVE_POINT_SUPER_TIE = 7, 'Two Sets with decisive point and super tie-break'
|
|
TWO_SETS_FOUR_GAME_DECISIVE_POINT = 8, 'Two sets of four games with decisive point'
|
|
NINE_GAMES_DECISIVE_POINT = 9, 'Nine games with decisive point'
|
|
|
|
class Club(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
name = models.CharField(max_length=50)
|
|
acronym = models.CharField(max_length=10)
|
|
phone = models.CharField(max_length=15, null=True, blank=True)
|
|
code = models.CharField(max_length=10, null=True, blank=True)
|
|
federal_club_data = models.JSONField(null=True, blank=True)
|
|
|
|
address = models.CharField(max_length=200, null=True, blank=True)
|
|
city = models.CharField(max_length=100, null=True, blank=True)
|
|
zip_code = models.CharField(max_length=10, null=True, blank=True)
|
|
latitude = models.FloatField(null=True, blank=True)
|
|
longitude = models.FloatField(null=True, blank=True)
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
class CustomUser(AbstractUser):
|
|
pass
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
umpire_code = models.CharField(max_length=50, blank=True, null=True)
|
|
clubs = models.ManyToManyField(Club)
|
|
phone = models.CharField(max_length=15, null=True, blank=True)
|
|
first_name = models.CharField(max_length=50)
|
|
last_name = models.CharField(max_length=50)
|
|
licence_id = models.CharField(max_length=10, null=True, blank=True)
|
|
|
|
def __str__(self):
|
|
return self.username
|
|
|
|
class Event(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
club = models.ForeignKey(Club, on_delete=models.CASCADE)
|
|
date = models.DateTimeField()
|
|
name = models.CharField(max_length=200, null=True, blank=True)
|
|
federal_tournament_data = models.JSONField(null=True, blank=True)
|
|
court_count = models.IntegerField(null=True, blank=True)
|
|
tenup_id = models.IntegerField(null=True, blank=True)
|
|
group_stage_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)
|
|
loser_round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
class Tournament(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
event = models.ForeignKey(Event, blank=True, null=True, on_delete=models.CASCADE)
|
|
creator = models.ForeignKey(CustomUser, 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()
|
|
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)
|
|
round_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)
|
|
# custom_name = models.CharField(max_length=100, 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)
|
|
#estimated_end_date = models.DateTimeField(null=True, blank=True)
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
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 team_calls(self):
|
|
|
|
team_calls = []
|
|
for team_registration in self.teamregistration_set.all():
|
|
call_date = team_registration.call_date
|
|
if call_date:
|
|
names = team_registration.team_names()
|
|
stage = team_registration.next_stage()
|
|
weight = team_registration.weight()
|
|
team_call = TeamCall(names, call_date, weight, stage, team_registration.logo)
|
|
team_calls.append(team_call)
|
|
|
|
return team_calls
|
|
|
|
# stage_call = StageCall(f"1/{self.index}")
|
|
# for match in self.match_set.all():
|
|
# names = map(lambda ts: ts.player_names(), match.teamstate_set.all())
|
|
# if names:
|
|
# team_call = TeamCall(names, match.formatted_start_date)
|
|
# stage_call.add_team(team_call)
|
|
|
|
# return stage_call
|
|
|
|
class Round(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
|
|
index = models.IntegerField(null=True, blank=True)
|
|
loser = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
|
|
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
|
|
|
|
def __str__(self):
|
|
return f"{self.tournament.name} - {self.name()}"
|
|
|
|
# def stage_call(self):
|
|
# stage_call = StageCall(f"1/{self.index}")
|
|
# for match in self.match_set.all():
|
|
# names = map(lambda ts: ts.player_names(), match.teamstate_set.all())
|
|
# if names:
|
|
# team_call = TeamCall(names, match.formatted_start_date)
|
|
# stage_call.add_team(team_call)
|
|
|
|
# return stage_call
|
|
|
|
def name(self):
|
|
if self.index == 0:
|
|
return "Finale"
|
|
elif self.index == 1:
|
|
return "Demi-Finales"
|
|
elif self.index == 2:
|
|
return "Quarts de finale"
|
|
elif self.index == 3:
|
|
return "Huitième de finale"
|
|
elif self.index == 4:
|
|
return "Seizième de finale"
|
|
else:
|
|
return ""
|
|
|
|
class GroupStage(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
|
|
index = models.IntegerField(null=True, blank=True)
|
|
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
|
|
|
|
def __str__(self):
|
|
return f"{self.tournament.name} - {self.name()}"
|
|
|
|
def name(self):
|
|
return f"Poule {self.index}"
|
|
|
|
# def stage_call(self):
|
|
# stage_call = StageCall(f"poule{self.index}")
|
|
|
|
# for team_registration in self.teamregistration_set.all():
|
|
# names = map(lambda pr: pr.name(), team_registration.playerregistration_set.all())
|
|
# time = self.next_match(team_registration).start_date.strftime("%H:%M") # "17h45" # which match do we take, the first unfinished?
|
|
# team_call = TeamCall(names, time)
|
|
# return stage_call
|
|
|
|
def next_match(self, player_registration):
|
|
matches = self.matches_for_registration(player_registration).filter(end_date__isnull=False).order_by('start_date')
|
|
return matches[0]
|
|
|
|
def matches_for_registration(self, player_registration):
|
|
team_states = TeamState.objects.filter(player_registrations=player_registration)
|
|
return map(lambda ts: ts.match, team_states)
|
|
|
|
class Match(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
round = models.ForeignKey(Round, null=True, blank=True, on_delete=models.CASCADE)
|
|
group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.CASCADE)
|
|
start_date = models.DateTimeField(null=True, blank=True)
|
|
end_date = models.DateTimeField(null=True, blank=True)
|
|
index = models.IntegerField(null=True, blank=True)
|
|
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
|
|
court = models.IntegerField(null=True, blank=True)
|
|
serving_team_id = models.UUIDField(null=True, blank=True)
|
|
winning_team_id = models.UUIDField(null=True, blank=True)
|
|
losing_team_id = models.UUIDField(null=True, blank=True)
|
|
broadcasted = models.BooleanField(default=False)
|
|
|
|
def __str__(self):
|
|
|
|
items = [f"Match {self.index}", self.formatted_start_date()]
|
|
desc = " - ".join(items)
|
|
player_names = " / ".join(self.player_names())
|
|
if self.round:
|
|
return f"{str(self.round)} > {desc} > {player_names}"
|
|
elif self.group_stage:
|
|
return f"{str(self.group_stage)} > {desc} > {player_names}"
|
|
|
|
def player_names(self):
|
|
return map(lambda ts: ts.player_names(), self.team_states.all())
|
|
|
|
def formatted_start_date(self):
|
|
if self.start_date:
|
|
return self.start_date.strftime("%H:%M")
|
|
else:
|
|
return "no date"
|
|
# return str(self.start_date) #.strftime("%H:%M")
|
|
|
|
def current_duration(self):
|
|
if self.end_date:
|
|
return (self.end_date - self.start_date).total_seconds()
|
|
else:
|
|
return (timezone.now() - self.start_date).total_seconds()
|
|
|
|
def durationPrefix(self):
|
|
if self.current_duration() > 0:
|
|
return "Temps de jeu"
|
|
else:
|
|
return "Démarrage prévu dans"
|
|
|
|
def formatted_duration(self):
|
|
|
|
_seconds = self.current_duration()
|
|
|
|
if _seconds > 0:
|
|
_hours = int(_seconds / 3600)
|
|
_minutes = int((_seconds % 3600) / 60)
|
|
return f"{_hours:02d}h{_minutes:02d}min"
|
|
else :
|
|
_seconds = _seconds * -1
|
|
_hours = int(_seconds / 3600)
|
|
_minutes = int((_seconds % 3600) / 60)
|
|
return f"{_hours:02d}h{_minutes:02d}min"
|
|
|
|
# def seconds(self):
|
|
# return (timezone.now() - self.start_date).total_seconds()
|
|
|
|
def live_match(self):
|
|
title = f"{self.index}"
|
|
date = self.formatted_start_date()
|
|
duration = self.formatted_duration()
|
|
|
|
livematch = LiveMatch(title, date, duration)
|
|
|
|
for team_state in self.team_states:
|
|
|
|
image = team_state.team_registration.logo
|
|
names = team_state.team_names()
|
|
scores = team_state.score
|
|
weight = team_state.weight
|
|
is_winner = False
|
|
team = Team(image, names, scores, weight, is_winner)
|
|
|
|
|
|
break
|
|
|
|
# def __init__(self, image, names, scores, weight, is_winner):
|
|
|
|
|
|
|
|
|
|
# def __init__(self, title, date, teams, duration):
|
|
|
|
|
|
|
|
|
|
class TeamRegistration(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
|
|
group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.SET_NULL)
|
|
registration_date = models.DateTimeField(null=True, blank=True)
|
|
call_date = models.DateTimeField(null=True, blank=True)
|
|
initial_position = models.IntegerField(null=True, blank=True)
|
|
group_stage_position = models.IntegerField(null=True, blank=True)
|
|
comment = models.CharField(max_length=200, null=True, blank=True)
|
|
source = models.CharField(max_length=20, null=True, blank=True)
|
|
source_value = models.CharField(max_length=200, null=True, blank=True)
|
|
logo = models.CharField(max_length=200, null=True, blank=True) #models.FilePathField(path=os.path.join(settings.STATIC_ROOT, "images"), null=True, blank=True)
|
|
name = models.CharField(max_length=200, null=True, blank=True)
|
|
|
|
def __str__(self):
|
|
return self.player_names()
|
|
|
|
def team_names(self):
|
|
if self.name:
|
|
return [self.name]
|
|
else:
|
|
return map(lambda pr: pr.name(), self.playerregistration_set.all())
|
|
|
|
def player_names(self):
|
|
names = map(lambda pr: pr.name(), self.playerregistration_set.all())
|
|
str = " - ".join(names)
|
|
if len(str) > 0:
|
|
return str
|
|
else:
|
|
return "no players"
|
|
|
|
def next_stage(self):
|
|
matches = Match.objects.filter(group_stage__isnull=True, team_states__player_registrations__id=self.id).order_by('round__index')
|
|
if matches:
|
|
return matches[0].round.name()
|
|
elif self.group_stage:
|
|
return self.group_stage.name()
|
|
else:
|
|
return "--"
|
|
|
|
def weight(self):
|
|
top_two_players = self.playerregistration_set.all().order_by('rank')[:2]
|
|
weight = 0
|
|
for player in top_two_players:
|
|
rank = player.rank if player.rank is not None else 0
|
|
weight += rank
|
|
return weight
|
|
|
|
class PlayerRegistration(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE)
|
|
first_name = models.CharField(max_length=50)
|
|
last_name = models.CharField(max_length=50)
|
|
licence_id = models.CharField(max_length=20, null=True, blank=True)
|
|
rank = models.IntegerField(null=True, blank=True)
|
|
has_paid = models.BooleanField(default=False)
|
|
unranked = models.BooleanField(default=False)
|
|
|
|
def __str__(self):
|
|
return self.name()
|
|
|
|
def name(self):
|
|
return f"{self.first_name} {self.last_name}"
|
|
|
|
class TeamState(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
match = models.ForeignKey(Match, on_delete=models.CASCADE, related_name="team_states")
|
|
player_registrations = models.ManyToManyField(PlayerRegistration, blank=True)
|
|
team_registration = models.ForeignKey(Match, on_delete=models.CASCADE, null=True, blank=True)
|
|
score = models.CharField(max_length=50, null=True, blank=True)
|
|
walk_out = models.IntegerField(null=True, blank=True) #id, int of the walked_out team
|
|
lucky_loser = models.BooleanField()
|
|
|
|
def __str__(self):
|
|
return f"{str(self.match)}: {self.player_names()}"
|
|
|
|
def player_names(self):
|
|
names = map(lambda player: player.name(), self.player_registrations.all())
|
|
return " - ".join(names)
|
|
|
|
def team_names(self):
|
|
names = []
|
|
if self.team_registration.name:
|
|
names.append(self.team_registration.name)
|
|
else:
|
|
names = self.player_names()
|
|
|
|
class Team:
|
|
def __init__(self, image, names, scores, weight, is_winner):
|
|
self.image = image
|
|
self.names = []
|
|
self.scores = []
|
|
self.weight = weight
|
|
self.is_winner = is_winner
|
|
|
|
def add_names(self, name):
|
|
self.names.append(name)
|
|
|
|
def add_set_score(self, score):
|
|
self.scores.append(score)
|
|
|
|
class LiveMatch:
|
|
def __init__(self, title, date, duration):
|
|
self.title = title
|
|
self.date = date
|
|
self.teams = []
|
|
self.duration = duration
|
|
|
|
def add_team(self, team):
|
|
self.teams.append(team)
|
|
|
|
class TeamCall:
|
|
def __init__(self, names, date, weight, stage, image):
|
|
self.names = []
|
|
self.names = names
|
|
self.date = date
|
|
self.weight = weight
|
|
self.stage = stage
|
|
self.image = image
|
|
|
|
|
|
# class Set(models.Model):
|
|
|
|
# class Game(models.Model):
|
|
# set = models.ForeignKey(Set, on_delete=models.CASCADE)
|
|
# format = models.IntegerField()
|
|
|
|
# class Point(models.Model):
|
|
# game = models.ForeignKey(Game, on_delete=models.CASCADE)
|
|
# action = models.IntegerField()
|
|
# date = models.DateTimeField()
|
|
# team_id = models.IntegerField()
|
|
|