Passwort-Anmeldung: Provider, Formulare, drei Zustaende der Shell
Some checks failed
CI / Lint, Typen, Tests, Build (push) Failing after 5m27s
CI / Migrationen auf leerer Datenbank (push) Successful in 10m3s

This commit is contained in:
2026-09-08 16:51:14 +02:00
parent cbde8cf3a8
commit c6cff9656e
13 changed files with 569 additions and 40 deletions

61
actions/passwort.ts Normal file
View File

@@ -0,0 +1,61 @@
"use server";
import { redirect } from "next/navigation";
import { currentUserId } from "@/lib/auth/session";
import { runMutation } from "@/lib/db/rpc";
// Das eigene Passwort wechseln.
//
// Getrennt von actions/auth.ts, weil es etwas anderes ist: dort geht es um das
// Herstellen einer Sitzung, hier um eine Änderung an den eigenen Daten. Und
// getrennt von actions/benutzer.ts (Benutzerverwaltung), weil diese Aktion die
// einzige ist, die **ohne** HR-Rechte funktionieren muss.
export type WechselZustand = { fehler: string | null };
/**
* Wechselt das Passwort der angemeldeten Person.
*
* Kein `revalidatePath`: der Weg danach ist eine Weiterleitung durch die
* Komponente, und es gibt keine zwischengespeicherte Seite, die den alten Stand
* zeigen könnte.
*
* Die Meldungen kommen aus app_passwort_aendern() und sind für die Oberfläche
* geschrieben („Das bisherige Passwort stimmt nicht.") — sie werden
* durchgereicht wie bei jeder anderen Mutation.
*/
export async function passwortAendern(
_zustand: WechselZustand,
formular: FormData
): Promise<WechselZustand> {
const altes = String(formular.get("altes_passwort") ?? "");
const neues = String(formular.get("neues_passwort") ?? "");
const wiederholung = String(formular.get("wiederholung") ?? "");
if (!altes || !neues) {
return { fehler: "Bitte das bisherige und das neue Passwort eingeben." };
}
// Diese eine Prüfung gehört hierher und nicht in die Datenbank: die
// Wiederholung ist ein Bedienelement gegen Vertippen, kein Datum. Die
// Datenbank sieht sie nie und soll sie auch nicht sehen.
if (neues !== wiederholung) {
return { fehler: "Die beiden neuen Passwörter stimmen nicht überein." };
}
const ergebnis = await runMutation(await currentUserId(), "app_passwort_aendern", {
altes_passwort: altes,
neues_passwort: neues,
});
if (!ergebnis.success) {
return { fehler: ergebnis.error ?? "Unbekannter Fehler." };
}
// Ab hier ist der Wechsel erledigt, is_hr_user() liefert wieder true und die
// Anwendung ist offen. Die Weiterleitung steht in der Aktion und nicht in der
// Komponente: `redirect()` wirft, die Aktion kehrt also nicht zurück, und es
// gibt keinen Zwischenzustand, in dem das Formular noch einmal abgeschickt
// werden könnte.
redirect("/");
}