style: format code biome
Local Build and Deploy / deploy (push) Failing after 46s

This commit is contained in:
openhands committed 2026-07-13 21:57:41 +02:00
1 parent 8efd032cc6
commit df38dccbf1
735 files changed
+128321 -120870

No files matched your search

+59 -51
View File
@@ -12,59 +12,67 @@ import { createOwnedTicketReply } from "@/lib/services/ticket-replies";
export const dynamic = "force-dynamic";
// POST /api/tickets/:id/reply body: { content }
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
const uid = await bearerUserId(req);
if (!uid) return apiError("Unauthorized", 401);
export async function POST(
req: Request,
{ params }: { params: Promise<{ id: string }> },
) {
const uid = await bearerUserId(req);
if (!uid) return apiError("Unauthorized", 401);
const { id } = await params;
const ticketId = positiveBigInt(id);
if (!ticketId) return apiError("Invalid ticket id", 422);
const { id } = await params;
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 ?? "")
.trim()
.slice(0, 5000);
if (!content) return apiError("Content is required");
const body = (await req.json().catch(() => ({}))) as { content?: unknown };
const content = String(body.content ?? "")
.trim()
.slice(0, 5000);
if (!content) return apiError("Content is required");
try {
// Ownership check — only the ticket owner may reply.
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 },
}),
},
{ ticketId, userId: uid, content },
),
);
if (!reply) return apiError("Ticket not found", 404);
try {
// Ownership check — only the ticket owner may reply.
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 },
}),
},
{ ticketId, userId: uid, content },
),
);
if (!reply) return apiError("Ticket not found", 404);
return apiJson(
{
reply: {
id: reply.id,
userId: reply.userId,
content: reply.content,
createdAt: reply.createdAt,
},
},
{ status: 201 },
);
} catch {
return apiError("Failed to post reply", 503);
}
return apiJson(
{
reply: {
id: reply.id,
userId: reply.userId,
content: reply.content,
createdAt: reply.createdAt,
},
},
{ status: 201 },
);
} catch {
return apiError("Failed to post reply", 503);
}
}
+60 -56
View File
@@ -11,66 +11,70 @@ import { prisma } from "@/lib/prisma";
export const dynamic = "force-dynamic";
// GET /api/tickets/:id
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
const uid = await bearerUserId(req);
if (!uid) return apiError("Unauthorized", 401);
export async function GET(
req: Request,
{ params }: { params: Promise<{ id: string }> },
) {
const uid = await bearerUserId(req);
if (!uid) return apiError("Unauthorized", 401);
const { id } = await params;
const ticketId = positiveBigInt(id);
if (!ticketId) return apiError("Invalid ticket id", 422);
const { id } = await params;
const ticketId = positiveBigInt(id);
if (!ticketId) return apiError("Invalid ticket id", 422);
try {
const ticket = await prisma.websiteHelpCenterTickets.findUnique({
where: { id: ticketId },
select: {
id: true,
userId: true,
categoryId: true,
title: true,
content: true,
open: true,
createdAt: true,
},
});
try {
const ticket = await prisma.websiteHelpCenterTickets.findUnique({
where: { id: ticketId },
select: {
id: true,
userId: true,
categoryId: true,
title: true,
content: true,
open: true,
createdAt: true,
},
});
// Ownership check — return 404 (not 403) so a foreign id is indistinguishable
// from a missing one.
if (!ticket || ticket.userId !== uid) return apiError("Ticket not found", 404);
// Ownership check — return 404 (not 403) so a foreign id is indistinguishable
// from a missing one.
if (!ticket || ticket.userId !== uid)
return apiError("Ticket not found", 404);
const replies = await prisma.websiteHelpCenterTicketReplies.findMany({
where: { ticketId },
select: { id: true, userId: true, content: true, createdAt: true },
orderBy: { id: "asc" },
});
const replies = await prisma.websiteHelpCenterTicketReplies.findMany({
where: { ticketId },
select: { id: true, userId: true, content: true, createdAt: true },
orderBy: { id: "asc" },
});
// Resolve author usernames in one query.
const authorIds = [...new Set(replies.map((r) => r.userId))];
const authors = authorIds.length
? await prisma.user.findMany({
where: { id: { in: authorIds } },
select: { id: true, username: true },
})
: [];
const nameById = new Map(authors.map((a) => [a.id, a.username]));
// Resolve author usernames in one query.
const authorIds = [...new Set(replies.map((r) => r.userId))];
const authors = authorIds.length
? await prisma.user.findMany({
where: { id: { in: authorIds } },
select: { id: true, username: true },
})
: [];
const nameById = new Map(authors.map((a) => [a.id, a.username]));
return apiJson({
ticket: {
id: ticket.id,
categoryId: ticket.categoryId,
title: ticket.title,
content: ticket.content,
open: ticket.open,
createdAt: ticket.createdAt,
replies: replies.map((r) => ({
id: r.id,
userId: r.userId,
username: nameById.get(r.userId) ?? null,
content: r.content,
createdAt: r.createdAt,
})),
},
});
} catch {
return apiError("Failed to load ticket", 503);
}
return apiJson({
ticket: {
id: ticket.id,
categoryId: ticket.categoryId,
title: ticket.title,
content: ticket.content,
open: ticket.open,
createdAt: ticket.createdAt,
replies: replies.map((r) => ({
id: r.id,
userId: r.userId,
username: nameById.get(r.userId) ?? null,
content: r.content,
createdAt: r.createdAt,
})),
},
});
} catch {
return apiError("Failed to load ticket", 503);
}
}
+73 -69
View File
@@ -12,84 +12,88 @@ export const dynamic = "force-dynamic";
// GET /api/tickets — the authed user's tickets (newest first).
export async function GET(req: Request) {
const uid = await bearerUserId(req);
if (!uid) return apiError("Unauthorized", 401);
const uid = await bearerUserId(req);
if (!uid) return apiError("Unauthorized", 401);
try {
const tickets = await prisma.websiteHelpCenterTickets.findMany({
where: { userId: uid },
select: { id: true, title: true, open: true, createdAt: true },
orderBy: { id: "desc" },
});
try {
const tickets = await prisma.websiteHelpCenterTickets.findMany({
where: { userId: uid },
select: { id: true, title: true, open: true, createdAt: true },
orderBy: { id: "desc" },
});
return apiJson({
tickets: tickets.map((t) => ({
id: t.id,
title: t.title,
open: t.open,
createdAt: t.createdAt,
})),
});
} catch {
return apiError("Failed to load tickets", 503);
}
return apiJson({
tickets: tickets.map((t) => ({
id: t.id,
title: t.title,
open: t.open,
createdAt: t.createdAt,
})),
});
} catch {
return apiError("Failed to load tickets", 503);
}
}
// POST /api/tickets — open a new ticket ({ title, content, categoryId? }).
export async function POST(req: Request) {
const uid = await bearerUserId(req);
if (!uid) return apiError("Unauthorized", 401);
const uid = await bearerUserId(req);
if (!uid) return apiError("Unauthorized", 401);
const body = (await req.json().catch(() => ({}))) as {
title?: unknown;
content?: unknown;
categoryId?: unknown;
};
const body = (await req.json().catch(() => ({}))) as {
title?: unknown;
content?: unknown;
categoryId?: unknown;
};
const title = String(body.title ?? "")
.trim()
.slice(0, 255);
const content = String(body.content ?? "")
.trim()
.slice(0, 5000);
if (!title) return apiError("Title is required");
if (!content) return apiError("Content is required");
const title = String(body.title ?? "")
.trim()
.slice(0, 255);
const content = String(body.content ?? "")
.trim()
.slice(0, 5000);
if (!title) return apiError("Title is required");
if (!content) return apiError("Content is required");
// categoryId is an optional unsigned BigInt FK — accept a positive numeric
// value, otherwise leave it null.
let categoryId: bigint | null = null;
if (body.categoryId !== undefined && body.categoryId !== null && body.categoryId !== "") {
categoryId = positiveBigInt(String(body.categoryId));
if (!categoryId) return apiError("A valid category id is required", 422);
}
// categoryId is an optional unsigned BigInt FK — accept a positive numeric
// value, otherwise leave it null.
let categoryId: bigint | null = null;
if (
body.categoryId !== undefined &&
body.categoryId !== null &&
body.categoryId !== ""
) {
categoryId = positiveBigInt(String(body.categoryId));
if (!categoryId) return apiError("A valid category id is required", 422);
}
try {
const now = new Date();
const ticket = await prisma.websiteHelpCenterTickets.create({
data: {
userId: uid,
categoryId,
title,
content,
open: true,
createdAt: now,
updatedAt: now,
},
select: { id: true, title: true, open: true, createdAt: true },
});
try {
const now = new Date();
const ticket = await prisma.websiteHelpCenterTickets.create({
data: {
userId: uid,
categoryId,
title,
content,
open: true,
createdAt: now,
updatedAt: now,
},
select: { id: true, title: true, open: true, createdAt: true },
});
return apiJson(
{
ticket: {
id: ticket.id,
title: ticket.title,
open: ticket.open,
createdAt: ticket.createdAt,
},
},
{ status: 201 },
);
} catch {
return apiError("Failed to create ticket", 503);
}
return apiJson(
{
ticket: {
id: ticket.id,
title: ticket.title,
open: ticket.open,
createdAt: ticket.createdAt,
},
},
{ status: 201 },
);
} catch {
return apiError("Failed to create ticket", 503);
}
}