Skip to content

Commit 269e01a

Browse files
authored
Merge pull request #1804 from MTG/issue1516
Profile updates enabled for antique usernames containing spaces
2 parents ef35004 + 94dd2de commit 269e01a

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

accounts/forms.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,24 @@ def get_user_by_email(email):
152152

153153
class UsernameField(forms.CharField):
154154
""" Username field, 3~30 characters, allows only alphanumeric chars, required by default """
155+
155156
def __init__(self, required=True):
157+
"""Validates the username field for a form. Validation for brand new usernames must have strong validation (see Regex).
158+
For profile modifications, the username validation is done in ProfileForm cleaning methods, as antique usernames can
159+
contain spaces but new modified ones cannot.
160+
161+
Args:
162+
required (bool, optional): True for RegistrationForms, false for ProfileForms
163+
"""
164+
if required:
165+
validators = [RegexValidator(r'^[\w.+-]+$')] # is the same as Django UsernameValidator except for '@' symbol
166+
else:
167+
validators = []
156168
super().__init__(
157169
label="Username",
158170
min_length=3,
159171
max_length=30,
160-
validators=[RegexValidator(r'^[\w.+-]+$')], # is the same as Django UsernameValidator except for '@' symbol
172+
validators=validators,
161173
help_text="30 characters or fewer. Can contain: letters, digits, underscores, dots, dashes and plus signs.",
162174
error_messages={'invalid': "The username field must contain only letters, digits, underscores, dots, dashes and "
163175
"plus signs."},
@@ -389,9 +401,16 @@ def clean_username(self):
389401
if not username:
390402
username = self.request.user.username
391403

392-
# If username was not changed, consider it valid
404+
# If username was not changed, consider it valid. If it has, validate it to check it does not contain space characters.
393405
if username.lower() == self.request.user.username.lower():
394406
return username
407+
else:
408+
validator = RegexValidator(regex=r'^[\w.+-]+$',
409+
message="The username field must contain only letters, digits, underscores, dots, dashes and plus signs.",
410+
code='invalid')
411+
if validator(username):
412+
return username
413+
395414

396415
# Check that username is not used by another user. Note that because when the maximum number of username
397416
# changes is reached, the "username" field of the ProfileForm is disabled and its contents won't change.

accounts/tests/test_user.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,30 @@ def test_oldusername_username_unique_case_insensitiveness(self):
10851085
OldUsername.objects.create(user=userA, username='newUserAUsername')
10861086
with self.assertRaises(IntegrityError):
10871087
OldUsername.objects.create(user=userA, username='NewUserAUsername')
1088+
1089+
def test_username_whitespace(self):
1090+
"""Test that for usernames created before stronger validation was applied, whitespaces are a valid character
1091+
but for new edited ones they are not."""
1092+
userA = User.objects.create_user('user A', email='[email protected]', password='testpass')
1093+
self.client.force_login(userA)
1094+
1095+
# Test save profile without changing username with whitespaces
1096+
resp = self.client.post(reverse('accounts-edit'), data={'profile-username': ['user A'], 'profile-ui_theme_preference': 'f'})
1097+
self.assertRedirects(resp, reverse('accounts-edit'))
1098+
self.assertEqual(OldUsername.objects.filter(user=userA).count(), 0)
10881099

1100+
# Test save profile changing username (no whitespaces)
1101+
resp = self.client.post(reverse('accounts-edit'), data={'profile-username': ['userANewName'], 'profile-ui_theme_preference': 'f'})
1102+
self.assertRedirects(resp, reverse('accounts-edit'))
1103+
userA.refresh_from_db()
1104+
self.assertEqual(OldUsername.objects.filter(user=userA).count(), 1)
1105+
1106+
# Test save profile changing username (whitespaces -> fail)
1107+
resp = self.client.post(reverse('accounts-edit'), data={'profile-username': ['userA SpaceName'], 'profile-ui_theme_preference': 'f'})
1108+
self.assertEqual(resp.status_code, 200)
1109+
userA.refresh_from_db()
1110+
self.assertEqual(userA.username, 'userANewName')
1111+
self.assertEqual(OldUsername.objects.filter(user=userA).count(), 1)
10891112

10901113
class ChangeEmailViaAdminTestCase(TestCase):
10911114

0 commit comments

Comments
 (0)