From eef72a98e440972a5a0fc7d84df72d7ac3cd9370 Mon Sep 17 00:00:00 2001 From: Vishnu Ks Date: Tue, 3 Oct 2017 00:04:32 +0000 Subject: [PATCH] backends: Create custom email backend EmailLogBackEnd. Create a new custom email backend which would automatically logs the emails that are send in the dev environment as well as print a friendly message in console to visit /emails for accessing all the emails that are sent in dev environment. Since django.core.mail.backends.console.EmailBackend is no longer userd emails would not be printed to the console anymore. --- templates/zerver/email.html | 26 ++++++++++------------ zerver/lib/send_email.py | 43 ++++--------------------------------- zerver/tests/test_docs.py | 24 ++++++++++----------- zerver/tests/test_signup.py | 2 +- zproject/backends.py | 40 ++++++++++++++++++++++++++++++++++ zproject/settings.py | 2 +- 6 files changed, 69 insertions(+), 68 deletions(-) diff --git a/templates/zerver/email.html b/templates/zerver/email.html index da4e670196..fca9f3f0fe 100644 --- a/templates/zerver/email.html +++ b/templates/zerver/email.html @@ -1,16 +1,12 @@ -{% if failed %} -

{{template}} failed to render: {{ reason }}

-{% else %} -

From: {{ from_email }}

-

To: - {% for recipient in recipients %} - {{ recipient }}  - {% endfor %} -

-

Subject: {{subject}}

- {% autoescape off %} - {{ html_message }} - {% endautoescape %} -
{{ body }}
-{% endif %} +

From: {{ from_email }}

+

To: + {% for recipient in recipients %} + {{ recipient }}  + {% endfor %} +

+

Subject: {{subject}}

+{% autoescape off %} +{{ html_message }} +{% endautoescape %} +
{{ body }}

diff --git a/zerver/lib/send_email.py b/zerver/lib/send_email.py index 9c4da4e7c2..e6781af1d3 100644 --- a/zerver/lib/send_email.py +++ b/zerver/lib/send_email.py @@ -23,35 +23,6 @@ class FromAddress(object): SUPPORT = parseaddr(settings.ZULIP_ADMINISTRATOR)[1] NOREPLY = parseaddr(settings.NOREPLY_EMAIL_ADDRESS)[1] -def log_email(email, template_prefix): - # type: (EmailMultiAlternatives, str) -> None - """Used in development to record sent emails in a nice HTML log""" - html_message = 'Missing HTML message' - if len(email.alternatives) > 0: - html_message = email.alternatives[0][0] - - context = { - 'template': template_prefix + ".html", - 'subject': email.subject, - 'from_email': email.from_email, - 'recipients': email.to, - 'body': email.body, - 'html_message': html_message - } - - new_email = loader.render_to_string('zerver/email.html', context) - - # Read in the pre-existing log, so that we can add the new entry - # at the top. - try: - with open(settings.EMAIL_CONTENT_LOG_PATH, "r") as f: - previous_emails = f.read() - except FileNotFoundError: - previous_emails = "" - - with open(settings.EMAIL_CONTENT_LOG_PATH, "w+") as f: - f.write(new_email + previous_emails) - def build_email(template_prefix, to_user_id=None, to_email=None, from_name=None, from_address=None, reply_to_email=None, context=None): # type: (str, Optional[int], Optional[Text], Optional[Text], Optional[Text], Optional[Text], Optional[Dict[str, Any]]) -> EmailMultiAlternatives @@ -117,9 +88,6 @@ def send_email(template_prefix, to_user_id=None, to_email=None, from_name=None, template = template_prefix.split("/")[-1] logger.info("Sending %s email to %s" % (template, mail.to)) - if settings.DEVELOPMENT: - log_email(mail, template_prefix) - if mail.send() == 0: logger.error("Error sending %s email to %s" % (template, mail.to)) raise EmailNotDeliveredException @@ -135,13 +103,10 @@ def send_future_email(template_prefix, to_user_id=None, to_email=None, from_name email_fields = {'template_prefix': template_prefix, 'to_user_id': to_user_id, 'to_email': to_email, 'from_name': from_name, 'from_address': from_address, 'context': context} - if settings.DEVELOPMENT: - mail = build_email(template_prefix, to_user_id=to_user_id, to_email=to_email, from_name=from_name, - from_address=from_address, context=context) - # Technically, this will be called. But we currently don't - # run the `manage.py deliver_email` backend job in the - # development environment. - log_email(mail, template_prefix) + if settings.DEVELOPMENT and not settings.TEST_SUITE: + send_email(template_prefix, to_user_id=to_user_id, to_email=to_email, from_name=from_name, + from_address=from_address, context=context) + # For logging the email assert (to_user_id is None) ^ (to_email is None) if to_user_id is not None: diff --git a/zerver/tests/test_docs.py b/zerver/tests/test_docs.py index 9795b6e009..bcfeeae1de 100644 --- a/zerver/tests/test_docs.py +++ b/zerver/tests/test_docs.py @@ -76,19 +76,19 @@ class DocPageTest(ZulipTestCase): self._test('/errors/404/', 'Page not found') self._test('/errors/5xx/', 'Internal server error') - # For reaching full coverage for clear_emails function - self._test('/emails/', 'manually generate most of the emails by clicking') - if os.path.isfile(settings.EMAIL_CONTENT_LOG_PATH): - os.remove(settings.EMAIL_CONTENT_LOG_PATH) - result = self.client_get('/emails/clear/') - self.assertEqual(result.status_code, 302) - result = self.client_get(result['Location']) - self.assertIn('manually generate most of the emails by clicking', str(result.content)) + with self.settings(EMAIL_BACKEND='zproject.backends.EmailLogBackEnd'): + # For reaching full coverage for clear_emails function + result = self.client_get('/emails/clear/') + self.assertEqual(result.status_code, 302) + result = self.client_get(result['Location']) + self.assertIn('manually generate most of the emails by clicking', str(result.content)) - result = self.client_get('/emails/generate/') - self.assertEqual(result.status_code, 302) - self.assertIn('emails', result['Location']) - self._test('/register/', 'Sign up for Zulip') + result = self.client_get('/emails/generate/') + self.assertEqual(result.status_code, 302) + self.assertIn('emails', result['Location']) + + self._test('/emails/', 'manually generate most of the emails by clicking') + self._test('/register/', 'Sign up for Zulip') result = self.client_get('/integrations/doc-html/nonexistent_integration', follow=True) self.assertEqual(result.status_code, 404) diff --git a/zerver/tests/test_signup.py b/zerver/tests/test_signup.py index 153172df9c..fed5f6ab9a 100644 --- a/zerver/tests/test_signup.py +++ b/zerver/tests/test_signup.py @@ -305,7 +305,7 @@ class LoginTest(ZulipTestCase): with queries_captured() as queries: self.register(self.nonreg_email('test'), "test") # Ensure the number of queries we make is not O(streams) - self.assert_length(queries, 68) + self.assert_length(queries, 66) user_profile = self.nonreg_user('test') self.assertEqual(get_session_dict_user(self.client.session), user_profile.id) self.assertFalse(user_profile.enable_stream_desktop_notifications) diff --git a/zproject/backends.py b/zproject/backends.py index 5a6f30ed4a..cc00d6b387 100644 --- a/zproject/backends.py +++ b/zproject/backends.py @@ -6,6 +6,9 @@ from django.contrib.auth.backends import RemoteUserBackend from django.conf import settings from django.http import HttpResponse import django.contrib.auth +from django.core.mail.backends.base import BaseEmailBackend +from django.core.mail import EmailMultiAlternatives +from django.template import loader from django_auth_ldap.backend import LDAPBackend, _LDAPUser from zerver.lib.actions import do_create_user @@ -575,3 +578,40 @@ AUTH_BACKEND_NAME_MAP = { u'LDAP': ZulipLDAPAuthBackend, u'RemoteUser': ZulipRemoteUserBackend, } # type: Dict[Text, Any] + +class EmailLogBackEnd(BaseEmailBackend): + def log_email(self, email): + # type: (EmailMultiAlternatives) -> None + """Used in development to record sent emails in a nice HTML log""" + html_message = 'Missing HTML message' + if len(email.alternatives) > 0: + html_message = email.alternatives[0][0] + + context = { + 'subject': email.subject, + 'from_email': email.from_email, + 'recipients': email.to, + 'body': email.body, + 'html_message': html_message + } + + new_email = loader.render_to_string('zerver/email.html', context) + + # Read in the pre-existing log, so that we can add the new entry + # at the top. + try: + with open(settings.EMAIL_CONTENT_LOG_PATH, "r") as f: + previous_emails = f.read() + except FileNotFoundError: + previous_emails = "" + + with open(settings.EMAIL_CONTENT_LOG_PATH, "w+") as f: + f.write(new_email + previous_emails) + + def send_messages(self, email_messages): + # type: (List[EmailMultiAlternatives]) -> int + for email in email_messages: + self.log_email(email) + email_log_url = settings.ROOT_DOMAIN_URI + "/emails" + print("You can access all the emails sent in development environment by visiting ", email_log_url) + return len(email_messages) diff --git a/zproject/settings.py b/zproject/settings.py index 798b638b97..1317d6df1e 100644 --- a/zproject/settings.py +++ b/zproject/settings.py @@ -1386,7 +1386,7 @@ elif not EMAIL_HOST and PRODUCTION: EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' elif DEVELOPMENT: # In the dev environment, emails are printed to the run-dev.py console. - EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + EMAIL_BACKEND = 'zproject.backends.EmailLogBackEnd' else: EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'