Files
EpicNext-Cms/src/actions/catalog-items.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

173 lines
4.3 KiB
TypeScript

"use server";
import { revalidatePath } from "next/cache";
import { requirePermission } from "@/lib/admin/guard";
import { PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
import { rcon } from "@/lib/services/rcon";
import { logStaffActivity } from "@/lib/services/staff-activity";
export async function createCatalogItem(data: {
pageId: number;
itemIds: string;
catalogName: string;
costCredits: number;
costPoints: number;
pointsType: number;
amount: number;
orderNumber: number;
offerId: number;
limitedSells: number;
limitedStack: number;
extradata: string;
songId: number;
haveOffer: "0" | "1";
clubOnly: "0" | "1";
}) {
const staff = await requirePermission(PERMS.CATALOG_EDIT);
const created = await prisma.catalogItems.create({ data });
await rcon.updateCatalog();
await logStaffActivity({
staffId: staff.id,
action: "catalog_item_create",
description: `Created catalog item #${created.id}`,
targetType: "catalog_item",
targetId: created.id,
});
revalidatePath("/admin/catalog");
return { ok: true as const, data: { id: created.id } };
}
export async function deleteCatalogItems({ ids }: { ids: number[] }) {
const staff = await requirePermission(PERMS.CATALOG_EDIT);
await prisma.catalogItems.deleteMany({ where: { id: { in: ids } } });
await rcon.updateCatalog();
await logStaffActivity({
staffId: staff.id,
action: "catalog_items_delete",
description: `Deleted catalog items: ${ids.join(", ")}`,
targetType: "catalog_item",
});
revalidatePath("/admin/catalog");
return { ok: true as const, data: {} };
}
export async function moveCatalogItems({
ids,
targetPageId,
}: {
ids: number[];
targetPageId: number;
}) {
await requirePermission(PERMS.CATALOG_EDIT);
await prisma.catalogItems.updateMany({
where: { id: { in: ids } },
data: { pageId: targetPageId },
});
await rcon.updateCatalog();
revalidatePath("/admin/catalog");
return { ok: true as const, data: {} };
}
export async function reorderCatalogItems({
orders,
}: {
orders: Array<{ id: number; orderNumber: number }>;
}) {
await requirePermission(PERMS.CATALOG_EDIT);
for (const { id, orderNumber } of orders) {
await prisma.catalogItems.update({ where: { id }, data: { orderNumber } });
}
await rcon.updateCatalog();
revalidatePath("/admin/catalog");
return { ok: true as const, data: {} };
}
export async function updateCatalogItem({
id,
catalogFields,
baseItem,
}: {
id: number;
catalogFields: Record<string, unknown>;
baseItem?: { id: number; fields: Record<string, unknown> };
}) {
const staff = await requirePermission(PERMS.CATALOG_EDIT);
await prisma.catalogItems.update({
where: { id },
data: catalogFields as any,
});
if (baseItem) {
await prisma.itemsBase.update({
where: { id: baseItem.id },
data: baseItem.fields as any,
});
}
await rcon.updateCatalog();
await logStaffActivity({
staffId: staff.id,
action: "catalog_item_update",
description: `Updated catalog item #${id}`,
targetType: "catalog_item",
targetId: id,
});
revalidatePath("/admin/catalog");
return { ok: true as const, data: {} };
}
export async function translateCatalogItems({
items,
}: {
items: Array<{ id: number; publicName: string; description: string }>;
}) {
await requirePermission(PERMS.CATALOG_EDIT);
let namesUpdated = 0;
let descriptionsUpdated = 0;
let furniDataUpdated = 0;
const _furniDataInserted = 0;
for (const item of items) {
const existing = await prisma.catalogItems.findUnique({
where: { id: item.id },
select: { catalogName: true },
});
if (!existing) continue;
if (item.publicName && item.publicName !== existing.catalogName) {
await prisma.catalogItems.update({
where: { id: item.id },
data: { catalogName: item.publicName },
});
namesUpdated++;
}
if (item.description) {
const baseItem = await prisma.itemsBase.findFirst({
where: { itemName: existing.catalogName },
select: { id: true, publicName: true },
});
if (baseItem) {
await prisma.itemsBase.update({
where: { id: baseItem.id },
data: { publicName: item.publicName || baseItem.publicName },
});
furniDataUpdated++;
}
descriptionsUpdated++;
}
}
await rcon.updateCatalog();
revalidatePath("/admin/catalog");
return {
ok: true as const,
data: {
namesUpdated,
descriptionsUpdated,
furniDataUpdated,
furniDataInserted: 0,
updated: items.length,
},
};
}