working views for tournament, matches and summons

clubs
Laurent 2 years ago
parent de3417b0d9
commit affaded5be
  1. 441
      tournaments/models.py
  2. 11
      tournaments/models/__init__.py
  3. 19
      tournaments/models/club.py
  4. 17
      tournaments/models/custom_user.py
  5. 37
      tournaments/models/enums.py
  6. 18
      tournaments/models/event.py
  7. 23
      tournaments/models/group_stage.py
  8. 109
      tournaments/models/match.py
  9. 19
      tournaments/models/player_registration.py
  10. 34
      tournaments/models/round.py
  11. 57
      tournaments/models/team_registration.py
  12. 30
      tournaments/models/team_score.py
  13. 91
      tournaments/models/tournament.py
  14. 29
      tournaments/static/tournaments/css/style.css
  15. 228
      tournaments/static/tournaments/test.html
  16. 2
      tournaments/templates/tournaments/match_cell.html
  17. 17
      tournaments/templates/tournaments/summon_row.html
  18. 20
      tournaments/templates/tournaments/summons.html
  19. 6
      tournaments/templates/tournaments/tournament_row.html
  20. 2
      tournaments/views.py

@ -1,441 +0,0 @@
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, json
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
def live_matches(self):
matches = []
for group_stage in self.groupstage_set.all():
for match in group_stage.match_set.all():
matches.append(match)
for round in self.round_set.all():
for match in round.match_set.all():
matches.append(match)
# matches = [m for m in matches if m.broadcasted==True]
print(len(matches))
return map(lambda match: match.live_match(), matches)
# # Convert object attributes to a dictionary
# dict = self.__dict__
# # Convert dictionary to JSON
# return json.dumps(dict)
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 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_scores = TeamScore.objects.filter(player_registrations=player_registration)
return map(lambda ts: ts.match, team_scores)
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.CharField(max_length=50, 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_scores.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"Match {self.index}"
date = self.formatted_start_date()
duration = self.formatted_duration()
court = ""
if self.court:
court = f"Terrain {self.court}"
livematch = LiveMatch(title, date, duration, court)
for team_score in self.team_scores.all():
image = team_score.team_registration.logo
names = team_score.team_names()
scores = team_score.scores_array()
weight = team_score.team_registration.weight()
is_winner = team_score.team_registration == self.winning_team_id
team = Team(image, names, scores, weight, is_winner)
livematch.add_team(team)
return livematch
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)
bracket_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_scores__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 TeamScore(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
match = models.ForeignKey(Match, on_delete=models.CASCADE, related_name="team_scores")
team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE, null=True, blank=True)
player_registrations = models.ManyToManyField(PlayerRegistration, 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 = list(map(lambda player: player.name(), self.player_registrations.all()))
return names
def scores_array(self):
return [int(x) for x in self.score.split(',')]
class Team:
def __init__(self, image, names, scores, weight, is_winner):
self.image = image
self.names = names
self.scores = scores
self.weight = weight
self.is_winner = is_winner
class LiveMatch:
def __init__(self, title, date, duration, court):
self.title = title
self.date = date
self.teams = []
self.duration = duration
self.court = court
def add_team(self, team):
self.teams.append(team)
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
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()

@ -0,0 +1,11 @@
from .club import Club
from .custom_user import CustomUser
from .enums import FederalCategory, FederalLevelCategory, FederalAgeCategory, FederalMatchCategory
from .event import Event
from .tournament import Tournament, TeamCall
from .group_stage import GroupStage
from .round import Round
from .match import Match, LiveMatch
from .team_registration import TeamRegistration
from .player_registration import PlayerRegistration
from .team_score import TeamScore

@ -0,0 +1,19 @@
from django.db import models
import uuid
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

@ -0,0 +1,17 @@
from django.db import models
from django.contrib.auth.models import AbstractUser
from . import Club
import uuid
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

@ -0,0 +1,37 @@
from django.db import models
import uuid
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'

@ -0,0 +1,18 @@
from django.db import models
from . import Club, FederalMatchCategory
import uuid
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

@ -0,0 +1,23 @@
from django.db import models
from . import Tournament, FederalMatchCategory
import uuid
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 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_scores = TeamScore.objects.filter(player_registrations=player_registration)
return map(lambda ts: ts.match, team_scores)

@ -0,0 +1,109 @@
from django.db import models
from . import Round, GroupStage, FederalMatchCategory
from django.utils import timezone
import uuid
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.CharField(max_length=50, 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_scores.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"Match {self.index}"
date = self.formatted_start_date()
duration = self.formatted_duration()
court = ""
if self.court:
court = f"Terrain {self.court}"
livematch = LiveMatch(title, date, duration, court)
for team_score in self.team_scores.all():
image = team_score.team_registration.logo
names = team_score.team_names()
scores = team_score.scores_array()
weight = team_score.team_registration.weight()
is_winner = team_score.team_registration == self.winning_team_id
team = Team(image, names, scores, weight, is_winner)
livematch.add_team(team)
return livematch
class Team:
def __init__(self, image, names, scores, weight, is_winner):
self.image = image
self.names = names
self.scores = scores
self.weight = weight
self.is_winner = is_winner
class LiveMatch:
def __init__(self, title, date, duration, court):
self.title = title
self.date = date
self.teams = []
self.duration = duration
self.court = court
def add_team(self, team):
self.teams.append(team)
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)

@ -0,0 +1,19 @@
from django.db import models
from . import TeamRegistration
import uuid
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}"

@ -0,0 +1,34 @@
from django.db import models
from . import Tournament, FederalMatchCategory
import uuid
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"
else:
squared = 2 ** self.index
return f"{squared}ème"

@ -0,0 +1,57 @@
from django.db import models
from . import Tournament, GroupStage
import uuid
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)
bracket_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 = map(lambda ts: ts.match, self.teamscore_set.all())
matches = [m for m in matches if m.group_stage is None]
matches = sorted(matches, key=lambda m: m.round.index)
# matches = self.teamscore_set
# matches = Match.objects.filter(group_stage__isnull=True, team_scores__player_registrations__id=self.id).order_by('round__index')
print(f"matches = {len(matches)}")
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

@ -0,0 +1,30 @@
from django.db import models
from . import Match, TeamRegistration, PlayerRegistration
import uuid
class TeamScore(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
match = models.ForeignKey(Match, on_delete=models.CASCADE, related_name="team_scores")
team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE, null=True, blank=True)
player_registrations = models.ManyToManyField(PlayerRegistration, 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 = list(map(lambda player: player.name(), self.player_registrations.all()))
return names
def scores_array(self):
return [int(x) for x in self.score.split(',')]

@ -0,0 +1,91 @@
from django.db import models
from . import Event, CustomUser, FederalMatchCategory, FederalCategory, FederalLevelCategory, FederalAgeCategory
import uuid
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
def live_matches(self):
matches = []
for group_stage in self.groupstage_set.all():
for match in group_stage.match_set.all():
matches.append(match)
for round in self.round_set.all():
for match in round.match_set.all():
matches.append(match)
# matches = [m for m in matches if m.broadcasted==True]
print(len(matches))
return map(lambda match: match.live_match(), matches)
# # Convert object attributes to a dictionary
# dict = self.__dict__
# # Convert dictionary to JSON
# return json.dumps(dict)
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

@ -34,6 +34,8 @@ body {
height: 100%; height: 100%;
padding: 0; padding: 0;
margin: 0; margin: 0;
overflow: hidden;
} }
label { label {
@ -420,16 +422,23 @@ tr {
width: 100px; width: 100px;
} }
.table-row { .table-row-3-colums {
display: grid; display: grid;
grid-template-columns: auto 1fr auto; grid-template-columns: auto 1fr auto;
align-items: center; /* Vertically center the content within each column */ align-items: center; /* Vertically center the content within each column */
padding: 5px 0px; padding: 5px 0px;
} }
.table-row-5-colums {
display: grid;
grid-template-columns: 60px auto 60px 60px 130px;
align-items: center; /* Vertically center the content within each column */
padding: 5px 0px;
}
.table-cell { .table-cell {
flex-grow: 1; flex-grow: 1;
text-align: center; /* text-align: center; */
/* padding: 5px; */ /* padding: 5px; */
} }
@ -437,3 +446,19 @@ tr {
grid-column: 2 / span 1; /* Center column spans from column 2 to column 3 */ grid-column: 2 / span 1; /* Center column spans from column 2 to column 3 */
text-align: left; text-align: left;
} }
.wrap {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 100vh; /*the height will need to be customized*/
width: 50px;
}
#xrow {
background: #000;
color: #fff;
height: 50px;
width: 50px;
margin-left: 10px;
}

@ -11,154 +11,88 @@
</head> </head>
<body> <body>
<div class="wrapper">
<main class="page-body">
<div class="container">
<div class="grid-x">
<div class="cell medium-6 large-6 topblock my-block">
<div class="bubble">
<img
src="images/PadelClub_logo_512.png"
class="logo inline"
/>
<div class="inline">
<h1 class="club">Bienvenue !</h1>
<h1 class="event">Matchs</h1>
<!-- <span>Propulsé par Padel Club</span> -->
</div>
</div>
</div>
</div>
<main> <div class="wrap my-block bubble">
<div id="xrow">1</div><br/>
<div id="xrow">2b</div><br/>
<div id="xrow">3c</div><br/>
<div id="xrow">1</div><br/>
<div class="grid-x"> <div id="xrow">2</div><br/>
<div class="cell medium-3 large-3 topblock my-block"> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<div id="xrow">2</div><br/>
<div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<div id="xrow">2</div><br/>
<div id="xrow">3</div><br/>
<div class="bubble"> <div id="xrow">1</div><br/>
<div id="xrow">2</div><br/>
<div class="flex-row"> <div id="xrow">3v</div><br/>
<label class="left-label matchtitle">Match 2</label> <div id="xrow">1</div><br/>
<label class="right-label info"></label> <div id="xrow">2</div><br/>
</div> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<div> <div id="xrow">2</div><br/>
<div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<div class="table-row bottom-border padding-bottom-small"> <div id="xrow">2</div><br/>
<div id="xrow">3</div><br/>
<div class="table-cell"> <div id="xrow">1</div><br/>
<img src="images/pc_icon_round_200.png" class="team_image" /> <div id="xrow">2</div><br/>
</div> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<div id="xrow">2</div><br/>
<div class="table-cell horizontal-padding table-cell table-cell-large"> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<div class=""> <div id="xrow">2</div><br/>
Jacky Gun <div id="xrow">3</div><br/>
</div> <div id="xrow">1</div><br/>
<div id="xrow">2</div><br/>
<div class=""> <div id="xrow">3</div><br/>
Joe Gun <div id="xrow">1</div><br/>
</div> <div id="xrow">2</div><br/>
<div id="xrow">3</div><br/>
</div> <div id="xrow">1</div><br/>
<div class="table-cell alignright"> <div id="xrow">2</div><br/>
<div id="xrow">3</div><br/>
<span class="score ws ">4</span> <div id="xrow">1</div><br/>
<div id="xrow">2</div><br/>
<span class="score ws ">6</span> <div id="xrow">3</div><br/>
<div id="xrow">2</div><br/>
<span class="score ws ">6</span> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
</div> <div id="xrow">2</div><br/>
</div> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<div class="table-row bottom-border padding-bottom-small"> <div id="xrow">2</div><br/>
<div id="xrow">3</div><br/>
<div class="table-cell"> <div id="xrow">1</div><br/>
<img src="images/pc_icon_round_200.png" class="team_image" /> <div id="xrow">2</div><br/>
</div> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<div id="xrow">2</div><br/>
<div class="table-cell horizontal-padding table-cell table-cell-large"> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<div class=""> <div id="xrow">2</div><br/>
Jolly Jumper Gun <div id="xrow">3</div><br/>
</div> <div id="xrow">2x</div><br/>
<div id="xrow">3</div><br/>
<div class=""> <div id="xrow">1</div><br/>
Miky mike Miker <div id="xrow">2</div><br/>
</div> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
</div> <div id="xrow">2</div><br/>
<div class="table-cell alignright"> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
<span class="score ws ">6</span> <div id="xrow">2</div><br/>
<div id="xrow">3</div><br/>
<span class="score ws ">4</span> <div id="xrow">1</div><br/>
<div id="xrow">2</div><br/>
<span class="score ws ">2</span> <div id="xrow">3</div><br/>
<div id="xrow">1</div><br/>
</div> <div id="xrow">2</div><br/>
</div> <div id="xrow">3aa</div><br/>
<!-- Add more rows as needed -->
</div>
<div class="top-margin flex-row">
<label class="left-label minor-info">50h42min</label>
<!-- <a href="" class="right-label">détails</a> -->
</div>
</div>
<div class="bubble">
<div class="flex-row">
<label class="left-label matchtitle">Match 2</label>
<label class="right-label info"></label>
</div>
<div>
</div>
<div class="top-margin flex-row">
<label class="left-label minor-info">29h46min</label>
<!-- <a href="" class="right-label">détails</a> -->
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</main>
</div> </div>
</body> </body>
</html> </html>

@ -12,7 +12,7 @@
{% for team in match.teams %} {% for team in match.teams %}
<div class="table-row {% cycle 'bottom-border' '' %} padding-bottom-small"> <div class="table-row-3-colums {% cycle 'bottom-border' '' %} padding-bottom-small">
{% if team.image %} {% if team.image %}
<div class="table-cell"> <div class="table-cell">
<img src="{% static 'tournaments/images/pc_icon_round_200.png' %}" class="team_image" /> <img src="{% static 'tournaments/images/pc_icon_round_200.png' %}" class="team_image" />

@ -0,0 +1,17 @@
{% load static %}
<div class="table-row-5-colums bottom-border">
<div class="table-cell">
<img class="team_image horizontal-margin" src="{% static 'tournaments/images/pc_icon_round_200.png' %}" />
</div>
<!-- <img src="{% static 'tournaments/images/{{ team_call.image }}' %}" class="team_image horizontal-margin"> -->
<div class="table-cell table-cell-large tight">
{% for name in team_call.names %}
<div>{{ name }}</div>
{% endfor %}
</div>
<div class="table-cell">{{ team_call.weight }}</div>
<div class="table-cell large">{{ team_call.date|date:'H:i' }}</div>
<div class="table-cell"><div class="mybox center">{{ team_call.stage }}</div></div>
</div>

@ -5,14 +5,14 @@
<meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link <link
rel="stylesheet" rel="stylesheet"
href="{% static 'tournaments/foundation.min.css' %}" href="{% static 'tournaments/css/foundation.min.css' %}"
/> />
<link rel="stylesheet" href="{% static 'tournaments/style.css' %}" /> <link rel="stylesheet" href="{% static 'tournaments/css/style.css' %}" />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
href="{% static 'tournaments/favicon.png' %}" href="{% static 'tournaments/images/favicon.png' %}"
/> />
<title>Padel Club - Convocations</title> <title>Padel Club - Convocations</title>
@ -27,7 +27,7 @@
<div class="cell medium-6 large-6 topblock my-block"> <div class="cell medium-6 large-6 topblock my-block">
<div class="bubble"> <div class="bubble">
<img <img
src="{% static 'tournaments/PadelClub_logo_512.png' %}" src="{% static 'tournaments/images/PadelClub_logo_512.png' %}"
class="logo inline" class="logo inline"
/> />
<div class="inline"> <div class="inline">
@ -45,9 +45,11 @@
<div class="bubble"> <div class="bubble">
{% for team_call in team_calls %} {% for team_call in team_calls %}
<div class="table-container bottom-border vertical-padding"> {% include 'tournaments/summon_row.html' %}
<!-- <div class="table-container bottom-border vertical-padding">
<img src="{% static 'tournaments/{{ team_call.image }}' %}" class="team_image horizontal-margin"> <img src="{% static 'tournaments/images/pc_icon_round_200.png' %}" class="team_image horizontal-margin" />
<div class="w50 tight table-cell hpadding10"> <div class="w50 tight table-cell hpadding10">
{% for name in team_call.names %} {% for name in team_call.names %}
<div>{{ name }}</div> <div>{{ name }}</div>
@ -57,14 +59,14 @@
<div class="table-cell horizontal-padding">{{ team_call.weight }}</div> <div class="table-cell horizontal-padding">{{ team_call.weight }}</div>
<div class="table-cell horizontal-padding large">{{ team_call.date }}</div> <div class="table-cell horizontal-padding large">{{ team_call.date }}</div>
<div class="table-cell"><div class="mybox">{{ team_call.stage }}</div></div> <div class="table-cell"><div class="mybox">{{ team_call.stage }}</div></div>
</div> </div> -->
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
<div class="cell medium-6 large-6 topblock my-block"> <!-- <div class="cell medium-6 large-6 topblock my-block">
<div class="bubble"> <div class="bubble">
<div class="table-container bottom-border vertical-padding"> <div class="table-container bottom-border vertical-padding">
@ -169,7 +171,7 @@
</div> </div>
</div> </div>
</div> </div> -->
</div> </div>
</div> </div>

@ -1,11 +1,11 @@
<a href="{% url 'tournament-planning' tournament.id %}"> <a href="{% url 'tournament' tournament.id %}">
<div class="table-container bottom-border vertical-padding"> <div class="table-row-3-colums bottom-border vertical-padding">
<div class="tight table-cell"> <div class="tight table-cell">
<div class="large">{{ tournament.level }}</div> <div class="large">{{ tournament.level }}</div>
<div class="small">{{ tournament.category }}</div> <div class="small">{{ tournament.category }}</div>
</div> </div>
<div class="w100 horizontal-padding table-cell">{{ tournament.event.club.name }}</div> <div class="table-cell table-cell-large horizontal-padding">{{ tournament.event.club.name }}</div>
<div class="table-cell"><div class="mybox">{{ tournament.formatted_start_date }}</div></div> <div class="table-cell"><div class="mybox">{{ tournament.formatted_start_date }}</div></div>
</div> </div>
</a> </a>

@ -70,7 +70,7 @@ def tournament_planning(request, tournament_id):
tournament = get_object_or_404(Tournament, pk=tournament_id) tournament = get_object_or_404(Tournament, pk=tournament_id)
team_calls = tournament.team_calls() team_calls = tournament.team_calls()
template = loader.get_template('tournaments/planning.html') template = loader.get_template('tournaments/summons.html')
context = { context = {
'team_calls': team_calls, 'team_calls': team_calls,
} }

Loading…
Cancel
Save