110 lines
3.3 KiB
TypeScript
110 lines
3.3 KiB
TypeScript
import { Elysia, t } from "elysia";
|
|
import { adminKeyGuard } from "../middleware/auth";
|
|
import {
|
|
listBugReports,
|
|
getBugReport,
|
|
getFile,
|
|
deleteBugReport,
|
|
updateBugReportStatus,
|
|
} from "../services/bugReportService";
|
|
import { Log } from "../logger";
|
|
import type { BugReportStatus } from "../types";
|
|
|
|
export const adminRoutes = new Elysia({ prefix: "/api/admin" })
|
|
.use(adminKeyGuard)
|
|
.get(
|
|
"/bug-reports",
|
|
async ({ query }) => {
|
|
const page = parseInt(query.page || "1");
|
|
const pageSize = Math.min(parseInt(query.pageSize || "20"), 100);
|
|
const status = query.status as BugReportStatus | undefined;
|
|
|
|
Log("ADMIN", `List bug reports page=${page} pageSize=${pageSize} status=${status || "all"}`);
|
|
return await listBugReports({ page, pageSize, status });
|
|
},
|
|
{
|
|
query: t.Object({
|
|
page: t.Optional(t.String()),
|
|
pageSize: t.Optional(t.String()),
|
|
status: t.Optional(
|
|
t.Union([
|
|
t.Literal("new"),
|
|
t.Literal("in_review"),
|
|
t.Literal("resolved"),
|
|
t.Literal("closed"),
|
|
])
|
|
),
|
|
}),
|
|
detail: { summary: "List bug reports (paginated)" },
|
|
}
|
|
)
|
|
.get(
|
|
"/bug-reports/:id",
|
|
async ({ params, error }) => {
|
|
Log("ADMIN", `Get bug report id=${params.id}`);
|
|
const result = await getBugReport(parseInt(params.id));
|
|
if (!result) return error(404, { success: false, message: "Report not found" });
|
|
return result;
|
|
},
|
|
{
|
|
params: t.Object({ id: t.String() }),
|
|
detail: { summary: "Get bug report with file metadata" },
|
|
}
|
|
)
|
|
.patch(
|
|
"/bug-reports/:id/status",
|
|
async ({ params, body, error }) => {
|
|
Log("ADMIN", `Update status id=${params.id} status=${body.status}`);
|
|
const updated = await updateBugReportStatus(
|
|
parseInt(params.id),
|
|
body.status
|
|
);
|
|
if (!updated)
|
|
return error(404, { success: false, message: "Report not found" });
|
|
return { success: true, message: "Status updated" };
|
|
},
|
|
{
|
|
params: t.Object({ id: t.String() }),
|
|
body: t.Object({
|
|
status: t.Union([
|
|
t.Literal("new"),
|
|
t.Literal("in_review"),
|
|
t.Literal("resolved"),
|
|
t.Literal("closed"),
|
|
]),
|
|
}),
|
|
detail: { summary: "Update bug report status" },
|
|
}
|
|
)
|
|
.get(
|
|
"/bug-reports/:id/files/:fileId",
|
|
async ({ params, error, set }) => {
|
|
const file = await getFile(parseInt(params.id), parseInt(params.fileId));
|
|
if (!file)
|
|
return error(404, { success: false, message: "File not found" });
|
|
|
|
set.headers["content-type"] = file.mime_type;
|
|
set.headers["content-disposition"] =
|
|
`attachment; filename="${file.filename}"`;
|
|
return new Response(file.data);
|
|
},
|
|
{
|
|
params: t.Object({ id: t.String(), fileId: t.String() }),
|
|
detail: { summary: "Download a bug report file" },
|
|
}
|
|
)
|
|
.delete(
|
|
"/bug-reports/:id",
|
|
async ({ params, error }) => {
|
|
Log("ADMIN", `Delete bug report id=${params.id}`);
|
|
const deleted = await deleteBugReport(parseInt(params.id));
|
|
if (!deleted)
|
|
return error(404, { success: false, message: "Report not found" });
|
|
return { success: true, message: "Report deleted" };
|
|
},
|
|
{
|
|
params: t.Object({ id: t.String() }),
|
|
detail: { summary: "Delete a bug report and its files" },
|
|
}
|
|
);
|