"use server"; import * as z from "zod"; import { revalidatePath } from "next/cache"; import { createAdminClient } from "@/lib/supabase/admin"; import { createClient } from "@/lib/supabase/server"; import { verifySession } from "@/lib/supabase/dal"; async function resolveClientId(profileId: string) { const supabase = createAdminClient(); const { data: profile, error } = await supabase .from("profiles") .select("client_id") .eq("id", profileId) .single(); if (error || !profile?.client_id) return null; return profile.client_id as string; } const CredentialSchema = z.object({ profileId: z.string().uuid(), service: z.string().min(1, { error: "Dienst ist erforderlich." }), username: z.string().min(1, { error: "Benutzername ist erforderlich." }), password: z.string().min(1, { error: "Passwort ist erforderlich." }), }); export type CredentialState = { error: string } | { success: true } | undefined; export async function createCredential( _prevState: CredentialState, formData: FormData ): Promise { const session = await verifySession(); const profileId = String(formData.get("profileId") ?? ""); if (!session.isAdmin && session.userId !== profileId) { return { error: "Keine Berechtigung." }; } const validatedFields = CredentialSchema.safeParse({ profileId, service: formData.get("service"), username: formData.get("username"), password: formData.get("password"), }); if (!validatedFields.success) { const { fieldErrors } = z.flattenError(validatedFields.error); const firstError = Object.values(fieldErrors).flat()[0]; return { error: firstError ?? "Bitte alle Felder ausfüllen." }; } const clientId = await resolveClientId(profileId); if (!clientId) { return { error: "Client hat noch keine Stammdaten hinterlegt." }; } const supabase = await createClient(); const { error } = await supabase.rpc("create_credential", { p_client_id: clientId, p_service: validatedFields.data.service, p_username: validatedFields.data.username, p_password: validatedFields.data.password, }); if (error) return { error: "Eintrag konnte nicht gespeichert werden." }; revalidatePath("/client/passwords"); revalidatePath(`/admin/clients/${profileId}/passwords`); return { success: true }; } const UpdateCredentialSchema = z.object({ profileId: z.string().uuid(), credentialId: z.string().uuid(), service: z.string().min(1, { error: "Dienst ist erforderlich." }), username: z.string().min(1, { error: "Benutzername ist erforderlich." }), password: z.string().optional(), }); export async function updateCredential( _prevState: CredentialState, formData: FormData ): Promise { const session = await verifySession(); const profileId = String(formData.get("profileId") ?? ""); if (!session.isAdmin && session.userId !== profileId) { return { error: "Keine Berechtigung." }; } const password = String(formData.get("password") ?? "").trim(); const validatedFields = UpdateCredentialSchema.safeParse({ profileId, credentialId: formData.get("credentialId"), service: formData.get("service"), username: formData.get("username"), password: password === "" ? undefined : password, }); if (!validatedFields.success) { const { fieldErrors } = z.flattenError(validatedFields.error); const firstError = Object.values(fieldErrors).flat()[0]; return { error: firstError ?? "Bitte alle Felder ausfüllen." }; } const supabase = await createClient(); const { error } = await supabase.rpc("update_credential", { p_id: validatedFields.data.credentialId, p_service: validatedFields.data.service, p_username: validatedFields.data.username, p_password: validatedFields.data.password ?? null, }); if (error) return { error: "Eintrag konnte nicht aktualisiert werden." }; revalidatePath("/client/passwords"); revalidatePath(`/admin/clients/${profileId}/passwords`); return { success: true }; } export async function revealCredential(credentialId: string): Promise<{ password: string } | { error: string }> { await verifySession(); const supabase = await createClient(); const { data, error } = await supabase.rpc("reveal_credential", { p_id: credentialId }); if (error || typeof data !== "string") { return { error: "Passwort konnte nicht abgerufen werden." }; } return { password: data }; } export async function deleteCredential(profileId: string, credentialId: string): Promise { const session = await verifySession(); if (!session.isAdmin) { return { error: "Keine Berechtigung." }; } const supabase = createAdminClient(); const { error } = await supabase.from("credentials").delete().eq("id", credentialId); if (error) return { error: "Eintrag konnte nicht gelöscht werden." }; revalidatePath(`/admin/clients/${profileId}/passwords`); return { success: true }; }