Laurent 9 months ago
commit 11ca00cebf
  1. 25
      tournaments/models/tournament.py
  2. 52
      tournaments/services/email_service.py
  3. 23
      tournaments/services/tournament_registration.py
  4. 18
      tournaments/services/tournament_unregistration.py
  5. 47
      tournaments/signals.py
  6. 1
      tournaments/views.py

@ -75,7 +75,6 @@ class Tournament(models.Model):
minimum_player_per_team = models.IntegerField(default=2) minimum_player_per_team = models.IntegerField(default=2)
maximum_player_per_team = models.IntegerField(default=2) maximum_player_per_team = models.IntegerField(default=2)
information = models.CharField(max_length=4000, null=True, blank=True) information = models.CharField(max_length=4000, null=True, blank=True)
_being_deleted = False # Class attribute
def __str__(self): def __str__(self):
if self.name: if self.name:
@ -1091,17 +1090,25 @@ class Tournament(models.Model):
# In waiting list with no limit # In waiting list with no limit
return current_team_count - self.team_count return current_team_count - self.team_count
def build_tournament_details_str(self): def build_tournament_type_array(self):
tournament_details = [] tournament_details = []
name_str = self.build_name_details_str()
if self.federal_level_category > 0: if self.federal_level_category > 0:
tournament_details.append(self.level()) tournament_details.append(self.level())
if self.category(): if self.category():
tournament_details.append(self.category()) tournament_details.append(self.category())
if self.age(): if self.age() and self.federal_age_category != FederalAgeCategory.SENIOR:
tournament_details.append(self.age()) tournament_details.append(self.age())
return tournament_details
def build_tournament_type_str(self):
tournament_details = self.build_tournament_type_array()
return " ".join(filter(None, tournament_details))
def build_tournament_details_str(self):
tournament_details = self.build_tournament_type_array()
name_str = self.build_name_details_str()
if len(name_str) > 0: if len(name_str) > 0:
tournament_details.append(name_str) tournament_details.append(name_str)
@ -1186,12 +1193,6 @@ class Tournament(models.Model):
return waiting_teams[0].team_registration return waiting_teams[0].team_registration
return None return None
def delete(self, *args, **kwargs):
# Mark this tournament as being deleted
self._being_deleted = True
super().delete(*args, **kwargs)
def broadcasted_prog(self): def broadcasted_prog(self):
# Get matches from broadcasted_matches_and_group_stages # Get matches from broadcasted_matches_and_group_stages
matches, _ = self.broadcasted_matches_and_group_stages() matches, _ = self.broadcasted_matches_and_group_stages()

@ -14,11 +14,17 @@ class TournamentEmailService:
</html> </html>
""" """
@staticmethod
def email_subject(tournament, topic):
base_subject = f"[{tournament.build_tournament_type_str()}] [{tournament.formatted_start_date()}] " + topic
return base_subject
@staticmethod @staticmethod
def send_registration_confirmation(request, tournament, team_registration, waiting_list_position): def send_registration_confirmation(request, tournament, team_registration, waiting_list_position):
tournament_details_str = tournament.build_tournament_details_str() tournament_details_str = tournament.build_tournament_details_str()
email_subject = TournamentEmailService._build_email_subject( email_subject = TournamentEmailService._build_email_subject(
tournament,
tournament_details_str, tournament_details_str,
waiting_list_position waiting_list_position
) )
@ -41,11 +47,12 @@ class TournamentEmailService:
email.send() email.send()
@staticmethod @staticmethod
def _build_email_subject(tournament_details_str, waiting_list_position): def _build_email_subject(tournament, tournament_details_str, waiting_list_position):
base_subject = f"Confirmation d'inscription au tournoi {tournament_details_str}"
if waiting_list_position >= 0: if waiting_list_position >= 0:
base_subject = f"En liste d'attente du tournoi {tournament_details_str}" base_subject = "En liste d'attente du tournoi"
return base_subject else:
base_subject = "Confirmation d'inscription au tournoi"
return TournamentEmailService.email_subject(tournament, base_subject)
@staticmethod @staticmethod
def _build_email_body(request, tournament, team_registration, tournament_details_str, waiting_list_position): def _build_email_body(request, tournament, team_registration, tournament_details_str, waiting_list_position):
@ -68,7 +75,7 @@ class TournamentEmailService:
body_parts.extend([ body_parts.extend([
f"\nDate d'inscription: {inscription_date}", f"\nDate d'inscription: {inscription_date}",
f"\nÉquipe inscrite: {team_members_str}", f"\nÉquipe inscrite: {team_members_str}",
f"\nLe tournoi commencera le {tournament.start_date.strftime('%d/%m/%Y')} au club {tournament.event.club.name}", f"\nLe tournoi commencera le {tournament.formatted_start_date()} au club {tournament.event.club.name}",
f"\nVoir les {absolute_url}", f"\nVoir les {absolute_url}",
"\nPour toute question, veuillez contacter votre juge-arbitre. Si vous n'êtes pas à l'origine de cette inscription, merci de le contacter rapidement.", "\nPour toute question, veuillez contacter votre juge-arbitre. Si vous n'êtes pas à l'origine de cette inscription, merci de le contacter rapidement.",
f"\n{tournament.event.creator.full_name()}\n{tournament.event.creator.email}", f"\n{tournament.event.creator.full_name()}\n{tournament.event.creator.email}",
@ -82,7 +89,7 @@ class TournamentEmailService:
def send_unregistration_confirmation(captain, tournament, other_player): def send_unregistration_confirmation(captain, tournament, other_player):
tournament_details_str = tournament.build_tournament_details_str() tournament_details_str = tournament.build_tournament_details_str()
email_subject = f"Désistement du tournoi {tournament_details_str}" email_subject = TournamentEmailService.email_subject(tournament, "Désistement du tournoi")
email_body = TournamentEmailService._build_unregistration_email_body( email_body = TournamentEmailService._build_unregistration_email_body(
tournament, tournament,
captain, captain,
@ -119,9 +126,8 @@ class TournamentEmailService:
@staticmethod @staticmethod
def send_out_of_waiting_list_confirmation(captain, tournament, other_player): def send_out_of_waiting_list_confirmation(captain, tournament, other_player):
tournament_details_str = tournament.build_tournament_details_str() tournament_details_str = tournament.build_tournament_details_str()
email_subject = TournamentEmailService.email_subject(tournament, "Participation au tournoi")
email_subject = f"Participation au tournoi {tournament_details_str}" email_body = TournamentEmailService._build_out_of_waiting_list_email_body(
email_body = TournamentEmailService._buil_out_of_waiting_list_email_body(
tournament, tournament,
captain, captain,
tournament_details_str, tournament_details_str,
@ -138,7 +144,7 @@ class TournamentEmailService:
email.send() email.send()
if other_player.email is not None: if other_player.email is not None:
email_body = TournamentEmailService._buil_out_of_waiting_list_email_body( email_body = TournamentEmailService._build_out_of_waiting_list_email_body(
tournament, tournament,
other_player, other_player,
tournament_details_str, tournament_details_str,
@ -158,7 +164,7 @@ class TournamentEmailService:
def _build_unregistration_email_body(tournament, captain, tournament_details_str, other_player): def _build_unregistration_email_body(tournament, captain, tournament_details_str, other_player):
body_parts = [ body_parts = [
"Bonjour,\n\n", "Bonjour,\n\n",
f"Votre inscription au tournoi {tournament_details_str}, prévu le {tournament.start_date.strftime('%d/%m/%Y')} au club {tournament.event.club.name} a été annulée" f"Votre inscription au tournoi {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name} a été annulée"
] ]
if other_player is not None: if other_player is not None:
@ -166,9 +172,17 @@ class TournamentEmailService:
f"\n\nVous étiez inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire." f"\n\nVous étiez inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire."
) )
absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info"
link_text = "informations sur le tournoi"
absolute_url = f'<a href="{absolute_url}">{link_text}</a>'
body_parts.append(
f"\n\nVoir les {absolute_url}",
)
body_parts.extend([ body_parts.extend([
"\n\nPour toute question, veuillez contacter votre juge-arbitre. " "\n\nPour toute question, veuillez contacter votre juge-arbitre. "
"Si vous n'êtes pas à l'origine de cette inscription, merci de le contacter rapidement.", "Si vous n'êtes pas à l'origine de cette désinscription, merci de le contacter rapidement.",
f"\n{tournament.event.creator.full_name()}\n{tournament.event.creator.email}", f"\n{tournament.event.creator.full_name()}\n{tournament.event.creator.email}",
"\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre."
]) ])
@ -176,14 +190,14 @@ class TournamentEmailService:
return "".join(body_parts) return "".join(body_parts)
@staticmethod @staticmethod
def _buil_out_of_waiting_list_email_body(tournament, captain, tournament_details_str, other_player): def _build_out_of_waiting_list_email_body(tournament, captain, tournament_details_str, other_player):
body_parts = [ body_parts = [
"Bonjour,\n\n", "Bonjour,\n\n",
f"Suite au désistement d'une paire, vous êtes maintenant inscrit au tournoi {tournament_details_str}, prévu le {tournament.start_date.strftime('%d/%m/%Y')} au club {tournament.event.club.name}" f"Suite au désistement d'une paire, vous êtes maintenant inscrit au tournoi {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name}"
] ]
absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info"
link_text = "informations sur le tournoi" link_text = "accéder au tournoi"
absolute_url = f'<a href="{absolute_url}">{link_text}</a>' absolute_url = f'<a href="{absolute_url}">{link_text}</a>'
if other_player is not None: if other_player is not None:
@ -192,8 +206,9 @@ class TournamentEmailService:
) )
body_parts.append( body_parts.append(
"\nSi vous n'êtes plus disponible pour participer à ce tournoi, cliquez sur ce lien ou contactez rapidement le juge-arbitre." "\n\nSi vous n'êtes plus disponible pour participer à ce tournoi, cliquez sur ce lien ou contactez rapidement le juge-arbitre."
f"\n{absolute_url}" f"\n{absolute_url}"
"\nPour vous désinscrire en ligne vous devez avoir un compte Padel Club."
) )
body_parts.extend([ body_parts.extend([
@ -206,8 +221,7 @@ class TournamentEmailService:
@staticmethod @staticmethod
def send_tournament_cancellation_notification(player, tournament, other_player): def send_tournament_cancellation_notification(player, tournament, other_player):
tournament_details_str = tournament.build_tournament_details_str() tournament_details_str = tournament.build_tournament_details_str()
email_subject = TournamentEmailService.email_subject(tournament, "Annulation du tournoi")
email_subject = f"Annulation du tournoi {tournament_details_str}"
email_body = TournamentEmailService._build_tournament_cancellation_email_body( email_body = TournamentEmailService._build_tournament_cancellation_email_body(
tournament, tournament,
player, player,
@ -228,7 +242,7 @@ class TournamentEmailService:
def _build_tournament_cancellation_email_body(tournament, player, tournament_details_str, other_player): def _build_tournament_cancellation_email_body(tournament, player, tournament_details_str, other_player):
body_parts = [ body_parts = [
"Bonjour,\n\n", "Bonjour,\n\n",
f"Le tournoi {tournament_details_str}, prévu le {tournament.start_date.strftime('%d/%m/%Y')} au club {tournament.event.club.name} a été annulé par le juge-arbitre." f"Le tournoi {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name} a été annulé par le juge-arbitre."
] ]
if other_player is not None: if other_player is not None:

@ -22,7 +22,6 @@ class TournamentRegistrationService:
'team_form': None, 'team_form': None,
'add_player_form': None, 'add_player_form': None,
'current_players': self.request.session.get('team_registration', []), 'current_players': self.request.session.get('team_registration', []),
'user_without_licence': self.request.session.get('user_without_licence', False)
} }
return self.context return self.context
@ -54,11 +53,18 @@ class TournamentRegistrationService:
if self._is_already_registered(licence_id): if self._is_already_registered(licence_id):
return return
# Handle player data if self.request.user.licence_id is None and len(self.context['current_players']) == 0:
if self.context['add_player_form'].names_is_valid(): # if no licence id for authentificated user and trying to add him as first player of the team, we check his federal data
self._handle_valid_names(player_data)
else:
self._handle_invalid_names(licence_id, player_data) self._handle_invalid_names(licence_id, player_data)
else:
# Handle player data
if self.context['add_player_form'].names_is_valid():
self._handle_valid_names(player_data)
else:
self._handle_invalid_names(licence_id, player_data)
if self.request.user.is_authenticated and self.request.user.licence_id is None:
self._update_user_license(player_data.get('licence_id'))
def handle_team_registration(self): def handle_team_registration(self):
if not self.context['team_form'].is_valid(): if not self.context['team_form'].is_valid():
@ -214,12 +220,6 @@ class TournamentRegistrationService:
self._set_default_rank(player_data) self._set_default_rank(player_data)
self.add_player_to_session(player_data) self.add_player_to_session(player_data)
if self.request.user.is_authenticated and self.request.user.licence_id is None:
self._update_user_license(player_data.get('licence_id'))
self.context['add_player_form'].user_without_licence = False
self.request.session.modified = True
self.context['add_player_form'] = AddPlayerForm() self.context['add_player_form'] = AddPlayerForm()
self.context['add_player_form'].first_tournament = False self.context['add_player_form'].first_tournament = False
@ -255,6 +255,7 @@ class TournamentRegistrationService:
self.request.user.licence_id = validator.computed_licence_id self.request.user.licence_id = validator.computed_licence_id
self.request.user.save() self.request.user.save()
self.request.user.refresh_from_db() self.request.user.refresh_from_db()
self.request.session.modified = True
# Reset the form state # Reset the form state
self.context['add_player_form'] = AddPlayerForm() self.context['add_player_form'] = AddPlayerForm()
self.context['add_player_form'].first_tournament = False self.context['add_player_form'].first_tournament = False

@ -29,10 +29,28 @@ class TournamentUnregistrationService:
"La désincription a échouée. Veuillez contacter le juge-arbitre.") "La désincription a échouée. Veuillez contacter le juge-arbitre.")
return False return False
self._unregister_team()
self._delete_registered_team() self._delete_registered_team()
self._cleanup_session() self._cleanup_session()
return True return True
def _unregister_team(self):
# Create unregistered team record
team_registration = self.player_registration.team_registration
unregistered_team = UnregisteredTeam.objects.create(
tournament=team_registration.tournament,
unregistration_date=timezone.now(),
)
for player in team_registration.playerregistration_set.all():
UnregisteredPlayer.objects.create(
unregistered_team=unregistered_team,
first_name=player.first_name,
last_name=player.last_name,
licence_id=player.licence_id,
)
def _find_player_registration(self): def _find_player_registration(self):
self.player_registration = PlayerRegistration.objects.filter( self.player_registration = PlayerRegistration.objects.filter(
licence_id__startswith=self.request.user.licence_id, licence_id__startswith=self.request.user.licence_id,

@ -1,6 +1,6 @@
import random import random
import string import string
from django.db.models.signals import post_save, pre_delete from django.db.models.signals import post_save, pre_delete, post_delete
from django.dispatch import receiver from django.dispatch import receiver
from django.conf import settings from django.conf import settings
from tournaments.models.tournament import Tournament from tournaments.models.tournament import Tournament
@ -63,19 +63,9 @@ def send_discord_message(webhook_url, content):
def unregister_team(sender, instance, **kwargs): def unregister_team(sender, instance, **kwargs):
team_registration = instance team_registration = instance
tournament = instance.tournament tournament = instance.tournament
if tournament.is_deleted is True:
# Skip creating unregistration records if tournament is being deleted
if not tournament or tournament._being_deleted == True:
return return
first_waiting_list_team = tournament.first_waiting_list_team()
# Create unregistered team record
unregistered_team = UnregisteredTeam.objects.create(
tournament=tournament,
unregistration_date=timezone.now(),
)
# Create unregistered player records and track captain/other player # Create unregistered player records and track captain/other player
captain = None captain = None
other_player = None other_player = None
@ -85,13 +75,17 @@ def unregister_team(sender, instance, **kwargs):
else: else:
other_player = player other_player = player
UnregisteredPlayer.objects.create( # Send unregistration confirmation
unregistered_team=unregistered_team, if captain and captain.registered_online and captain.email:
first_name=player.first_name, TournamentEmailService.send_unregistration_confirmation(
last_name=player.last_name, captain,
licence_id=player.licence_id, tournament,
other_player
) )
first_waiting_list_team = tournament.first_waiting_list_team()
print("first_waiting_list_team", first_waiting_list_team)
# Handle waiting list notifications # Handle waiting list notifications
if first_waiting_list_team: if first_waiting_list_team:
waiting_captain = None waiting_captain = None
@ -109,18 +103,13 @@ def unregister_team(sender, instance, **kwargs):
waiting_other_player waiting_other_player
) )
# Send unregistration confirmation @receiver(post_save, sender=Tournament)
if captain and captain.registered_online and captain.email:
TournamentEmailService.send_unregistration_confirmation(
captain,
tournament,
other_player
)
@receiver(pre_delete, sender=Tournament)
def notify_players_of_tournament_cancellation(sender, instance, **kwargs): def notify_players_of_tournament_cancellation(sender, instance, **kwargs):
tournament = instance tournament = instance
if tournament.is_deleted is False:
return
# Get all team registrations # Get all team registrations
team_registrations = tournament.teamregistration_set.all() team_registrations = tournament.teamregistration_set.all()
@ -130,16 +119,14 @@ def notify_players_of_tournament_cancellation(sender, instance, **kwargs):
# Get players who registered online and have email # Get players who registered online and have email
for player in team_registration.playerregistration_set.all(): for player in team_registration.playerregistration_set.all():
if not player.registered_online: print(player, player.registered_online)
continue
if player.captain: if player.captain:
captain = player captain = player
else: else:
other_player = player other_player = player
# Send email to captain # Send email to captain
if captain: if captain and captain.registered_online and captain.email:
TournamentEmailService.send_tournament_cancellation_notification( TournamentEmailService.send_tournament_cancellation_notification(
captain, captain,
tournament, tournament,

@ -63,6 +63,7 @@ from django.core.mail import EmailMessage
from django.views.decorators.csrf import csrf_protect from django.views.decorators.csrf import csrf_protect
from .services.tournament_registration import TournamentRegistrationService from .services.tournament_registration import TournamentRegistrationService
from .services.tournament_unregistration import TournamentUnregistrationService from .services.tournament_unregistration import TournamentUnregistrationService
from django.core.exceptions import ValidationError
# Local application imports # Local application imports

Loading…
Cancel
Save