3.0.0 #220

Merged
flfeders merged 676 commits from dev into main 2026-09-20 16:10:48 +00:00
Showing only changes of commit b1785a35a9 - Show all commits

View File

@@ -3,6 +3,9 @@ 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 { stat, unlink } from "node:fs/promises";
import { pipeline } from "node:stream/promises";
import {
authTenantUsers,
@@ -1446,6 +1449,7 @@ export default async function adminRoutes(server: FastifyInstance) {
// -------------------------------------------------------------
server.post("/admin/tenant-imports", { bodyLimit: 1024 * 1024 * 1024 }, async (req, reply) => {
let archiveStoragePath: string | null = null;
let temporaryArchivePath: string | null = null;
try {
const currentUser = await requireAdmin(req, reply);
if (!currentUser) return;
@@ -1469,13 +1473,19 @@ export default async function adminRoutes(server: FastifyInstance) {
}
archiveStoragePath = `tenant-imports/${randomUUID()}-${filename}`;
temporaryArchivePath = `${process.env.TMPDIR || "/tmp"}/fedeo-tenant-import-${randomUUID()}.zip`;
await pipeline(data.file, createWriteStream(temporaryArchivePath, { flags: "wx" }));
const temporaryArchive = await stat(temporaryArchivePath);
await s3.send(new PutObjectCommand({
Bucket: secrets.S3_BUCKET,
Key: archiveStoragePath,
Body: data.file,
Body: createReadStream(temporaryArchivePath),
ContentLength: temporaryArchive.size,
ContentType: data.mimetype || "application/zip",
}));
fileSize = data.file.bytesRead || null;
fileSize = temporaryArchive.size;
await unlink(temporaryArchivePath);
temporaryArchivePath = null;
source = { archiveStoragePath };
} else {
const body = req.body as TenantFullExport | { exportData?: TenantFullExport; targetTenantId?: number };
@@ -1520,6 +1530,11 @@ export default async function adminRoutes(server: FastifyInstance) {
});
} catch (err: any) {
console.error("ERROR /admin/tenant-imports:", err);
if (temporaryArchivePath) {
await unlink(temporaryArchivePath).catch((cleanupError) => {
console.error("ERROR cleanup temporary tenant import archive:", cleanupError);
});
}
if (archiveStoragePath) {
await s3.send(new DeleteObjectCommand({
Bucket: secrets.S3_BUCKET,