Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom account email verification through adapter #1946 #3648

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -130,6 +130,7 @@ Matt Nishi-Broach
Mauro Stettler
Mikhail Mitiaev
Morgante Pell
Muneeb Shahid
Nariman Gharib
Nathan Strobbe
Nicolas Acosta
Expand Down
3 changes: 2 additions & 1 deletion ChangeLog.rst
Expand Up @@ -9,6 +9,7 @@
accordingly. Migrations are in place. For rationale, see the note about email
case sensitivity in the documentation.

- Added support for custom account email verification based on the user's email.

0.62.1 (2024-04-24)
*******************
Expand Down Expand Up @@ -711,4 +712,4 @@ Backwards incompatible changes
- The default of ``SOCIALACCOUNT_STORE_TOKENS`` has been changed to
``False``. Rationale is that storing sensitive information should be opt in, not
opt out. If you were relying on this functionality without having it
explicitly turned on, please add it to your ``settings.py``.
explicitly turned on, please add it to your ``settings.py``.
3 changes: 3 additions & 0 deletions allauth/account/adapter.py
Expand Up @@ -727,6 +727,9 @@ def get_reauthentication_methods(self, user):
)
return ret

def get_email_verification_method(self, login=None):
return app_settings.EMAIL_VERIFICATION

def send_notification_mail(self, template_prefix, user, context=None, email=None):
from allauth.account.models import EmailAddress

Expand Down
2 changes: 1 addition & 1 deletion allauth/account/models.py
Expand Up @@ -235,7 +235,7 @@ def __init__(
):
self.user = user
if not email_verification:
email_verification = app_settings.EMAIL_VERIFICATION
email_verification = get_adapter().get_email_verification_method(self)
self.email_verification = email_verification
self.redirect_url = redirect_url
self.signal_kwargs = signal_kwargs
Expand Down
10 changes: 10 additions & 0 deletions allauth/account/tests/test_adapter.py
Expand Up @@ -2,6 +2,9 @@
from django.urls import reverse

from allauth.account.adapter import DefaultAccountAdapter
from allauth.account.app_settings import (
EmailVerificationMethod,
)
from allauth.core.exceptions import ImmediateHttpResponse


Expand All @@ -10,6 +13,13 @@ def pre_login(self, *args, **kwargs):
raise ImmediateHttpResponse(HttpResponseRedirect("/foo"))


class CustomAccountEmailVerificationAdapter(DefaultAccountAdapter):
def get_email_verification_method(self, login):
if login.user.email == "mandatory@example.com":
return EmailVerificationMethod.MANDATORY
return EmailVerificationMethod.OPTIONAL


def test_adapter_pre_login(settings, user, user_password, client):
settings.ACCOUNT_ADAPTER = (
"allauth.account.tests.test_adapter.PreLoginRedirectAccountAdapter"
Expand Down
34 changes: 34 additions & 0 deletions allauth/account/tests/test_signup.py
Expand Up @@ -288,6 +288,40 @@ def test_django_password_validation(self):
"password1",
["This password is too short. It must contain at least 9 characters."],
)
@override_settings(
ACCOUNT_ADAPTER="allauth.account.tests.test_adapter.CustomAccountEmailVerificationAdapter"
)
def test_signup_custom_account_email_verification(self):
# with mandatory email verification
resp = self.client.post(
reverse("account_signup"),
{
"username": "mandatory",
"email": "mandatory@example.com",
"password1": "mandatory123",
"password2": "mandatory123",
},
)
self.assertEqual(resp.status_code, 302)
self.assertEqual(
resp["location"], reverse("account_email_verification_sent")
)
self.assertEqual(len(mail.outbox), 1)

# with optional email verification
resp = self.client.post(
reverse("account_signup"),
{
"username": "optional",
"email": "optional@example.com",
"password1": "optional123",
"password2": "optional123",
},
)
self.assertEqual(resp.status_code, 302)
self.assertEqual(
resp["location"], app_settings.SIGNUP_REDIRECT_URL
)


def test_prevent_enumeration_with_mandatory_verification(
Expand Down
2 changes: 1 addition & 1 deletion allauth/account/utils.py
Expand Up @@ -506,7 +506,7 @@ def assess_unique_email(email) -> Optional[bool]:
# Fail right away.
return False
elif (
app_settings.EMAIL_VERIFICATION
get_adapter().get_email_verification_method()
== app_settings.EmailVerificationMethod.MANDATORY
):
# In case of mandatory verification and enumeration prevention,
Expand Down