Skip to content

Commit

Permalink
Merge pull request #1 from molokov/accounts-2066
Browse files Browse the repository at this point in the history
Accounts 2066
  • Loading branch information
molokov authored Dec 24, 2023
2 parents a89ef45 + f10dc82 commit 67cf3d0
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 5 deletions.
4 changes: 2 additions & 2 deletions mezzanine/accounts/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def clean_email(self):
Ensure the email address is not already registered.
"""
email = self.cleaned_data.get("email")
qs = User.objects.exclude(id=self.instance.id).filter(email=email)
qs = User.objects.exclude(id=self.instance.id).filter(email__iexact=email)
if len(qs) == 0:
return email
raise forms.ValidationError(gettext("This email is already registered"))
Expand Down Expand Up @@ -261,7 +261,7 @@ class PasswordResetForm(Html5Mixin, forms.Form):

def clean(self):
username = self.cleaned_data.get("username")
username_or_email = Q(username=username) | Q(email=username)
username_or_email = Q(username__iexact=username) | Q(email__iexact=username)
try:
user = User.objects.get(username_or_email, is_active=True)
except User.DoesNotExist:
Expand Down
4 changes: 3 additions & 1 deletion mezzanine/core/auth_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class MezzanineBackend(ModelBackend):
Args are either ``username`` and ``password``, or ``uidb36``
and ``token``. In either case, ``is_active`` can also be given.
Usernames and Email addresses are not case sensitive
For login, is_active is not given, so that the login form can
raise a specific error for inactive users.
For password reset, True is given for is_active.
Expand All @@ -25,7 +27,7 @@ def authenticate(self, *args, **kwargs):
if kwargs:
username = kwargs.pop("username", None)
if username:
username_or_email = Q(username=username) | Q(email=username)
username_or_email = Q(username__iexact=username) | Q(email__iexact=username)
password = kwargs.pop("password", None)
try:
user = User.objects.get(username_or_email, **kwargs)
Expand Down
163 changes: 161 additions & 2 deletions tests/test_accounts.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from django.contrib.auth import get_user_model
import django
from django.contrib.auth import get_user, get_user_model
from django.contrib.auth.tokens import default_token_generator
from django.core import mail
from django.forms.fields import DateField, DateTimeField
from django.urls import reverse
from django.utils.http import int_to_base36

from mezzanine.accounts import ProfileNotConfigured
from mezzanine.accounts.forms import ProfileForm
from mezzanine.accounts.forms import ProfileForm, PasswordResetForm
from mezzanine.conf import settings
from mezzanine.utils.tests import TestCase

Expand Down Expand Up @@ -79,3 +80,161 @@ def test_account(self):
self.assertEqual(response.status_code, 200)
users = User.objects.filter(email=data["email"], is_active=True)
self.assertEqual(len(users), 1)

self.client.logout()

if django.VERSION[0:1] >= (4, 1):
# This form of assertFormError is only available since Django 4.1

# Create another account with the same user name
settings.ACCOUNTS_VERIFICATION_REQUIRED = False
data = self.account_data("test1")
form = ProfileForm(data=data)
self.assertFormError(form, 'username', 'This username is already registered')

# Create another account with the same user name, but case is different
data['username'] = 'TEST1'
form = ProfileForm(data=data)
self.assertFormError(form, 'username', 'This username is already registered')

# Create another account with a different username, but same email
data['username'] = 'test3'
form = ProfileForm(data=data)
self.assertFormError(form, 'email', 'This email is already registered')

# Create another account with a different username, but same email with different case
data['email'] = '[email protected]'
form = ProfileForm(data=data)
self.assertFormError(form, 'email', 'This email is already registered')


def test_account_login(self):
"""
Test account login
"""
# Create test user account
data = self.account_data("test1")
settings.ACCOUNTS_VERIFICATION_REQUIRED = False
response = self.client.post(reverse("signup"), data, follow=True)
self.assertEqual(response.status_code, 200)
# Find the valid user
users = User.objects.filter(email=data["email"], is_active=True)
self.assertEqual(len(users), 1)
test_user = users[0]

self.client.logout()

# Log in with username/password
self.assertTrue(self.client.login(username=data['username'],
password=data['password1']))
user = get_user(self.client)
self.assertEqual(user, test_user)
self.assertTrue(user.is_authenticated)
self.client.logout()

# Log in with email/password
self.assertTrue(self.client.login(username=data['email'],
password=data['password1']))
user = get_user(self.client)
self.assertEqual(user, test_user)
self.assertTrue(user.is_authenticated)
self.client.logout()

# Log in with bad password
self.assertFalse(self.client.login(username=data['username'],
password=data['password1'] + 'badbit'))
user = get_user(self.client)
self.assertFalse(user.is_authenticated)
self.client.logout()

# Log in with username (different case) and password
self.assertTrue(self.client.login(username=data['username'].upper(),
password=data['password1']))
user = get_user(self.client)
self.assertEqual(user, test_user)
self.assertTrue(user.is_authenticated)
self.client.logout()

# Log in with email (different case) and password
self.assertTrue(self.client.login(username=data['email'].upper(),
password=data['password1']))
user = get_user(self.client)
self.assertEqual(user, test_user)
self.assertTrue(user.is_authenticated)
self.client.logout()

def _verify_password_reset_email(self, new_user, num_emails):
# Check email was sent
self.assertEqual(len(mail.outbox), num_emails + 1)
self.assertEqual(len(mail.outbox[0].to), 1)
self.assertEqual(mail.outbox[0].to[0], new_user.email)
verification_url = reverse(
"password_reset_verify",
kwargs={
"uidb36": int_to_base36(new_user.id),
"token": default_token_generator.make_token(new_user),
},
)
response = self.client.get(verification_url, follow=True)
self.assertEqual(response.status_code, 200)


def test_account_password_reset(self):
"""
Test account password reset verification email
"""
# Create test user account
data = self.account_data("test1")
settings.ACCOUNTS_VERIFICATION_REQUIRED = False
response = self.client.post(reverse("signup"), data, follow=True)
self.assertEqual(response.status_code, 200)
# Find the valid user
users = User.objects.filter(email=data["email"], is_active=True)
self.assertEqual(len(users), 1)
new_user = users[0]
self.client.logout()

# Reset password with username
emails = len(mail.outbox)
rdata = {'username': data['username']}
response = self.client.post(reverse("mezzanine_password_reset"), rdata, follow=True)
self.assertEqual(response.status_code, 200)
self._verify_password_reset_email(new_user, emails)
self.client.logout()

# Reset password with email
emails = len(mail.outbox)
rdata = {'username': data['email']}
response = self.client.post(reverse("mezzanine_password_reset"), rdata, follow=True)
self.assertEqual(response.status_code, 200)
self._verify_password_reset_email(new_user, emails)
self.client.logout()

# Reset password with username (different case)
emails = len(mail.outbox)
rdata = {'username': data['username'].upper()}
response = self.client.post(reverse("mezzanine_password_reset"), rdata, follow=True)
self.assertEqual(response.status_code, 200)
self._verify_password_reset_email(new_user, emails)
self.client.logout()

# Reset password with email (different case)
emails = len(mail.outbox)
rdata = {'username': data['email'].upper()}
response = self.client.post(reverse("mezzanine_password_reset"), rdata, follow=True)
self.assertEqual(response.status_code, 200)
self._verify_password_reset_email(new_user, emails)
self.client.logout()

if django.VERSION[0:1] >= (4, 1):
# This form of assertFormError is only available since Django 4.1

# Reset password with invalid username
rdata = {'username': 'badusername'}
form = PasswordResetForm(data=rdata)
self.assertFormError(form, None, 'Invalid username/email')

# Reset password with invalid email
rdata = {'username': '[email protected]'}
form = PasswordResetForm(data=rdata)
self.assertFormError(form, None, 'Invalid username/email')

0 comments on commit 67cf3d0

Please sign in to comment.