feat: implement bug report submission with server upload functionality
- Updated documentation to include new API server details and configuration options. - Enhanced `SubmitBugReport` method to attempt server upload and handle errors gracefully. - Added `UploadBugReport` method to handle multipart file uploads to the API server. - Introduced new API server with MySQL backend for managing bug reports. - Implemented rate limiting and authentication for the API. - Created database schema and migration scripts for bug report storage. - Added admin routes for managing bug reports and files. - Updated frontend to reflect changes in bug report submission and success/error messages.
This commit is contained in:
104
server/src/routes/admin.ts
Normal file
104
server/src/routes/admin.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { Elysia, t } from "elysia";
|
||||
import { adminKeyGuard } from "../middleware/auth";
|
||||
import {
|
||||
listBugReports,
|
||||
getBugReport,
|
||||
getFile,
|
||||
deleteBugReport,
|
||||
updateBugReportStatus,
|
||||
} from "../services/bugReportService";
|
||||
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;
|
||||
|
||||
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 }) => {
|
||||
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 }) => {
|
||||
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 }) => {
|
||||
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" },
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user