fix: Export includes documents that have identical names (#3098)

This commit is contained in:
Tom Moor
2022-02-12 13:35:57 -08:00
committed by GitHub
parent 289f01970f
commit 229f01513c

View File

@@ -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);
}
}
}