Skip to content

Commit

Permalink
feat: capability to send HTML emails
Browse files Browse the repository at this point in the history
  • Loading branch information
sirtawast committed Dec 8, 2023
1 parent 9252c6f commit 4064493
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

from django.core.management.base import BaseCommand
from django.utils import timezone
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _

from applications.enums import ApplicationStatus
from applications.models import Application
from messages.automatic_messages import send_email_to_applicant
from messages.automatic_messages import (
get_email_template_context,
render_email_template,
send_email_to_applicant,
)

APPLICATION_ABOUT_TO_BE_DELETED_MESSAGE = _(
"Your application {id} will be deleted soon. If you want to continue the application process, please do so by "
Expand Down Expand Up @@ -65,14 +68,14 @@ def notify_applications(days_to_deletion: int, days_to_keep: int) -> int:
def _send_notification_mail(application: Application, days_to_deletion: int) -> int:
"""Send a notification mail to the applicant about the upcoming application deletion"""

subject = _("Your application is about to be deleted")
application_deletion_date = (
application.modified_at + timedelta(days=days_to_deletion)
).strftime("%d.%m.%Y")
context = get_email_template_context(application)
context["application_deletion_date"] = application_deletion_date

message = format_lazy(
APPLICATION_ABOUT_TO_BE_DELETED_MESSAGE,
id=application.application_number,
application_deletion_date=(
application.modified_at + timedelta(days=days_to_deletion)
).strftime("%d.%m.%Y"),
)
subject = _("Your Helsinki benefit draft application will expire")
message = render_email_template(context, "draft-notice", "txt")
html_message = render_email_template(context, "draft-notice", "html")

return send_email_to_applicant(application, subject, message)
return send_email_to_applicant(application, subject, message, html_message)
7 changes: 6 additions & 1 deletion backend/benefit/helsinkibenefit/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,15 @@
"simple_history.middleware.HistoryRequestMiddleware",
]

MJML_COMPILED_EMAIL_TEMPLATE_PATHS = [
os.path.join(BASE_DIR, "helsinkibenefit/templates/emails/mjml-generated/html"),
os.path.join(BASE_DIR, "helsinkibenefit/templates/emails/mjml-generated/txt"),
]

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"DIRS": [] + MJML_COMPILED_EMAIL_TEMPLATE_PATHS,
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
Expand Down
5 changes: 4 additions & 1 deletion backend/benefit/locale/en/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ msgid ""
"processed."
msgstr ""

msgid "You have received a new message from Helsinki benefit"
msgid "You have received a new message regarding your Helsinki benefit application"
msgstr ""

#, python-format
Expand Down Expand Up @@ -819,3 +819,6 @@ msgstr "The Helsinki Benefit card"

msgid "employee_consent"
msgstr "Employee's consent for processing personal data"

msgid "Your Helsinki benefit application requires additional information"
msgstr ""
10 changes: 8 additions & 2 deletions backend/benefit/locale/fi/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,8 @@ msgstr ""
"{additional_information_needed_by} mennessä, muuten hakemusta ei voida "
"käsitellä."

msgid "You have received a new message from Helsinki benefit"
msgstr "Olet saanut uuden viestin Helsinki-lisä -hakemukseen"
msgid "You have received a new message regarding your Helsinki benefit application"
msgstr "Olet saanut uuden viestin Helsinki-lisä -hakemukseen littyen"

#, python-format
msgid ""
Expand Down Expand Up @@ -989,3 +989,9 @@ msgstr "Ei myönnetty"

msgid "Printed at"
msgstr "Tulostettu"

msgid "Your Helsinki benefit draft application will expire"
msgstr "Helsinki-lisä -hakemuksesi luonnos vanhenee"

msgid "Your Helsinki benefit application requires additional information"
msgstr "Helsinki-lisä -hakemus tarvitsee lisätietoja"
10 changes: 8 additions & 2 deletions backend/benefit/locale/sv/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -657,8 +657,8 @@ msgstr ""
"Din ansökan har öppnats för redigering. Gör ändringarna senast "
"{additional_information_needed_by}, annars kan ansökan inte behandlas."

msgid "You have received a new message from Helsinki benefit"
msgstr "Du har fått ett nytt meddelande om Helsingforstilläg"
msgid "You have received a new message regarding your Helsinki benefit application"
msgstr "Du har fått ett nytt meddelande om ansökningen om Helsingforstillägget"

#, python-format
msgid ""
Expand Down Expand Up @@ -981,3 +981,9 @@ msgstr "Inget stöd"

msgid "Printed at"
msgstr "Tryckt"

msgid "Your Helsinki benefit draft application will expire"
msgstr "Ditt utkast för ansökan går ut"

msgid "Your Helsinki benefit application requires additional information"
msgstr "Ansökan om Helsingforstillägget behöver ytterligare information"
65 changes: 55 additions & 10 deletions backend/benefit/messages/automatic_messages.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import datetime
import logging
from smtplib import SMTPException

from django.conf import settings
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils import translation
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _
Expand All @@ -19,10 +21,12 @@
)


def _message_notification_email_subject():
def default_email_notification_subject():
# force evaluation of lazy string so that the messages in local memory queue remain translated
# correctly during unit tests
return str(_("You have received a new message from Helsinki benefit"))
return str(
_("You have received a new message regarding your Helsinki benefit application")
)


def _message_notification_email_body(application):
Expand All @@ -46,8 +50,31 @@ def _message_notification_email_body(application):
)


def get_email_template_context(application: Application):
year = datetime.date.today().year

return {
"current_year": year,
"application": {
"created_at": application.created_at,
"application_number": application.application_number,
},
"language": application.applicant_language,
}


def render_email_template(
email_context: dict, template_name: str, template_type: str = "txt"
):
lang = email_context["language"] or "fi"
return render_to_string(f"{template_name}_{lang}.{template_type}", email_context)


def send_email_to_applicant(
application: Application, subject: str = None, message: str = None
application: Application,
subject: str = None,
text_message: str = None,
html_message: str = None,
) -> int:
"""
:param application: The application being reopened
Expand All @@ -64,10 +91,11 @@ def send_email_to_applicant(
with translation.override(application.applicant_language):
try:
return send_mail(
subject=subject if subject else _message_notification_email_subject(),
message=message
if message
subject=subject if subject else default_email_notification_subject(),
message=text_message
if text_message
else _message_notification_email_body(application),
html_message=html_message or None,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[application.company_contact_person_email],
fail_silently=False,
Expand All @@ -94,16 +122,33 @@ def send_application_reopened_message(
:param application: The application being reopened
:param additional_information_needed_by: The date by which the applicant must provide the additional information
"""

formatted_info_needed_by = additional_information_needed_by.strftime("%d.%m.%Y")

with translation.override(application.applicant_language):
Message.objects.create(
sender=user,
application=application,
message_type=MessageType.HANDLER_MESSAGE,
content=format_lazy(
APPLICATION_REOPENED_MESSAGE,
additional_information_needed_by=additional_information_needed_by.strftime(
"%d.%m.%Y"
),
additional_information_needed_by=formatted_info_needed_by,
),
)
send_email_to_applicant(application)

context = get_email_template_context(application)
context["additional_information_deadline_date"] = formatted_info_needed_by
context["additional_information_deadline_time"] = "23:00"

message = render_email_template(
context, "additional-information-required", "txt"
)
html_message = render_email_template(
context, "additional-information-required", "html"
)
send_email_to_applicant(
application,
_("Your Helsinki benefit application requires additional information"),
message,
html_message,
)
13 changes: 11 additions & 2 deletions backend/benefit/messages/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import email
import uuid
from copy import deepcopy

Expand Down Expand Up @@ -322,12 +323,20 @@ def test_create_message(
assert_email_subject_language(str(mailoutbox[0].subject), email_language)
assert_email_body_language(str(mailoutbox[0].body), email_language)
if email_language == "fi":
assert "Olet saanut uuden viestin" in mailoutbox[0].subject
assert "on tullut uusi viesti" in mailoutbox[0].body
assert mailoutbox[0].to == [
handling_application.company_contact_person_email
]
assert mailoutbox[0].from_email == settings.DEFAULT_FROM_EMAIL
assert "Olet saanut uuden viestin" in mailoutbox[0].subject

# Parse email to an object and assert that it contains the correct text content
email_parts = email.message_from_string(mailoutbox[0].body)
for part in email_parts.walk():
if part.get_content_type() == "text/plain":
assert (
"Olet saanut uuden viestin Helsinki-lisä -hakemukseen littyen. Voit lukea viestin"
in part.get_payload()
)

assert result.status_code == 201
message_qs = Message.objects.filter(message_type=msg_type)
Expand Down
21 changes: 19 additions & 2 deletions backend/benefit/messages/views.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
from django.conf import settings
from django.db import transaction
from django.utils import translation
from django.utils.translation import gettext_lazy as _
from rest_framework import viewsets
from rest_framework.exceptions import NotFound

from applications.models import Application
from common.permissions import BFIsApplicant, BFIsHandler, TermsOfServiceAccepted
from messages.automatic_messages import send_email_to_applicant
from messages.automatic_messages import (
default_email_notification_subject,
get_email_template_context,
render_email_template,
send_email_to_applicant,
)
from messages.models import Message, MessageType
from messages.permissions import HasMessagePermission
from messages.serializers import MessageSerializer, NoteSerializer
Expand Down Expand Up @@ -48,12 +54,23 @@ class HandlerMessageViewSet(ApplicantMessageViewSet):

def perform_create(self, serializer):
message = serializer.save()
application = message.application
# Never send email if it's a handler's note!
if message.message_type in [
MessageType.HANDLER_MESSAGE,
MessageType.APPLICANT_MESSAGE,
]:
send_email_to_applicant(message.application)
with translation.override(application.applicant_language):
subject = default_email_notification_subject()
context = get_email_template_context(application)
text_message = render_email_template(context, "received-message", "txt")
html_message = render_email_template(
context, "received-message", "html"
)

send_email_to_applicant(
application, subject, text_message, html_message
)

def get_queryset(self):
try:
Expand Down

0 comments on commit 4064493

Please sign in to comment.