Merge branch 'phase/028-benachrichtigungen'

# Conflicts:
#	docker-compose.yml
#	scripts/screenshots.ts
This commit is contained in:
2026-10-12 16:55:57 +02:00
31 changed files with 3397 additions and 16 deletions
+66
View File
@@ -0,0 +1,66 @@
"use server";
import { revalidatePath } from "next/cache";
import { empfaengerAus, type BenachrichtigungEingabe } from "@/lib/benachrichtigung/einstellungen";
import { ANLAESSE, type AnlassArt } from "@/lib/benachrichtigung/regeln";
import {
akteurVon,
fehlerZustand,
listenfeld,
textfeld,
type FormularZustand,
} from "@/server/actions/formular";
import { RechteFehler, rechtErforderlich } from "@/server/auth/sitzungspflicht";
import { benachrichtigungSpeichern, testAnfordern } from "@/server/services/benachrichtigung";
import { FachFehler } from "@/server/services/fachfehler";
/** Einstellungen speichern und Testnachrichten anstossen (#028). Nur `einstellungenVerwalten`. */
function felder(formular: FormData): BenachrichtigungEingabe {
const ja = (name: string) => formular.get(name) === "ja";
return {
emailAktiv: ja("emailAktiv"),
emailServer: textfeld(formular, "emailServer") ?? "",
emailPort: textfeld(formular, "emailPort") ?? "",
emailSicherheit: (textfeld(formular, "emailSicherheit") ??
"STARTTLS") as BenachrichtigungEingabe["emailSicherheit"],
emailAbsender: textfeld(formular, "emailAbsender") ?? "",
emailBenutzer: textfeld(formular, "emailBenutzer") ?? "",
emailPasswort: textfeld(formular, "emailPasswort"),
emailPasswortEntfernen: ja("emailPasswortEntfernen"),
emailEmpfaenger: empfaengerAus(textfeld(formular, "emailEmpfaenger") ?? ""),
webhookAktiv: ja("webhookAktiv"),
webhookUrl: textfeld(formular, "webhookUrl") ?? "",
webhookHttpErlaubt: ja("webhookHttpErlaubt"),
webhookGeheimnis: textfeld(formular, "webhookGeheimnis"),
webhookGeheimnisEntfernen: ja("webhookGeheimnisEntfernen"),
anlaesse: listenfeld(formular, "anlaesse").filter((a): a is AnlassArt =>
(ANLAESSE as readonly string[]).includes(a),
),
};
}
export async function benachrichtigungSpeichernAktion(
_vorher: FormularZustand,
formular: FormData,
): Promise<FormularZustand & { gespeichert?: boolean }> {
try {
const { benutzer } = await rechtErforderlich("einstellungenVerwalten");
await benachrichtigungSpeichern(felder(formular), akteurVon(benutzer));
} catch (fehler) {
return fehlerZustand(fehler);
}
revalidatePath("/einstellungen");
return { gespeichert: true };
}
export async function testSendenAktion(kanal: string): Promise<{ vorgangId?: string; fehler?: string }> {
try {
const { benutzer } = await rechtErforderlich("einstellungenVerwalten");
if (kanal !== "EMAIL" && kanal !== "WEBHOOK") return { fehler: "Unbekannter Kanal." };
return { vorgangId: await testAnfordern(kanal, benutzer.id) };
} catch (fehler) {
if (fehler instanceof RechteFehler || fehler instanceof FachFehler) return { fehler: fehler.message };
throw fehler;
}
}