Skip to content

Commit

Permalink
feat(api): add management command to send emails
Browse files Browse the repository at this point in the history
  • Loading branch information
peterthomassen committed Aug 11, 2022
1 parent 84067f3 commit 801cb51
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 3 deletions.
62 changes: 62 additions & 0 deletions api/desecapi/management/commands/outreach-email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import argparse
import sys

from django.core.exceptions import ImproperlyConfigured
from django.core.management import BaseCommand
from django.template import engines
from django.template.backends.django import DjangoTemplates
from django.urls import resolve, reverse

from desecapi.models import User


def _get_default_template_backend():
# Ad-hoc implementation of https://github.com/django/django/pull/15944
for backend in engines.all():
if isinstance(backend, DjangoTemplates):
return backend
raise ImproperlyConfigured("No DjangoTemplates backend is configured.")


class Command(BaseCommand):
help = 'Reach out to users with an email. Takes email template on stdin.'

def add_arguments(self, parser):
parser.add_argument('email', nargs='*', help='User(s) to contact, identified by their email addresses')
parser.add_argument('--contentfile', nargs='?', type=argparse.FileType('r'), default=sys.stdin,
help='File to take email content from. Defaults to stdin.')
parser.add_argument('--reason', nargs='?', default='change-outreach-preference',
help='Kind of message to send. Choose from reasons given in serializers.py. Defaults to '
'newsletter with unsubscribe link (reason: change-outreach-preference).')
parser.add_argument('--subject', nargs='?', default=None, help='Subject, default according to "reason".')

def handle(self, *args, **options):
reason = options['reason']
path = reverse(f'v1:confirm-{reason}', args=['code'])
serializer_class = resolve(path).func.cls.serializer_class

content = options['contentfile'].read().strip()
if not content and options['contentfile'].name != '/dev/null':
raise RuntimeError('Empty content only allowed from /dev/null')

try:
subject = '[deSEC] ' + options['subject']
except TypeError:
subject = None

base_file = f'emails/{reason}/content.txt'
template_code = ('{%% extends "%s" %%}' % base_file)
if content:
template_code += '{% block content %}' + content + '{% endblock %}'
template = _get_default_template_backend().from_string(template_code)

if options['email']:
users = User.objects.filter(email__in=options['email'])
elif content:
users = User.objects.filter(outreach_preference=True)
else:
raise RuntimeError('To send default content, specify recipients explicitly.')

for user in users:
action = serializer_class.Meta.model(user=user)
serializer_class(action).save(subject=subject, template=template)
7 changes: 4 additions & 3 deletions api/desecapi/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def delete(self):
logger.warning(f'User {pk} deleted')
return ret

def send_email(self, reason, context=None, recipient=None):
def send_email(self, reason, context=None, recipient=None, subject=None, template=None):
fast_lane = 'email_fast_lane'
slow_lane = 'email_slow_lane'
immediate_lane = 'email_immediate_lane'
Expand All @@ -181,12 +181,13 @@ def send_email(self, reason, context=None, recipient=None):
raise ValueError(f'Cannot send email to user {self.pk} without a good reason: {reason}')

context = context or {}
content = get_template(f'emails/{reason}/content.txt').render(context)
template = template or get_template(f'emails/{reason}/content.txt')
content = template.render(context)
content += f'\nSupport Reference: user_id = {self.pk}\n'

logger.warning(f'Queuing email for user account {self.pk} (reason: {reason}, lane: {lanes[reason]})')
num_queued = EmailMessage(
subject=get_template(f'emails/{reason}/subject.txt').render(context).strip(),
subject=(subject or get_template(f'emails/{reason}/subject.txt').render(context)).strip(),
body=content,
from_email=get_template('emails/from.txt').render(),
to=[recipient or self.email],
Expand Down

0 comments on commit 801cb51

Please sign in to comment.