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

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 _ 

7 

8from members.models import Member 

9from thabloid.models.thabloid_user import ThabloidUser 

10 

11from .models import Profile 

12 

13 

14class ProfileForm(forms.ModelForm): 

15 """Form with all the user editable fields of a Profile model. 

16 

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 """ 

21 

22 birthday = forms.DateField() 

23 

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 

49 

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 

65 

66 if not kwargs["instance"].user.is_staff: 

67 self.fields["email_gsuite_only"].widget = self.fields[ 

68 "email_gsuite_only" 

69 ].hidden_widget() 

70 

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 ) 

79 

80 self.fields["birthday"].widget.input_type = "date" 

81 if not user.profile.is_minimized: 

82 self.fields["birthday"].disabled = True 

83 

84 self.render_app_specific_profile_form_fields() 

85 

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) 

92 

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() 

100 

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) 

106 

107 return instance 

108 

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(" ", "") 

114 

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() 

120 

121 

122class UserCreationForm(BaseUserCreationForm): 

123 """Custom Form that lowercases the username on creation.""" 

124 

125 def clean(self): 

126 if "username" in self.cleaned_data: 

127 self.cleaned_data["username"] = self.cleaned_data["username"].lower() 

128 

129 super().clean() 

130 

131 class Meta: 

132 fields = ("username", "first_name", "last_name") 

133 

134 

135class UserChangeForm(BaseUserChangeForm): 

136 """Custom user edit form that adds fields for first/last name and email. 

137 

138 It also force-lowercases the username on save 

139 """ 

140 

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 ) 

155 

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 ) 

171 

172 def clean(self): 

173 if "username" in self.cleaned_data: 

174 self.cleaned_data["username"] = self.cleaned_data["username"].lower() 

175 super().clean()