From 1ad4970cbca43e65eed5385337e18695a0142da9 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 7 Oct 2025 19:44:28 +0200 Subject: [PATCH] Add decision mailers for applicants and staff with approval/denial templates --- input/mailer.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 input/mailer.py diff --git a/input/mailer.py b/input/mailer.py new file mode 100644 index 0000000..d3df345 --- /dev/null +++ b/input/mailer.py @@ -0,0 +1,87 @@ +from django.conf import settings +from django.core.mail import EmailMultiAlternatives +from django.template.loader import get_template +from django.utils.html import strip_tags +from .models import TYPE_CHOICES + + +def _type_labels(choice: str): + """ + Resolve the human-readable type label. + Returns (HTML label, plain text label). + """ + html = TYPE_CHOICES.get(choice, choice) + plain = strip_tags(str(html)) + return html, plain + + +def _decision_context(obj, choice_code: str) -> dict: + """ + Build a minimal, consistent context for decision mails (applicant & staff). + Also exposes the full project object as 'project' for template access. + """ + type_html, type_plain = _type_labels(choice_code) + realname = getattr(obj, 'realname', '') or getattr(obj, 'email', '') + return { + 'data': { + 'realname': realname, + 'typestring': type_html, + 'typestring_plain': type_plain, + 'name': getattr(obj, 'name', None), + }, + 'project': obj, + } + + +def send_decision_mail(obj, choice_code: str, granted: bool) -> None: + """ + Send a decision email to the applicant after manual approval/denial. + Uses: input/approval_granted.(txt|html) or input/approval_denied.(txt|html) + """ + recipient = getattr(obj, 'email', None) + if not recipient: + return # no recipient -> skip + + ctx = _decision_context(obj, choice_code) + base = 'input/approval_granted' if granted else 'input/approval_denied' + + project_name = getattr(obj, 'name', None) or '(ohne Projektnamen)' + decision_word = 'bewilligt' if granted else 'abgelehnt' + subject = f'Deine Förderanfrage „{project_name}“ – {decision_word}' + + txt = get_template(f'{base}.txt').render(ctx) + html = get_template(f'{base}.html').render(ctx) + + msg = EmailMultiAlternatives( + subject, + txt, + settings.IF_EMAIL, + [recipient], + ) + msg.attach_alternative(html, 'text/html') + msg.send() + + +def send_staff_decision_mail(obj, choice_code: str, granted: bool) -> None: + """ + Send a decision email to the internal team (staff) after approval/denial. + Uses: input/approval_granted_staff.(txt|html) or input/approval_denied_staff.(txt|html) + """ + ctx = _decision_context(obj, choice_code) + base = 'input/approval_granted_staff' if granted else 'input/approval_denied_staff' + + project_name = getattr(obj, 'name', None) or '(ohne Projektnamen)' + decision_word = 'bewilligt' if granted else 'abgelehnt' + subject = f'Entscheidung: {project_name} ({decision_word})' + + txt = get_template(f'{base}.txt').render(ctx) + html = get_template(f'{base}.html').render(ctx) + + msg = EmailMultiAlternatives( + subject, + txt, + settings.IF_EMAIL, + [settings.IF_EMAIL], + ) + msg.attach_alternative(html, 'text/html') + msg.send()