Projektstart

This commit is contained in:
2026-01-22 15:49:12 +01:00
parent 7212eb6f7a
commit 57e5f652f8
10637 changed files with 2598792 additions and 64 deletions

166
backend/src/admin/routes.ts Normal file
View File

@@ -0,0 +1,166 @@
import { FastifyInstance } from "fastify";
import { z } from "zod";
import { prisma } from "../db.js";
const roleSchema = z.object({
role: z.enum(["USER", "ADMIN"])
});
const activeSchema = z.object({
isActive: z.boolean()
});
const resetSchema = z.object({
password: z.string().min(10)
});
export async function adminRoutes(app: FastifyInstance) {
app.addHook("preHandler", app.requireAdmin);
app.get("/tenants", async () => {
const tenants = await prisma.tenant.findMany({
include: { _count: { select: { users: true, mailboxAccounts: true, jobs: true } } },
orderBy: { createdAt: "desc" }
});
return { tenants };
});
app.put("/tenants/:id", async (request, reply) => {
const params = request.params as { id: string };
const input = activeSchema.parse(request.body);
const tenant = await prisma.tenant.findUnique({ where: { id: params.id } });
if (!tenant) return reply.code(404).send({ message: "Tenant not found" });
const updated = await prisma.tenant.update({
where: { id: params.id },
data: { isActive: input.isActive }
});
return { tenant: updated };
});
app.get("/users", async () => {
const users = await prisma.user.findMany({
include: { tenant: true },
orderBy: { createdAt: "desc" }
});
const sanitized = users.map((user) => ({
id: user.id,
email: user.email,
role: user.role,
isActive: user.isActive,
tenant: user.tenant ? { id: user.tenant.id, name: user.tenant.name } : null
}));
return { users: sanitized };
});
app.put("/users/:id/role", async (request, reply) => {
const params = request.params as { id: string };
const input = roleSchema.parse(request.body);
const user = await prisma.user.findUnique({ where: { id: params.id } });
if (!user) return reply.code(404).send({ message: "User not found" });
const updated = await prisma.user.update({
where: { id: params.id },
data: { role: input.role }
});
return { user: updated };
});
app.put("/users/:id", async (request, reply) => {
const params = request.params as { id: string };
const input = activeSchema.parse(request.body);
const user = await prisma.user.findUnique({ where: { id: params.id } });
if (!user) return reply.code(404).send({ message: "User not found" });
const updated = await prisma.user.update({
where: { id: params.id },
data: { isActive: input.isActive }
});
return { user: updated };
});
app.post("/users/:id/reset", async (request, reply) => {
const params = request.params as { id: string };
const input = resetSchema.parse(request.body);
const user = await prisma.user.findUnique({ where: { id: params.id } });
if (!user) return reply.code(404).send({ message: "User not found" });
const argon2 = (await import("argon2")).default;
const hashed = await argon2.hash(input.password);
const updated = await prisma.user.update({
where: { id: params.id },
data: { password: hashed }
});
return { user: updated };
});
app.get("/accounts", async () => {
const accounts = await prisma.mailboxAccount.findMany({
include: { tenant: true },
orderBy: { createdAt: "desc" }
});
const sanitized = accounts.map((account) => ({
id: account.id,
email: account.email,
provider: account.provider,
isActive: account.isActive,
tenant: account.tenant ? { id: account.tenant.id, name: account.tenant.name } : null,
imapHost: account.imapHost,
imapPort: account.imapPort,
imapTLS: account.imapTLS
}));
return { accounts: sanitized };
});
app.put("/accounts/:id", async (request, reply) => {
const params = request.params as { id: string };
const input = activeSchema.parse(request.body);
const account = await prisma.mailboxAccount.findUnique({ where: { id: params.id } });
if (!account) return reply.code(404).send({ message: "Account not found" });
const updated = await prisma.mailboxAccount.update({
where: { id: params.id },
data: { isActive: input.isActive }
});
return { account: updated };
});
app.get("/jobs", async () => {
const jobs = await prisma.cleanupJob.findMany({
include: { tenant: true, mailboxAccount: true },
orderBy: { createdAt: "desc" }
});
const sanitized = jobs.map((job) => ({
id: job.id,
status: job.status,
createdAt: job.createdAt,
tenant: job.tenant ? { id: job.tenant.id, name: job.tenant.name } : null,
mailboxAccount: job.mailboxAccount ? { id: job.mailboxAccount.id, email: job.mailboxAccount.email } : null
}));
return { jobs: sanitized };
});
app.get("/jobs/:id/events", async (request, reply) => {
const params = request.params as { id: string };
const job = await prisma.cleanupJob.findUnique({ where: { id: params.id } });
if (!job) return reply.code(404).send({ message: "Job not found" });
const events = await prisma.cleanupJobEvent.findMany({
where: { jobId: job.id },
orderBy: { createdAt: "asc" }
});
return { events };
});
}