@@ -33,21 +33,56 @@ def clean_email(self):
3333 return email
3434
3535
36+ class PasswordStrengthField (forms .CharField ):
37+ widget = PasswordStrengthInput (
38+ attrs = {
39+ "class" : "password_strength" ,
40+ "data-disable-strength-enforcement" : "" , # usually removed in init
41+ }
42+ )
43+
44+ def __init__ (self , * args , ** kwargs ):
45+ super ().__init__ (* args , ** kwargs )
46+ for pwval in password_validation .get_default_password_validators ():
47+ if isinstance (pwval , password_validation .MinimumLengthValidator ):
48+ self .widget .attrs ["minlength" ] = pwval .min_length
49+ elif isinstance (pwval , StrongPasswordValidator ):
50+ self .widget .attrs .pop (
51+ "data-disable-strength-enforcement" , None
52+ )
53+
54+
55+
3656class PasswordForm (forms .Form ):
37- password = forms . CharField ( widget = PasswordStrengthInput ( attrs = { 'class' : 'password_strength' }) )
57+ password = PasswordStrengthField ( )
3858 password_confirmation = forms .CharField (widget = PasswordConfirmationInput (
3959 confirm_with = 'password' ,
4060 attrs = {'class' :'password_confirmation' }),
4161 help_text = "Enter the same password as above, for verification." ,)
42-
62+
63+ def __init__ (self , * args , user = None , ** kwargs ):
64+ # user is a kw-only argument to avoid interfering with the signature
65+ # when this class is mixed with ModelForm in PersonPasswordForm
66+ self .user = user
67+ super ().__init__ (* args , ** kwargs )
4368
4469 def clean_password_confirmation (self ):
45- password = self .cleaned_data .get ("password" , "" )
46- password_confirmation = self .cleaned_data ["password_confirmation" ]
70+ # clean fields here rather than a clean() method so validation is
71+ # still enforced in PersonPasswordForm without having to override its
72+ # clean() method
73+ password = self .cleaned_data .get ("password" )
74+ password_confirmation = self .cleaned_data .get ("password_confirmation" )
4775 if password != password_confirmation :
48- raise forms .ValidationError ("The two password fields didn't match." )
76+ raise ValidationError (
77+ "The password confirmation is different than the new password"
78+ )
79+ try :
80+ password_validation .validate_password (password_confirmation , self .user )
81+ except ValidationError as err :
82+ self .add_error ("password" , err )
4983 return password_confirmation
5084
85+
5186def ascii_cleaner (supposedly_ascii ):
5287 outside_printable_ascii_pattern = r'[^\x20-\x7F]'
5388 if re .search (outside_printable_ascii_pattern , supposedly_ascii ):
@@ -174,35 +209,13 @@ class Meta:
174209 exclude = ['by' , 'time' ]
175210
176211
177- class ChangePasswordForm (forms . Form ):
212+ class ChangePasswordForm (PasswordForm ):
178213 current_password = forms .CharField (widget = forms .PasswordInput )
214+ field_order = ["current_password" , "password" , "password_confirmation" ]
179215
180- new_password = forms .CharField (
181- widget = PasswordStrengthInput (
182- attrs = {
183- "class" : "password_strength" ,
184- "data-disable-strength-enforcement" : "" , # usually removed in init
185- }
186- ),
187- )
188- new_password_confirmation = forms .CharField (
189- widget = PasswordConfirmationInput (
190- confirm_with = "new_password" , attrs = {"class" : "password_confirmation" }
191- )
192- )
193-
194- def __init__ (self , user , data = None ):
195- self .user = user
196- super ().__init__ (data )
197- # Check whether we have validators to enforce
198- new_password_field = self .fields ["new_password" ]
199- for pwval in password_validation .get_default_password_validators ():
200- if isinstance (pwval , password_validation .MinimumLengthValidator ):
201- new_password_field .widget .attrs ["minlength" ] = pwval .min_length
202- elif isinstance (pwval , StrongPasswordValidator ):
203- new_password_field .widget .attrs .pop (
204- "data-disable-strength-enforcement" , None
205- )
216+ def __init__ (self , user , * args , ** kwargs ):
217+ # user arg is optional in superclass, but required for this form
218+ super ().__init__ (* args , user = user , ** kwargs )
206219
207220 def clean_current_password (self ):
208221 # n.b., password = None is handled by check_password and results in a failed check
@@ -211,15 +224,6 @@ def clean_current_password(self):
211224 raise ValidationError ("Invalid password" )
212225 return password
213226
214- def clean (self ):
215- new_password = self .cleaned_data .get ("new_password" , "" )
216- conf_password = self .cleaned_data .get ("new_password_confirmation" , "" )
217- if new_password != conf_password :
218- raise ValidationError (
219- "The password confirmation is different than the new password"
220- )
221- password_validation .validate_password (conf_password , self .user )
222-
223227
224228class ChangeUsernameForm (forms .Form ):
225229 username = forms .ChoiceField (choices = [('-' ,'--------' )])
0 commit comments