diff --git a/gregui/admin.py b/gregui/admin.py index d5ea59b0fcf2cf68ccd9aeb3737e09cf4c2c2962..7c3f771755952b78e409029ce4c17be9bd6412eb 100644 --- a/gregui/admin.py +++ b/gregui/admin.py @@ -1,11 +1,17 @@ from django.contrib import admin from reversion.admin import VersionAdmin -from gregui.models import GregUserProfile +from gregui.models import EmailTemplate, GregUserProfile class GregUserProfileAdmin(VersionAdmin): pass +class EmailTemplateAdmin(VersionAdmin): + list_display = ["id", "template_key", "subject", "from_email"] + save_as = True + + admin.site.register(GregUserProfile, GregUserProfileAdmin) +admin.site.register(EmailTemplate, EmailTemplateAdmin) diff --git a/gregui/mailutils.py b/gregui/mailutils.py index 19795179783c9b54b8b60652045159895fa2618b..9ccbe5e3dad930357c69fb3c261253afc0034d73 100644 --- a/gregui/mailutils.py +++ b/gregui/mailutils.py @@ -1,41 +1,64 @@ +from typing import Union from django.conf import settings -from django.template.loader import render_to_string +from django.template.context import Context from django_q.tasks import async_task +from gregui.models import EmailTemplate -def registration_template(institution, sponsor) -> str: - keywords = { - "institution": institution, - "sponsor": sponsor, - "registration_link": "www.google.com", - } - return render_to_string("guest_registration.txt", keywords) +def prepare_arguments( + template: EmailTemplate, context: dict[str, str], mail_to: str +) -> dict[str, Union[str, list[str]]]: + """Combine input to a dict ready for use as arguments ti django's send_mail""" + return { + "subject": template.get_subject(context), + "message": template.get_body(context), + "from_email": template.from_email or None, + "recipient_list": [mail_to], + } -def confirmation_template(guest) -> str: - keywords = {"guest": guest, "confirmation_link": "www.google.com"} - return render_to_string("sponsor_confirmation.txt", keywords) +def registration_template( + institution: str, sponsor: str, mail_to: str +) -> dict[str, Union[str, list[str]]]: + """ + Prepare email for registration -def send_registration_mail(mail_to, sponsor) -> str: - return async_task( - "django.core.mail.send_mail", - **{ - "subject": "Subject", - "message": registration_template(settings.INSTANCE_NAME, sponsor), - "from_email": None, - "recipient_list": [mail_to], + Produces a complete set of arguments ready for use with django.core.mail.send_mail + when sending a registration email to the guest. + """ + template = EmailTemplate.objects.get( + template_key=EmailTemplate.EmailType.GUEST_REGISTRATION + ) + context = Context( + { + "institution": institution, + "sponsor": sponsor, + "registration_link": "www.google.com", } ) + return prepare_arguments(template, context, mail_to) -def send_confirmation_mail(mail_to, guest) -> str: - return async_task( - "django.core.mail.send_mail", - **{ - "subject": "Subject", - "message": confirmation_template(guest), - "from_email": None, - "recipient_list": [mail_to], - } +def confirmation_template(guest: str, mail_to: str) -> dict[str, Union[str, list[str]]]: + """ + Prepare email for confirmation + + Produces a complete set of arguments ready for use with django.core.mail.send_mail + when sending a confirmation email to the sponsor. + """ + template = EmailTemplate.objects.get( + template_key=EmailTemplate.EmailType.SPONSOR_CONFIRMATION ) + context = Context({"guest": guest, "confirmation_link": "www.google.com"}) + return prepare_arguments(template, context, mail_to) + + +def send_registration_mail(mail_to: str, sponsor: str) -> str: + arguments = registration_template(settings.INSTANCE_NAME, sponsor, mail_to) + return async_task("django.core.mail.send_mail", **arguments) + + +def send_confirmation_mail(mail_to: str, guest: str) -> str: + arguments = confirmation_template(guest, mail_to) + return async_task("django.core.mail.send_mail", **arguments) diff --git a/gregui/migrations/0002_emailtemplate.py b/gregui/migrations/0002_emailtemplate.py new file mode 100644 index 0000000000000000000000000000000000000000..15c4b7b6a3c3b1fe58631cb3b613f54d40eb736e --- /dev/null +++ b/gregui/migrations/0002_emailtemplate.py @@ -0,0 +1,48 @@ +# Generated by Django 3.2.8 on 2021-11-02 12:49 + +import dirtyfields.dirtyfields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("gregui", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="EmailTemplate", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created", models.DateTimeField(auto_now_add=True)), + ("updated", models.DateTimeField(auto_now=True)), + ( + "template_key", + models.CharField( + choices=[ + ("guest_registration", "Guest Registration"), + ("sponsor_confirmation", "Sponsor Confirmation"), + ], + max_length=64, + unique=True, + ), + ), + ("subject", models.CharField(blank=True, max_length=255, null=True)), + ("from_email", models.CharField(blank=True, max_length=255, null=True)), + ("body", models.TextField(blank=True, null=True)), + ], + options={ + "abstract": False, + }, + bases=(dirtyfields.dirtyfields.DirtyFieldsMixin, models.Model), + ), + ] diff --git a/gregui/models.py b/gregui/models.py index 48b579bed9dae968c69c4e84f5ebce32171b7cd6..551b20f8127c5a265b39f69b027381ef99a25292 100644 --- a/gregui/models.py +++ b/gregui/models.py @@ -1,3 +1,4 @@ +from django import template from django.conf import settings from django.db import models from django.utils.translation import gettext_lazy @@ -24,3 +25,34 @@ class GregUserProfile(BaseModel): null=True, ) userid_feide = models.CharField(gettext_lazy("userid-feide"), max_length=150) + + +class EmailTemplate(BaseModel): + """ + Stores templates for emails. + + Only one template of each type is allowed. To introduce new ones, simply add a new + EmailType. + """ + + class EmailType(models.TextChoices): + """Types of Emails""" + + GUEST_REGISTRATION = "guest_registration" + SPONSOR_CONFIRMATION = "sponsor_confirmation" + + template_key = models.CharField( + max_length=64, choices=EmailType.choices, unique=True + ) + subject = models.CharField(max_length=255, blank=True, null=True) + from_email = models.CharField(max_length=255, blank=True, null=True) + body = models.TextField(blank=True, null=True) + + def get_rendered_template(self, tpl, context): + return template.Template(tpl).render(context) + + def get_subject(self, context): + return self.get_rendered_template(self.subject, context) + + def get_body(self, context): + return self.get_rendered_template(self.body, context) diff --git a/gregui/tests/conftest.py b/gregui/tests/conftest.py index fc70bdca4858316b191b6c1d1e7b7860363521a3..2e34c790b013086e4e3241c54fa396779a37e1b3 100644 --- a/gregui/tests/conftest.py +++ b/gregui/tests/conftest.py @@ -19,7 +19,7 @@ from greg.models import ( Sponsor, ) -from gregui.models import GregUserProfile +from gregui.models import EmailTemplate, GregUserProfile # faker spams the logs with localisation warnings # see https://github.com/joke2k/faker/issues/753 @@ -256,3 +256,33 @@ def log_in(client): return client return _log_in + + +@pytest.fixture +def confirmation_template(): + et = EmailTemplate.objects.create( + template_key=EmailTemplate.EmailType.SPONSOR_CONFIRMATION, + subject="confirmation subject", + body="""Dette er en automatisk generert melding fra gjesteregistreringstjenesten. +Din gjest, {{ guest }}, har fullført registrering, bekreft gjesten her: {{ confirmation_link }} + +This message has been automatically generated by the guest registration system. +Your guest, {{ guest }}, has completed their registration, please confirm the guest here: {{ confirmation_link }}""", + ) + return EmailTemplate.objects.get(id=et.id) + + +@pytest.fixture +def registration_template(): + et = EmailTemplate.objects.create( + template_key=EmailTemplate.EmailType.GUEST_REGISTRATION, + subject="registration subject", + body="""Dette er en automatisk generert melding fra gjesteregistreringstjenesten. +Du har blitt registrert som gjest på {{ institution }} av {{ sponsor }}. +For å fullføre registreringen av gjestekontoen følg denne lenken: {{ registration_link }} + +This message has been automatically generated by the guest registration system. +You have been registered as a guest at {{ institution }} by {{ sponsor }}. +To complete the registration of your guest account, please follow this link: {{ registration_link }}""", + ) + return EmailTemplate.objects.get(id=et.id) diff --git a/gregui/tests/test_mailutils.py b/gregui/tests/test_mailutils.py index 03f30f3de2d4604859dbf5e1945e47a0830faf4e..7977f4cfac3568e8064c65ebe7d273035d941234 100644 --- a/gregui/tests/test_mailutils.py +++ b/gregui/tests/test_mailutils.py @@ -6,33 +6,43 @@ from gregui import mailutils @pytest.mark.django_db -def test_registration_template(): - prefilled_template = """Dette er en automatisk generert melding fra gjesteregistreringstjenesten. +def test_registration_template(registration_template): + prefilled_template = { + "from_email": None, + "recipient_list": ["test@example.com"], + "subject": "registration subject", + "message": """Dette er en automatisk generert melding fra gjesteregistreringstjenesten. Du har blitt registrert som gjest på InstanceName av Foo Bar. For å fullføre registreringen av gjestekontoen følg denne lenken: www.google.com This message has been automatically generated by the guest registration system. You have been registered as a guest at InstanceName by Foo Bar. -To complete the registration of your guest account, please follow this link: www.google.com -""" - rendered_template = mailutils.registration_template("InstanceName", "Foo Bar") +To complete the registration of your guest account, please follow this link: www.google.com""", + } + rendered_template = mailutils.registration_template( + "InstanceName", "Foo Bar", "test@example.com" + ) assert rendered_template == prefilled_template @pytest.mark.django_db -def test_confirmation_template(): - prefilled_template = """Dette er en automatisk generert melding fra gjesteregistreringstjenesten. +def test_confirmation_template(confirmation_template): + prefilled_template = { + "from_email": None, + "recipient_list": ["test@example.com"], + "subject": "confirmation subject", + "message": """Dette er en automatisk generert melding fra gjesteregistreringstjenesten. Din gjest, Foo Bar, har fullført registrering, bekreft gjesten her: www.google.com This message has been automatically generated by the guest registration system. -Your guest, Foo Bar, has completed their registration, please confirm the guest here: www.google.com -""" - rendered_template = mailutils.confirmation_template("Foo Bar") +Your guest, Foo Bar, has completed their registration, please confirm the guest here: www.google.com""", + } + rendered_template = mailutils.confirmation_template("Foo Bar", "test@example.com") assert rendered_template == prefilled_template @pytest.mark.django_db -def test_registration_mail(): +def test_registration_mail(registration_template): mail.outbox = [] task_id = mailutils.send_registration_mail("test@example.no", "Foo") assert result(task_id) == 1 @@ -41,7 +51,7 @@ def test_registration_mail(): @pytest.mark.django_db -def test_confirmation_mail(): +def test_confirmation_mail(confirmation_template): mail.outbox = [] task_id = mailutils.send_confirmation_mail("test@example.no", "Foo") assert result(task_id) == 1