Skip to content

Commit

Permalink
[ckan#1527] Read email subjects from templates as well
Browse files Browse the repository at this point in the history
As per @wardi's suggestion. Added a new example plugin with tests
  • Loading branch information
amercader committed Jun 15, 2015
1 parent 3607016 commit 422df75
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 73 deletions.
24 changes: 16 additions & 8 deletions ckan/lib/mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,20 +145,28 @@ def get_reset_link(user):
def send_reset_link(user):
create_reset_key(user)
body = get_reset_link_body(user)
site_title = config.get('ckan.site_title')
subject = config.get('ckan.emails.reset_password.subject',
'Reset your password - {site_title}').decode('utf8')
subject = _(subject).format(site_title=site_title)
extra_vars = {
'site_title': config.get('ckan.site_title')
}
subject = render_jinja2('emails/reset_password_subject.txt', extra_vars)

# Make sure we only use the first line
subject = subject.split('\n')[0]

mail_user(user, subject, body)


def send_invite(user, group_dict=None, role=None):
create_reset_key(user)
body = get_invite_body(user, group_dict, role)
site_title = config.get('ckan.site_title')
subject = config.get('ckan.emails.invite_user.subject',
'Invite for {site_title}').decode('utf8')
subject = _(subject).format(site_title=site_title)
extra_vars = {
'site_title': config.get('ckan.site_title')
}
subject = render_jinja2('emails/invite_user_subject.txt', extra_vars)

# Make sure we only use the first line
subject = subject.split('\n')[0]

mail_user(user, subject, body)


Expand Down
1 change: 1 addition & 0 deletions ckan/templates/emails/invite_user_subject.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Invite for {{ site_title }}
1 change: 1 addition & 0 deletions ckan/templates/emails/reset_password_subject.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reset your password - {{ site_title }}
38 changes: 9 additions & 29 deletions ckan/tests/lib/test_mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pylons import config
from email.mime.text import MIMEText
from email.parser import Parser
from email.header import decode_header
import hashlib
import base64

Expand All @@ -14,7 +15,7 @@
import ckan.tests.factories as factories


class TestMailer(SmtpServerHarness):
class MailerBase(SmtpServerHarness):

@classmethod
def setup_class(cls):
Expand Down Expand Up @@ -51,6 +52,13 @@ def get_email_body(self, msg):
payload = Parser().parsestr(msg).get_payload()
return base64.b64decode(payload)

def get_email_subject(self, msg):
header = Parser().parsestr(msg)['Subject']
return decode_header(header)[0][0]


class TestMailer(MailerBase):

def test_mail_recipient(self):
user = factories.User()

Expand Down Expand Up @@ -213,31 +221,3 @@ def test_send_invite_email_with_org(self):
body = self.get_email_body(msg[3])
assert_in(org['title'], body)
assert_in(h.roles_translated()[role], body)

@helpers.change_config('ckan.emails.reset_password.subject', 'Password!')
def test_send_reset_email_custom_subject(self):
user = factories.User()
user_obj = model.User.by_name(user['name'])

mailer.send_reset_link(user_obj)

# check it went to the mock smtp server
msgs = self.get_smtp_messages()
assert_equal(len(msgs), 1)
msg = msgs[0]

assert_in('Password!', msg[3])

@helpers.change_config('ckan.emails.invite_user.subject', 'Invite!')
def test_send_invite_custom_subject(self):
user = factories.User()
user_obj = model.User.by_name(user['name'])

mailer.send_invite(user_obj)

# check it went to the mock smtp server
msgs = self.get_smtp_messages()
assert_equal(len(msgs), 1)
msg = msgs[0]

assert_in('Invite!', msg[3])
Empty file.
15 changes: 15 additions & 0 deletions ckanext/example_theme/custom_emails/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit


class ExampleCustomEmailsPlugin(plugins.SingletonPlugin):
'''An example plugin with custom emails.
'''
plugins.implements(plugins.IConfigurer)

def update_config(self, config):

# Add this plugin's templates dir to CKAN's extra_template_paths, so
# that CKAN will use this plugin's custom templates.
toolkit.add_template_directory(config, 'templates')
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Dear {{ user_name }}, come join {{ site_title }}!

{{ reset_link }}

**test**
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Come join {{ site_title }} **test**

# These lines should be ignored
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Reset your password!

{{ reset_link }}

**test**
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Lost your password ? - {{ site_title }} **test**

# These lines should be ignored
114 changes: 114 additions & 0 deletions ckanext/example_theme/custom_emails/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import os
from pylons import config
from ckan import plugins
import ckan.model as model
import ckan.lib.mailer as mailer
from ckan.tests import factories
from ckan.lib.base import render_jinja2

from ckan.tests.lib.test_mailer import MailerBase

from nose.tools import assert_equal, assert_in


class TestExampleCustomEmailsPlugin(MailerBase):
@classmethod
def setup_class(cls):
super(TestExampleCustomEmailsPlugin, cls).setup_class()
if not plugins.plugin_loaded('example_theme_custom_emails'):
plugins.load('example_theme_custom_emails')

@classmethod
def teardown_class(cls):
super(TestExampleCustomEmailsPlugin, cls).teardown_class()
plugins.unload('example_theme_custom_emails')

def _get_template_content(self, name):

templates_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'templates', 'emails')
with open(os.path.join(templates_path, name), 'r') as f:
return f.read()

def test_reset_password_custom_subject(self):
user = factories.User()
user_obj = model.User.by_name(user['name'])

mailer.send_reset_link(user_obj)

# check it went to the mock smtp server
msgs = self.get_smtp_messages()
assert_equal(len(msgs), 1)
msg = msgs[0]
extra_vars = {
'site_title': config.get('ckan.site_title')
}
expected = render_jinja2('emails/reset_password_subject.txt',
extra_vars)
expected = expected.split('\n')[0]

subject = self.get_email_subject(msg[3])
assert_equal(expected, subject)
assert_in('**test**', subject)

def test_reset_password_custom_body(self):
user = factories.User()
user_obj = model.User.by_name(user['name'])

mailer.send_reset_link(user_obj)

# check it went to the mock smtp server
msgs = self.get_smtp_messages()
assert_equal(len(msgs), 1)
msg = msgs[0]
extra_vars = {
'reset_link': mailer.get_reset_link(user_obj)
}
expected = render_jinja2('emails/reset_password.txt',
extra_vars)
body = self.get_email_body(msg[3])
assert_equal(expected, body)
assert_in('**test**', body)

def test_invite_user_custom_subject(self):
user = factories.User()
user_obj = model.User.by_name(user['name'])

mailer.send_invite(user_obj)

# check it went to the mock smtp server
msgs = self.get_smtp_messages()
assert_equal(len(msgs), 1)
msg = msgs[0]
extra_vars = {
'site_title': config.get('ckan.site_title'),
}
expected = render_jinja2('emails/invite_user_subject.txt',
extra_vars)
expected = expected.split('\n')[0]

subject = self.get_email_subject(msg[3])
assert_equal(expected, subject)
assert_in('**test**', subject)

def test_invite_user_custom_body(self):
user = factories.User()
user_obj = model.User.by_name(user['name'])

mailer.send_invite(user_obj)

# check it went to the mock smtp server
msgs = self.get_smtp_messages()
assert_equal(len(msgs), 1)
msg = msgs[0]
extra_vars = {
'reset_link': mailer.get_reset_link(user_obj),
'user_name': user['name'],
'site_title': config.get('ckan.site_title'),
}
expected = render_jinja2('emails/invite_user.txt',
extra_vars)
body = self.get_email_body(msg[3])
assert_equal(expected, body)
assert_in('**test**', body)
36 changes: 0 additions & 36 deletions doc/maintaining/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1694,39 +1694,3 @@ Example::
Default value: ``None``

This controls from which email the error messages will come from.


.. _ckan.emails.reset_password.subject:

ckan.emails.reset_password.subject
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Example::

ckan.emails.reset_password.subject = Password reset

Default value: ``Reset your password - {site_title}``

Sets the subject of the email sent when resetting a users's password. This string is translated.
``{site_title}`` will be replaced with the value of :ref:`ckan.site_title`.

.. note:: To customize the email body, override the ``emails/reset_password.txt`` template
from your extension


.. _ckan.emails.invite_user.subject:

ckan.emails.invite_user.subject
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Example::

ckan.emails.invite_user.subject = You have been invited to {site_title}

Default value: ``Invite for {site_title}``

Sets the subject of the email sent when resetting a users's password. This string is translated.
``{site_title}`` will be replaced with the value of :ref:`ckan.site_title`.

.. note:: To customize the email body, override the ``emails/invite_user.txt`` template
from your extension
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
'example_theme_v20_pubsub = ckanext.example_theme.v20_pubsub.plugin:ExampleThemePlugin',
'example_theme_v21_custom_jquery_plugin = ckanext.example_theme.v21_custom_jquery_plugin.plugin:ExampleThemePlugin',
'example_theme_custom_config_setting = ckanext.example_theme.custom_config_setting.plugin:ExampleThemePlugin',
'example_theme_custom_emails = ckanext.example_theme.custom_emails.plugin:ExampleCustomEmailsPlugin',
'example_iresourcecontroller = ckanext.example_iresourcecontroller.plugin:ExampleIResourceControllerPlugin',
'example_ivalidators = ckanext.example_ivalidators.plugin:ExampleIValidatorsPlugin',
'example_iconfigurer = ckanext.example_iconfigurer.plugin:ExampleIConfigurerPlugin',
Expand Down

0 comments on commit 422df75

Please sign in to comment.