+ {% endif %}
+ {% endif %}
diff --git a/tournaments/urls.py b/tournaments/urls.py
index e4b316b..59fc932 100644
--- a/tournaments/urls.py
+++ b/tournaments/urls.py
@@ -1,3 +1,4 @@
+from django.contrib.auth import views as auth_views
from django.urls import include, path
from . import views
@@ -38,4 +39,11 @@ urlpatterns = [
path('terms-of-use/', views.terms_of_use, name='terms-of-use'),
path('utils/xls-to-csv/', views.xls_to_csv, name='xls-to-csv'),
path('mail-test/', views.simple_form_view, name='mail-test'),
+ path('login/', auth_views.LoginView.as_view(), name='login'),
+ path('logout/', auth_views.LogoutView.as_view(), name='logout'),
+ path('signup/', views.signup, name='signup'), # URL pattern for signup
+ path('profile/', views.profile, name='profile'), # URL pattern for signup
+ path('tournaments//register/', views.register_tournament, name='register_tournament'),
+ path('tournaments//unregister/', views.unregister_tournament, name='unregister_tournament'),
+
]
diff --git a/tournaments/utils/licence_validator.py b/tournaments/utils/licence_validator.py
new file mode 100644
index 0000000..9b096c9
--- /dev/null
+++ b/tournaments/utils/licence_validator.py
@@ -0,0 +1,44 @@
+import re
+
+class LicenseValidator:
+ def __init__(self, license_id: str):
+ self.license_id = license_id.upper() # Ensure uppercase for consistency
+
+ @property
+ def stripped_license(self) -> str:
+ # Remove leading zero if present and match only the numeric part
+ license_without_leading_zero = self.license_id.lstrip("0")
+ match = re.match(r"^[0-9]{6,8}", license_without_leading_zero)
+ if match:
+ return match.group(0)
+ return 'licence invalide'
+
+ @property
+ def computed_license_key(self) -> str:
+ stripped = self.stripped_license
+ if stripped and stripped.isdigit():
+ int_value = int(stripped)
+ value = (int_value - 1) % 23
+ char_code = ord('A') + value
+
+ # Adjust for letters to skip: I, O, Q
+ if char_code >= ord('I'):
+ char_code += 1
+ if char_code >= ord('O'):
+ char_code += 1
+ if char_code >= ord('Q'):
+ char_code += 1
+
+ return chr(char_code)
+ return 'aucune clé de licence'
+
+ def validate_license(self) -> bool:
+ if not self.license_id or len(self.license_id) < 7:
+ return False # Invalid length for a license ID
+
+ # Separate the numeric part and the letter
+ numeric_part = self.license_id[:-1]
+ given_letter = self.license_id[-1]
+
+ # Verify that the last character matches the computed license key
+ return self.computed_license_key == given_letter
diff --git a/tournaments/utils/player_search.py b/tournaments/utils/player_search.py
new file mode 100644
index 0000000..b14d799
--- /dev/null
+++ b/tournaments/utils/player_search.py
@@ -0,0 +1,33 @@
+import csv
+import os
+import re
+
+def clean_licence_id(licence_id):
+ # This regex matches the trailing letters (non-digits) and removes them
+ cleaned_licence_id = re.sub(r'\D+$', '', str(licence_id)) # \D+ matches non-digits at the end
+ return cleaned_licence_id
+
+def get_player_name_from_csv(licence_id):
+ # Define the file path
+ file_path = '/Users/razmig/Documents/XLR Sport/padelclub_backend/tournaments/static/rankings/CLASSEMENT-PADEL-MESSIEURS-11-2024.csv'
+ cleaned_licence_id = clean_licence_id(licence_id)
+ print(cleaned_licence_id)
+ # Open the file and read it
+ with open(file_path, newline='', encoding='utf-8') as file:
+ reader = csv.reader(file, delimiter=';')
+
+ # Iterate through each row in the CSV
+ for row in reader:
+ # Ensure the row is not empty and has the expected number of columns
+ if len(row) >= 13:
+ current_licence_id = row[5] # The 5th column contains the licence_id
+
+ # Check if the current row matches the given licence_id
+ if current_licence_id == str(cleaned_licence_id):
+ # Return first name and last name from the row (3rd and 4th columns)
+ first_name = row[3] # 4th column: first name
+ last_name = row[2] # 3rd column: last name
+ return first_name, last_name
+
+ # Return None if no match is found
+ return None, None
diff --git a/tournaments/views.py b/tournaments/views.py
index e30e420..4bb728a 100644
--- a/tournaments/views.py
+++ b/tournaments/views.py
@@ -33,6 +33,23 @@ from .forms import SimpleForm
from django.core.mail import EmailMessage
from datetime import timedelta
from django.utils import timezone
+from django.shortcuts import render, redirect
+from django.contrib.auth.forms import UserCreationForm
+from django.contrib.auth import login
+
+from django.urls import reverse
+from django.contrib import messages
+from .forms import TournamentRegistrationForm, AddPlayerForm
+
+from .utils.licence_validator import LicenseValidator
+from .utils.player_search import get_player_name_from_csv
+
+from django.contrib.auth.decorators import login_required
+from .forms import SimpleCustomUserCreationForm
+from django.contrib.sites.shortcuts import get_current_site
+from django.template.loader import render_to_string
+from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
+from django.utils.encoding import force_bytes
def index(request):
@@ -85,10 +102,23 @@ def future_tournaments(club_id):
def tournament_info(request, tournament_id):
tournament = get_object_or_404(Tournament, pk=tournament_id)
+ is_registered = False
+
+ if request.user.is_authenticated:
+ # Assuming user's licence_id is stored in the user profile (e.g., request.user.profile.licence_id)
+ user_licence_id = request.user.licence_id
+ # Check if there is a PlayerRegistration for this user in this tournament
+ is_registered = PlayerRegistration.objects.filter(
+ licence_id__startswith=user_licence_id,
+ team_registration__tournament=tournament
+ ).exists()
+
return render(request, 'tournaments/tournament_info.html', {
'tournament': tournament,
+ 'is_registered': is_registered,
})
+
def tournaments(request):
filter = int(request.GET.get('filter'))
@@ -315,7 +345,8 @@ def activate(request, uidb64, token):
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
- return HttpResponse('Votre email est confirmé. Vous pouvez maintenant vous connecter.')
+ login(request, user)
+ return redirect('index') # Redirect to the homepage or any other page you prefer
else:
return HttpResponse('Le lien est invalide.')
@@ -483,3 +514,204 @@ def send_email(mail, name):
email = EmailMessage(subject, body, to=[mail])
email.send()
+
+@csrf_exempt
+def signup(request):
+ if request.method == 'POST':
+ form = SimpleCustomUserCreationForm(request.POST)
+ if form.is_valid():
+ user = form.save(commit=False)
+ user.is_active = False # Deactivate account until email is verified
+ user.save()
+
+ # Send verification email
+ send_verification_email(request, user)
+ request.session['pre_login_username'] = user.username
+ request.session['pre_login_password'] = user.password # Store hashed password, or handle with caution
+
+ messages.success(request, "Votre compte a été créé ! Veuillez vérifier votre e-mail pour confirmer votre compte.")
+ return redirect('login') # Redirect to login page or a custom message page
+ else:
+ form = SimpleCustomUserCreationForm()
+ return render(request, 'registration/signup.html', {'form': form})
+
+def send_verification_email(request, user):
+
+ current_site = get_current_site(request)
+ mail_subject = 'Activez votre compte Padel Club !'
+ message = render_to_string('tournaments/acc_active_email.html', {
+ 'user': user,
+ 'domain': current_site.domain,
+ 'uid': urlsafe_base64_encode(force_bytes(user.pk)),
+ 'token': account_activation_token.make_token(user),
+ })
+ email = EmailMessage(mail_subject, message, to=[user.email])
+ email.send()
+
+@login_required
+def profile(request):
+ user = request.user # Get the currently authenticated user
+
+ # Query tournaments where the user is registered
+ tournaments = Tournament.objects.all()
+
+ return render(request, 'registration/profile.html', {
+ 'tournaments': tournaments,
+ 'user_name': user.username
+ })
+
+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
+
+ # Process forms
+ if request.method == 'POST':
+ team_form = TournamentRegistrationForm(request.POST)
+ add_player_form = AddPlayerForm(request.POST)
+ # Check if the add player form is submitted
+ 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:
+ messages.error(request, f"Le numéro de licence est invalide, la lettre ne correspond pas. {validator.computed_license_key}")
+ 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'],
+ })
+
+ # 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 licence_id in existing_players:
+ messages.error(request, 'This player is already added to the team.')
+ 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'],
+ })
+ else:
+ # Check if a PlayerRegistration with the same licence_id already exists in the database
+ stripped_license = validator.stripped_license
+ if validate_license_id(stripped_license, tournament):
+ messages.error(request, 'A player with this licence ID is already registered in a team.')
+ 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'],
+ })
+ elif add_player_form.names_is_valid():
+ request.session['team_registration'].append(player_data)
+ request.session.modified = True # Ensure session is updated
+ else:
+ if add_player_form.first_tournament is False:
+ # Retrieve player names from the CSV file
+ first_name, last_name = get_player_name_from_csv(licence_id)
+ if first_name and last_name:
+ player_data['first_name'] = first_name
+ player_data['last_name'] = last_name
+ # 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
+ else:
+ add_player_form.first_tournament = True
+
+
+
+ # Check if the team registration form is valid and finalize the registration
+ elif 'register_team' in request.POST and team_form.is_valid():
+ team_registration = TeamRegistration.objects.create(
+ tournament=tournament,
+ registration_date=timezone.now()
+ )
+ # Create PlayerRegistration objects for each player in the session
+ for player_data in request.session['team_registration']:
+ player_registration = PlayerRegistration.objects.create(
+ team_registration=team_registration,
+ first_name=player_data['first_name'],
+ last_name=player_data['last_name'],
+ licence_id=player_data['licence_id'],
+ email = player_data.get('email', None),
+ phone_number = player_data.get('phone_number', None)
+ )
+
+ request.session['team_registration'] = []
+ registration_successful = True
+ else:
+ request.session['team_registration'] = []
+ initial_data = {}
+ # Add the authenticated user to the session as the first player if not already added
+ if request.user.is_authenticated:
+ initial_data = {
+ 'email': request.user.email,
+ 'phone': request.user.phone,
+ }
+ existing_players = [player['licence_id'] for player in request.session['team_registration']]
+ if request.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': request.user.licence_id,
+ }
+ request.session['team_registration'].insert(0, player_data) # Add them as the first player
+ request.session.modified = True # Ensure session is updated
+
+ team_form = TournamentRegistrationForm(initial=initial_data)
+ add_player_form = AddPlayerForm()
+
+ 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'],
+ })
+
+
+
+
+@login_required
+def unregister_tournament(request, tournament_id):
+ user_licence_id = request.user.licence_id
+ player_registration = PlayerRegistration.objects.filter(
+ licence_id__startswith=user_licence_id,
+ team_registration__tournament_id=tournament_id
+ ).first() # Get the first match, if any
+
+ if player_registration:
+ team_registration = player_registration.team_registration # Get the related TeamRegistration
+ team_registration.delete() # Delete the team registration
+
+ request.session['team_registration'] = []
+
+ return redirect('tournament-info', tournament_id=tournament_id)
+
+def validate_license_id(licence_id, tournament):
+ teams = TeamRegistration.objects.filter(tournament=tournament)
+
+ # 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.startswith(licence_id):
+ return True
+
+ # If all checks pass, return True (you can add further logic here if needed)
+ return False