117 lines
3.9 KiB
TypeScript
117 lines
3.9 KiB
TypeScript
import { PutObjectCommand } from "@aws-sdk/client-s3"
|
||
import { s3 } from "./s3"
|
||
import { secrets } from "./secrets"
|
||
|
||
// Drizzle schema
|
||
import { files } from "../../db/schema"
|
||
import { eq } from "drizzle-orm"
|
||
import { FastifyInstance } from "fastify"
|
||
import { storeExtractedTextForFile } from "./documentText"
|
||
|
||
export const saveFile = async (
|
||
server: FastifyInstance,
|
||
tenant: number,
|
||
messageId: string | number | null, // Typ angepasst (oft null bei manueller Gen)
|
||
attachment: any, // Kann File, Buffer oder Mailparser-Objekt sein
|
||
folder: string | null,
|
||
type: string | null,
|
||
other: Record<string, any> = {}
|
||
) => {
|
||
try {
|
||
const {
|
||
filename: providedFilename,
|
||
filesize: _providedFilesize,
|
||
mimeType: providedMimeType,
|
||
...dbFields
|
||
} = other
|
||
|
||
// ---------------------------------------------------
|
||
// 1️⃣ FILE ENTRY ANLEGEN
|
||
// ---------------------------------------------------
|
||
const insertRes = await server.db
|
||
.insert(files)
|
||
.values({
|
||
tenant,
|
||
folder,
|
||
type,
|
||
...dbFields
|
||
})
|
||
.returning()
|
||
|
||
const created = insertRes?.[0]
|
||
if (!created) {
|
||
console.error("File creation failed (no row returned)")
|
||
return null
|
||
}
|
||
|
||
// Name ermitteln (Fallback Logik)
|
||
// Wenn attachment ein Buffer ist, muss der Name in 'other' stehen oder generiert werden
|
||
const filename = attachment.filename || providedFilename || `${created.id}.pdf`
|
||
|
||
// ---------------------------------------------------
|
||
// 2️⃣ BODY & CONTENT TYPE ERMITTELN
|
||
// ---------------------------------------------------
|
||
let body: Buffer | Uint8Array | string
|
||
let contentType = providedMimeType || "application/octet-stream"
|
||
|
||
if (Buffer.isBuffer(attachment)) {
|
||
// FALL 1: RAW BUFFER (von finishManualGeneration)
|
||
body = attachment
|
||
// ContentType wurde oben schon über 'type' Parameter gesetzt (z.B. application/pdf)
|
||
} else if (typeof File !== "undefined" && attachment instanceof File) {
|
||
// FALL 2: BROWSER FILE
|
||
body = Buffer.from(await attachment.arrayBuffer())
|
||
contentType = attachment.type || contentType
|
||
} else if (attachment.content) {
|
||
// FALL 3: MAILPARSER OBJECT
|
||
body = attachment.content
|
||
contentType = attachment.contentType || contentType
|
||
} else {
|
||
console.error("saveFile: Unknown attachment format")
|
||
return null
|
||
}
|
||
|
||
// ---------------------------------------------------
|
||
// 3️⃣ S3 UPLOAD
|
||
// ---------------------------------------------------
|
||
const key = `${tenant}/filesbyid/${created.id}/${filename}`
|
||
|
||
await s3.send(
|
||
new PutObjectCommand({
|
||
Bucket: secrets.S3_BUCKET,
|
||
Key: key,
|
||
Body: body,
|
||
ContentType: contentType,
|
||
ContentLength: body.length // <--- WICHTIG: Behebt den AWS Fehler
|
||
})
|
||
)
|
||
|
||
// ---------------------------------------------------
|
||
// 4️⃣ PATH IN DB SETZEN
|
||
// ---------------------------------------------------
|
||
await server.db
|
||
.update(files)
|
||
.set({
|
||
path: key,
|
||
mimeType: contentType,
|
||
name: filename,
|
||
size: body.length
|
||
})
|
||
.where(eq(files.id, created.id))
|
||
|
||
await storeExtractedTextForFile(
|
||
server,
|
||
created.id,
|
||
Buffer.isBuffer(body) ? body : Buffer.from(body),
|
||
contentType,
|
||
filename
|
||
)
|
||
|
||
console.log(`File saved: ${key}`)
|
||
return { id: created.id, key }
|
||
} catch (err) {
|
||
console.error("saveFile error:", err)
|
||
return null
|
||
}
|
||
}
|