Files
EpicNext-Cms/src/actions/admin-vouchers.ts
T
simoleo89andCursor 0e89d03940 Finish fine-grained ACL across remaining admin pages and actions.
Replace leftover requireStaff gates with module PERMS, drop hardcoded room rank thresholds, and expand contract tests so admin mutations cannot regress to dashboard-only checks.

Co-authored-by: Cursor <[email protected]>
2026-07-15 20:15:22 +02:00

73 lines
1.8 KiB
TypeScript

"use server";
import { revalidatePath } from "next/cache";
import { requirePermission } from "@/lib/admin/guard";
import { PERMS } from "@/lib/permissions";
import { formPositiveBigInt } from "@/lib/form-data";
import { prisma } from "@/lib/prisma";
import { logServerError } from "@/lib/server-log";
export async function createVoucher(formData: FormData): Promise<void> {
await requirePermission(PERMS.SHOP_EDIT);
const code = String(formData.get("code") ?? "")
.normalize("NFC")
.trim()
.slice(0, 255);
const amount = Number(formData.get("amount"));
const maxUsesRaw = Number(formData.get("maxUses"));
const maxUses =
Number.isFinite(maxUsesRaw) && maxUsesRaw > 0 ? Math.floor(maxUsesRaw) : 1;
if (!code || !(amount > 0)) return;
const expiresRaw = String(formData.get("expiresAt") ?? "")
.normalize("NFC")
.trim();
let expiresAt: Date | null = null;
if (expiresRaw) {
const parsed = new Date(expiresRaw);
if (!Number.isNaN(parsed.getTime())) expiresAt = parsed;
}
const now = new Date();
try {
await prisma.websiteShopVouchers.create({
data: {
code,
amount: Math.floor(amount),
maxUses,
useCount: 0,
expiresAt,
createdAt: now,
updatedAt: now,
},
});
} catch (error) {
logServerError("admin.voucher_create_failed", error);
// Unique constraint on `code` (or DB unavailable) — swallow and re-render.
return;
}
revalidatePath("/admin/vouchers");
}
export async function deleteVoucher(formData: FormData): Promise<void> {
await requirePermission(PERMS.SHOP_EDIT);
const id = formPositiveBigInt(formData, "id");
if (!id) return;
try {
await prisma.websiteShopVouchers.delete({ where: { id } });
} catch (error) {
logServerError("admin.voucher_delete_failed", error, {
voucherId: String(id),
});
return;
}
revalidatePath("/admin/vouchers");
}