Skip to content

Commit

Permalink
Add ability to pass extra context when rendering email templates (#82)
Browse files Browse the repository at this point in the history
Add ability to pass extra context when rendering email templates.
  • Loading branch information
gingrassia committed May 28, 2021
1 parent a0466c8 commit 8d2c117
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 2 deletions.
6 changes: 6 additions & 0 deletions docs/source/overview.rst
Expand Up @@ -415,6 +415,9 @@ Default: ``None``
A raw template string to use for the email body. The render context will
include the generated token in the ``token`` key.

Dictionary sent to :meth:`~django_otp.plugins.otp_email.models.EmailDevice.generate_challenge`
under ``extra_context`` will be also used as context for building the email.

If this and :setting:`OTP_EMAIL_BODY_TEMPLATE_PATH` are not set, we'll render
the template 'otp/email/token.txt', which you'll most likely want to override.

Expand All @@ -428,6 +431,9 @@ Default: ``otp/email/token.txt``
A path string to a template file to use for the email body. The render context
will include the generated token in the ``token`` key.

Dictionary sent to :meth:`~django_otp.plugins.otp_email.models.EmailDevice.generate_challenge`
under ``extra_context`` will be also used as context for building the email.

If this and :setting:`OTP_EMAIL_BODY_TEMPLATE` are not set, we'll render the
template 'otp/email/token.txt', which you'll most likely want to override.

Expand Down
8 changes: 6 additions & 2 deletions src/django_otp/plugins/otp_email/models.py
Expand Up @@ -47,13 +47,17 @@ class EmailDevice(ThrottlingMixin, SideChannelDevice):
def get_throttle_factor(self):
return settings.OTP_EMAIL_THROTTLE_FACTOR

def generate_challenge(self):
def generate_challenge(self, extra_context=None):
"""
Generates a random token and emails it to the user.
:param extra_context: If provided, the dictionary will be used as context,
along with the token, for generating the email. Default is ``None``.
:type extra_context: dict
"""
self.generate_token(valid_secs=settings.OTP_EMAIL_TOKEN_VALIDITY)

context = {'token': self.token}
context = {'token': self.token, **(extra_context or {})}
if settings.OTP_EMAIL_BODY_TEMPLATE:
body = Template(settings.OTP_EMAIL_BODY_TEMPLATE).render(Context(context))
else:
Expand Down
23 changes: 23 additions & 0 deletions src/django_otp/plugins/otp_email/tests.py
Expand Up @@ -132,6 +132,29 @@ def test_settings_template_path(self):
with self.subTest(field='body'):
self.assertEqual(msg.body, "Test template 3: {}\n".format(self.device.token))

@override_settings(
OTP_EMAIL_SENDER="webmaster@example.com",
OTP_EMAIL_SUBJECT="Test subject",
OTP_EMAIL_BODY_TEMPLATE="Test template 4: {{token}} {{foo}} {{bar}}",
)
def test_settings_extra_template_options(self):
extra_context = {"foo": "extra 1", "bar": "extra 2"}
self.device.generate_challenge(extra_context)

self.assertEqual(len(mail.outbox), 1)

msg = mail.outbox[0]

with self.subTest(field='from_email'):
self.assertEqual(msg.from_email, "webmaster@example.com")
with self.subTest(field='subject'):
self.assertEqual(msg.subject, "Test subject")
with self.subTest(field='body'):
self.assertEqual(
msg.body,
"Test template 4: {} {} {}".format(self.device.token, extra_context["foo"], extra_context["bar"])
)

def test_alternative_email(self):
self.device.email = 'alice2@example.com'
self.device.save()
Expand Down

0 comments on commit 8d2c117

Please sign in to comment.