from typing import Any from django import forms from django.core.exceptions import ValidationError from django.core import validators from django.utils.translation import gettext_lazy as _ from module_project import constants from . import models # from .backend import EmailBackend # from phonenumber_field.formfields import PhoneNumberField from .iam_constant import PRINCIPAL_TYPE_ADMIN, PRINCIPAL_TYPE_SUBADMIN from django.contrib.auth import authenticate class CustomAuthenticationForm(forms.Form): email = forms.EmailField( max_length=254, widget=forms.TextInput(attrs={"autofocus": True}), label=_("Email"), ) password = forms.CharField( label=_("Password"), strip=False, widget=forms.PasswordInput(attrs={"autocomplete": "current-password"}), ) def clean(self): email = self.cleaned_data.get("email") password = self.cleaned_data.get("password") self.user = None if email and password: user = authenticate(email=email, password=password) if user is None: raise ValidationError({"__all__": [constants.INVALID_EMAIL_PASSWORD]}) elif not user.is_active: raise ValidationError({"__all__": [constants.ACCOUNT_DEACTIVATED]}) self.user = user return self.cleaned_data class IAmPrincipalForm(forms.ModelForm): password = forms.CharField( widget=forms.PasswordInput(attrs={"autocomplete": "off"}), validators=[ validators.MinLengthValidator( limit_value=6, message="Password must be at least 6 characters long. " ) ], ) confirm_password = forms.CharField( widget=forms.PasswordInput(attrs={"autocomplete": "off"}) ) class Meta: model = models.IAmPrincipal fields = [ "principal_type", "first_name", "last_name", "email", "password", "confirm_password", ] def __init__(self, *args, **kwargs): instance = kwargs.get("instance") super().__init__(*args, **kwargs) self.fields["principal_type"].queryset = models.IAmPrincipalType.objects.filter( active=True, deleted=False, name__in=(PRINCIPAL_TYPE_ADMIN, PRINCIPAL_TYPE_SUBADMIN) ) # If it's a create action, exclude 'is_active' field if instance is not None and instance.pk is not None: self.fields.pop("password", None) self.fields.pop("confirm_password", None) def clean_email(self): email = self.cleaned_data.get("email") # Skip uniqueness validation if it's an update action (instance exists) if self.instance and self.instance.email == email: return email if models.IAmPrincipal.objects.filter(email=email).exists(): raise forms.ValidationError(constants.EMAIL_EXISTS) return email def save(self, commit=True): instance = super().save(commit=False) # Check if it's a new object (create action) or an existing one (update action) if not instance.pk: # pk is None for new objects instance.username = self.cleaned_data["email"] instance.set_password(self.cleaned_data["password"]) principal_type = self.cleaned_data.get("principal_type") if principal_type is not None: # Set is_superuser and is_staff based on principal_type if principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_ADMIN): instance.is_superuser = True elif principal_type == models.IAmPrincipalType.objects.get(name=PRINCIPAL_TYPE_SUBADMIN): instance.is_staff = True if commit: instance.save() return instance class IAmPrincipalProfileForm(forms.ModelForm): GENDER_CHOICES = ( ("male", "Male"), ("female", "Female"), ("other", "Other"), ) first_name = forms.CharField(required=True) last_name = forms.CharField(required=True) email = forms.EmailField(required=True) password = forms.CharField( widget=forms.PasswordInput(attrs={"autocomplete": "off"}) ) confirm_password = forms.CharField( widget=forms.PasswordInput(attrs={"autocomplete": "off"}) ) # date_of_birth = forms.CharField(widget=forms.DateInput(attrs={'type': 'date'})) phone_number = forms.CharField( widget=forms.TextInput(), ) # is_staff = forms.BooleanField( # label="Staff Status", # label_suffix="", # initial=True, # required=False, # help_text="Check this box to designate that this user will be assigned permissions in the future.", # ) # is_superuser = forms.BooleanField( # label="SuperAdmin Status", # label_suffix="", # required=False, # help_text="Check this box to designates that this user has all permissions without explicitly assigning them.", # ) # gender = forms.ChoiceField(choices=GENDER_CHOICES) class Meta: model = models.IAmPrincipal fields = [ "principal_type", "first_name", "last_name", "email", "password", "confirm_password", # 'gender', # 'date_of_birth', "phone_number", # 'address_line1', # 'address_line2', # 'city', # 'state', # 'country', # 'post_code', # 'profile_photo', # "is_staff", # "is_superuser", ] def __init__(self, *args, **kwargs): instance = kwargs.get("instance") super().__init__(*args, **kwargs) self.fields["principal_type"].queryset = models.IAmPrincipalType.objects.filter( active=True, deleted=False ) # self.fields['principal_source'].queryset = models.IAmPrincipalSource.objects.filter(active=True, deleted=False) # Check if an instance is provided and customize the form fields accordingly if instance is not None: # Exclude the 'password' and 'confirm_password' fields self.fields.pop("password", None) self.fields.pop("confirm_password", None) # Make the 'email' field read-only self.fields["email"].widget.attrs["readonly"] = True # Modify the 'is_superuser' field to be not required # self.fields["is_superuser"].required = False # self.fields["is_staff"].required = False # Add or modify the 'is_active' field self.fields["is_active"] = forms.BooleanField( label="Active", initial=instance.is_active, help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", required=False, ) def clean(self): cleaned_data = super().clean() password = cleaned_data.get("password") confirm_password = cleaned_data.get("confirm_password") if password and confirm_password and password != confirm_password: self.add_error("confirm_password", "Password does not match") return cleaned_data def save(self, commit=True): user = super().save(commit=False) user.set_password(self.cleaned_data["password"]) if commit: user.save() return user class ProfileEditForm(forms.ModelForm): gender = forms.ChoiceField(choices=(('Male', 'Male'),('Female', 'Female'),('Other', 'Other'))) profile_photo = forms.ImageField(required=False) class Meta: model = models.IAmPrincipal fields = [ "profile_photo", "first_name", "last_name", "date_of_birth", "gender", "phone_no" ] class IAmPrincipalResourceLinkForm(IAmPrincipalForm): class Meta: model = models.IAmPrincipal fields = [ "principal_type", "first_name", "last_name", "email", "password", "confirm_password", "principal_resource", ] principal_resource = forms.ModelMultipleChoiceField( label="Module Permission", queryset=models.IAmAppResource.objects.filter(active=True, deleted=False), required=False, widget=forms.widgets.SelectMultiple( attrs={"class": "form_select js-example-basic-multiple"} ), ) def save(self, commit=True): # First, save the instance of the IAmPrincipal model as usual principal = super().save(commit=False) # If the principal_resource field has data if self.cleaned_data['principal_resource']: # Get the principal_resource data principal_resource_data = self.cleaned_data['principal_resource'] # Update the many-to-many relationship principal.principal_resource.set(principal_resource_data) # Save the instance to the database if commit: principal.save() class IAmPrincipalGroupLinkForm(IAmPrincipalForm): class Meta: model = models.IAmPrincipal fields = [ "principal_type", "first_name", "last_name", "email", "password", "confirm_password", "principal_group", ] principal_group = forms.ModelMultipleChoiceField( label="Groups", queryset=models.IAmPrincipalGroup.objects.filter(active=True, deleted=False), required=False, widget=forms.widgets.SelectMultiple( attrs={"class": "form_select js-example-basic-multiple"} ), ) def save(self, commit=True): # First, save the instance of the IAmPrincipal model as usual principal = super().save(commit=False) # If the principal_group field has data if self.cleaned_data['principal_group']: # Get the principal_group data principal_group_data = self.cleaned_data['principal_group'] # Update the many-to-many relationship principal.principal_group.set(principal_group_data) # Save the instance to the database if commit: principal.save() class IAmPrincipalTypeForm(forms.ModelForm): class Meta: model = models.IAmPrincipalType fields = ["name", "active"] def __init__(self, *args, **kwargs): instance = kwargs.get("instance") super().__init__(*args, **kwargs) if instance is None: self.fields.pop("active") class IAmPrincipalGroupRoleLinkForm(forms.ModelForm): class Meta: model = models.IAmPrincipalGroup fields = ["name", "role", "active"] role = forms.ModelMultipleChoiceField( queryset=models.IAmRole.objects.filter(active=True, deleted=False), required=False, widget=forms.widgets.SelectMultiple( attrs={"class": "form-select js-example-basic-multiple"} ), ) def __init__(self, *args, **kwargs): instance = kwargs.get("instance") # data = kwargs.get('data') super().__init__(*args, **kwargs) if instance is None: # This is an add operation, exclude the 'active' field self.fields.pop("active") class IAmPrincipalRoleAppResourceActionLinkForm(forms.ModelForm): class Meta: model = models.IAmRole fields = ["name", "active", "app_resource_action"] required = {"app_resource_action": False} app_resource_action = forms.ModelMultipleChoiceField( queryset=models.IAmAppResourceActionLink.objects.all(), widget=forms.CheckboxSelectMultiple, required=False, ) def __init__(self, *args, **kwargs): instance = kwargs.get("instance") super().__init__(*args, **kwargs) if instance is None: self.fields.pop("active")