diff --git a/opentech/apply/activity/messaging.py b/opentech/apply/activity/messaging.py index c52bd74b3261d8ed533ce2142dfbd86d1fac6d31..1d973043d39e8ea6971d83616d6dab685c90e9da 100644 --- a/opentech/apply/activity/messaging.py +++ b/opentech/apply/activity/messaging.py @@ -4,9 +4,10 @@ import requests from django.conf import settings from django.contrib import messages -from django.core.mail import send_mail from django.template.loader import render_to_string +from .tasks import send_mail, update_message_status + def link_to(target, request): return request.scheme + '://' + request.get_host() + target.get_absolute_url() @@ -69,13 +70,13 @@ class AdapterBase: return for recipient in self.recipients(message_type, **kwargs): + message_log = self.create_log(message, recipient, event) if settings.SEND_MESSAGES or self.always_send: - status = self.send_message(message, recipient=recipient, **kwargs) + status = self.send_message(message, recipient=recipient, message_log=message_log, **kwargs) else: status = 'Message not sent as SEND_MESSAGES==FALSE' - if status: - self.log_message(message, recipient, event, status) + message_log.update_status(status) if not settings.SEND_MESSAGES: if recipient: @@ -84,14 +85,13 @@ class AdapterBase: message = '{}: {}'.format(self.adapter_type, message) messages.add_message(kwargs['request'], messages.INFO, message) - def log_message(self, message, recipient, event, status): - from.models import Message - Message.objects.create( + def create_log(self, message, recipient, event): + from .models import Message + return Message.objects.create( type=self.adapter_type, content=message, recipient=recipient, event=event, - status=status, ) def send_message(self, message, **kwargs): @@ -253,18 +253,18 @@ class EmailAdapter(AdapterBase): def send_message(self, message, submission, subject, recipient, **kwargs): try: - emails_sent = send_mail( - subject, - message, - submission.page.specific.from_address, - [recipient], - fail_silently=False, + emails_sent = send_mail.apply_async( + ( + subject, + message, + submission.page.specific.from_address, + [recipient], + ), + link=update_message_status.s(kwargs['message_log'].id), ) except Exception as e: return 'Error: ' + str(e) - return 'Emails sent: ' + str(emails_sent) - class MessengerBackend: def __init__(self, *adpaters): diff --git a/opentech/apply/activity/models.py b/opentech/apply/activity/models.py index 7970cf9eb5fe928833f5bf5a38eb4da0466c5227..caa8cd54a7b77cb12a21a350269db671e79a5545 100644 --- a/opentech/apply/activity/models.py +++ b/opentech/apply/activity/models.py @@ -1,5 +1,7 @@ from django.conf import settings from django.db import models +from django.db.models import Case, When, Value +from django.db.models.functions import Concat from .messaging import MESSAGES @@ -121,3 +123,11 @@ class Message(models.Model): recipient = models.CharField(max_length=250) event = models.ForeignKey(Event, on_delete=models.CASCADE) status = models.TextField() + + def update_status(self, status): + if status: + self.status = Case( + When(status='', then=Value(status)), + default=Concat('status', Value('<br />' + status)) + ) + self.save() diff --git a/opentech/apply/activity/tasks.py b/opentech/apply/activity/tasks.py new file mode 100644 index 0000000000000000000000000000000000000000..53a16f845d12d775132b063ebb4bd3c5b2879f42 --- /dev/null +++ b/opentech/apply/activity/tasks.py @@ -0,0 +1,28 @@ +from celery import Celery + +from django.conf import settings +from django.core.mail import send_mail as dj_send_mail + +app = Celery('tasks') + +app.config_from_object(settings, namespace='CELERY', force=True) + + +@app.task +def send_mail(*args, **kwargs): + try: + emails_sent = dj_send_mail( + *args, + fail_silently=False, + **kwargs, + ) + except Exception as e: + return 'Error: ' + str(e) + + return 'Emails sent: ' + str(emails_sent) + + +@app.task +def update_message_status(status, message): + from .models import Message + Message.objects.get(id=message).update_status(status) diff --git a/opentech/apply/activity/tests/test_tasks.py b/opentech/apply/activity/tests/test_tasks.py new file mode 100644 index 0000000000000000000000000000000000000000..b9c73a965b073f08c166c91b8f88dbb64e589186 --- /dev/null +++ b/opentech/apply/activity/tests/test_tasks.py @@ -0,0 +1,13 @@ +from unittest.mock import patch + +from django.test import TestCase + +from ..tasks import send_mail + + +class TestSendEmail(TestCase): + @patch('opentech.apply.activity.tasks.dj_send_mail') + def test_args_passed_to_django(self, dj_send_mail): + args = ['subject', 'message', 'from', ['to@to.com']] + send_mail(*args) + dj_send_mail.assert_called_once_with(*args, fail_silently=False) diff --git a/opentech/settings/base.py b/opentech/settings/base.py index c4da25f92ef4553be9dbb4358242a49b94d39b46..6d4b5579fe4f8396baa34b8e2abfc1d5775d8e29 100644 --- a/opentech/settings/base.py +++ b/opentech/settings/base.py @@ -356,3 +356,10 @@ HIJACK_DECORATOR = 'opentech.apply.users.decorators.superuser_decorator' SEND_MESSAGES = env.get('SEND_MESSAGES', 'false').lower() == 'true' SLACK_DESTINATION_URL = env.get('SLACK_DESTINATION_URL', None) SLACK_DESTINATION_ROOM = env.get('SLACK_DESTINATION_ROOM', None) + + +# Celery config +if 'REDIS_URL' in env: + CELERY_BROKER_URL = env.get('REDIS_URL') +else: + CELERY_TASK_ALWAYS_EAGER = True diff --git a/requirements.txt b/requirements.txt index beb571c642a3e18eba3c76d4ec83563eaed9a745..0ea9b0b33fa436dc7538579fffaa11c5336c4588 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,6 +12,8 @@ stellar==0.4.3 django-tinymce4-lite==1.7.0 uwsgidecorators==1.1.0 django-hijack==2.1.9 +django-anymail==3.0 +celery==4.2.1 factory_boy==2.9.2 # wagtail_factories - waiting on merge and release form master branch