Coverage for website/members/forms.py: 28.57%
68 statements
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
1from django import forms
2from django.apps import apps
3from django.contrib.auth.forms import UserChangeForm as BaseUserChangeForm
4from django.contrib.auth.forms import UserCreationForm as BaseUserCreationForm
5from django.core.validators import RegexValidator
6from django.utils.translation import gettext_lazy as _
8from members.models import Member
9from thabloid.models.thabloid_user import ThabloidUser
11from .models import Profile
14class ProfileForm(forms.ModelForm):
15 """Form with all the user editable fields of a Profile model.
17 If the profile is minimized, no fields are required, unless the `require_address`
18 keyword argument is True, which is set if a user is filling a minimized profile
19 in order to be able to create a Renewal.
20 """
22 birthday = forms.DateField()
24 class Meta:
25 fields = [
26 "birthday",
27 "show_birthday",
28 "address_street",
29 "address_street2",
30 "address_postal_code",
31 "address_city",
32 "address_country",
33 "phone_number",
34 "emergency_contact",
35 "emergency_contact_phone_number",
36 "website",
37 "profile_description",
38 "nickname",
39 "initials",
40 "display_name_preference",
41 "photo",
42 "receive_optin",
43 "receive_newsletter",
44 "receive_registration_confirmation",
45 "receive_oldmembers",
46 "email_gsuite_only",
47 ]
48 model = Profile
50 def __init__(self, *args, require_address=False, **kwargs):
51 super().__init__(*args, **kwargs)
52 user = Member.objects.get(pk=kwargs["instance"].user_id)
53 for field in [
54 "birthday",
55 "address_street",
56 "address_city",
57 "address_postal_code",
58 "address_city",
59 "address_country",
60 ]:
61 if require_address or not user.profile.is_minimized:
62 self.fields[field].required = True
63 else:
64 self.fields[field].required = False
66 if not kwargs["instance"].user.is_staff:
67 self.fields["email_gsuite_only"].widget = self.fields[
68 "email_gsuite_only"
69 ].hidden_widget()
71 if not user.has_been_member() and not kwargs["instance"].receive_oldmembers:
72 self.fields["receive_oldmembers"].disabled = True
73 self.fields["receive_oldmembers"].help_text = (
74 "If you are a past member, receive emails about Thalia events aimed at alumni. "
75 "You cannot enable this option, as we don't have any records of you having been a member "
76 "(a long time ago, we didn't keep track of this yet). Contact "
77 "<a href='mailto:info@thalia.nu'>info@thalia.nu</a> if you want to receive alumni emails."
78 )
80 self.fields["birthday"].widget.input_type = "date"
81 if not user.profile.is_minimized:
82 self.fields["birthday"].disabled = True
84 self.render_app_specific_profile_form_fields()
86 def render_app_specific_profile_form_fields(self):
87 """Render app-specific profile form fields."""
88 for app in apps.get_app_configs():
89 if hasattr(app, "user_profile_form_fields"):
90 fields, _ = app.user_profile_form_fields(self.instance)
91 self.fields.update(fields)
93 def save(self, commit=True):
94 instance = super().save(commit)
95 if commit:
96 if self.cleaned_data["receive_thabloid"]:
97 ThabloidUser.objects.get(pk=instance.user.pk).allow_thabloid()
98 else:
99 ThabloidUser.objects.get(pk=instance.user.pk).disallow_thabloid()
101 # Save app-specific fields by calling the callback that was registered
102 for app in apps.get_app_configs():
103 if hasattr(app, "user_profile_form_fields"):
104 _, callback = app.user_profile_form_fields()
105 callback(self, instance, commit)
107 return instance
109 def clean(self):
110 if self.cleaned_data.get("phone_number") is not None:
111 self.cleaned_data["phone_number"] = self.cleaned_data[
112 "phone_number"
113 ].replace(" ", "")
115 if self.cleaned_data.get("emergency_contact_phone_number") is not None:
116 self.cleaned_data["emergency_contact_phone_number"] = self.cleaned_data[
117 "emergency_contact_phone_number"
118 ].replace(" ", "")
119 super().clean()
122class UserCreationForm(BaseUserCreationForm):
123 """Custom Form that lowercases the username on creation."""
125 def clean(self):
126 if "username" in self.cleaned_data:
127 self.cleaned_data["username"] = self.cleaned_data["username"].lower()
129 super().clean()
131 class Meta:
132 fields = ("username", "first_name", "last_name")
135class UserChangeForm(BaseUserChangeForm):
136 """Custom user edit form that adds fields for first/last name and email.
138 It also force-lowercases the username on save
139 """
141 username = forms.CharField(
142 label=_("Username"),
143 required=True,
144 help_text=_("Required. 64 characters or fewer. Letters and digits only."),
145 widget=forms.TextInput(attrs={"class": "vTextField", "maxlength": 64}),
146 validators=[
147 RegexValidator(
148 regex="^[a-zA-Z0-9]{1,64}$",
149 message=_(
150 "Please use 64 characters or fewer. Letters and digits only."
151 ),
152 )
153 ],
154 )
156 first_name = forms.CharField(
157 label=_("First name"),
158 required=True,
159 widget=forms.TextInput(attrs={"class": "vTextField", "maxlength": 30}),
160 )
161 last_name = forms.CharField(
162 label=_("Last name"),
163 required=True,
164 widget=forms.TextInput(attrs={"class": "vTextField", "maxlength": 150}),
165 )
166 email = forms.CharField(
167 label=_("Email address"),
168 required=True,
169 widget=forms.EmailInput(attrs={"class": "vTextField", "maxlength": 254}),
170 )
172 def clean(self):
173 if "username" in self.cleaned_data:
174 self.cleaned_data["username"] = self.cleaned_data["username"].lower()
175 super().clean()