From c44a876f8e5eaf1cf34f49e10dd9804009898b85 Mon Sep 17 00:00:00 2001
From: Raz
Date: Sat, 29 Mar 2025 10:09:48 +0100
Subject: [PATCH 01/12] fix p500+ stuff
---
.../0113_tournament_team_count_limit.py | 18 ++++
tournaments/models/tournament.py | 88 +++++++++++++++----
tournaments/services/email_service.py | 8 ++
tournaments/signals.py | 4 +-
.../templates/register_tournament.html | 24 ++++-
5 files changed, 121 insertions(+), 21 deletions(-)
create mode 100644 tournaments/migrations/0113_tournament_team_count_limit.py
diff --git a/tournaments/migrations/0113_tournament_team_count_limit.py b/tournaments/migrations/0113_tournament_team_count_limit.py
new file mode 100644
index 0000000..2b113cb
--- /dev/null
+++ b/tournaments/migrations/0113_tournament_team_count_limit.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.1 on 2025-03-29 08:15
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('tournaments', '0112_tournament_disable_ranking_federal_ruling_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='tournament',
+ name='team_count_limit',
+ field=models.BooleanField(default=True),
+ ),
+ ]
diff --git a/tournaments/models/tournament.py b/tournaments/models/tournament.py
index 24af6d5..42ab95b 100644
--- a/tournaments/models/tournament.py
+++ b/tournaments/models/tournament.py
@@ -67,6 +67,7 @@ class Tournament(BaseModel):
initial_seed_round = models.IntegerField(default=0)
initial_seed_count = models.IntegerField(default=0)
enable_online_registration = models.BooleanField(default=False) # Equivalent to Bool = false
+ team_count_limit = models.BooleanField(default=True)
registration_date_limit = models.DateTimeField(null=True, blank=True) # Equivalent to Date? = nil
opening_registration_date = models.DateTimeField(null=True, blank=True) # Equivalent to Date? = nil
waiting_list_limit = models.IntegerField(null=True, blank=True) # Equivalent to Int? = nil
@@ -397,7 +398,7 @@ class Tournament(BaseModel):
complete_teams.append(team)
else:
waiting_teams.append(team)
- wildcard_bracket = []
+
return complete_teams, wildcard_bracket, wildcard_group_stage, waiting_teams
def sort_teams(self, include_waiting_list, complete_teams, wildcard_bracket, wildcard_group_stage, waiting_teams):
@@ -1051,19 +1052,22 @@ class Tournament(BaseModel):
def options_online_registration(self):
options = []
+ timezone = self.timezone()
# Date d'ouverture
if self.opening_registration_date:
- date = formats.date_format(timezone.localtime(self.opening_registration_date), format='j F Y H:i')
+ date = formats.date_format(self.opening_registration_date.astimezone(timezone), format='j F Y H:i')
options.append(f"Ouverture des inscriptions le {date}")
# Date limite
if self.registration_date_limit:
- date = formats.date_format(timezone.localtime(self.registration_date_limit), format='j F Y H:i')
+ date = formats.date_format(self.registration_date_limit.astimezone(timezone), format='j F Y H:i')
options.append(f"Clôture des inscriptions le {date}")
+ options.append(self.get_selection_status_localized)
+
# Cible d'équipes
- if self.team_count:
+ if self.team_count_limit is True:
options.append(f"Maximum {self.team_count} équipes")
# Liste d'attente
@@ -1122,11 +1126,17 @@ class Tournament(BaseModel):
return False
return True
+ def get_selection_status_localized(self):
+ if self.team_sorting == TeamSortingType.RANK:
+ return "La sélection se fait par le poids de l'équipe"
+ else:
+ return "La sélection se fait par date d'inscription"
+
def get_online_registration_status(self):
if self.supposedly_in_progress():
return OnlineRegistrationStatus.ENDED
if self.closed_registration_date is not None:
- return OnlineRegistrationStatus.ENDED
+ return OnlineRegistrationStatus.WAITING_LIST_POSSIBLE
if self.end_date is not None:
return OnlineRegistrationStatus.ENDED_WITH_RESULTS
@@ -1140,9 +1150,12 @@ class Tournament(BaseModel):
if self.registration_date_limit is not None:
timezoned_datetime = timezone.localtime(self.registration_date_limit)
if now > timezoned_datetime:
- return OnlineRegistrationStatus.ENDED
+ return OnlineRegistrationStatus.WAITING_LIST_POSSIBLE
+
+ if self.team_sorting == TeamSortingType.RANK:
+ return OnlineRegistrationStatus.OPEN
- if self.team_count is not None:
+ if self.team_count_limit is True:
# Get all team registrations excluding walk_outs
current_team_count = self.team_registrations.exclude(walk_out=True).count()
if current_team_count >= self.team_count:
@@ -1174,8 +1187,14 @@ class Tournament(BaseModel):
return True
def get_waiting_list_position(self):
+ current_time = timezone.now()
+ local_registration_federal_limit = self.local_registration_federal_limit()
+ if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None:
+ if current_time < local_registration_federal_limit:
+ return -1
+
# If no target team count exists, no one goes to waiting list
- if self.team_count is None:
+ if self.team_count_limit is False:
return -1
# Get count of active teams (not walked out)
@@ -1257,7 +1276,6 @@ class Tournament(BaseModel):
current_year += 1
user_age = current_year - int(birth_year)
- print("user_age", user_age)
# Check age category restrictions
if self.federal_age_category == FederalAgeCategory.A11_12 and user_age > 12:
@@ -1290,12 +1308,49 @@ class Tournament(BaseModel):
def min_player_rank(self):
return FederalLevelCategory.min_player_rank(self.federal_level_category, self.federal_category, self.federal_age_category)
- def first_waiting_list_team(self, teams):
+ def local_registration_federal_limit(self):
+ timezone = self.timezone()
+ if self.registration_date_limit is not None:
+ return self.registration_date_limit.astimezone(timezone)
+
+ if self.closed_registration_date is not None:
+ return self.closed_registration_date.astimezone(timezone)
+
+ local_start_date = self.local_start_date()
+
+ if local_start_date is None:
+ return None
+
+ if self.federal_level_category == FederalLevelCategory.P500:
+ # 7 days before at 23:59
+ return (local_start_date - timedelta(days=7)).replace(hour=23, minute=59, second=59)
+ elif self.federal_level_category in [FederalLevelCategory.P1000,
+ FederalLevelCategory.P1500,
+ FederalLevelCategory.P2000]:
+ # 14 days before at 23:59
+ return (local_start_date - timedelta(days=14)).replace(hour=23, minute=59, second=59)
+ return None
+
+ def waiting_list_teams(self, teams):
+ current_time = timezone.now()
+ local_registration_federal_limit = self.local_registration_federal_limit()
+ if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None:
+ if current_time < local_registration_federal_limit:
+ return None
+
if len(teams)<=self.team_count:
return None
waiting_teams = [team for team in teams if team.stage == "Attente"]
- if len(waiting_teams) > 0:
- return waiting_teams[0].team_registration
+ return waiting_teams
+
+ def first_waiting_list_team(self, teams):
+ waiting_list_team = self.waiting_list_teams(teams)
+ if waiting_list_team is None:
+ return None
+ if len(waiting_list_team) > 0:
+ return waiting_list_team[0].team_registration
+ else:
+ return None
def broadcasted_prog(self):
# Get matches from broadcasted_matches_and_group_stages
@@ -1418,19 +1473,16 @@ class Tournament(BaseModel):
def umpire_contact(self):
if self.umpire_custom_contact is not None:
- print(self.umpire_custom_contact)
return self.umpire_custom_contact
return self.event.creator.full_name()
def umpire_mail(self):
if self.umpire_custom_mail is not None:
- print(self.umpire_custom_mail)
return self.umpire_custom_mail
return self.event.creator.email
def umpire_phone(self):
if self.umpire_custom_phone is not None:
- print(self.umpire_custom_phone)
return self.umpire_custom_phone
return self.event.creator.phone
@@ -1486,6 +1538,12 @@ class TeamSummon:
}
class TeamItem:
+ def __str__(self):
+ return f"TeamItem({self.team_registration.id}, names={self.names}, stage={self.stage})"
+
+ def __repr__(self):
+ return self.__str__()
+
def __init__(self, team_registration):
self.names = team_registration.team_names()
self.date = team_registration.local_call_date()
diff --git a/tournaments/services/email_service.py b/tournaments/services/email_service.py
index 6a3a59d..c017685 100644
--- a/tournaments/services/email_service.py
+++ b/tournaments/services/email_service.py
@@ -2,6 +2,7 @@ from django.core.mail import EmailMessage
from django.utils import timezone
from django.urls import reverse
from enum import Enum
+from ..models.tournament import TeamSortingType
class TeamEmailType(Enum):
REGISTERED = "registered"
@@ -74,6 +75,13 @@ class TournamentEmailService:
body_parts.append(f"Votre inscription en liste d'attente du tournoi {tournament_details_str} est confirmée.")
else:
body_parts.append(f"Votre inscription au tournoi {tournament_details_str} est confirmée.")
+ if tournament.team_sort == TeamSortingType.RANK:
+ cloture_date = tournament.local_registration_federal_limit().strftime("%d/%m/%Y à %H:%M")
+ loc = ""
+ if cloture_date is not None:
+ loc = f", prévu le {cloture_date}"
+ body_parts.append(f"Attention, la sélection définitive se fera par poids d'équipe à la clôture des inscriptions{loc}.")
+
absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info"
link_text = "informations sur le tournoi"
diff --git a/tournaments/signals.py b/tournaments/signals.py
index 48859cb..0eacdf9 100644
--- a/tournaments/signals.py
+++ b/tournaments/signals.py
@@ -113,10 +113,10 @@ def check_waiting_list(sender, instance, **kwargs):
teams_out_to_warn = []
teams_in_to_warn = []
+ previous_state_teams = previous_state.teams(True)
if previous_state.team_count > instance.team_count:
teams_to_remove_count = previous_state.team_count - instance.team_count
- previous_state_teams = previous_state.teams(True)
sorted_teams = sorted(
[team for team in previous_state_teams if team.stage != "Attente" and not (team.wildcard_bracket or team.wildcard_groupstage)],
key=lambda t: (
@@ -127,7 +127,7 @@ def check_waiting_list(sender, instance, **kwargs):
teams_out_to_warn = sorted_teams[-teams_to_remove_count:]
elif previous_state.team_count < instance.team_count:
teams_in_to_warn = [
- team for team in previous_state.teams(True)[(instance.team_count - previous_state.team_count):]
+ team for team in previous_state_teams[(instance.team_count - previous_state.team_count):]
if team.stage == "Attente"
]
diff --git a/tournaments/templates/register_tournament.html b/tournaments/templates/register_tournament.html
index 59f9d6d..c8349d1 100644
--- a/tournaments/templates/register_tournament.html
+++ b/tournaments/templates/register_tournament.html
@@ -26,6 +26,22 @@
Un email de confirmation a été envoyé à l'adresse associée à votre compte Padel Club ({{ user.email }}). Pensez à vérifier vos spams si vous ne recevez pas l'email. En cas de problème, contactez le juge-arbitre.
{% else %}
+
+ {% if team_form.errors %}
+
+ {% if team_form.non_field_errors %}
+ {% for error in team_form.non_field_errors %}
+
{{ error }}
+ {% endfor %}
+ {% endif %}
+
+ {% for field in team_form %}
+ {% for error in field.errors %}
+
{{ error }}
+ {% endfor %}
+ {% endfor %}
+
+ {% endif %}