Include letterhead files in tenant archive
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 27s
Build and Push Docker Images / build-frontend (push) Successful in 1m10s
Build and Push Docker Images / build-website (push) Successful in 17s
Build and Push Docker Images / build-docs (push) Successful in 16s

This commit is contained in:
2026-07-14 17:33:05 +02:00
parent a9b063aa89
commit 4e3f1e0c15

View File

@@ -265,6 +265,22 @@ const archiveEntryPathForFile = (path: string) => {
return `files/${normalizedPath || "unnamed-file"}`
}
const filenameFromPath = (path: string) => {
const filename = path
.replace(/\\/g, "/")
.split("/")
.filter(Boolean)
.pop()
if (!filename) return null
try {
return decodeURIComponent(filename)
} catch {
return filename
}
}
const jsonBuffer = (value: unknown) => Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf8")
export const buildTenantFullExport = async (
@@ -329,11 +345,17 @@ export const buildTenantFullExport = async (
tables.entitybankaccounts = decryptEntityBankAccountsForExport(tables.entitybankaccounts)
}
const fileRows = tables.files || []
const files = []
for (const file of fileRows) {
if (!file.path) continue
const filePaths = new Set<string>()
const addExportFile = async (file: {
id: string
path: string
name?: string | null
mimeType?: string | null
size?: number | null
}) => {
if (!file.path || filePaths.has(file.path)) return
filePaths.add(file.path)
const object = includeFileContents
? await loadObjectAsBase64(file.path)
@@ -350,7 +372,7 @@ export const buildTenantFullExport = async (
files.push({
id: file.id,
path: file.path,
name: file.name || null,
name: file.name || filenameFromPath(file.path),
mimeType: file.mimeType || null,
size: file.size || null,
contentBase64: object.contentBase64,
@@ -359,6 +381,30 @@ export const buildTenantFullExport = async (
})
}
for (const file of tables.files || []) {
if (!file.path) continue
await addExportFile({
id: file.id,
path: file.path,
name: file.name || null,
mimeType: file.mimeType || null,
size: file.size || null,
})
}
for (const letterhead of tables.letterheads || []) {
if (!letterhead.path) continue
await addExportFile({
id: `letterhead:${letterhead.id}`,
path: letterhead.path,
name: filenameFromPath(letterhead.path),
mimeType: "application/pdf",
size: null,
})
}
return {
format: "fedeo.tenant-full-export",
version: 1,
@@ -384,7 +430,7 @@ export const createTenantFullExportArchive = async (
.toLowerCase()
const filename = options.filename || `fedeo-tenant-${safeTenantName || tenantId}-${new Date().toISOString().slice(0, 10)}.fedeo-export.zip`
const storagePath = options.storagePath || `tenant-exports/${tenantId}/${Date.now()}-${filename}`
const fileRows = exportData.tables.files || []
const fileRows = exportData.files || []
const archive = archiver("zip", { zlib: { level: 6 } })
const tempPath = path.join(os.tmpdir(), `fedeo-tenant-export-${tenantId}-${Date.now()}-${filename}`)
const output = createWriteStream(tempPath)
@@ -523,7 +569,7 @@ const restoreArchiveFiles = async (
let skipped = 0
const filesByPath = new Map((manifest.files || []).map((file) => [file.path, file]))
for (const fileRow of exportData.tables.files || []) {
for (const fileRow of exportData.files || []) {
const originalPath = fileRow.path
if (!originalPath) {
skipped += 1