feat: add email notifications for disclosure request decisions

Replace direct Notification inserts with notification_service functions
that send both in-app and email notifications. Admins receive an email
when a DAK-Mitarbeiter submits a new disclosure request. The requesting
Mitarbeiter receives an email when their request is approved (with
expiration date) or rejected. SMTP was already configured.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
CCS Admin 2026-02-28 12:59:21 +00:00
parent 5da1e523d3
commit 3216dd6d53
2 changed files with 33 additions and 20 deletions

View file

@ -5,9 +5,10 @@ from typing import Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.models.audit import DisclosureRequest, Notification from app.models.audit import DisclosureRequest
from app.models.case import Case from app.models.case import Case
from app.models.user import User from app.models.user import User
from app.services.notification_service import create_notification, notify_all_users_with_role
def _utcnow_naive() -> datetime: def _utcnow_naive() -> datetime:
@ -60,24 +61,26 @@ def create_disclosure_request(
db.add(dr) db.add(dr)
db.flush() db.flush()
# Notify all active admins # Notify all active admins (in-app + email)
case = db.query(Case).filter(Case.id == case_id).first() case = db.query(Case).filter(Case.id == case_id).first()
fall_id = case.fall_id if case else str(case_id) fall_id = case.fall_id if case else str(case_id)
requester = db.query(User).filter(User.id == user_id).first() requester = db.query(User).filter(User.id == user_id).first()
requester_name = requester.username if requester else str(user_id) requester_name = requester.username if requester else str(user_id)
admins = db.query(User).filter(User.role == "admin", User.is_active == True).all() # noqa: E712 notify_all_users_with_role(
for admin in admins: db,
db.add(Notification( "admin",
recipient_id=admin.id, "disclosure_request",
notification_type="disclosure_request", title=f"Neue Freigabe-Anfrage für Fall {fall_id}",
title=f"Freigabe-Anfrage für Fall {fall_id}", message=(
message=f"{requester_name} bittet um Einsicht in Personendaten. Begründung: {reason}", f"{requester_name} hat eine Freigabe für Personendaten beantragt.\n"
f"Begründung: {reason}\n\n"
"Bitte prüfen Sie die Anfrage im DAK Portal."
),
related_entity_type="disclosure_request", related_entity_type="disclosure_request",
related_entity_id=dr.id, related_entity_id=dr.id,
)) )
db.commit()
db.refresh(dr) db.refresh(dr)
return dr return dr
@ -99,21 +102,31 @@ def review_disclosure_request(
if new_status == "approved": if new_status == "approved":
dr.expires_at = _utcnow_naive() + timedelta(hours=24) dr.expires_at = _utcnow_naive() + timedelta(hours=24)
# Notify requester # Notify requester (in-app + email)
case = db.query(Case).filter(Case.id == dr.case_id).first() case = db.query(Case).filter(Case.id == dr.case_id).first()
fall_id = case.fall_id if case else str(dr.case_id) fall_id = case.fall_id if case else str(dr.case_id)
status_text = "genehmigt" if new_status == "approved" else "abgelehnt" status_text = "genehmigt" if new_status == "approved" else "abgelehnt"
db.add(Notification(
if new_status == "approved":
expires_str = dr.expires_at.strftime("%d.%m.%Y %H:%M Uhr") if dr.expires_at else "24h"
message = (
f"Ihre Freigabe-Anfrage für Fall {fall_id} wurde genehmigt.\n"
f"Die Personendaten sind bis {expires_str} sichtbar."
)
else:
message = f"Ihre Freigabe-Anfrage für Fall {fall_id} wurde abgelehnt."
create_notification(
db,
recipient_id=dr.requester_id, recipient_id=dr.requester_id,
notification_type="disclosure_resolved", notification_type="disclosure_resolved",
title=f"Freigabe-Anfrage {status_text}", title=f"Freigabe-Anfrage {status_text} — Fall {fall_id}",
message=f"Ihre Anfrage für Fall {fall_id} wurde {status_text}.", message=message,
related_entity_type="disclosure_request", related_entity_type="disclosure_request",
related_entity_id=dr.id, related_entity_id=dr.id,
)) )
db.commit()
db.refresh(dr) db.refresh(dr)
return dr return dr

View file

@ -2,7 +2,7 @@
## Hohe Priorität ## Hohe Priorität
- [ ] **Gutachten-Statistik Seite** — Route `/gutachten-statistik` existiert als Platzhalter. Visualisierung von Gutachten-Typen (Bestätigung/Alternative), Therapieänderungen, Diagnosekorrektur/Unterversorgung/Übertherapie und Trends pro KW/Jahr. - [x] **Gutachten-Statistik Seite** — ✅ Implementiert: 4 KPIs, Stacked-Bar (Typ pro KW), Donut (Typ-Verteilung), Grouped-Bar (Therapieänderungen pro KW), Horizontal-Bars (Gründe). Backend-Endpoint + Frontend komplett.
- [ ] **Fallliste als Excel exportieren** — Export-Button auf der Cases-Seite für gefilterte Falllisten als .xlsx Download. Nutzt aktive Filter (Jahr, Fallgruppe, ICD-Status). - [ ] **Fallliste als Excel exportieren** — Export-Button auf der Cases-Seite für gefilterte Falllisten als .xlsx Download. Nutzt aktive Filter (Jahr, Fallgruppe, ICD-Status).
- [ ] **E-Mail-Benachrichtigungen bei Freigabe-Entscheidung** — DAK-Mitarbeiter per E-Mail informieren, wenn ihre Freigabe-Anfrage genehmigt oder abgelehnt wurde. SMTP ist bereits konfiguriert. - [ ] **E-Mail-Benachrichtigungen bei Freigabe-Entscheidung** — DAK-Mitarbeiter per E-Mail informieren, wenn ihre Freigabe-Anfrage genehmigt oder abgelehnt wurde. SMTP ist bereits konfiguriert.