djoser
djoser copied to clipboard
URLs for emails can't be configured for other domains
It looks like djoser is restricted to using the current site's object for building URLs (ie, ACTIVATE_URL
) which leaves you with the protocol and domain of the django server. This is a scenario that needs to be configurable, imho, to account for a frontend hosted on some other domain.
For example, I typically have a Django-based API on the api
domain (api.foobar.com) and web files served up on the www
domain (www.foobar.com) via some static-file-only CDN.
Evidence:
The djoser Activation Email object that produces an evaluated template: https://github.com/sunscrapers/djoser/blob/84f2ca4e7ce3dd05ce9b145fcc5353e77ebffc05/djoser/email.py#L8
The email template using protocol
/domain
:
https://github.com/sunscrapers/djoser/blob/84f2ca4e7ce3dd05ce9b145fcc5353e77ebffc05/djoser/templates/email/activation.html#L22
The django-templated-email handler that fills in the template:
(you could set DOMAIN
, sure, but this seems like a hack and likely will be disruptive to another module)
https://github.com/sunscrapers/django-templated-mail/blob/65e5a34f69d50d4d1b6acdd337f9efcc44b32fae/templated_mail/mail.py#L33
Would something like this fly? This puts it in the context so it's an override:
diff --git a/djoser/email.py b/djoser/email.py
index 8c01925..0ee0551 100644
--- a/djoser/email.py
+++ b/djoser/email.py
@@ -15,7 +15,15 @@ class ActivationEmail(BaseEmailMessage):
user = context.get("user")
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
+
+ # Use the [possibly] user supplied values to build links within emails.
+ keys = ("protocol", "domain")
+ for key in keys:
+ settings_value = getattr(settings, key.upper(), None)
+ if settings_value:
+ context[key] = settings_value
context["url"] = settings.ACTIVATION_URL.format(**context)
+
return context
diff --git a/docs/source/base_endpoints.rst b/docs/source/base_endpoints.rst
index ac357e0..a4aaf4e 100644
--- a/docs/source/base_endpoints.rst
+++ b/docs/source/base_endpoints.rst
@@ -38,9 +38,9 @@ User Activate
Use this endpoint to activate user account. This endpoint is not a URL which
will be directly exposed to your users - you should provide site in your
-frontend application (configured by ``ACTIVATION_URL``) which will send ``POST``
-request to activate endpoint. ``HTTP_403_FORBIDDEN`` will be raised if user is already
-active when calling this endpoint (this will happen if you call it more than once).
+frontend application (configured by ``DOMAIN``, ``PROTOCOL``, and ``ACTIVATION_URL``) which will
+send a ``POST`` request to the activate endpoint. ``HTTP_403_FORBIDDEN`` will be raised if user is
+already active when calling this endpoint (this will happen if you call it more than once).
**Default URL**: ``/users/activation/``
Had the same problem, solved by overriding email classes. It would be nice to working as @LyleScott suggests.
@LyleScott Did you create a pull request already?
@LyleScott This is handy, I want the URL to redirect on the frontend. Because my frontend is separate from the backend.
@LyleScott I have created the pull request for this issue. https://github.com/sunscrapers/djoser/pull/566
I have the same issue, it would be great to implement this feature.
For those who want a fix until then, here is what I did for my app:
- Add an emails.py file to your app
- Add this code to your emails.py file:
from templated_mail.mail import BaseEmailMessage
from django.contrib.auth.tokens import default_token_generator
from djoser import utils
from djoser.conf import settings
class ActivationEmail(BaseEmailMessage):
template_name = "email/activation.html"
def get_context_data(self):
# ActivationEmail can be deleted
context = super().get_context_data()
user = context.get("user")
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
context["url"] = settings.ACTIVATION_URL.format(**context)
context["domain"] = "site_domain" # Your site domain
context["protocol"] = "site_protocol" # Your site protocol e.g. ("http", "https")
return context
- Add this code to your settings.py file:
DJOSER = {
#... your other settings
"EMAIL": {
"activation": "app.emails.ActivationEmail" # app being your app's name
}
}
Everything should now work properly.
How does djoser decide which protocol to use?
Whoa, sorry, y'all. I just saw this notification. Tales from the crypt. I don't use any of this stuff anymore, but I can perhaps revisit in the near future to see what needs to be done to get this across this finishline. I'm happy to contribute if time allows, cheers.