Skip to content

Commit

Permalink
feat(account): Add DefaultAccountAdapter.send_password_reset_mail
Browse files Browse the repository at this point in the history
This new adapter method can be used to apply custom logic regarding
whether a user should be able to initiate the reset password flow.
  • Loading branch information
mecampbellsoup authored and pennersr committed Aug 22, 2024
1 parent b8b06c3 commit b242ded
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 11 deletions.
12 changes: 11 additions & 1 deletion allauth/account/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,9 +563,19 @@ def is_safe_url(self, url):

return url_has_allowed_host_and_scheme(url, allowed_hosts=allowed_hosts)

def send_password_reset_mail(self, user, email, context):
"""
Method intended to be overridden in case you need to customize the logic
used to determine whether a user is permitted to request a password reset.
For example, if you are enforcing something like "social only" authentication
in your app, you may want to intervene here by checking `user.has_usable_password`
"""
return self.send_mail("account/email/password_reset_key", email, context)

def get_reset_password_from_key_url(self, key):
"""
Method intented to be overriden in case the password reset email
Method intended to be overridden in case the password reset email
needs to be adjusted.
"""
from allauth.account.internal import flows
Expand Down
18 changes: 8 additions & 10 deletions allauth/account/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from allauth.utils import get_username_max_length, set_form_field_order

from . import app_settings
from .adapter import get_adapter
from .adapter import DefaultAccountAdapter, get_adapter
from .app_settings import AuthenticationMethod
from .models import EmailAddress, Login
from .utils import (
Expand Down Expand Up @@ -598,18 +598,15 @@ def clean_email(self):
raise get_adapter().validation_error("unknown_email")
return self.cleaned_data["email"]

def save(self, request, **kwargs):
def save(self, request, **kwargs) -> str:
email = self.cleaned_data["email"]
if not self.users:
flows.signup.send_unknown_account_mail(request, email)
else:
self._send_password_reset_mail(request, email, self.users, **kwargs)
return email
return email

def _send_password_reset_mail(self, request, email, users, **kwargs):
adapter: DefaultAccountAdapter = get_adapter()
token_generator = kwargs.get("token_generator", default_token_generator)

for user in users:
for user in self.users:
temp_key = token_generator.make_token(user)

# send the password reset email
Expand All @@ -618,7 +615,7 @@ def _send_password_reset_mail(self, request, email, users, **kwargs):
# not implementation details such as a separate `uidb36` and
# `key. Ideally, this should have done on `urls` level as well.
key = f"{uid}-{temp_key}"
url = get_adapter().get_reset_password_from_key_url(key)
url = adapter.get_reset_password_from_key_url(key)
context = {
"user": user,
"password_reset_url": url,
Expand All @@ -629,7 +626,8 @@ def _send_password_reset_mail(self, request, email, users, **kwargs):

if app_settings.AUTHENTICATION_METHOD != AuthenticationMethod.EMAIL:
context["username"] = user_username(user)
get_adapter().send_mail("account/email/password_reset_key", email, context)
adapter.send_password_reset_mail(user, email, context)
return email


class ResetPasswordKeyForm(PasswordVerificationMixin, forms.Form):
Expand Down

0 comments on commit b242ded

Please sign in to comment.