diff --git a/tournaments/models/tournament.py b/tournaments/models/tournament.py index a35b1b9..77c05d1 100644 --- a/tournaments/models/tournament.py +++ b/tournaments/models/tournament.py @@ -11,6 +11,7 @@ from django.utils import timezone, formats from datetime import datetime, timedelta from zoneinfo import ZoneInfo +from tournaments.utils.player_search import get_player_name_from_csv from shared.cryptography import encryption_util from ..utils.extensions import plural_format @@ -1078,6 +1079,89 @@ class Tournament(models.Model): name_str = f" {name_str}" return name_str + def user_register_check(self, user): + reasons = [] + + if not user.licence_id: + return None + + data, found = get_player_name_from_csv(self.federal_category, user.licence_id) + if not found or not data: + return None + + birth_year = data.get('birth_year', None) + is_woman = data.get('is_woman', None) + + # Check gender category restrictions + if is_woman is not None and self.federal_category == FederalCategory.WOMEN and is_woman is False: + reasons.append("Ce tournoi est réservé aux femmes") + + if birth_year is None: + return reasons if reasons else None + + current_year = timezone.now().year + if timezone.now().month >= 9: # Check if current month is September or later + current_year += 1 + + user_age = current_year - int(birth_year) + + # Check age category restrictions + if self.federal_age_category == FederalAgeCategory.A11_12 and user_age > 12: + reasons.append("Ce tournoi est réservé aux -12 ans") + if self.federal_age_category == FederalAgeCategory.A13_14 and user_age > 14: + reasons.append("Ce tournoi est réservé aux -14 ans") + if self.federal_age_category == FederalAgeCategory.A15_16 and user_age > 16: + reasons.append("Ce tournoi est réservé aux -16 ans") + if self.federal_age_category == FederalAgeCategory.A17_18 and user_age > 18: + reasons.append("Ce tournoi est réservé aux -18 ans") + if self.federal_age_category == FederalAgeCategory.A45 and user_age < 45: + reasons.append("Ce tournoi est réservé aux +45 ans") + if self.federal_age_category == FederalAgeCategory.A55 and user_age < 55: + reasons.append("Ce tournoi est réservé aux +55 ans") + + return reasons if reasons else None +def user_can_register(self, user): + if not user.licence_id: + return True + + data, found = get_player_name_from_csv(self.federal_category, user.licence_id) + if not found: + return True + if not data: + return True + + birth_year = data.get('birth_year', None) + is_woman = data.get('is_woman', None) + + # Check gender category restrictions + if is_woman is not None and self.federal_category == FederalCategory.WOMEN and is_woman is False: + return False + + if birth_year is None: + return True + + current_year = timezone.now().year + if timezone.now().month >= 9: # Check if current month is September or later + current_year += 1 + + user_age = current_year - int(birth_year) + + # Check age category restrictions + if self.federal_age_category == FederalAgeCategory.A11_12 and user_age > 12: + return False + if self.federal_age_category == FederalAgeCategory.A13_14 and user_age > 14: + return False + if self.federal_age_category == FederalAgeCategory.A15_16 and user_age > 16: + return False + if self.federal_age_category == FederalAgeCategory.A17_18 and user_age > 18: + return False + if self.federal_age_category == FederalAgeCategory.A45 and user_age < 45: + return False + if self.federal_age_category == FederalAgeCategory.A55 and user_age < 55: + return False + + return True + class MatchGroup: def __init__(self, name, matches, formatted_schedule): self.name = name diff --git a/tournaments/repositories.py b/tournaments/repositories.py new file mode 100644 index 0000000..6d621ea --- /dev/null +++ b/tournaments/repositories.py @@ -0,0 +1,71 @@ +from django.utils import timezone +from .models import TeamRegistration, PlayerRegistration +from .models.player_enums import PlayerSexType, PlayerDataSource +from .models.enums import FederalCategory +from tournaments.utils.licence_validator import LicenseValidator + +class TournamentRegistrationRepository: + @staticmethod + def create_team_registration(tournament, registration_date): + team_registration = TeamRegistration.objects.create( + tournament=tournament, + registration_date=registration_date + ) + return team_registration + + @staticmethod + def create_player_registrations(request, team_registration, players_data, team_form_data): + stripped_license = None + if request.user.is_authenticated and request.user.licence_id: + stripped_license = LicenseValidator(request.user.licence_id).stripped_license + + for player_data in players_data: + is_captain = False + player_licence_id = player_data['licence_id'] + if player_licence_id and stripped_license: + if player_licence_id.startswith(stripped_license): + is_captain = True + + sex, rank, computed_rank = TournamentRegistrationRepository._compute_rank_and_sex( + team_registration.tournament, + player_data + ) + + player_registration = PlayerRegistration.objects.create( + team_registration=team_registration, + captain=is_captain, + source=PlayerDataSource.ONLINE_REGISTRATION, + first_name=player_data.get('first_name'), + last_name=player_data.get('last_name'), + points=player_data.get('points'), + assimilation=player_data.get('assimilation'), + tournament_played=player_data.get('tournament_count'), + ligue_name=player_data.get('ligue_name'), + club_name=player_data.get('club_name'), + birthdate=player_data.get('birth_year'), + sex=sex, + rank=rank, + computed_rank=computed_rank, + licence_id=player_data['licence_id'], + email=team_form_data['email'], + phone_number=team_form_data['mobile_number'] + ) + player_registration.save() + + team_registration.set_weight() + team_registration.save() + + @staticmethod + def _compute_rank_and_sex(tournament, player_data): + is_woman = player_data.get('is_woman', False) + rank = player_data.get('rank', 0) + computed_rank = rank + sex = PlayerSexType.MALE + + if is_woman: + sex = PlayerSexType.FEMALE + if tournament.federal_category == FederalCategory.MEN: + computed_rank = str(int(computed_rank) + + FederalCategory.female_in_male_assimilation_addition(int(rank))) + + return sex, rank, computed_rank diff --git a/tournaments/services/email_service.py b/tournaments/services/email_service.py new file mode 100644 index 0000000..b799bf7 --- /dev/null +++ b/tournaments/services/email_service.py @@ -0,0 +1,111 @@ +from django.core.mail import EmailMessage +from django.utils import timezone + +class TournamentEmailService: + @staticmethod + def send_registration_confirmation(request, tournament, team_registration): + waiting_list_position = tournament.get_waiting_list_position() + tournament_details_str = tournament.build_tournament_details_str() + name_str = tournament.build_name_details_str() + + email_subject = TournamentEmailService._build_email_subject( + tournament_details_str, + name_str, + waiting_list_position + ) + + email_body = TournamentEmailService._build_email_body( + request, + tournament, + team_registration, + tournament_details_str, + name_str, + waiting_list_position + ) + + email = EmailMessage( + subject=email_subject, + body=email_body, + to=[request.user.email] + ) + email.send() + + @staticmethod + def _build_email_subject(tournament_details_str, name_str, waiting_list_position): + base_subject = f"Confirmation d'inscription au tournoi {tournament_details_str}{name_str}" + if waiting_list_position >= 0: + base_subject = f"En liste d'attente du tournoi {tournament_details_str}{name_str}" + return base_subject + + @staticmethod + def _build_email_body(request, tournament, team_registration, tournament_details_str, + name_str, waiting_list_position): + inscription_date = timezone.now().strftime("%d/%m/%Y à %H:%M") + team_members = [player.name() for player in team_registration.playerregistration_set.all()] + team_members_str = " et ".join(team_members) + + body_parts = [] + body_parts.append(f"Bonjour,\n") + + if waiting_list_position >= 0: + body_parts.append(f"Votre inscription en liste d'attente du tournoi {tournament_details_str}{name_str} est confirmée.") + else: + body_parts.append(f"Votre inscription au tournoi{tournament_details_str}{name_str} est confirmée.") + + body_parts.extend([ + f"\nDate d'inscription: {inscription_date}", + f"\nÉquipe inscrite: {team_members_str}", + f"\nLe tournoi commencera le {tournament.start_date.strftime('%d/%m/%Y')} @ {tournament.event.club.name}", + f"\nVoir les informations sur {request.build_absolute_uri(f'/tournament/{tournament.id}/')}", + "\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}", + "\nCeci est un e-mail automatique, veuillez ne pas y répondre.", + "\nCordialement,\n\nPadel Club" + ]) + + return "\n".join(body_parts) + + @staticmethod + def send_unregistration_confirmation(request, tournament, other_player): + tournament_details_str = tournament.build_tournament_details_str() + name_str = tournament.build_name_details_str() + + email_subject = f"Confirmation de désistement du tournoi{tournament_details_str}{name_str}" + email_body = TournamentEmailService._build_unregistration_email_body( + request, + tournament, + tournament_details_str, + name_str, + other_player + ) + + email = EmailMessage( + subject=email_subject, + body=email_body, + to=[request.user.email] + ) + email.send() + + @staticmethod + def _build_unregistration_email_body(request, tournament, tournament_details_str, + name_str, other_player): + body_parts = [ + f"Bonjour,\n", + f"Vous venez de vous désinscrire du tournoi {tournament_details_str}{name_str}", + f" du {tournament.start_date.strftime('%d/%m/%Y')} @ {tournament.event.club.name}" + ] + + if other_player: + body_parts.append( + f"\n\nVous étiez inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire." + ) + + body_parts.extend([ + f"\n\nVoir les informations sur {request.build_absolute_uri(f'/tournament/{tournament.id}/')}", + "\n\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}", + "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." + ]) + + return "".join(body_parts) diff --git a/tournaments/services/tournament_registration.py b/tournaments/services/tournament_registration.py new file mode 100644 index 0000000..658bb84 --- /dev/null +++ b/tournaments/services/tournament_registration.py @@ -0,0 +1,147 @@ +from django.utils import timezone +from ..forms import TournamentRegistrationForm, AddPlayerForm +from ..validators import TournamentRegistrationValidator +from ..repositories import TournamentRegistrationRepository +from .email_service import TournamentEmailService + +class TournamentRegistrationService: + def __init__(self, request, tournament): + self.request = request + self.tournament = tournament + self.context = {} + self.repository = TournamentRegistrationRepository() + self.validator = TournamentRegistrationValidator() + self.email_service = TournamentEmailService() + + def initialize_context(self): + self.context = { + 'tournament': self.tournament, + 'registration_successful': False, + 'team_form': None, + 'add_player_form': None, + 'current_players': self.request.session.get('team_registration', []), + 'user_without_licence': self.request.session.get('user_without_licence', False) + } + return self.context + + def handle_post_request(self): + self.context['team_form'] = TournamentRegistrationForm(self.request.POST) + self.context['add_player_form'] = AddPlayerForm(self.request.POST) + + if 'add_player' in self.request.POST: + self.handle_add_player() + elif 'register_team' in self.request.POST: + self.handle_team_registration() + + def handle_add_player(self): + if not self.context['add_player_form'].is_valid(): + return + + player_data = self.context['add_player_form'].cleaned_data + if not self.validator.validate_player_license(self.request, self.tournament, player_data): + return + + self.add_player_to_session(player_data) + self.context['add_player_form'] = AddPlayerForm() + + def handle_team_registration(self): + if not self.context['team_form'].is_valid(): + return + + team_registration = self.repository.create_team_registration( + self.tournament, + timezone.now().replace(microsecond=0) + ) + + self.repository.create_player_registrations( + self.request, + team_registration, + self.request.session['team_registration'], + self.context['team_form'].cleaned_data + ) + + self.email_service.send_registration_confirmation( + self.request, + self.tournament, + team_registration + ) + + self.clear_session_data() + self.context['registration_successful'] = True + + def handle_get_request(self): + self.context['add_player_form'] = AddPlayerForm() + self.context['team_form'] = self.initialize_team_form() + self.initialize_session_data() + + def add_player_to_session(self, player_data): + if not self.request.session.get('team_registration'): + self.request.session['team_registration'] = [] + + self.request.session['team_registration'].append(player_data) + self.request.session.modified = True + + def clear_session_data(self): + self.request.session['team_registration'] = [] + self.request.session.modified = True + + def initialize_team_form(self): + initial_data = {} + if self.request.user.is_authenticated: + initial_data = { + 'email': self.request.user.email, + 'phone': self.request.user.phone, + } + return TournamentRegistrationForm(initial=initial_data) + + def initialize_session_data(self): + self.request.session['team_registration'] = [] + if self.request.user.is_authenticated: + self._add_authenticated_user_to_session() + + def _add_authenticated_user_to_session(self): + if not self.request.user.licence_id: + self._handle_user_without_license() + return + + player_data = self._get_authenticated_user_data() + if player_data: + self.request.session['team_registration'].insert(0, player_data) + self.request.session.modified = True + + def _handle_user_without_license(self): + player_data = { + 'first_name': self.request.user.first_name, + 'last_name': self.request.user.last_name.upper(), + } + self.context['add_player_form'] = AddPlayerForm(initial=player_data) + self.request.session['user_without_licence'] = True + self.request.session.modified = True + + def _get_authenticated_user_data(self): + from ..utils.player_search import get_player_name_from_csv + from ..validators import LicenseValidator + user = self.request.user + validator = LicenseValidator(user.licence_id) + + player_data = { + 'first_name': user.first_name, + 'last_name': user.last_name.upper(), + 'email': user.email, + 'phone': user.phone, + 'licence_id': validator.computed_licence_id + } + + data, found = get_player_name_from_csv(self.tournament.federal_category, user.licence_id) + if found and data: + player_data.update({ + 'rank': data['rank'], + 'points': data.get('points'), + 'assimilation': data.get('assimilation'), + 'tournament_count': data.get('tournament_count'), + 'ligue_name': data.get('ligue_name'), + 'club_name': data.get('club_name'), + 'birth_year': data.get('birth_year') + }) + + return player_data diff --git a/tournaments/services/tournament_unregistration.py b/tournaments/services/tournament_unregistration.py new file mode 100644 index 0000000..010189f --- /dev/null +++ b/tournaments/services/tournament_unregistration.py @@ -0,0 +1,78 @@ +from django.contrib import messages +from django.utils import timezone +from ..models import PlayerRegistration, UnregisteredTeam, UnregisteredPlayer +from ..models.player_enums import PlayerDataSource +from ..services.email_service import TournamentEmailService + +class TournamentUnregistrationService: + def __init__(self, request, tournament): + self.request = request + self.tournament = tournament + self.player_registration = None + self.other_player = None + + def can_unregister(self): + if not self.tournament.is_unregistration_possible(): + messages.error(self.request, "Le désistement n'est plus possible pour ce tournoi.") + return False + + if not self.request.user.licence_id: + messages.error(self.request, + "Vous ne pouvez pas vous désinscrire car vous n'avez pas de numéro de licence associé.") + return False + + return True + + def process_unregistration(self): + if not self._find_player_registration(): + messages.error(self.request, + "La désincription a échouée. Veuillez contacter le juge-arbitre.") + return False + + self._create_unregistered_team() + self._send_unregistration_email() + self._cleanup_session() + return True + + def _find_player_registration(self): + self.player_registration = PlayerRegistration.objects.filter( + licence_id__startswith=self.request.user.licence_id, + team_registration__tournament_id=self.tournament.id, + ).first() + + if self.player_registration: + team_registration = self.player_registration.team_registration + self.other_player = team_registration.get_other_player(self.player_registration) + return True + return False + + def _create_unregistered_team(self): + team_registration = self.player_registration.team_registration + + unregistered_team = UnregisteredTeam.objects.create( + tournament=self.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, + ) + + team_registration.delete() + + def _cleanup_session(self): + self.request.session['team_registration'] = [] + + def _send_unregistration_email(self): + if not self.request.user.email: + return + + TournamentEmailService.send_unregistration_confirmation( + self.request, + self.tournament, + self.other_player + ) diff --git a/tournaments/templates/tournaments/tournament_info.html b/tournaments/templates/tournaments/tournament_info.html index f4f35a5..8a29253 100644 --- a/tournaments/templates/tournaments/tournament_info.html +++ b/tournaments/templates/tournaments/tournament_info.html @@ -78,39 +78,43 @@ {% endif %} {% if tournament.online_register_is_enabled and team is None %} - - {% if tournament.account_is_required is False or user.is_authenticated and user.is_active %} - -

-

- S'inscrire -
-

- {% else %} - - {% for message in messages %} -
{{ message }}
- {% endfor %} - - -

-

- Connectez-vous ! -
-

- -

-

- Vous avez besoin d'un compte Padel Club pour pouvoir vous inscrire en ligne. - Créer le tout de suite ! -
-

- {% endif %} - - - + {% if tournament.account_is_required is False or user.is_authenticated and user.is_active %} + {% if user_register_check is None %} +

+

+ S'inscrire +
+

+ {% else %} +

+

+ Vous ne pouvez pas vous inscrire à ce tournoi. +
+
+ {% for reason in user_register_check %} +
{{ reason }}
+ {% endfor %} +
+

+ {% endif %} + {% else %} + {% for message in messages %} +
{{ message }}
+ {% endfor %} +

+

+ Connectez-vous ! +
+

+ +

+

+ Vous avez besoin d'un compte Padel Club pour pouvoir vous inscrire en ligne. + Créer le tout de suite ! +
+

+ {% endif %} {% endif %} - {% if tournament.online_register_is_enabled and team %} diff --git a/tournaments/validators.py b/tournaments/validators.py new file mode 100644 index 0000000..d6ffdc5 --- /dev/null +++ b/tournaments/validators.py @@ -0,0 +1,49 @@ +from django.contrib import messages +from .models import PlayerRegistration +from tournaments.utils.licence_validator import LicenseValidator +# Remove unused import since get_player_name_from_csv is not used in this class + +class TournamentRegistrationValidator: + @staticmethod + def validate_player_license(request, tournament, player_data): + licence_id = player_data['licence_id'].upper() + validator = LicenseValidator(licence_id) + + if not validator.validate_license() and tournament.license_is_required: + TournamentRegistrationValidator._handle_invalid_license(request, licence_id) + return False + + if validator.validate_license() and TournamentRegistrationValidator._is_duplicate_license( + licence_id, request.session['team_registration']): + messages.error(request, "Ce joueur est déjà dans l'équipe.") + return False + + if validator.validate_license() and tournament.license_is_required: + stripped_license = validator.stripped_license + if TournamentRegistrationValidator._license_already_registered(stripped_license, tournament): + messages.error(request, "Un joueur avec ce numéro de licence est déjà inscrit dans une équipe.") + return False + + return True + + @staticmethod + def _handle_invalid_license(request, licence_id): + if not licence_id: + if not request.session.get('team_registration'): + messages.error(request, "Le numéro de licence est obligatoire.") + else: + messages.error(request, "Le numéro de licence de votre partenaire est obligatoire.") + else: + messages.error(request, "Le numéro de licence est invalide, la lettre ne correspond pas.") + + @staticmethod + def _is_duplicate_license(licence_id, team_registration): + existing_licenses = [player['licence_id'] for player in team_registration] + return licence_id in existing_licenses + + @staticmethod + def _license_already_registered(stripped_license, tournament): + return PlayerRegistration.objects.filter( + team_registration__tournament=tournament, + licence_id__startswith=stripped_license + ).exists() diff --git a/tournaments/views.py b/tournaments/views.py index 2700533..4e0bfc6 100644 --- a/tournaments/views.py +++ b/tournaments/views.py @@ -34,6 +34,10 @@ from django.views.decorators.csrf import csrf_exempt from django.core.files.storage import default_storage from django.core.files.base import ContentFile from django.core.mail import EmailMessage +from django.views.decorators.csrf import csrf_protect +from .services.tournament_registration import TournamentRegistrationService +from .services.tournament_unregistration import TournamentUnregistrationService + # Local application imports from .models import ( @@ -70,6 +74,7 @@ from api.tokens import account_activation_token from tournaments.models.device_token import DeviceToken from tournaments.models.player_enums import PlayerDataSource, PlayerSexType from django.views.generic.edit import UpdateView +from .forms import CustomPasswordChangeForm def index(request): @@ -125,10 +130,12 @@ def tournament_info(request, tournament_id): registered_user = None team_registration = None is_captain = False + user_can_register = True if request.user.is_authenticated: # Assuming user's licence_id is stored in the user profile (e.g., request.user.licence_id) user_licence_id = request.user.licence_id + if user_licence_id is not None: validator = LicenseValidator(user_licence_id) stripped_license = validator.stripped_license @@ -143,11 +150,14 @@ def tournament_info(request, tournament_id): if registered_user: is_captain = registered_user.captain team_registration = registered_user.team_registration + else: + user_register_check = tournament.user_register_check(request.user) return render(request, 'tournaments/tournament_info.html', { 'tournament': tournament, 'team': team_registration, - 'is_captain': is_captain + 'is_captain': is_captain, + 'user_register_check': user_register_check }) @@ -596,376 +606,30 @@ def profile(request): 'user_name': user.username }) -from django.views.decorators.csrf import csrf_protect - @csrf_protect def register_tournament(request, tournament_id): tournament = get_object_or_404(Tournament, id=tournament_id) - registration_successful = False # Flag for registration status - team_form = None - add_player_form = None - if 'user_without_licence' not in request.session: - request.session['user_without_licence'] = False + service = TournamentRegistrationService(request, tournament) + service.initialize_context() - user_without_licence = request.session['user_without_licence'] - - # Process forms if request.method == 'POST': - team_form = TournamentRegistrationForm(request.POST) - # Check if the add player form is submitted - add_player_form = AddPlayerForm(request.POST) - if 'add_player' in request.POST and add_player_form.is_valid(): - player_data = add_player_form.cleaned_data - # Validate the license ID before adding the player - licence_id = player_data['licence_id'].upper() - # Instantiate your custom validator and validate the license ID - - validator = LicenseValidator(licence_id) - if validator.validate_license() is False and tournament.license_is_required is True: - if len(licence_id) == 0: - if len(request.session.get('team_registration', [])) == 0: - messages.error(request, "Le numéro de licence est obligatoire.") - else: - messages.error(request, "Le numéro de licence de votre partenaire est obligatoire.") - else: - messages.error(request, "Le numéro de licence est invalide, la lettre ne correspond pas.") - return render(request, 'register_tournament.html', { - 'team_form': team_form, - 'add_player_form': add_player_form, - 'tournament': tournament, - 'registration_successful': registration_successful, - 'current_players': request.session['team_registration'], - 'user_without_licence': user_without_licence - }) - - # Check if the player with the same licence_id already exists in the session - existing_players = [player['licence_id'] for player in request.session['team_registration']] - if validator.validate_license() and licence_id in existing_players: - messages.error(request, "Ce joueur est déjà dans l'équipe.") - return render(request, 'register_tournament.html', { - 'team_form': team_form, - 'add_player_form': add_player_form, - 'tournament': tournament, - 'registration_successful': registration_successful, - 'current_players': request.session['team_registration'], - 'user_without_licence': user_without_licence - }) - else: - # Check if a PlayerRegistration with the same licence_id already exists in the database - stripped_license = validator.stripped_license - if validator.validate_license() and validate_license_id(stripped_license, tournament) and tournament.license_is_required is True: - messages.error(request, "Un joueur avec ce numéro de licence est déjà inscrit dans une équipe.") - return render(request, 'register_tournament.html', { - 'team_form': team_form, - 'add_player_form': add_player_form, - 'tournament': tournament, - 'registration_successful': registration_successful, - 'current_players': request.session['team_registration'], - 'user_without_licence': user_without_licence - }) - elif add_player_form.names_is_valid(): - if player_data.get('rank', None) is None: - if request.session.get('last_rank', None) is None: - data, found = get_player_name_from_csv(tournament.federal_category, None) - if data: - request.session['last_rank'] = data['rank'] - request.session['is_woman'] = data['is_woman'] - request.session.modified = True - player_data['rank'] = request.session.get('last_rank', 0) - player_data['is_woman'] = request.session.get('is_woman', False) - request.session['team_registration'].append(player_data) - if request.user.is_authenticated and request.user.licence_id is None: - request.session['user_without_licence'] = False - request.user.licence_id = validator.computed_licence_id - request.user.save() - request.session.modified = True # Ensure session is updated - add_player_form = AddPlayerForm() - - else: - if add_player_form.first_tournament is False: - # Retrieve player names from the CSV file - data, found = get_player_name_from_csv(tournament.federal_category, licence_id) - if found and data: - player_data['first_name'] = data['first_name'] - player_data['last_name'] = data['last_name'] - player_data['rank'] = data['rank'] - player_data['is_woman'] = data['is_woman'] - # If validation passes, add the player to the session without clearing previous ones - request.session['team_registration'].append(player_data) - request.session.modified = True # Ensure session is updated - add_player_form = AddPlayerForm() - else: - if data: - request.session['last_rank'] = data['rank'] - request.session['is_woman'] = data['is_woman'] - request.session.modified = True # Ensure session is updated - add_player_form.first_tournament = True - if add_player_form.names_is_valid() is False: - if len(request.session.get('team_registration', [])) == 0: - messages.error(request, "Pour confirmer votre inscription votre prénom et votre nom sont obligatoires.") - else: - messages.error(request, "Pour rajouter un partenaire, son prénom et son nom sont obligatoires.") - return render(request, 'register_tournament.html', { - 'team_form': team_form, - 'add_player_form': add_player_form, - 'tournament': tournament, - 'registration_successful': registration_successful, - 'current_players': request.session['team_registration'], - 'user_without_licence': user_without_licence - }) - - - - - # Check if the team registration form is valid and finalize the registration - elif 'register_team' in request.POST and team_form.is_valid(): - waiting_list_position = tournament.get_waiting_list_position() - registration_date = timezone.now().replace(microsecond=0) - team_registration = TeamRegistration.objects.create( - tournament=tournament, - registration_date=registration_date - ) - - stripped_license = None - if request.user.is_authenticated and request.user.licence_id is not None: - stripped_license = LicenseValidator(request.user.licence_id).stripped_license - - # Create PlayerRegistration objects for each player in the session - for player_data in request.session['team_registration']: - is_captain = False - player_licence_id = player_data['licence_id'] - if player_licence_id is not None and stripped_license is not None: - if player_licence_id.startswith(stripped_license): - is_captain = True - - is_woman = player_data.get('is_woman', False) - rank = player_data.get('rank', 0) - computed_rank = None - sex = PlayerSexType.MALE - if is_woman is None: - computed_rank = rank - else: - computed_rank = rank - is_woman = player_data.get('is_woman', False) == True - if is_woman: - sex = PlayerSexType.FEMALE - if tournament.federal_category == FederalCategory.MEN and is_woman: - computed_rank = str(int(computed_rank) + FederalCategory.female_in_male_assimilation_addition(int(rank))) - - - player_registration = PlayerRegistration.objects.create( - team_registration=team_registration, - captain=is_captain, - source=PlayerDataSource.ONLINE_REGISTRATION, - first_name=player_data.get('first_name', None), - last_name=player_data.get('last_name', None), - points=player_data.get('points', None), - assimilation=player_data.get('assimilation', None), - tournament_played=player_data.get('tournament_count', None), - ligue_name=player_data.get('ligue_name', None), - club_name=player_data.get('club_name', None), - birthdate=player_data.get('birth_year', None), - sex = sex, - rank = rank, - computed_rank = computed_rank, - licence_id=player_data['licence_id'], - email = team_form.cleaned_data['email'], - phone_number = team_form.cleaned_data['mobile_number'] - ) - player_registration.save() - - team_registration.set_weight() - team_registration.save() - - request.session['team_registration'] = [] - registration_successful = True - - # Send confirmation email - tournament_details_str = tournament.build_tournament_details_str() - name_str = tournament.build_name_details_str() - - email_subject = f"Confirmation d'inscription au tournoi {tournament_details_str}{name_str}" - if waiting_list_position >= 0: - email_subject = f"En liste d'attente du tournoi {tournament_details_str}{name_str}" - - inscription_date = timezone.now().strftime("%d/%m/%Y à %H:%M") - team_members = [player.name() for player in team_registration.playerregistration_set.all()] - team_members_str = " et ".join(team_members) - - email_body = f"Bonjour,\n\nVotre inscription au tournoi{tournament_details_str}{name_str} est confirmée." - if tournament.get_waiting_list_position() >= 0: - email_body = f"Bonjour,\n\nVotre inscription en liste d'attente du tournoi{tournament_details_str}{name_str} est confirmée." - - email_body += f"\n\nDate d'inscription: {inscription_date}" - email_body += f"\n\nÉquipe inscrite: {team_members_str}" - email_body += f"\n\nLe tournoi commencera le {tournament.start_date.strftime('%d/%m/%Y')}" - email_body += f" @ {tournament.event.club.name}" - email_body += f"\n\nVoir les informations sur {request.build_absolute_uri(f'/tournament/{tournament.id}/')}" - email_body += "\n\nPour toute question, veuillez contacter votre juge-arbitre. Si vous n'êtes pas à l'origine de cette inscription, merci de le contacter rapidement." - email_body += f"\n{tournament.event.creator.full_name()}\n{tournament.event.creator.email}" - email_body += "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." - - email_body += "\n\nCordialement,\n\nPadel Club" - - - email = EmailMessage( - subject=email_subject, - body=email_body, - to=[team_form.cleaned_data['email']] - ) - email.send() + service.handle_post_request() else: - add_player_form = AddPlayerForm() - - request.session['team_registration'] = [] - initial_data = {} - player_data = {} - - # Add the authenticated user to the session as the first player if not already added - if request.user.is_authenticated: - user_licence_id = request.user.licence_id - initial_data = { - 'email': request.user.email, - 'phone': request.user.phone, - } - - if user_licence_id is not None: - validator = LicenseValidator(user_licence_id) - existing_players = [player['licence_id'] for player in request.session['team_registration']] - if user_licence_id not in existing_players: - # Add the authenticated user as the first player in the session - player_data = { - 'first_name': request.user.first_name, - 'last_name': request.user.last_name.upper(), - 'email': request.user.email, - 'phone': request.user.phone, - 'licence_id': validator.computed_licence_id - } - - data, found = get_player_name_from_csv(tournament.federal_category, user_licence_id) - if found and data: - player_data['rank'] = data['rank'] - player_data['points'] = data.get('points', None) - player_data['assimilation'] = data.get('assimilation', None) - player_data['tournament_count'] = data.get('tournament_count', None) - player_data['ligue_name'] = data.get('ligue_name', None) - player_data['club_name'] = data.get('club_name', None) - player_data['birth_year'] = data.get('birth_year', None) - - request.session['team_registration'].insert(0, player_data) # Add them as the first player - request.session.modified = True # Ensure session is updated - else: - player_data = { - 'first_name': request.user.first_name, - 'last_name': request.user.last_name.upper(), - } - add_player_form = AddPlayerForm(initial=player_data) - request.session['user_without_licence'] = True - request.session.modified = True # Ensure session is updated - user_without_licence = True - - team_form = TournamentRegistrationForm(initial=initial_data) - return render(request, 'register_tournament.html', { - 'team_form': team_form, - 'add_player_form': add_player_form, - 'tournament': tournament, - 'registration_successful': registration_successful, - 'current_players': request.session['team_registration'], - 'user_without_licence': request.session['user_without_licence'] - }) - - + service.handle_get_request() + return render(request, 'register_tournament.html', service.context) @login_required def unregister_tournament(request, tournament_id): tournament = get_object_or_404(Tournament, id=tournament_id) + service = TournamentUnregistrationService(request, tournament) - if not tournament or not tournament.is_unregistration_possible(): - messages.error(request, "Le désistement n'est plus possible pour ce tournoi.") - return redirect('tournament-info', tournament_id=tournament_id) - - user_licence_id = request.user.licence_id - if not user_licence_id: - messages.error(request, "Vous ne pouvez pas vous désinscrire car vous n'avez pas de numéro de licence associé.") - return redirect('tournament-info', tournament_id=tournament_id) - - player_registration = PlayerRegistration.objects.filter( - licence_id__startswith=user_licence_id, - team_registration__tournament_id=tournament_id, - source=PlayerDataSource.ONLINE_REGISTRATION, - ).first() # Get the first match, if any - - other_player = None - if player_registration: - team_registration = player_registration.team_registration # Get the related TeamRegistration - other_player = team_registration.get_other_player(player_registration) - - unregistered_team = UnregisteredTeam.objects.create( - tournament=tournament, - unregistration_date=timezone.now(), - ) - - for player in team_registration.playerregistration_set.all(): - unregistered_player = UnregisteredPlayer.objects.create( - unregistered_team=unregistered_team, - first_name=player.first_name, - last_name=player.last_name, - licence_id=player.licence_id, - ) - unregistered_player.save() - - unregistered_team.save() - team_registration.delete() - - else: - messages.error(request, "La désincription a échouée. Veuillez contacter le juge-arbitre.") + if not service.can_unregister(): return redirect('tournament-info', tournament_id=tournament_id) - request.session['team_registration'] = [] - # Get the tournament information and player details before deleting - if tournament and request.user.email: # Ensure we have valid tournament and user email - tournament_details_str = tournament.build_tournament_details_str() - name_str = tournament.build_name_details_str() - email_subject = f"Confirmation de désistement du tournoi{tournament_details_str}{name_str}" - - email_body = f"Bonjour,\n\nVous venez de vous désinscrire du tournoi{tournament_details_str}{name_str}" - email_body += f" du {tournament.start_date.strftime('%d/%m/%Y')}" - email_body += f" au {tournament.event.club.name}" - if other_player is not None: - email_body += f"\n\nVous étiez inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire." - - email_body += f"\n\nVoir les informations sur {request.build_absolute_uri(f'/tournament/{tournament.id}/')}" - email_body += "\n\nPour toute question, veuillez contacter votre juge-arbitre. Si vous n'êtes pas à l'origine de cette inscription, merci de le contacter rapidement." - email_body += f"\n{tournament.event.creator.full_name()}\n{tournament.event.creator.email}" - email_body += "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." - - email = EmailMessage( - subject=email_subject, - body=email_body, - to=[request.user.email] - ) - email.send() - + service.process_unregistration() return redirect('tournament-info', tournament_id=tournament_id) -def validate_license_id(licence_id, tournament): - teams = TeamRegistration.objects.filter(tournament=tournament) - - # Filter out walkouts and unregistered teams - teams = teams.filter(walk_out=False) - - # Check if any player in any team in the tournament already has this licence_id - # Normalize the licence ID before querying - # Loop through each team and check if any of its players has the same licence_id - for team in teams: - for player in team.playerregistration_set.all(): - if player.licence_id is not None and player.licence_id.startswith(licence_id): - return True - - # If all checks pass, return True (you can add further logic here if needed) - return False - class CustomPasswordResetConfirmView(PasswordResetConfirmView): template_name = 'registration/password_reset_confirm.html' # Custom template @@ -1034,8 +698,6 @@ def my_tournaments(request): 'user_name': user.username }) -from .forms import CustomPasswordChangeForm - class ProfileUpdateView(UpdateView): model = CustomUser form_class = ProfileUpdateForm