feat(vorlagen): Editor, Liste und Versionsgeschichte (#24)
This commit was merged in pull request #24.
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { z } from "@/lib/validierung";
|
||||
import { StrukturSchema } from "@/lib/vorlagen-format";
|
||||
import { StrukturSchema, stelleBenennen } from "@/lib/vorlagen-format";
|
||||
import { kundeZugriffPruefen, kundenEbeneSichtbar } from "@/server/mandant";
|
||||
import { rechtErforderlich } from "@/server/auth/sitzungspflicht";
|
||||
import { RechteFehler, rechtErforderlich } from "@/server/auth/sitzungspflicht";
|
||||
import {
|
||||
VorlagenFehler,
|
||||
entwurfHolenOderErzeugen,
|
||||
@@ -36,10 +36,40 @@ function alsErgebnis(fehler: unknown, neutral: string): AktionsErgebnis {
|
||||
if (fehler instanceof VorlagenFehler || fehler instanceof AustauschFehler) {
|
||||
return { fehler: fehler.message };
|
||||
}
|
||||
if (fehler instanceof RechteFehler) {
|
||||
return { fehler: RECHTE_MELDUNG };
|
||||
}
|
||||
console.error(`${neutral}:`, fehler instanceof Error ? `${fehler.name}: ${fehler.message}` : fehler);
|
||||
return { fehler: neutral };
|
||||
}
|
||||
|
||||
const RECHTE_MELDUNG =
|
||||
"Deine Anmeldung gilt nicht mehr. Melde dich in einem zweiten Tab neu an und klicke dann hier " +
|
||||
"noch einmal — was du eingegeben hast, steht weiterhin auf dieser Seite.";
|
||||
|
||||
/**
|
||||
* Die Rechtepruefung so, dass ein abgelaufenes Cookie kein Datenverlust ist.
|
||||
*
|
||||
* `rechtErforderlich` wirft. Wird der Wurf nicht gefangen, endet er in Nexts
|
||||
* Fehlergrenze — die Seite wird ausgehaengt, und im Editor ist damit alles weg,
|
||||
* was noch nicht gespeichert war. Nach zwoelf Stunden laeuft die Sitzung von
|
||||
* selbst ab; das trifft genau die Person, die lange an einer Vorlage sitzt.
|
||||
*
|
||||
* Deshalb: fangen, und dem Benutzer sagen, was zu tun ist. Der Editor behaelt
|
||||
* seinen Zustand, weil die Aktion ganz normal ein Ergebnis zurueckgibt.
|
||||
*/
|
||||
async function angemeldetOderMeldung(): Promise<
|
||||
{ readonly benutzerId: string } | { readonly fehler: string }
|
||||
> {
|
||||
try {
|
||||
const { benutzer } = await rechtErforderlich("vorlagenBearbeiten");
|
||||
return { benutzerId: benutzer.id };
|
||||
} catch (fehler) {
|
||||
if (fehler instanceof RechteFehler) return { fehler: RECHTE_MELDUNG };
|
||||
throw fehler;
|
||||
}
|
||||
}
|
||||
|
||||
const AnlegenSchema = z.object({
|
||||
name: z.string().trim().min(1, "Bitte einen Namen angeben."),
|
||||
beschreibung: z.string().trim().optional(),
|
||||
@@ -127,7 +157,8 @@ export async function entwurfSpeichernAktion(
|
||||
_vorher: AktionsErgebnis,
|
||||
formular: FormData,
|
||||
): Promise<AktionsErgebnis & { readonly stand?: string }> {
|
||||
await rechtErforderlich("vorlagenBearbeiten");
|
||||
const zugang = await angemeldetOderMeldung();
|
||||
if ("fehler" in zugang) return zugang;
|
||||
|
||||
const roh = formular.get("struktur");
|
||||
let geparst: unknown;
|
||||
@@ -145,7 +176,7 @@ export async function entwurfSpeichernAktion(
|
||||
if (!eingabe.success) {
|
||||
const erster = eingabe.error.issues[0];
|
||||
return {
|
||||
fehler: erster ? `${erster.path.join(".")}: ${erster.message}` : "Der Aufbau ist unvollständig.",
|
||||
fehler: erster ? `${stelleBenennen(erster.path)}${erster.message}` : "Der Aufbau ist unvollständig.",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -197,6 +228,16 @@ export async function vorlageBearbeitenAktion(
|
||||
await kundeZugriffPruefen(kundeId, benutzer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ein fehlendes Feld heisst „nicht angefasst“, ein leeres heisst „fuer alle“.
|
||||
*
|
||||
* Im Modus Intern zeigt das Formular gar keine Kundenwahl. Ohne diese
|
||||
* Unterscheidung haette jedes Speichern der Kopfdaten die Kundenzuordnung
|
||||
* stillschweigend geloescht — und nach einem Wechsel zurueck in den Modus
|
||||
* Dienstleistung waere die Vorlage ploetzlich fuer alle sichtbar gewesen.
|
||||
*/
|
||||
const kundeAngegeben = formular.has("kundeId");
|
||||
|
||||
try {
|
||||
await vorlageBearbeiten(
|
||||
eingabe.data.vorlageId,
|
||||
@@ -208,7 +249,7 @@ export async function vorlageBearbeitenAktion(
|
||||
.split(",")
|
||||
.map((wort) => wort.trim())
|
||||
.filter(Boolean),
|
||||
kundeId,
|
||||
...(kundeAngegeben ? { kundeId } : {}),
|
||||
},
|
||||
benutzer.id,
|
||||
);
|
||||
@@ -223,7 +264,8 @@ export async function veroeffentlichenAktion(
|
||||
_vorher: AktionsErgebnis,
|
||||
formular: FormData,
|
||||
): Promise<AktionsErgebnis> {
|
||||
const { benutzer } = await rechtErforderlich("vorlagenBearbeiten");
|
||||
const zugang = await angemeldetOderMeldung();
|
||||
if ("fehler" in zugang) return zugang;
|
||||
const eingabe = z
|
||||
.object({ versionId: z.string().min(1), aenderungsnotiz: z.string().trim().optional() })
|
||||
.safeParse({
|
||||
@@ -236,7 +278,7 @@ export async function veroeffentlichenAktion(
|
||||
const version = await versionVeroeffentlichen(
|
||||
eingabe.data.versionId,
|
||||
eingabe.data.aenderungsnotiz ?? null,
|
||||
benutzer.id,
|
||||
zugang.benutzerId,
|
||||
);
|
||||
revalidatePath("/vorlagen");
|
||||
return { erfolg: `Version ${version.version} ist veröffentlicht.` };
|
||||
|
||||
Reference in New Issue
Block a user