Update
This commit is contained in:
1 parent
87d6c9b3ce
commit
9a08bfbf44
2 files changed
+47
-12
No files matched your search
+31
-8
@@ -27,9 +27,11 @@ const port = Number(process.env.PORT ?? 3000);
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const frontendDist = path.resolve(__dirname, "../../frontend/dist");
|
||||
const serveFrontend = process.env.SERVE_FRONTEND !== "false";
|
||||
const requestBodyLimit = process.env.REQUEST_BODY_LIMIT ?? "250mb";
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json({ limit: "50mb" }));
|
||||
app.use(express.text({ type: ["text/plain", "text/sql"], limit: requestBodyLimit }));
|
||||
app.use(express.json({ limit: requestBodyLimit }));
|
||||
|
||||
app.get("/api/health", async (_req, res) => {
|
||||
await query("SELECT 1");
|
||||
@@ -3340,6 +3342,18 @@ app.get("/api/setup/status", async (_req, res) => {
|
||||
res.json({ required: !(await hasAdminUser()) });
|
||||
});
|
||||
|
||||
function restoreSqlFromRequestBody(body: unknown) {
|
||||
if (typeof body === "string") {
|
||||
return requireString(body, "sql");
|
||||
}
|
||||
|
||||
if (isPlainObject(body)) {
|
||||
return requireString(body.sql, "sql");
|
||||
}
|
||||
|
||||
throw badRequest("sql is required");
|
||||
}
|
||||
|
||||
app.post("/api/setup/admin", async (req, res) => {
|
||||
if (await hasAdminUser()) {
|
||||
res.status(409).json({ error: "Setup wurde bereits abgeschlossen" });
|
||||
@@ -3390,7 +3404,7 @@ app.post("/api/setup/restore", async (req, res) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const sql = requireString(req.body.sql, "sql");
|
||||
const sql = restoreSqlFromRequestBody(req.body);
|
||||
const result = await restoreTicketTrackerBackup(sql);
|
||||
res.status(201).json(result);
|
||||
});
|
||||
@@ -3401,7 +3415,7 @@ app.post("/api/setup/restore/validate", async (req, res) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const sql = requireString(req.body.sql, "sql");
|
||||
const sql = restoreSqlFromRequestBody(req.body);
|
||||
res.json(await validateTicketTrackerBackup(sql));
|
||||
});
|
||||
|
||||
@@ -4157,12 +4171,12 @@ app.get("/api/admin/export/database", requireAdmin, async (_req, res) => {
|
||||
});
|
||||
|
||||
app.post("/api/admin/restore/database/validate", requireAdmin, async (req, res) => {
|
||||
const sql = requireString(req.body.sql, "sql");
|
||||
const sql = restoreSqlFromRequestBody(req.body);
|
||||
res.json(await validateTicketTrackerBackup(sql));
|
||||
});
|
||||
|
||||
app.post("/api/admin/restore/database", requireAdmin, async (req, res) => {
|
||||
const sql = requireString(req.body.sql, "sql");
|
||||
const sql = restoreSqlFromRequestBody(req.body);
|
||||
const result = await restoreTicketTrackerBackup(sql);
|
||||
|
||||
res.clearCookie("tickettracker_session", {
|
||||
@@ -7781,10 +7795,19 @@ if (serveFrontend) {
|
||||
});
|
||||
}
|
||||
|
||||
app.use((error: Error & { status?: number }, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
|
||||
app.use((error: Error & { status?: number; statusCode?: number; type?: string }, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
|
||||
console.error(error);
|
||||
res.status(error.status ?? 500).json({
|
||||
error: error.status ? error.message : "Internal server error"
|
||||
|
||||
if (error.type === "entity.too.large" || error.status === 413 || error.statusCode === 413) {
|
||||
res.status(413).json({
|
||||
error: `Upload ist zu groß. Aktuelles Limit: ${requestBodyLimit}.`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const status = error.status ?? error.statusCode ?? 500;
|
||||
res.status(status).json({
|
||||
error: status < 500 ? error.message : "Internal server error"
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+16
-4
@@ -140,6 +140,10 @@ async function request<T>(url: string, options: ApiRequestInit = {}): Promise<T>
|
||||
throw new ApiError("Anfrage hat zu lange gedauert", 408);
|
||||
}
|
||||
|
||||
if (error instanceof TypeError) {
|
||||
throw new ApiError("Verbindung zum Server wurde unterbrochen. Bitte prüfen, ob Backend und Frontend laufen und ob das Backup kleiner als das Upload-Limit ist.", 503);
|
||||
}
|
||||
|
||||
throw error;
|
||||
} finally {
|
||||
if (timeout) {
|
||||
@@ -223,14 +227,18 @@ export function createSetupAdmin(payload: { username: string; displayName: strin
|
||||
export function restoreSetupBackup(sql: string) {
|
||||
return request<{ ok: boolean }>("/api/setup/restore", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ sql })
|
||||
timeoutMs: 10 * 60 * 1000,
|
||||
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
||||
body: sql
|
||||
});
|
||||
}
|
||||
|
||||
export function validateSetupBackup(sql: string) {
|
||||
return request<RestoreValidationResult>("/api/setup/restore/validate", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ sql })
|
||||
timeoutMs: 10 * 60 * 1000,
|
||||
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
||||
body: sql
|
||||
});
|
||||
}
|
||||
|
||||
@@ -287,14 +295,18 @@ export async function downloadDatabaseExport() {
|
||||
export function restoreDatabaseBackup(sql: string) {
|
||||
return request<{ ok: boolean }>("/api/admin/restore/database", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ sql })
|
||||
timeoutMs: 10 * 60 * 1000,
|
||||
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
||||
body: sql
|
||||
});
|
||||
}
|
||||
|
||||
export function validateDatabaseBackup(sql: string) {
|
||||
return request<RestoreValidationResult>("/api/admin/restore/database/validate", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ sql })
|
||||
timeoutMs: 10 * 60 * 1000,
|
||||
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
||||
body: sql
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user