"use server"; import { revalidatePath } from "next/cache"; import { prisma } from "@/lib/prisma"; import { logAdminAction } from "@/lib/audit-log"; import { CONTENT_REGISTRY } from "@/lib/content-registry"; import { isValidUploadPath, isValidVideoUploadPath } from "@/lib/uploads"; import { requireAdmin } from "./_shared"; import { succeed } from "@/lib/flash"; /** * Generisch fuer alle drei Inhalts-Gruppen (Firmendaten/Homepage/Rechtstexte) * — jede Gruppen-Form sendet nur ihre eigenen Feldnamen, diese Action * verarbeitet einfach, was tatsaechlich in formData vorhanden ist. Nicht * lokalisierte Felder kommen als "{key}", lokalisierte als "de::{key}" / * "en::{key}" (siehe admin/inhalte/page.tsx). */ export async function updateSiteContentAction(formData: FormData): Promise { const admin = await requireAdmin(); const group = String(formData.get("group") ?? ""); const updates: { key: string; valueDe: string; valueEn: string | null }[] = []; for (const def of CONTENT_REGISTRY) { if (def.localized) { const de = formData.get(`de::${def.key}`); const en = formData.get(`en::${def.key}`); if (de === null && en === null) continue; updates.push({ key: def.key, valueDe: String(de ?? ""), valueEn: String(en ?? ""), }); } else { const value = formData.get(def.key); if (value === null) continue; const valueDe = String(value); // Bild-Felder duerfen nur einen Pfad enthalten, den unser eigener // Upload-Endpunkt tatsaechlich erzeugt hat (siehe lib/uploads.ts) — // ein manipuliertes Hidden-Feld (z.B. eine externe URL oder ein // "javascript:"-Wert) wird ignoriert statt ungeprueft gespeichert und // spaeter als /next/image src ausgeliefert zu werden. if (def.type === "image" && valueDe !== "" && !isValidUploadPath(valueDe)) { continue; } // Analog zum Bild-Feld: ein Video-Feld darf nur einen Pfad enthalten, // den app/api/admin/upload-video/route.ts tatsaechlich erzeugt hat. if (def.type === "video" && valueDe !== "" && !isValidVideoUploadPath(valueDe)) { continue; } updates.push({ key: def.key, valueDe, valueEn: null }); } } await prisma.$transaction( updates.map((u) => prisma.siteContent.upsert({ where: { key: u.key }, create: { key: u.key, valueDe: u.valueDe, valueEn: u.valueEn }, update: { valueDe: u.valueDe, valueEn: u.valueEn }, }) ) ); await logAdminAction(admin, { action: "site_content.update", entityType: "SiteContent", entityId: group || undefined, detail: `${updates.length} Feld(er)`, }); revalidatePath("/", "layout"); return succeed("/admin/inhalte", "Inhalte gespeichert."); }