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

+91 -76
View File
@@ -1,7 +1,8 @@
"use server";
import { eq } from "drizzle-orm";
import { db, WebsiteTicket, WebsiteTicketMessage } from "@/lib/db";
import { PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
import { adminAction, authAction } from "@/lib/safe-action";
import { ActionError, actionOk } from "@/lib/safe-action-shared";
import { logAudit } from "@/lib/services/audit";
@@ -24,32 +25,31 @@ export const createTicket = authAction(
rateLimitWindowMs: 60_000,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.create({
data: {
subject: ctx.data.subject,
category: ctx.data.category,
creatorId: ctx.session.user.id,
},
const now = new Date();
const [result] = await db.insert(WebsiteTicket).values({
subject: ctx.data.subject,
category: ctx.data.category,
creatorId: ctx.session.user.id,
updatedAt: now,
});
const ticketId = Number(result.insertId);
// Create the first message
await prisma.websiteTicketMessage.create({
data: {
ticketId: ticket.id,
userId: ctx.session.user.id,
message: ctx.data.message,
isStaff: 0,
},
await db.insert(WebsiteTicketMessage).values({
ticketId,
userId: ctx.session.user.id,
message: ctx.data.message,
isStaff: 0,
});
notify({
action: "ticket_create",
actor: ctx.session.user.username,
target: `#${ticket.id} - ${ticket.subject}`,
details: `Category: ${ticket.category}`,
target: `#${ticketId} - ${ctx.data.subject}`,
details: `Category: ${ctx.data.category}`,
});
return actionOk({ id: ticket.id });
return actionOk({ id: ticketId });
},
);
@@ -61,30 +61,30 @@ export const userReplyTicket = authAction(
rateLimitWindowMs: 60_000,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.findUnique({
where: { id: ctx.data.ticketId },
});
const [ticket] = await db
.select()
.from(WebsiteTicket)
.where(eq(WebsiteTicket.id, ctx.data.ticketId))
.limit(1);
if (!ticket) throw new ActionError("Ticket not found");
if (ticket.creatorId !== ctx.session.user.id)
throw new ActionError("Unauthorized");
if (ticket.status === "closed") throw new ActionError("Ticket is closed");
await prisma.websiteTicketMessage.create({
data: {
ticketId: ctx.data.ticketId,
userId: ctx.session.user.id,
message: ctx.data.message,
isStaff: 0,
},
await db.insert(WebsiteTicketMessage).values({
ticketId: ctx.data.ticketId,
userId: ctx.session.user.id,
message: ctx.data.message,
isStaff: 0,
});
// If ticket was in "waiting" (waiting for user), move back to open
if (ticket.status === "waiting") {
await prisma.websiteTicket.update({
where: { id: ctx.data.ticketId },
data: { status: "open" },
});
await db
.update(WebsiteTicket)
.set({ status: "open", updatedAt: new Date() })
.where(eq(WebsiteTicket.id, ctx.data.ticketId));
}
return actionOk();
@@ -99,9 +99,11 @@ export const closeTicketByUser = authAction(
rateLimitWindowMs: 60_000,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.findUnique({
where: { id: ctx.data.ticketId },
});
const [ticket] = await db
.select()
.from(WebsiteTicket)
.where(eq(WebsiteTicket.id, ctx.data.ticketId))
.limit(1);
if (!ticket) throw new ActionError("Ticket not found");
if (ticket.creatorId !== ctx.session.user.id)
@@ -109,10 +111,10 @@ export const closeTicketByUser = authAction(
if (ticket.status === "closed")
throw new ActionError("Ticket is already closed");
await prisma.websiteTicket.update({
where: { id: ctx.data.ticketId },
data: { status: "closed", closedAt: new Date() },
});
await db
.update(WebsiteTicket)
.set({ status: "closed", closedAt: new Date(), updatedAt: new Date() })
.where(eq(WebsiteTicket.id, ctx.data.ticketId));
return actionOk();
},
@@ -126,31 +128,34 @@ export const adminReplyTicket = adminAction(
schema: replyTicketSchema,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.findUnique({
where: { id: ctx.data.ticketId },
});
const [ticket] = await db
.select()
.from(WebsiteTicket)
.where(eq(WebsiteTicket.id, ctx.data.ticketId))
.limit(1);
if (!ticket) throw new ActionError("Ticket not found");
await prisma.websiteTicketMessage.create({
data: {
ticketId: ctx.data.ticketId,
userId: ctx.session.user.id,
message: ctx.data.message,
isStaff: 1,
},
await db.insert(WebsiteTicketMessage).values({
ticketId: ctx.data.ticketId,
userId: ctx.session.user.id,
message: ctx.data.message,
isStaff: 1,
});
// Auto-assign if not assigned yet
const updates: Record<string, unknown> = { status: "waiting" };
const updates: Partial<typeof WebsiteTicket.$inferInsert> = {
status: "waiting",
updatedAt: new Date(),
};
if (!ticket.assigneeId) {
updates.assigneeId = ctx.session.user.id;
}
await prisma.websiteTicket.update({
where: { id: ctx.data.ticketId },
data: updates,
});
await db
.update(WebsiteTicket)
.set(updates)
.where(eq(WebsiteTicket.id, ctx.data.ticketId));
logAudit({
userId: ctx.session.user.id,
@@ -169,13 +174,18 @@ export const updateTicketStatus = adminAction(
schema: updateTicketStatusSchema,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.findUnique({
where: { id: ctx.data.ticketId },
});
const [ticket] = await db
.select()
.from(WebsiteTicket)
.where(eq(WebsiteTicket.id, ctx.data.ticketId))
.limit(1);
if (!ticket) throw new ActionError("Ticket not found");
const data: Record<string, unknown> = { status: ctx.data.status };
const data: Partial<typeof WebsiteTicket.$inferInsert> = {
status: ctx.data.status,
updatedAt: new Date(),
};
if (ctx.data.status === "closed") {
data.closedAt = new Date();
}
@@ -183,10 +193,10 @@ export const updateTicketStatus = adminAction(
data.assigneeId = ctx.session.user.id;
}
await prisma.websiteTicket.update({
where: { id: ctx.data.ticketId },
data,
});
await db
.update(WebsiteTicket)
.set(data)
.where(eq(WebsiteTicket.id, ctx.data.ticketId));
logAudit({
userId: ctx.session.user.id,
@@ -207,19 +217,22 @@ export const assignTicket = adminAction(
schema: assignTicketSchema,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.findUnique({
where: { id: ctx.data.ticketId },
});
const [ticket] = await db
.select()
.from(WebsiteTicket)
.where(eq(WebsiteTicket.id, ctx.data.ticketId))
.limit(1);
if (!ticket) throw new ActionError("Ticket not found");
await prisma.websiteTicket.update({
where: { id: ctx.data.ticketId },
data: {
await db
.update(WebsiteTicket)
.set({
assigneeId: ctx.data.assigneeId,
status: ctx.data.assigneeId ? "in_progress" : "open",
},
});
updatedAt: new Date(),
})
.where(eq(WebsiteTicket.id, ctx.data.ticketId));
logAudit({
userId: ctx.session.user.id,
@@ -240,16 +253,18 @@ export const updateTicketPriority = adminAction(
schema: updateTicketPrioritySchema,
},
async (ctx) => {
const ticket = await prisma.websiteTicket.findUnique({
where: { id: ctx.data.ticketId },
});
const [ticket] = await db
.select()
.from(WebsiteTicket)
.where(eq(WebsiteTicket.id, ctx.data.ticketId))
.limit(1);
if (!ticket) throw new ActionError("Ticket not found");
await prisma.websiteTicket.update({
where: { id: ctx.data.ticketId },
data: { priority: ctx.data.priority },
});
await db
.update(WebsiteTicket)
.set({ priority: ctx.data.priority, updatedAt: new Date() })
.where(eq(WebsiteTicket.id, ctx.data.ticketId));
logAudit({
userId: ctx.session.user.id,