Harden CMS security and theme contrast
This commit is contained in:
1 parent
2465ff2170
commit
4a1e1115b3
57 files changed
+1023
-231
No files matched your search
@@ -4,9 +4,10 @@
|
||||
// into website_help_center_ticket_replies. The target ticket must exist and
|
||||
// belong to the authed user. Fail-soft: never a 500.
|
||||
|
||||
import { apiError, apiJson } from "@/lib/api";
|
||||
import { apiError, apiJson, positiveBigInt } from "@/lib/api";
|
||||
import { bearerUserId } from "@/lib/api-auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { createOwnedTicketReply } from "@/lib/services/ticket-replies";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -16,8 +17,8 @@ export async function POST(req: Request, { params }: { params: Promise<{ id: str
|
||||
if (!uid) return apiError("Unauthorized", 401);
|
||||
|
||||
const { id } = await params;
|
||||
if (!/^\d+$/.test(id)) return apiError("Invalid ticket id");
|
||||
const ticketId = BigInt(id);
|
||||
const ticketId = positiveBigInt(id);
|
||||
if (!ticketId) return apiError("Invalid ticket id", 422);
|
||||
|
||||
const body = (await req.json().catch(() => ({}))) as { content?: unknown };
|
||||
const content = String(body.content ?? "")
|
||||
@@ -27,28 +28,25 @@ export async function POST(req: Request, { params }: { params: Promise<{ id: str
|
||||
|
||||
try {
|
||||
// Ownership check — only the ticket owner may reply.
|
||||
const ticket = await prisma.websiteHelpCenterTickets.findUnique({
|
||||
where: { id: ticketId },
|
||||
select: { id: true, userId: true },
|
||||
});
|
||||
if (!ticket || ticket.userId !== uid) return apiError("Ticket not found", 404);
|
||||
|
||||
const now = new Date();
|
||||
const reply = await prisma.websiteHelpCenterTicketReplies.create({
|
||||
data: {
|
||||
ticketId,
|
||||
userId: uid,
|
||||
content,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
const reply = await prisma.$transaction((tx) => createOwnedTicketReply(
|
||||
{
|
||||
findTicket: (ticketId) => tx.websiteHelpCenterTickets.findUnique({
|
||||
where: { id: ticketId },
|
||||
select: { id: true, userId: true },
|
||||
}),
|
||||
createReply: (data) => tx.websiteHelpCenterTicketReplies.create({
|
||||
data,
|
||||
select: { id: true, userId: true, content: true, createdAt: true },
|
||||
}),
|
||||
touchTicket: (ticketId, updatedAt) => tx.websiteHelpCenterTickets.update({
|
||||
where: { id: ticketId },
|
||||
data: { updatedAt },
|
||||
select: { id: true },
|
||||
}),
|
||||
},
|
||||
select: { id: true, userId: true, content: true, createdAt: true },
|
||||
});
|
||||
|
||||
// Touch the parent ticket so its updatedAt reflects the latest activity.
|
||||
prisma.websiteHelpCenterTickets
|
||||
.update({ where: { id: ticketId }, data: { updatedAt: now }, select: { id: true } })
|
||||
.catch(() => {});
|
||||
{ ticketId, userId: uid, content },
|
||||
));
|
||||
if (!reply) return apiError("Ticket not found", 404);
|
||||
|
||||
return apiJson(
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// together with its replies; reply author usernames are resolved in a single
|
||||
// users lookup. Fail-soft: never a 500.
|
||||
|
||||
import { apiError, apiJson } from "@/lib/api";
|
||||
import { apiError, apiJson, positiveBigInt } from "@/lib/api";
|
||||
import { bearerUserId } from "@/lib/api-auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
@@ -16,8 +16,8 @@ export async function GET(req: Request, { params }: { params: Promise<{ id: stri
|
||||
if (!uid) return apiError("Unauthorized", 401);
|
||||
|
||||
const { id } = await params;
|
||||
if (!/^\d+$/.test(id)) return apiError("Invalid ticket id");
|
||||
const ticketId = BigInt(id);
|
||||
const ticketId = positiveBigInt(id);
|
||||
if (!ticketId) return apiError("Invalid ticket id", 422);
|
||||
|
||||
try {
|
||||
const ticket = await prisma.websiteHelpCenterTickets.findUnique({
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Backed by website_help_center_tickets (WebsiteHelpCenterTickets). Fail-soft:
|
||||
// DB errors return an apiError envelope, never a 500.
|
||||
|
||||
import { apiError, apiJson } from "@/lib/api";
|
||||
import { apiError, apiJson, positiveBigInt } from "@/lib/api";
|
||||
import { bearerUserId } from "@/lib/api-auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
@@ -59,8 +59,8 @@ export async function POST(req: Request) {
|
||||
// value, otherwise leave it null.
|
||||
let categoryId: bigint | null = null;
|
||||
if (body.categoryId !== undefined && body.categoryId !== null && body.categoryId !== "") {
|
||||
const raw = String(body.categoryId);
|
||||
if (/^\d+$/.test(raw)) categoryId = BigInt(raw);
|
||||
categoryId = positiveBigInt(String(body.categoryId));
|
||||
if (!categoryId) return apiError("A valid category id is required", 422);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user