From 7b4bedae5964191b9bf0cb5591cad21c80c9486e Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Thu, 16 Nov 2023 22:09:51 -0500 Subject: [PATCH] fix: Handle public attachments in Markdown export, closes #6161 --- .../tasks/ImportMarkdownZipTask.test.ts | 33 +++++++++++++++++- server/queues/tasks/ImportMarkdownZipTask.ts | 24 +++++++++---- .../test/fixtures/outline-markdown-public.zip | Bin 0 -> 7078 bytes .../{outline.zip => outline-markdown.zip} | Bin 4 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 server/test/fixtures/outline-markdown-public.zip rename server/test/fixtures/{outline.zip => outline-markdown.zip} (100%) diff --git a/server/queues/tasks/ImportMarkdownZipTask.test.ts b/server/queues/tasks/ImportMarkdownZipTask.test.ts index 789b42e03..d5a9287d0 100644 --- a/server/queues/tasks/ImportMarkdownZipTask.test.ts +++ b/server/queues/tasks/ImportMarkdownZipTask.test.ts @@ -16,7 +16,7 @@ describe("ImportMarkdownZipTask", () => { "..", "test", "fixtures", - "outline.zip" + "outline-markdown.zip" ), cleanup: async () => {}, }; @@ -36,6 +36,37 @@ describe("ImportMarkdownZipTask", () => { expect(response.attachments.size).toEqual(6); }, 10000); + it("should import the documents, public attachments", async () => { + const fileOperation = await buildFileOperation(); + Object.defineProperty(fileOperation, "handle", { + get() { + return { + path: path.resolve( + __dirname, + "..", + "..", + "test", + "fixtures", + "outline-markdown-public.zip" + ), + cleanup: async () => {}, + }; + }, + }); + jest.spyOn(FileOperation, "findByPk").mockResolvedValue(fileOperation); + + const props = { + fileOperationId: fileOperation.id, + }; + + const task = new ImportMarkdownZipTask(); + const response = await task.perform(props); + + expect(response.collections.size).toEqual(1); + expect(response.documents.size).toEqual(2); + expect(response.attachments.size).toEqual(1); + }, 10000); + it("should throw an error with corrupt zip", async () => { const fileOperation = await buildFileOperation(); Object.defineProperty(fileOperation, "handle", { diff --git a/server/queues/tasks/ImportMarkdownZipTask.ts b/server/queues/tasks/ImportMarkdownZipTask.ts index 6f12160f2..4496a0d19 100644 --- a/server/queues/tasks/ImportMarkdownZipTask.ts +++ b/server/queues/tasks/ImportMarkdownZipTask.ts @@ -5,6 +5,7 @@ import { v4 as uuidv4 } from "uuid"; import documentImporter from "@server/commands/documentImporter"; import Logger from "@server/logging/Logger"; import { FileOperation, User } from "@server/models"; +import { Buckets } from "@server/models/helpers/AttachmentHelper"; import ImportHelper, { FileTreeNode } from "@server/utils/ImportHelper"; import ImportTask, { StructuredImportData } from "./ImportTask"; @@ -51,8 +52,11 @@ export default class ImportMarkdownZipTask extends ImportTask { children.map(async (child) => { // special case for folders of attachments if ( - child.name === "uploads" || - (child.children.length > 0 && child.path.includes("/uploads/")) + child.name === Buckets.uploads || + child.name === Buckets.public || + (child.children.length > 0 && + (child.path.includes(`/${Buckets.public}/`) || + child.path.includes(`/${Buckets.uploads}/`))) ) { return parseNodeChildren(child.children, collectionId); } @@ -60,7 +64,11 @@ export default class ImportMarkdownZipTask extends ImportTask { const id = uuidv4(); // this is an attachment - if (child.path.includes("/uploads/") && child.children.length === 0) { + if ( + child.children.length === 0 && + (child.path.includes(`/${Buckets.uploads}/`) || + child.path.includes(`/${Buckets.public}/`)) + ) { output.attachments.push({ id, name: child.name, @@ -145,10 +153,12 @@ export default class ImportMarkdownZipTask extends ImportTask { // Pull the collection and subdirectory out of the path name, upload // folders in an export are relative to the document itself - const normalizedAttachmentPath = encodedPath.replace( - /(.*)uploads\//, - "uploads/" - ); + const normalizedAttachmentPath = encodedPath + .replace( + new RegExp(`(.*)/${Buckets.uploads}/`), + `${Buckets.uploads}/` + ) + .replace(new RegExp(`(.*)/${Buckets.public}/`), `${Buckets.public}/`); const reference = `<<${attachment.id}>>`; document.text = document.text diff --git a/server/test/fixtures/outline-markdown-public.zip b/server/test/fixtures/outline-markdown-public.zip new file mode 100644 index 0000000000000000000000000000000000000000..264b6d7ed81da60cdce136ba2ca5949a7b7ff39b GIT binary patch literal 7078 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 literal 0 HcmV?d00001 diff --git a/server/test/fixtures/outline.zip b/server/test/fixtures/outline-markdown.zip similarity index 100% rename from server/test/fixtures/outline.zip rename to server/test/fixtures/outline-markdown.zip