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. ' 'Defaults to everyone with outreach_preference = True.') 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)