diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index dd3dbec5..2c987e3c 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -1805,7 +1805,7 @@ def add_workout_indoorrace(ws,race,r,recordid=0,doregister=False): else: record.distance = ws[0].distance record.duration = ws[0].duration - else: + else: # pragma: no cover t = ws[0].duration seconds = t.second+t.minute*60.+t.hour*3600.+t.microsecond/1.e6 if seconds != race.sessionvalue*60.: # pragma: no cover diff --git a/rowers/tests/test_newusers.py b/rowers/tests/test_newusers.py index 3c53115a..e60450f0 100644 --- a/rowers/tests/test_newusers.py +++ b/rowers/tests/test_newusers.py @@ -28,8 +28,8 @@ class NewUserRegistrationTest(TestCase): 'last_name':'Roeiert', 'email':'jan@loop.nl', 'username':'janderoeiert', - 'password1':'aapindewei2', - 'password2':'aapindewei2', + 'password1':'Aapindewei2', + 'password2':'Aapindewei2', 'tos':True, 'weightcategory':'hwt', 'adaptiveclass': 'None', @@ -47,12 +47,12 @@ class NewUserRegistrationTest(TestCase): # set opt-in user = User.objects.get(username='janderoeiert') user.rower.gdpr_optin = True - user.set_password('aapindewei2') + user.set_password('Aapindewei2') user.is_active = True user.save() user.rower.save() - login = self.c.login(username=user.username,password='aapindewei2') + login = self.c.login(username=user.username,password='Aapindewei2') self.assertTrue(login) @@ -104,3 +104,23 @@ class NewUserRegistrationTest(TestCase): self.assertRedirects(response, expected_url='/login/', status_code=302,target_status_code=200) + + @patch('rowers.dataprep.workout_summary_to_df',side_effect=mock_workout_summaries) + def test_newuser_false(self,mock_workout_summaries): + form_data = { + 'first_name':'Jan', + 'last_name':'Roeiert', + 'email':'jan@loop.nl', + 'username':'janderoeiert', + 'password1':'aapindewei2', + 'password2':'aapindewei2', + 'tos':True, + 'weightcategory':'hwt', + 'adaptiveclass': 'None', + 'sex':'male', + 'next':'/rowers/list-workouts', + 'birthdate':datetime.datetime(year=1970,month=4,day=2) + } + + form = RegistrationFormUniqueEmail(form_data) + self.assertFalse(form.is_valid()) diff --git a/rowers/validator.py b/rowers/validator.py new file mode 100644 index 00000000..ee4c327d --- /dev/null +++ b/rowers/validator.py @@ -0,0 +1,23 @@ +from django.core.exceptions import ValidationError +from django.utils.translation import gettext as _ + +class LettersAndDigitsValidator: + + def validate(self, password, user=None): + vals = { + 'Password must contain an uppercase letter.': lambda s: any(x.isupper() for x in s), + 'Password must contain a lowercase letter.': lambda s: any(x.islower() for x in s), + 'Password must contain a digit.': lambda s: any(x.isdigit() for x in s), + 'Password cannot contain white spaces.': lambda s: not any(x.isspace() for x in s) + } + valid = None + for n, val in vals.items(): + if not val(password): + valid = False + raise ValidationError(n) + return valid + + def get_help_text(self): + return _( + "Your password must contain an uppercase letter, a lowercase letter, and a digit" + ) diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index 80fd504f..83fa7153 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -197,6 +197,9 @@ AUTH_PASSWORD_VALIDATORS = [ }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'OPTIONS': { + 'min_length': 9, + } }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', @@ -204,6 +207,9 @@ AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, + { + 'NAME': 'rowers.validator.LettersAndDigitsValidator', + } ]