feat(documents): add Epson scanner inbox and document shelf

This commit is contained in:
2026-09-29 12:42:05 +02:00
parent 552a90e9e1
commit 2192fa5bb4
13 changed files with 942 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
import { and, eq } from "drizzle-orm"
import type { FastifyInstance } from "fastify"
import { authProfiles } from "../../db/schema"
import { createScannerInboxService, SCANNER_DAV_PATH, SCANNER_UPLOAD_LIMIT, type ScannerInboxService } from "../modules/scanner-inbox.service"
export default async function documentInboxRoutes(server: FastifyInstance, options: { service?: ScannerInboxService }) {
const service = options.service || createScannerInboxService(server.db)
server.addHook("preHandler", async (req, reply) => {
if (!req.user?.tenant_id) return reply.code(400).send({ error: "Bitte einen Mandanten auswählen." })
const [profile] = await server.db.select({ portal: authProfiles.customer_for_portal }).from(authProfiles)
.where(and(eq(authProfiles.tenant_id, req.user.tenant_id), eq(authProfiles.user_id, req.user.user_id))).limit(1)
if (profile?.portal) return reply.code(403).send({ error: "Die Dokumentenablage ist nur intern verfügbar." })
if (req.routeOptions.url?.includes("/scanner") && !req.user.is_admin) {
return reply.code(403).send({ error: "Scanner-Zugänge können nur Administratoren verwalten." })
}
reply.header("Cache-Control", "no-store")
})
server.get("/document-inbox", async (req, reply) => {
const query = req.query as { limit?: string; offset?: string; search?: string }
const limit = Number(query.limit ?? 50)
const offset = Number(query.offset ?? 0)
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100 || !Number.isSafeInteger(offset) || offset < 0 || (query.search?.length || 0) > 200) {
return reply.code(400).send({ error: "Ungültige Such- oder Seiteneinstellungen." })
}
return service.list(req.user.tenant_id!, limit, offset, query.search?.trim() || "")
})
server.get("/document-inbox/scanner", async req => ({
connection: await service.connection(req.user.tenant_id!), path: SCANNER_DAV_PATH, maxFileSize: SCANNER_UPLOAD_LIMIT,
}))
server.post("/document-inbox/scanner/credentials", async req => ({
connection: await service.credentials(req.user.tenant_id!), path: SCANNER_DAV_PATH,
}))
server.delete("/document-inbox/scanner", async (_req, reply) => {
await service.disable(_req.user.tenant_id!)
return reply.code(204).send()
})
}