refactor(db): migrate staff and app actions from Prisma facade to Drizzle

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-31 21:35:05 +02:00
1 parent 9854719cfd
commit ed9c23c702
85 files changed
+2612 -1832

No files matched your search

+84 -75
View File
@@ -1,9 +1,10 @@
"use server";
import { eq, inArray } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { requirePermission } from "@/lib/admin/guard";
import { CatalogItemsBc, CatalogPagesBc, db } from "@/lib/db";
import { PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
import { rcon } from "@/lib/services/rcon";
import { logStaffActivity } from "@/lib/services/staff-activity";
@@ -55,10 +56,10 @@ export async function updateBcPage({
if (Object.keys(data).length === 0) {
return { ok: false as const, error: "No valid fields to update" };
}
await prisma.catalogPagesBc.update({
where: { id },
data: data as any,
});
await db
.update(CatalogPagesBc)
.set(data as Partial<typeof CatalogPagesBc.$inferInsert>)
.where(eq(CatalogPagesBc.id, id));
await rcon.updateCatalog();
await logStaffActivity({
staffId: staff.id,
@@ -73,7 +74,7 @@ export async function updateBcPage({
export async function deleteBcItem({ id }: { id: number }) {
const staff = await requirePermission(PERMS.CATALOG_EDIT);
await prisma.catalogItemsBc.delete({ where: { id } });
await db.delete(CatalogItemsBc).where(eq(CatalogItemsBc.id, id));
await rcon.updateCatalog();
await logStaffActivity({
staffId: staff.id,
@@ -101,10 +102,10 @@ export async function updateBcItem({
if (Object.keys(safe).length === 0) {
return { ok: false as const, error: "No valid fields to update" };
}
await prisma.catalogItemsBc.update({
where: { id },
data: safe as any,
});
await db
.update(CatalogItemsBc)
.set(safe as Partial<typeof CatalogItemsBc.$inferInsert>)
.where(eq(CatalogItemsBc.id, id));
await rcon.updateCatalog();
await logStaffActivity({
staffId: staff.id,
@@ -128,19 +129,18 @@ export async function createBcItem({
extradata: string;
}) {
const staff = await requirePermission(PERMS.CATALOG_EDIT);
const created = await prisma.catalogItemsBc.create({
data: { pageId, ...data },
});
const [result] = await db.insert(CatalogItemsBc).values({ pageId, ...data });
const createdId = Number(result.insertId);
await rcon.updateCatalog();
await logStaffActivity({
staffId: staff.id,
action: "bc_item_create",
description: `Created BC catalog item #${created.id}`,
description: `Created BC catalog item #${createdId}`,
targetType: "catalog_item_bc",
targetId: created.id,
targetId: createdId,
});
revalidatePath("/admin/catalog/builder-club");
return { ok: true as const, data: { id: created.id } };
return { ok: true as const, data: { id: createdId } };
}
export async function toggleBcPage({
@@ -151,15 +151,19 @@ export async function toggleBcPage({
field: "enabled" | "visible";
}) {
await requirePermission(PERMS.CATALOG_EDIT);
const page = await prisma.catalogPagesBc.findUnique({
where: { id },
select: { enabled: true, visible: true },
});
const [page] = await db
.select({
enabled: CatalogPagesBc.enabled,
visible: CatalogPagesBc.visible,
})
.from(CatalogPagesBc)
.where(eq(CatalogPagesBc.id, id))
.limit(1);
if (!page) return { ok: false as const, error: "Page not found" };
await prisma.catalogPagesBc.update({
where: { id },
data: { [field]: page[field] === "1" ? "0" : "1" },
});
await db
.update(CatalogPagesBc)
.set({ [field]: page[field] === "1" ? "0" : "1" })
.where(eq(CatalogPagesBc.id, id));
await rcon.updateCatalog();
revalidatePath("/admin/catalog/builder-club");
return { ok: true as const };
@@ -176,31 +180,30 @@ export async function createBcPage(input: {
orderNum?: number;
}) {
const staff = await requirePermission(PERMS.CATALOG_EDIT);
const created = await prisma.catalogPagesBc.create({
data: {
caption: input.caption,
parentId: input.parentId,
pageLayout: input.pageLayout ?? "default_3x3",
iconColor: input.iconColor ?? 0,
iconImage: input.iconImage ?? 0,
orderNum: input.orderNum ?? 0,
visible: input.visible ?? "1",
enabled: input.enabled ?? "1",
pageHeadline: "",
pageTeaser: "",
},
const [result] = await db.insert(CatalogPagesBc).values({
caption: input.caption,
parentId: input.parentId,
pageLayout: input.pageLayout ?? "default_3x3",
iconColor: input.iconColor ?? 0,
iconImage: input.iconImage ?? 0,
orderNum: input.orderNum ?? 0,
visible: input.visible ?? "1",
enabled: input.enabled ?? "1",
pageHeadline: "",
pageTeaser: "",
});
const createdId = Number(result.insertId);
await rcon.updateCatalog();
await logStaffActivity({
staffId: staff.id,
action: "bc_page_create",
description: `Created BC catalog page "${input.caption}"`,
targetType: "catalog_page_bc",
targetId: created.id,
targetId: createdId,
});
revalidatePath("/admin/catalog");
revalidatePath("/admin/catalog/builder-club");
return { ok: true as const, data: { id: created.id } };
return { ok: true as const, data: { id: createdId } };
}
async function moveBcPage(pageId: number, newParentId: number): Promise<void> {
@@ -210,18 +213,19 @@ async function moveBcPage(pageId: number, newParentId: number): Promise<void> {
if (currentId === pageId) {
throw new Error("Cannot move page: would create a circular hierarchy");
}
const parent = await prisma.catalogPagesBc.findUnique({
where: { id: currentId },
select: { parentId: true },
});
const [parent] = await db
.select({ parentId: CatalogPagesBc.parentId })
.from(CatalogPagesBc)
.where(eq(CatalogPagesBc.id, currentId))
.limit(1);
if (!parent || parent.parentId <= 0) break;
currentId = parent.parentId;
}
}
await prisma.catalogPagesBc.update({
where: { id: pageId },
data: { parentId: newParentId },
});
await db
.update(CatalogPagesBc)
.set({ parentId: newParentId })
.where(eq(CatalogPagesBc.id, pageId));
}
export async function reorderBcTreePage(input: {
@@ -240,10 +244,10 @@ export async function reorderBcTreePage(input: {
};
}
}
await prisma.catalogPagesBc.update({
where: { id: input.pageId },
data: { orderNum: input.newOrderNum },
});
await db
.update(CatalogPagesBc)
.set({ orderNum: input.newOrderNum })
.where(eq(CatalogPagesBc.id, input.pageId));
await rcon.updateCatalog();
revalidatePath("/admin/catalog");
revalidatePath("/admin/catalog/builder-club");
@@ -255,43 +259,48 @@ export async function deleteBcTreePage(input: {
mode: "reparent" | "cascade";
}) {
await requirePermission(PERMS.CATALOG_EDIT);
const page = await prisma.catalogPagesBc.findUnique({
where: { id: input.pageId },
select: { parentId: true },
});
const [page] = await db
.select({ parentId: CatalogPagesBc.parentId })
.from(CatalogPagesBc)
.where(eq(CatalogPagesBc.id, input.pageId))
.limit(1);
if (!page) return { ok: false as const, error: "Page not found" };
if (input.mode === "reparent") {
await prisma.$transaction([
prisma.catalogPagesBc.updateMany({
where: { parentId: input.pageId },
data: { parentId: page.parentId },
}),
prisma.catalogItemsBc.deleteMany({ where: { pageId: input.pageId } }),
prisma.catalogPagesBc.delete({ where: { id: input.pageId } }),
]);
await db.transaction(async (tx) => {
await tx
.update(CatalogPagesBc)
.set({ parentId: page.parentId })
.where(eq(CatalogPagesBc.parentId, input.pageId));
await tx
.delete(CatalogItemsBc)
.where(eq(CatalogItemsBc.pageId, input.pageId));
await tx
.delete(CatalogPagesBc)
.where(eq(CatalogPagesBc.id, input.pageId));
});
} else {
const toDelete: number[] = [input.pageId];
const queue: number[] = [input.pageId];
while (queue.length > 0) {
const children = await prisma.catalogPagesBc.findMany({
where: { parentId: { in: queue } },
select: { id: true },
});
const children = await db
.select({ id: CatalogPagesBc.id })
.from(CatalogPagesBc)
.where(inArray(CatalogPagesBc.parentId, queue));
queue.length = 0;
for (const child of children) {
toDelete.push(child.id);
queue.push(child.id);
}
}
await prisma.$transaction([
prisma.catalogItemsBc.deleteMany({
where: { pageId: { in: toDelete } },
}),
prisma.catalogPagesBc.deleteMany({
where: { id: { in: toDelete } },
}),
]);
await db.transaction(async (tx) => {
await tx
.delete(CatalogItemsBc)
.where(inArray(CatalogItemsBc.pageId, toDelete));
await tx
.delete(CatalogPagesBc)
.where(inArray(CatalogPagesBc.id, toDelete));
});
}
await rcon.updateCatalog();