Projektstart

This commit is contained in:
2026-01-22 16:40:19 +01:00
parent 43c83e96bb
commit 85dee61a4d
25 changed files with 533 additions and 157 deletions

View File

@@ -2,9 +2,10 @@ import { FastifyInstance } from "fastify";
import { z } from "zod";
import { prisma } from "../db.js";
import { logJobEvent } from "../queue/jobEvents.js";
import { queueCleanupJob, removeQueueJob } from "../queue/queue.js";
import { queueCleanupJob, removeQueueJob, queueExportJob } from "../queue/queue.js";
import { createReadStream } from "node:fs";
import { access } from "node:fs/promises";
import { access, unlink } from "node:fs/promises";
import { cleanupExpiredExports } from "./exportCleanup.js";
const roleSchema = z.object({
role: z.enum(["USER", "ADMIN"])
@@ -74,6 +75,7 @@ export async function adminRoutes(app: FastifyInstance) {
scope: scope
}
});
await queueExportJob(exportJob.id);
return { jobId: exportJob.id };
}
@@ -111,8 +113,10 @@ export async function adminRoutes(app: FastifyInstance) {
return reply.send(createReadStream(job.filePath));
});
app.get("/exports", async () => {
app.get("/exports", async (request) => {
const query = request.query as { status?: string };
const exports = await prisma.exportJob.findMany({
where: query.status ? { status: query.status as "QUEUED" | "RUNNING" | "DONE" | "FAILED" } : undefined,
orderBy: { createdAt: "desc" }
});
const sanitized = exports.map((job) => ({
@@ -120,12 +124,33 @@ export async function adminRoutes(app: FastifyInstance) {
status: job.status,
format: job.format,
scope: job.scope,
progress: job.progress,
expiresAt: job.expiresAt,
createdAt: job.createdAt
}));
return { exports: sanitized };
});
app.post("/exports/purge", async () => {
await cleanupExpiredExports();
return { success: true };
});
app.delete("/exports/:id", async (request, reply) => {
const params = request.params as { id: string };
const job = await prisma.exportJob.findUnique({ where: { id: params.id } });
if (!job) return reply.code(404).send({ message: "Export job not found" });
if (job.filePath) {
try {
await unlink(job.filePath);
} catch {
// ignore
}
}
await prisma.exportJob.delete({ where: { id: job.id } });
return { success: true };
});
app.delete("/tenants/:id", async (request, reply) => {
const params = request.params as { id: string };
const tenant = await prisma.tenant.findUnique({ where: { id: params.id } });
@@ -241,7 +266,11 @@ export async function adminRoutes(app: FastifyInstance) {
tenant: account.tenant ? { id: account.tenant.id, name: account.tenant.name } : null,
imapHost: account.imapHost,
imapPort: account.imapPort,
imapTLS: account.imapTLS
imapTLS: account.imapTLS,
oauthExpiresAt: account.oauthExpiresAt,
oauthLastCheckedAt: account.oauthLastCheckedAt,
oauthLastErrorCode: account.oauthLastErrorCode,
hasOauth: Boolean(account.oauthRefreshToken || account.oauthAccessToken)
}));
return { accounts: sanitized };