diff --git a/server/commands/documentBatchImporter.js b/server/commands/documentBatchImporter.js index 9de70ab0..884a5822 100644 --- a/server/commands/documentBatchImporter.js +++ b/server/commands/documentBatchImporter.js @@ -8,7 +8,7 @@ import invariant from "invariant"; import { values, keys } from "lodash"; import uuid from "uuid"; import { parseOutlineExport } from "../../shared/utils/zip"; -import { InvalidRequestError } from "../errors"; +import { FileImportError } from "../errors"; import { Attachment, Document, Collection, User } from "../models"; import attachmentCreator from "./attachmentCreator"; import documentCreator from "./documentCreator"; @@ -34,7 +34,13 @@ export default async function documentBatchImporter({ try { items = await await parseOutlineExport(zipData); } catch (err) { - throw new InvalidRequestError(err.message); + throw new FileImportError(err.message); + } + + if (!items.filter((item) => item.type === "document").length) { + throw new FileImportError( + "Uploaded file does not contain importable documents" + ); } // store progress and pointers @@ -96,6 +102,8 @@ export default async function documentBatchImporter({ ip, }); + await fs.promises.unlink(tmpFilePath); + // must be a nested document, find and reference the parent document let parentDocumentId; if (item.depth > 1) { diff --git a/server/commands/documentBatchImporter.test.js b/server/commands/documentBatchImporter.test.js index 14390543..2f296076 100644 --- a/server/commands/documentBatchImporter.test.js +++ b/server/commands/documentBatchImporter.test.js @@ -1,6 +1,7 @@ // @flow import path from "path"; import File from "formidable/lib/file"; +import { Attachment, Document, Collection } from "../models"; import { buildUser } from "../test/factories"; import { flushdb } from "../test/support"; import documentBatchImporter from "./documentBatchImporter"; @@ -31,5 +32,59 @@ describe("documentBatchImporter", () => { expect(response.collections.length).toEqual(1); expect(response.documents.length).toEqual(8); expect(response.attachments.length).toEqual(6); + + expect(await Collection.count()).toEqual(1); + expect(await Document.count()).toEqual(8); + expect(await Attachment.count()).toEqual(6); + }); + + it("should throw an error with corrupt zip", async () => { + const user = await buildUser(); + const name = "corrupt.zip"; + const file = new File({ + name, + type: "application/zip", + path: path.resolve(__dirname, "..", "test", "fixtures", name), + }); + + let error; + try { + await documentBatchImporter({ + type: "outline", + user, + file, + ip, + }); + } catch (err) { + error = err; + } + + expect(error && error.message).toBeTruthy(); + }); + + it("should throw an error with empty zip", async () => { + const user = await buildUser(); + const name = "empty.zip"; + const file = new File({ + name, + type: "application/zip", + path: path.resolve(__dirname, "..", "test", "fixtures", name), + }); + + let error; + try { + await documentBatchImporter({ + type: "outline", + user, + file, + ip, + }); + } catch (err) { + error = err; + } + + expect(error && error.message).toBe( + "Uploaded file does not contain importable documents" + ); }); }); diff --git a/server/test/fixtures/corrupt.zip b/server/test/fixtures/corrupt.zip new file mode 100644 index 00000000..9056068e --- /dev/null +++ b/server/test/fixtures/corrupt.zip @@ -0,0 +1 @@ +CORRUPT \ No newline at end of file diff --git a/server/test/fixtures/empty.zip b/server/test/fixtures/empty.zip new file mode 100644 index 00000000..92cef7a0 Binary files /dev/null and b/server/test/fixtures/empty.zip differ diff --git a/shared/i18n/locales/en_US/translation.json b/shared/i18n/locales/en_US/translation.json index c5aa5ea3..ae74c485 100644 --- a/shared/i18n/locales/en_US/translation.json +++ b/shared/i18n/locales/en_US/translation.json @@ -279,6 +279,8 @@ "Export in progress…": "Export in progress…", "Import": "Import", "It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.": "It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.", + "Sorry, the file <1>{{fileName}} is missing valid collections or documents.": "Sorry, the file <1>{{fileName}} is missing valid collections or documents.", + "<0>{{fileName}} looks good, the following collections and their documents will be imported:": "<0>{{fileName}} looks good, the following collections and their documents will be imported:", "Importing": "Importing", "Confirm & Import": "Confirm & Import", "Choose File…": "Choose File…",