fix: Export includes documents that have identical names (#3098)
This commit is contained in:
@@ -23,7 +23,10 @@ export type Item = {
|
||||
item: JSZipObject;
|
||||
};
|
||||
|
||||
async function addToArchive(zip: JSZip, documents: NavigationNode[]) {
|
||||
async function addDocumentTreeToArchive(
|
||||
zip: JSZip,
|
||||
documents: NavigationNode[]
|
||||
) {
|
||||
for (const doc of documents) {
|
||||
const document = await Document.findByPk(doc.id);
|
||||
|
||||
@@ -44,8 +47,9 @@ async function addToArchive(zip: JSZip, documents: NavigationNode[]) {
|
||||
text = text.replace(attachment.redirectUrl, encodeURI(attachment.key));
|
||||
}
|
||||
|
||||
const title = serializeFilename(document.title) || "Untitled";
|
||||
zip.file(`${title}.md`, text, {
|
||||
let title = serializeFilename(document.title) || "Untitled";
|
||||
|
||||
title = safeAddFileToArchive(zip, `${title}.md`, text, {
|
||||
date: document.updatedAt,
|
||||
comment: JSON.stringify({
|
||||
createdAt: document.createdAt,
|
||||
@@ -54,15 +58,21 @@ async function addToArchive(zip: JSZip, documents: NavigationNode[]) {
|
||||
});
|
||||
|
||||
if (doc.children && doc.children.length) {
|
||||
const folder = zip.folder(title);
|
||||
const folder = zip.folder(path.parse(title).name);
|
||||
|
||||
if (folder) {
|
||||
await addToArchive(folder, doc.children);
|
||||
await addDocumentTreeToArchive(folder, doc.children);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the content of a file in remote storage to the given zip file.
|
||||
*
|
||||
* @param zip JSZip object to add to
|
||||
* @param key path to file in S3 storage
|
||||
*/
|
||||
async function addImageToArchive(zip: JSZip, key: string) {
|
||||
try {
|
||||
const img = await getFileByKey(key);
|
||||
@@ -78,6 +88,52 @@ async function addImageToArchive(zip: JSZip, key: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds content to a zip file, if the given filename already exists in the zip
|
||||
* then it will automatically increment numbers at the end of the filename.
|
||||
*
|
||||
* @param zip JSZip object to add to
|
||||
* @param key filename with extension
|
||||
* @param content the content to add
|
||||
* @param options options for added content
|
||||
* @returns The new title
|
||||
*/
|
||||
function safeAddFileToArchive(
|
||||
zip: JSZip,
|
||||
key: string,
|
||||
content: string | Uint8Array | ArrayBuffer | Blob,
|
||||
options: JSZip.JSZipFileOptions
|
||||
) {
|
||||
// @ts-expect-error root exists
|
||||
const root = zip.root;
|
||||
|
||||
// Filenames in the directory already
|
||||
const keysInDirectory = Object.keys(zip.files)
|
||||
.filter((k) => k.includes(root))
|
||||
.filter((k) => !k.endsWith("/"))
|
||||
.map((k) => path.basename(k).replace(/\s\((\d+)\)\./, "."));
|
||||
|
||||
// The number of duplicate filenames
|
||||
const existingKeysCount = keysInDirectory.filter((t) => t === key).length;
|
||||
const filename = path.parse(key).name;
|
||||
const extension = path.extname(key);
|
||||
|
||||
// Construct the new de-duplicated filename (if any)
|
||||
const safeKey =
|
||||
existingKeysCount > 0
|
||||
? `${filename} (${existingKeysCount})${extension}`
|
||||
: key;
|
||||
|
||||
zip.file(safeKey, content, options);
|
||||
return safeKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a zip file to a temporary disk location
|
||||
*
|
||||
* @param zip JSZip object
|
||||
* @returns pathname of the temporary file where the zip was written to disk
|
||||
*/
|
||||
async function archiveToPath(zip: JSZip) {
|
||||
return new Promise((resolve, reject) => {
|
||||
tmp.file(
|
||||
@@ -110,7 +166,7 @@ export async function archiveCollections(collections: Collection[]) {
|
||||
const folder = zip.folder(collection.name);
|
||||
|
||||
if (folder) {
|
||||
await addToArchive(folder, collection.documentStructure);
|
||||
await addDocumentTreeToArchive(folder, collection.documentStructure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user