KI-AGENT: Mandantenbezogenen IMAP-Dokumentenimport umsetzen
This commit is contained in:
118
backend/src/routes/documentImports.ts
Normal file
118
backend/src/routes/documentImports.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { and, desc, eq } from "drizzle-orm"
|
||||
import { FastifyInstance } from "fastify"
|
||||
|
||||
import { documentImportItems, documentImportSources } from "../../db/schema"
|
||||
import { decrypt, encrypt } from "../utils/crypt"
|
||||
|
||||
const decrypted = (value: unknown) => value ? decrypt(value as any) : null
|
||||
|
||||
export default async function documentImportRoutes(server: FastifyInstance) {
|
||||
const tenantId = (req: any) => {
|
||||
if (!req.user?.tenant_id) throw new Error("Kein aktiver Mandant")
|
||||
return Number(req.user.tenant_id)
|
||||
}
|
||||
|
||||
const response = (row: any) => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
provider: row.provider,
|
||||
enabled: row.enabled,
|
||||
mailboxAddress: decrypted(row.mailboxAddressEncrypted),
|
||||
imapHost: decrypted(row.imapHostEncrypted),
|
||||
imapPort: row.imapPort,
|
||||
imapSecure: row.imapSecure,
|
||||
mailboxPath: row.mailboxPath,
|
||||
targetFolderId: row.targetFolderId,
|
||||
defaultFiletypeId: row.defaultFiletypeId,
|
||||
markAsSeen: row.markAsSeen,
|
||||
hasPassword: Boolean(row.passwordEncrypted),
|
||||
lastSyncedAt: row.lastSyncedAt,
|
||||
lastError: row.lastError,
|
||||
createdAt: row.createdAt,
|
||||
})
|
||||
|
||||
server.get("/document-imports", async (req) => {
|
||||
const rows = await server.db.select().from(documentImportSources)
|
||||
.where(eq(documentImportSources.tenantId, tenantId(req)))
|
||||
.orderBy(documentImportSources.name)
|
||||
return rows.map(response)
|
||||
})
|
||||
|
||||
server.get("/document-imports/:id", async (req, reply) => {
|
||||
const { id } = req.params as { id: string }
|
||||
const [row] = await server.db.select().from(documentImportSources).where(and(
|
||||
eq(documentImportSources.id, id),
|
||||
eq(documentImportSources.tenantId, tenantId(req)),
|
||||
)).limit(1)
|
||||
if (!row) return reply.code(404).send({ error: "Importquelle wurde nicht gefunden" })
|
||||
return response(row)
|
||||
})
|
||||
|
||||
server.post("/document-imports/:id?", async (req, reply) => {
|
||||
const currentTenantId = tenantId(req)
|
||||
const { id } = req.params as { id?: string }
|
||||
const body = (req.body || {}) as any
|
||||
if (!body.name?.trim()) return reply.code(400).send({ error: "Name fehlt" })
|
||||
if ((body.provider || "imap") !== "imap") return reply.code(400).send({ error: "Aktuell wird nur IMAP unterstützt" })
|
||||
if (!body.mailboxAddress || !body.imapHost) return reply.code(400).send({ error: "Postfachadresse und IMAP-Host sind erforderlich" })
|
||||
|
||||
const values: any = {
|
||||
name: body.name.trim(),
|
||||
provider: "imap",
|
||||
enabled: body.enabled !== false,
|
||||
mailboxAddressEncrypted: encrypt(body.mailboxAddress),
|
||||
imapHostEncrypted: encrypt(body.imapHost),
|
||||
imapPort: Number(body.imapPort || 993),
|
||||
imapSecure: body.imapSecure !== false,
|
||||
mailboxPath: body.mailboxPath?.trim() || "INBOX",
|
||||
targetFolderId: body.targetFolderId || null,
|
||||
defaultFiletypeId: body.defaultFiletypeId || null,
|
||||
markAsSeen: body.markAsSeen !== false,
|
||||
updatedAt: new Date(),
|
||||
}
|
||||
if (body.password) values.passwordEncrypted = encrypt(body.password)
|
||||
|
||||
if (id) {
|
||||
const [existing] = await server.db.select({ id: documentImportSources.id }).from(documentImportSources).where(and(
|
||||
eq(documentImportSources.id, id),
|
||||
eq(documentImportSources.tenantId, currentTenantId),
|
||||
)).limit(1)
|
||||
if (!existing) return reply.code(404).send({ error: "Importquelle wurde nicht gefunden" })
|
||||
await server.db.update(documentImportSources).set(values).where(eq(documentImportSources.id, id))
|
||||
return { success: true, id }
|
||||
}
|
||||
|
||||
if (!body.password) return reply.code(400).send({ error: "Passwort fehlt" })
|
||||
const [created] = await server.db.insert(documentImportSources).values({
|
||||
...values,
|
||||
tenantId: currentTenantId,
|
||||
createdBy: req.user.user_id,
|
||||
}).returning({ id: documentImportSources.id })
|
||||
return { success: true, id: created.id }
|
||||
})
|
||||
|
||||
server.post("/document-imports/:id/test", async (req, reply) => {
|
||||
try {
|
||||
return await server.services.documentImports.testConnection(tenantId(req), (req.params as { id: string }).id)
|
||||
} catch (error: any) {
|
||||
return reply.code(400).send({ error: error?.message || "Verbindung fehlgeschlagen" })
|
||||
}
|
||||
})
|
||||
|
||||
server.post("/document-imports/:id/sync", async (req, reply) => {
|
||||
try {
|
||||
return await server.services.documentImports.syncSource(tenantId(req), (req.params as { id: string }).id)
|
||||
} catch (error: any) {
|
||||
return reply.code(400).send({ error: error?.message || "Synchronisierung fehlgeschlagen" })
|
||||
}
|
||||
})
|
||||
|
||||
server.get("/document-imports/:id/items", async (req) => {
|
||||
const currentTenantId = tenantId(req)
|
||||
const { id } = req.params as { id: string }
|
||||
return server.db.select().from(documentImportItems).where(and(
|
||||
eq(documentImportItems.tenantId, currentTenantId),
|
||||
eq(documentImportItems.sourceId, id),
|
||||
)).orderBy(desc(documentImportItems.createdAt)).limit(100)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user