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

get_email_options not work when AllAuthPasswordResetForm is used #651

Open
ugnelis opened this issue Aug 22, 2024 · 3 comments
Open

get_email_options not work when AllAuthPasswordResetForm is used #651

ugnelis opened this issue Aug 22, 2024 · 3 comments

Comments

@ugnelis
Copy link

ugnelis commented Aug 22, 2024

I am trying to have a custom email template. When I use PasswordResetForm, everything seems to work fine:

from django.contrib.auth.forms import PasswordResetForm

class CustomPasswordResetSerializer(PasswordResetSerializer):
    password_reset_form_class = PasswordResetForm

    def get_email_options(self):
        return {
            "subject_template_name": "account/email/password_reset_subject.txt",
            "email_template_name": "account/email/password_reset_message.html",
            "html_email_template_name": "account/email/password_reset_message.html",
            "extra_email_context": {
                "settings": settings,
            }
        }

I am using allauth. In this case, in order to have the correct uid and token, I need to use AllAuthPasswordResetForm.

from dj_rest_auth.forms import AllAuthPasswordResetForm

class CustomPasswordResetSerializer(PasswordResetSerializer):
    password_reset_form_class = AllAuthPasswordResetForm

    def get_email_options(self):
        return {
            "subject_template_name": "account/email/password_reset_subject.txt",
            "email_template_name": "account/email/password_reset_message.html",
            "html_email_template_name": "account/email/password_reset_message.html",
            "extra_email_context": {
                "settings": settings,
            }
        }

But then get_email_options not working. It keeps sending the default template.

My settings look like this:

REST_AUTH = {
    "USE_JWT": True,
    "JWT_AUTH_HTTPONLY": False,
    "JWT_AUTH_COOKIE": "authToken",
    "JWT_AUTH_REFRESH_COOKIE": "refreshToken",
    "JWT_TOKEN_CLAIMS_SERIALIZER":
        "apps.authentication.serializers.CustomTokenObtainPairSerializer",
    "REGISTER_SERIALIZER":
        "apps.authentication.serializers.CustomRegisterSerializer",
    "PASSWORD_RESET_SERIALIZER":
        "apps.authentication.serializers.CustomPasswordResetSerializer",
}

Dependencies:

dj-rest-auth[with_social]==6.0.0
django-allauth==0.61.1
djangorestframework-simplejwt==5.2.2
djangorestframework==3.14.0

How to use my custom email template?

@ugnelis
Copy link
Author

ugnelis commented Aug 23, 2024

Based on dj_rest_auth/forms.py:

class AllAuthPasswordResetForm(DefaultPasswordResetForm):
    # ...
    def save(self, request, **kwargs):
        # ...
            for user in self.users:
                # ...
                if (
                    allauth_account_settings.AUTHENTICATION_METHOD != allauth_account_settings.AuthenticationMethod.EMAIL
                 ):
                    context['username'] = user_username(user)
                    get_adapter(request).send_mail(
                        'account/email/password_reset_key', email, context
                    )

It expects the template to be in account/email/password_reset_key, so having files like this:

  • templates/account/email/password_reset_key_subject.txt
  • templates/account/email/password_reset_key_message.html

solves the problem.

get_email_options pretty much does nothing even though it is being called

@ugnelis
Copy link
Author

ugnelis commented Aug 23, 2024

My solution is to override DefaultPasswordResetForm logic:

forms.py

from allauth.account import app_settings as allauth_account_settings
from allauth.account.adapter import get_adapter
from allauth.account.forms import ResetPasswordForm as DefaultPasswordResetForm
from allauth.account.forms import default_token_generator
from allauth.account.utils import (
    filter_users_by_email,
    user_pk_to_url_str,
    user_username,
)
from dj_rest_auth.forms import default_url_generator


class CustomPasswordResetForm(DefaultPasswordResetForm):
    def clean_email(self):
        email = self.cleaned_data["email"]
        email = get_adapter().clean_email(email)
        self.users = filter_users_by_email(email, is_active=True)
        return self.cleaned_data["email"]

    def save(self, request, **kwargs):
        email = self.cleaned_data["email"]
        token_generator = kwargs.get("token_generator", default_token_generator)

        for user in self.users:

            temp_key = token_generator.make_token(user)
            url_generator = kwargs.get("url_generator", default_url_generator)
            url = url_generator(request, user, temp_key)
            uid = user_pk_to_url_str(user)

            context = {
                "user": user,
                "password_reset_url": url,
                "request": request,
                "token": temp_key,
                "uid": uid,
            }
            extra_email_context = kwargs.get("extra_email_context", {})
            context.update(extra_email_context)

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

        return self.cleaned_data["email"]

serializers.py

from dj_rest_auth.serializers import PasswordResetSerializer

from config import settings
from .forms import CustomPasswordResetForm

class CustomPasswordResetSerializer(PasswordResetSerializer):
    password_reset_form_class = CustomPasswordResetForm

    def get_email_options(self):
        return {
            "extra_email_context": {
                "settings": settings,
            }
        }

and have files templates/account/email/password_reset_key_message.html and templates/account/email/password_reset_key_subject.txt

settings.py

REST_AUTH = {
    # ...
    "PASSWORD_RESET_SERIALIZER":
        "apps.authentication.serializers.CustomPasswordResetSerializer",
}

@paulrogov
Copy link

paulrogov commented Nov 6, 2024

You're right @ugnelis

The method dj_rest_auth.forms.AllAuthPasswordResetForm.save() is broken.
It's missing **(extra_email_context or {}), from the original django.contrib.auth.forms.PasswordResetForm

extra_email_context = kwargs.get("extra_email_context", {})
context.update(extra_email_context)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants