Drift, ablaufende und abgelaufene Schluessel, unerreichbare Hosts und geaenderte Host-Keys sollen auffallen, ohne dass jemand taeglich in die Oberflaeche schaut. Versand per SMTP (Microsoft 365, STARTTLS) und per Webhook mit HMAC-Signatur, eingestellt unter /einstellungen. Die Anlaesse liest der Worker aus der Datenbank, statt sie im Abgleich auszuloesen: der Abgleich-Ablauf bleibt unberuehrt, und ein verpasster Lauf holt sich der naechste. Ein Versandprotokoll (Zustellung) mit Anlass-Fingerabdruck verhindert Doppelmeldungen und haelt Fehlschlaege fuer begrenzte Wiederholungen fest. Taeglich eine Zusammenfassung, geaenderte Host-Keys im Fuenf-Minuten-Takt sofort. Versand und Testnachricht laufen im Worker, damit der Webprozess keinen Weg zu Mailserver oder Webhook-Ziel braucht. Passwort und Geheimnis liegen nur verschluesselt in der Datenbank; die Seite zeigt "gesetzt". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
2.7 KiB
TypeScript
67 lines
2.7 KiB
TypeScript
"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;
|
|
}
|
|
}
|