diff --git a/input/admin.py b/input/admin.py index 8620f0c..39bf13b 100755 --- a/input/admin.py +++ b/input/admin.py @@ -4,7 +4,7 @@ from django.contrib import admin from django.db import models, transaction from django.http import HttpResponse -from input.utils.mail import send_decision_mail, send_staff_decision_mail +from input.utils.mail import send_decision_mails from .forms import BaseProjectForm from .models import ( @@ -181,15 +181,10 @@ class ProjectRequestAdmin(BaseProjectAdmin): if obj.granted is None: return None - transaction.on_commit(lambda: self.send_decision_mails(obj)) + transaction.on_commit(lambda: send_decision_mails(obj)) return obj.granted - @staticmethod - def send_decision_mails(obj): - send_decision_mail(obj, TYPE_PROJ, obj.granted) - send_staff_decision_mail(obj, TYPE_PROJ, obj.granted) - @admin.register(ProjectDeclined) class ProjectDeclinedAdmin(BaseProjectAdmin): diff --git a/input/templates/mails/approval_denied.html b/input/templates/mails/approval_denied_applicant.html similarity index 100% rename from input/templates/mails/approval_denied.html rename to input/templates/mails/approval_denied_applicant.html diff --git a/input/templates/mails/approval_denied.txt b/input/templates/mails/approval_denied_applicant.txt similarity index 100% rename from input/templates/mails/approval_denied.txt rename to input/templates/mails/approval_denied_applicant.txt diff --git a/input/templates/mails/approval_granted.html b/input/templates/mails/approval_granted_applicant.html similarity index 100% rename from input/templates/mails/approval_granted.html rename to input/templates/mails/approval_granted_applicant.html diff --git a/input/templates/mails/approval_granted.txt b/input/templates/mails/approval_granted_applicant.txt similarity index 100% rename from input/templates/mails/approval_granted.txt rename to input/templates/mails/approval_granted_applicant.txt diff --git a/input/utils/mail/__init__.py b/input/utils/mail/__init__.py index 25945ce..ec25b3f 100644 --- a/input/utils/mail/__init__.py +++ b/input/utils/mail/__init__.py @@ -1,9 +1,8 @@ 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 input.models import TYPE_CHOICES +from input.models import Project from .attachments import collect_attachment_paths, attach_files @@ -12,8 +11,9 @@ __all__ = [ 'send_email', 'collect_attachment_paths', 'attach_files', - 'send_decision_mail', + 'send_applicant_decision_mail', 'send_staff_decision_mail', + 'send_decision_mails', ] @@ -38,63 +38,47 @@ def send_email(template_name: str, context: dict, subject: str, *recipients: str return build_email(template_name, context, subject, *recipients, **kwargs).send(fail_silently) -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(html) - return html, plain - - -def _decision_context(obj, choice_code: str) -> dict: +def get_decision_mail_context(obj: Project): """ 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, - 'type_label': type_html, - 'type_label_plain': type_plain, - 'name': getattr(obj, 'name', None), - }, 'project': obj, + 'data': { + 'realname': obj.realname or obj.email, + 'name': obj.name, + }, } -def send_decision_mail(obj, choice_code: str, granted: bool) -> None: +def send_base_decision_mail(obj: Project, scope: str, subject: str, recipient: str): + context = get_decision_mail_context(obj) + decision = 'granted' if obj.granted else 'denied' + decision_label = 'bewilligt' if obj.granted else 'abgelehnt' + subject = subject.format(name=obj.name, decision=decision_label) + + return send_email(f'approval_{scope}_{decision}', context, subject, recipient) + + +def send_applicant_decision_mail(obj: Project): """ 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) - template_suffix = 'granted' if granted else 'denied' + if recipient := obj.email: + return send_base_decision_mail(obj, 'applicant', 'Deine Förderanfrage „{name}“ – {decision}', recipient) - 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}' - - return send_email(f'approval_{template_suffix}', ctx, subject, recipient) + return 0 -def send_staff_decision_mail(obj, choice_code: str, granted: bool) -> None: +def send_staff_decision_mail(obj: Project): """ 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) - template_suffix = 'granted' if granted else 'denied' - project_name = getattr(obj, 'name', None) or '(ohne Projektnamen)' - decision_word = 'bewilligt' if granted else 'abgelehnt' - subject = f'Entscheidung: {project_name} ({decision_word})' + return send_base_decision_mail(obj, 'staff', 'Entscheidung: {name} ({decision})', settings.IF_EMAIL) - return send_email(f'approval_{template_suffix}_staff', ctx, subject, settings.IF_EMAIL) + +def send_decision_mails(obj: Project): + return send_applicant_decision_mail(obj) + send_staff_decision_mail(obj)