diff --git a/backend/src/routes/admin.ts b/backend/src/routes/admin.ts index 0246993..45177fc 100644 --- a/backend/src/routes/admin.ts +++ b/backend/src/routes/admin.ts @@ -3,7 +3,7 @@ import { and, eq, inArray, isNull, sql } from "drizzle-orm"; import multipart from "@fastify/multipart"; import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"; import { randomUUID } from "node:crypto"; -import { createReadStream, createWriteStream } from "node:fs"; +import { createReadStream, createWriteStream, openAsBlob } from "node:fs"; import { stat, unlink } from "node:fs/promises"; import { pipeline } from "node:stream/promises"; @@ -469,6 +469,7 @@ export default async function adminRoutes(server: FastifyInstance) { currentUser: { id: string; email: string }, source: { archiveStoragePath: string } | { exportData: TenantFullExport } ) => { + let temporaryArchivePath: string | null = null; try { await server.db .update(tenantExportJobs) @@ -499,8 +500,10 @@ export default async function adminRoutes(server: FastifyInstance) { })); if (!object.Body) throw new Error("Importarchiv konnte nicht aus dem Speicher gelesen werden"); - const archiveBuffer = Buffer.from(await object.Body.transformToByteArray()); - result = await importTenantFullExportArchive(server, archiveBuffer, { onProgress }); + temporaryArchivePath = `${process.env.TMPDIR || "/tmp"}/fedeo-tenant-import-${randomUUID()}.zip`; + await pipeline(object.Body as NodeJS.ReadableStream, createWriteStream(temporaryArchivePath, { flags: "wx" })); + const archive = await openAsBlob(temporaryArchivePath); + result = await importTenantFullExportArchive(server, archive, { onProgress }); } else { result = await importTenantFullExport(server, source.exportData, { onProgress }); } @@ -532,6 +535,11 @@ export default async function adminRoutes(server: FastifyInstance) { }) .where(eq(tenantExportJobs.id, jobId)); } finally { + if (temporaryArchivePath) { + await unlink(temporaryArchivePath).catch((cleanupError) => { + console.error("ERROR cleanup temporary tenant import archive:", cleanupError); + }); + } if ("archiveStoragePath" in source) { await s3.send(new DeleteObjectCommand({ Bucket: secrets.S3_BUCKET, diff --git a/backend/src/utils/tenantFullExport.ts b/backend/src/utils/tenantFullExport.ts index f8b0dc5..347b6c7 100644 --- a/backend/src/utils/tenantFullExport.ts +++ b/backend/src/utils/tenantFullExport.ts @@ -982,10 +982,10 @@ export const importTenantFullExport = async ( export const importTenantFullExportArchive = async ( server: FastifyInstance, - archiveBuffer: Buffer, + archive: Buffer | Blob, options: ImportOptions = {} ): Promise => { - const reader = new ZipReader(new BlobReader(new Blob([archiveBuffer]))) + const reader = new ZipReader(new BlobReader(archive instanceof Blob ? archive : new Blob([archive]))) try { const entries = await reader.getEntries()