Open anuj9196 opened 3 years ago
The PasswordResetForm
inside dj_rest_auth/forms.py
, overrides the allauth save method
path = reverse(
'password_reset_confirm',
args=[user_pk_to_url_str(user), temp_key],
)
url = build_absolute_uri(request, path)
context = {
'current_site': current_site,
'user': user,
'password_reset_url': url,
'request': request,
}
password_reset_url
in the context is using the API endpoint host, i.e., api.host.com
, instead it should have the URL of the frontend application where the user will be landed to reset the password.
Also it does not exposes uid
and token
in the context, which can be used to generate custom URL.
Similar problem here. In latest version of the library the form AllAuthPasswordResetForm
is used when allauth is include in the installed apps and it does not allow any customization since the **kwargs received in the save method are basically ignored. I think it would be great to have an easy way to override the form class or be able to inject via kwargs the email template name and the template context.
During a recent upgrade of both allauth and dj-rest-auth I had the same problem with non functional password reset emails. As other mentioned I wanted the url to link to the pwa client domain and not the api domain, and through the client and dj-rest-auth call the password-reset-confirm endpoint.
It was possible to override the serializer form and this is my complete solution that gave me back full control of the template, form and context. I've replaced the template path and default context names which is not necessary but because I have multiple client app domains using the same api, I've some extra steps that just makes the renaming more reasonable.
# serializers.py
from dj_rest_auth.serializers import PasswordResetSerializer
from myapp.models import ClientApp
class CustomPasswordResetSerializer(PasswordResetSerializer):
@property
def password_reset_form_class(self):
return CustomResetPasswordForm
def get_email_options(self):
return {
"email_template": "email/account/user_password_reset",
"extra_email_context": {"client_app": ClientApp.from_request(self.context.get("request"))},
}
# forms.py
from allauth.account.adapter import get_adapter
from allauth.account.forms import ResetPasswordForm
from allauth.account.utils import user_pk_to_url_str
class CustomResetPasswordForm(ResetPasswordForm):
def save(self, request, **kwargs):
email = self.cleaned_data['email']
token_generator = kwargs.get('token_generator')
template = kwargs.get("email_template")
extra = kwargs.get("extra_email_context", {})
client_app = extra["client_app"]
for user in self.users:
uid = user_pk_to_url_str(user)
token = token_generator.make_token(user)
reset_url = f"https://{client_app.domain}/{client_app.reset_path}/{uid}/{token}"
context = {"user": user, "request": request, "email": email, "reset_url": reset_url}
context.update(extra)
with translation.override(user.locale):
get_adapter(request).send_mail(template, email, context)
return email
# templates/email/account/user_password_reset_(message.txt | message.html | subject.txt)
Hi from {{ client_app.name }}!
{{ reset_url }}
...
I've removed some generic steps so this is specialized for my situation. But just doing the context.update(kwargs.get("extra_email_context", {}))
in the dj_rest_auth.forms.AllAuthPasswordResetForm
save method would probably solve the general problem for this library. Just allowing the api host for password reset urls I feel is somewhat limiting and probably not the intention.
I have a custom template to send password reset email with the following content
and using a custom serializer
in
settings.py
But the value for
uid
andtoken
as welldomain
is blank and it appears like below in the email