"use server"; import { db } from "@/db"; import { forms } from "@/db/schema"; import { eq } from "drizzle-orm"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { requireAdmin } from "@/lib/auth"; import { sanitizeHtml } from "@/lib/sanitize-html"; import { sse } from "@/lib/sse"; import { isValidDiscordWebhookUrl } from "@/lib/discord-webhook-settings"; export async function createForm(formData: FormData) { await requireAdmin(); const title = formData.get("title") as string; const description = formData.get("description") as string | null; const [form] = await db .insert(forms) .values({ title, description: description ? sanitizeHtml(description) : null }) .returning(); void sse.forms.pub("update", { formId: form.id, entity: "form", action: "created", }); revalidatePath("/admin/form"); redirect(`/admin/form/${form.id}`); } export async function createDefaultForm() { await requireAdmin(); const [form] = await db .insert(forms) .values({ title: "New Form", description: "" }) .returning(); void sse.forms.pub("update", { formId: form.id, entity: "form", action: "created", }); revalidatePath("/admin/form"); redirect(`/admin/form/${form.id}`); } export async function updateForm(id: string, data: { title?: string; description?: string | null; isOpen?: boolean; allowMultipleSubmissions?: boolean; discordWebhookUrl?: string | null; discordWebhookTemplate?: string | null; discordWebhookUpdateTemplate?: string | null; allowedRoles?: string[]; deniedRoles?: string[] }) { await requireAdmin(); if (data.title !== undefined && !data.title.trim()) { throw new Error("Form title is required."); } if ( data.discordWebhookUrl && !isValidDiscordWebhookUrl(data.discordWebhookUrl) ) { throw new Error("Enter a valid Discord webhook URL."); } const nextData = { ...data, description: data.description === undefined ? undefined : data.description ? sanitizeHtml(data.description) : data.description, }; await db.update(forms).set(nextData).where(eq(forms.id, id)); void sse.forms.pub("update", { formId: id, entity: "form", action: "updated", }); revalidatePath("/form"); revalidatePath("/admin/form"); } export async function testDiscordWebhook(url: string, content: string) { await requireAdmin(); const trimmedUrl = url.trim(); if (!isValidDiscordWebhookUrl(trimmedUrl)) { throw new Error("Enter a valid Discord webhook URL."); } if (!content.trim()) { throw new Error("The test message is empty."); } const response = await fetch(trimmedUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content: content.slice(0, 2000) }), }); if (!response.ok) { throw new Error(`Discord rejected the test message (${response.status}).`); } return { ok: true }; } export async function deleteForm(id: string) { await requireAdmin(); await db.delete(forms).where(eq(forms.id, id)); void sse.forms.pub("update", { formId: id, entity: "form", action: "deleted", }); revalidatePath("/admin/form"); }