from django.contrib.auth.forms import UserCreationForm, UserChangeForm, PasswordResetForm from django import forms from .models import CustomUser import re # Import the re module for regular expressions from .utils.licence_validator import LicenseValidator from django.core.mail import send_mail from django.template.loader import render_to_string from django.utils.http import urlsafe_base64_encode from django.contrib.auth.tokens import default_token_generator from django.contrib.sites.shortcuts import get_current_site from django.utils.encoding import force_bytes from django.contrib.auth.forms import PasswordChangeForm from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth import authenticate # Add this import import logging class CustomUserCreationForm(UserCreationForm): usable_password = None def clean_licence_id(self): licence_id = self.cleaned_data.get('licence_id') if licence_id: licence_id = licence_id.replace(' ', '').strip().upper() validator = LicenseValidator(licence_id) if validator.validate_license(): licence_id = validator.computed_licence_id else: raise forms.ValidationError('Le numéro de licence est invalide, la lettre ne correspond pas.') return licence_id def clean_email(self): email = self.cleaned_data.get('email') if email: email = email.lower() if CustomUser.objects.filter(email__iexact=email).exclude(pk=self.instance.pk).exists(): raise forms.ValidationError("Cet email est déjà utilisé. Veuillez en choisir un autre :)") return email def clean_username(self): username = self.cleaned_data.get('username') if username: username = username.lower() if CustomUser.objects.filter(username__iexact=username).exclude(pk=self.instance.pk).exists() | CustomUser.objects.filter(email__iexact=username).exclude(pk=self.instance.pk).exists(): raise forms.ValidationError("Cet identifiant est déjà utilisé. Veuillez en choisir un autre :)") return username class Meta: model = CustomUser error_messages = { 'email': { 'unique': "Cette adresse email est déjà utilisée.", }, 'username': { 'unique': "Ce nom d'utilisateur est déjà pris.", }, 'licence_id': { 'unique': "Cette licence est déjà utilisée par un autre compte.", }, } fields = UserCreationForm.Meta.fields + ('umpire_code', 'clubs', 'phone', 'first_name', 'last_name', 'licence_id', 'country') class SimpleCustomUserCreationForm(UserCreationForm): usable_password = None def clean_licence_id(self): licence_id = self.cleaned_data.get('licence_id') if licence_id: licence_id = licence_id.replace(' ', '').strip().upper() validator = LicenseValidator(licence_id) if validator.validate_license(): licence_id = validator.computed_licence_id else: raise forms.ValidationError('Le numéro de licence est invalide, la lettre ne correspond pas.') return licence_id def clean_phone(self): phone = self.cleaned_data.get('phone') if phone: # Remove all spaces, dots, dashes, and parentheses phone = re.sub(r'[\s\.\-\(\)]', '', phone) # Basic regex for phone numbers, allowing 6-15 digits for international numbers if not re.match(r"^\+?\d{6,15}$", phone): raise forms.ValidationError("Entrer un numéro de téléphone valide.") return phone class Meta: model = CustomUser fields = UserCreationForm.Meta.fields + ('email', 'phone', 'first_name', 'last_name', 'licence_id', 'country') error_messages = { 'email': { 'unique': "Cette adresse email est déjà utilisée.", }, 'username': { 'unique': "Ce nom d'utilisateur est déjà pris.", }, 'licence_id': { 'unique': "Cette licence est déjà utilisée par un autre compte.", }, } labels = { 'username': 'Nom d’utilisateur', 'email': 'E-mail', 'phone': 'Numéro de téléphone', 'first_name': 'Prénom', 'last_name': 'Nom de famille', 'licence_id': 'Numéro de licence', 'country': 'Pays', 'password1': 'Mot de passe', 'password2': 'Confirmer le mot de passe', } def clean_email(self): email = self.cleaned_data.get('email') if email: email = email.lower() if CustomUser.objects.filter(email__iexact=email).exclude(pk=self.instance.pk).exists(): raise forms.ValidationError("Cet email est déjà utilisé. Veuillez en choisir un autre :)") return email def clean_username(self): username = self.cleaned_data.get('username') if username: username = username.lower() if CustomUser.objects.filter(username__iexact=username).exclude(pk=self.instance.pk).exists() | CustomUser.objects.filter(email__iexact=username).exclude(pk=self.instance.pk).exists(): raise forms.ValidationError("Cet identifiant est déjà utilisé. Veuillez en choisir un autre :)") return username class CustomUserChangeForm(UserChangeForm): def clean_username(self): username = self.cleaned_data.get('username') if username: username = username.lower() if CustomUser.objects.filter(username__iexact=username).exclude(pk=self.instance.pk).exists() | CustomUser.objects.filter(email__iexact=username).exclude(pk=self.instance.pk).exists(): raise forms.ValidationError("Cet identifiant est déjà utilisé. Veuillez en choisir un autre :)") return username def clean_licence_id(self): licence_id = self.cleaned_data.get('licence_id') if licence_id: licence_id = licence_id.replace(' ', '').strip().upper() validator = LicenseValidator(licence_id) if validator.validate_license(): licence_id = validator.computed_licence_id else: raise forms.ValidationError('Le numéro de licence est invalide, la lettre ne correspond pas.') return licence_id class Meta: model = CustomUser error_messages = { 'email': { 'unique': "Cette adresse email est déjà utilisée.", }, 'username': { 'unique': "Ce nom d'utilisateur est déjà pris.", }, 'licence_id': { 'unique': "Cette licence est déjà utilisée par un autre compte.", }, } fields = UserCreationForm.Meta.fields + ('umpire_code', 'clubs', 'phone', 'first_name', 'last_name', 'licence_id', 'country') class SimpleForm(forms.Form): # A single field for user input (e.g., a text field) name = forms.CharField(label='Enter your name!', max_length=100) class TournamentRegistrationForm(forms.Form): #first_name = forms.CharField(label='Prénom', max_length=50) #last_name = forms.CharField(label='Nom', max_length=50) email = forms.EmailField(label='E-mail') mobile_number = forms.CharField( label='Téléphone', max_length=15, required=True ) def clean_mobile_number(self): mobile_number = self.cleaned_data.get('mobile_number') if mobile_number: # Remove spaces, dots, dashes, and parentheses from the number first mobile_number = re.sub(r'[\s\.\-\(\)]', '', mobile_number) if not re.match(r"^\+?\d{6,15}$", mobile_number): raise forms.ValidationError("Entrer un numéro de téléphone valide.") return mobile_number class AddPlayerForm(forms.Form): licence_id = forms.CharField(label='Numéro de licence (avec la lettre)', max_length=20, required=False) first_name = forms.CharField(label='Prénom', min_length=2, max_length=50, required=False) last_name = forms.CharField(label='Nom', min_length=2, max_length=50, required=False) first_tournament = False user_without_licence = False def names_is_valid(self): first_name = self.cleaned_data.get('first_name') last_name = self.cleaned_data.get('last_name') return len(first_name) >= 2 and len(last_name) >= 2 def clean_licence_id(self): licence_id = self.cleaned_data.get('licence_id') if licence_id: licence_id = licence_id.replace(' ', '').strip().upper() return licence_id def clean_last_name(self): last_name = self.cleaned_data.get('last_name') # Convert to uppercase last_name = last_name.upper() # Update the cleaned_data with the modified licence_id self.cleaned_data['last_name'] = last_name return last_name def clean_first_name(self): first_name = self.cleaned_data.get('first_name') # Convert to capitalize first_name = first_name.capitalize() # Update the cleaned_data with the modified licence_id self.cleaned_data['first_name'] = first_name return first_name class CustomPasswordResetForm(PasswordResetForm): def save(self, *args, **kwargs): """ Override the save method to send a custom email. """ email = self.cleaned_data["email"] users = self.get_users(email) for user in users: # Generate the token for password reset token = default_token_generator.make_token(user) uid = urlsafe_base64_encode(force_bytes(user.pk)) # Prepare the context for the email template context = { "email": user.email, "domain": get_current_site(self.request).domain, "site_name": "Padel Club", "uid": uid, "token": token, "protocol": "http", # Use 'https' in production } # Render the email content from the template subject = "Réinitialisation du mot de passe" message = render_to_string("registration/password_reset_email.html", context) # Send the email send_mail(subject, message, None, [user.email]) class ProfileUpdateForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Remove autofocus from the 'username' field self.fields['username'].widget.attrs.pop("autofocus", None) def clean_email(self): email = self.cleaned_data.get('email') if email: email = email.lower() if CustomUser.objects.filter(email__iexact=email).exclude(pk=self.instance.pk).exists(): raise forms.ValidationError("Cet email est déjà utilisé. Veuillez en choisir un autre :)") return email def clean_username(self): username = self.cleaned_data.get('username') if username: username = username.lower() if CustomUser.objects.filter(username__iexact=username).exclude(pk=self.instance.pk).exists() | CustomUser.objects.filter(email__iexact=username).exclude(pk=self.instance.pk).exists(): raise forms.ValidationError("Cet identifiant est déjà utilisé. Veuillez en choisir un autre :)") return username def clean_licence_id(self): licence_id = self.cleaned_data.get('licence_id') if licence_id: licence_id = licence_id.replace(' ', '').strip().upper() validator = LicenseValidator(licence_id) if validator.validate_license(): licence_id = validator.computed_licence_id else: raise forms.ValidationError('Le numéro de licence est invalide, la lettre ne correspond pas.') return licence_id def clean_phone(self): phone = self.cleaned_data.get('phone') if phone: # Remove all spaces, dots, dashes, and parentheses phone = re.sub(r'[\s\.\-\(\)]', '', phone) # Basic regex for phone numbers, allowing 6-15 digits for international numbers if not re.match(r"^\+?\d{6,15}$", phone): raise forms.ValidationError("Entrer un numéro de téléphone valide.") return phone class Meta: model = CustomUser fields = ['first_name', 'last_name', 'licence_id', 'username', 'email', 'phone'] labels = { 'username': 'Nom d’utilisateur', 'email': 'E-mail', 'phone': 'Numéro de téléphone', 'first_name': 'Prénom', 'last_name': 'Nom de famille', 'licence_id': 'Numéro de licence', } error_messages = { 'email': { 'unique': "Cette adresse email est déjà utilisée.", }, 'username': { 'unique': "Ce nom d'utilisateur est déjà pris.", }, 'licence_id': { 'unique': "Cette licence est déjà utilisée par un autre compte.", }, } class CustomPasswordChangeForm(PasswordChangeForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Remove autofocus from all fields in the PasswordChangeForm for field in self.fields.values(): field.widget.attrs.pop("autofocus", None) logger = logging.getLogger(__name__) class EmailOrUsernameAuthenticationForm(AuthenticationForm): username = forms.CharField(label='Username or Email') def clean(self): username = self.cleaned_data.get('username') password = self.cleaned_data.get('password') logger.info(f"Login attempt with username/email: {username}") if username and password: # Check if user exists first (either by username or email) user_exists = None try: # Try to find user by username first user_exists = CustomUser.objects.get(username__iexact=username) except CustomUser.DoesNotExist: # Try to find user by email try: user_exists = CustomUser.objects.get(email__iexact=username) except CustomUser.DoesNotExist: pass # If user exists but is inactive, provide specific feedback if user_exists and not user_exists.is_active: # Store the inactive user in session for template use if hasattr(self, 'request') and self.request.session: self.request.session['inactive_user_email'] = user_exists.email self.request.session['inactive_user_id'] = str(user_exists.id) raise forms.ValidationError( "Votre compte n'est pas encore activé. Veuillez cliquer sur le lien d'activation envoyé à votre adresse e-mail.", code='inactive_account' ) # Try regular authentication self.user_cache = authenticate( self.request, username=username, password=password ) if self.user_cache is None: logger.warning("Authentication failed") raise forms.ValidationError( "Identifiant/E-mail ou mot de passe incorrect. Les champs sont sensibles à la casse.", code='invalid_login' ) else: logger.info(f"Authentication successful for user: {self.user_cache}") # Clear any inactive user session data on successful login if hasattr(self, 'request') and self.request.session: self.request.session.pop('inactive_user_email', None) self.request.session.pop('inactive_user_id', None) self.confirm_login_allowed(self.user_cache) return self.cleaned_data