This repository has been archived on 2022-08-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
outline/server/commands/documentBatchImporter.js
Tom Moor a51af98d43 refactor
2020-12-24 10:18:53 -08:00

148 lines
3.7 KiB
JavaScript

// @flow
import fs from "fs";
import path from "path";
import File from "formidable/lib/file";
import invariant from "invariant";
import JSZip from "jszip";
import { Collection, User } from "../models";
import attachmentCreator from "./attachmentCreator";
import documentCreator from "./documentCreator";
import documentImporter from "./documentImporter";
export default async function documentBatchImporter({
file,
type,
user,
ip,
}: {
file: File,
user: User,
type: "outline",
ip: string,
}) {
// load the zip structure into memory
const zipData = await fs.promises.readFile(file.path);
const zip = await JSZip.loadAsync(zipData);
// store progress and pointers
let attachments = {};
let collections = {};
let documents = {};
// this is so we can use async / await a little easier
let folders = [];
zip.forEach(async function (path, item) {
folders.push([path, item]);
});
for (const [rawPath, item] of folders) {
const itemPath = rawPath.replace(/\/$/, "");
const itemDir = path.dirname(itemPath);
const name = path.basename(item.name);
const depth = itemPath.split("/").length - 1;
// known skippable items
if (itemPath.startsWith("__MACOSX") || itemPath.endsWith(".DS_Store")) {
continue;
}
// all top level items must be directories representing collections
console.log("iterating over", itemPath, depth);
if (depth === 0 && item.dir && name) {
// check if collection with name exists
let [collection, isCreated] = await Collection.findOrCreate({
where: {
teamId: user.teamId,
name,
},
defaults: {
creatorId: user.id,
private: false,
},
});
// create new collection if name already exists, yes it's possible that
// there is also a "Name (Imported)" but this is a case not worth dealing
// with right now
if (!isCreated) {
collection = await Collection.create({
teamId: user.teamId,
creatorId: user.id,
name: `${name} (Imported)`,
private: false,
});
}
collections[itemPath] = collection;
continue;
}
if (depth > 0 && !item.dir && item.name.endsWith(".md")) {
const collection = collections[itemDir];
invariant(collection, "Collection must exist for document", itemDir);
// we have a document
const content = await item.async("string");
const name = path.basename(item.name);
await fs.promises.writeFile(`/tmp/${name}`, content);
const file = new File({
name,
type: "text/markdown",
path: `/tmp/${name}`,
});
const { text, title } = await documentImporter({
file,
user,
ip,
});
// must be a nested document, find the parent
if (depth > 1) {
console.log("nested doc", itemDir);
}
const document = await documentCreator({
title,
text,
publish: true,
collectionId: collection.id,
parentDocumentId: undefined,
user,
ip,
});
documents[itemPath] = document;
continue;
}
if (depth > 0 && item.dir && name !== "uploads") {
// we have a nested document, create if it doesn't exist based on title
continue;
}
if (depth > 0 && !item.dir && itemPath.includes("uploads")) {
// we have an attachment
const buffer = await item.async("nodebuffer");
const attachment = await attachmentCreator({
name,
type,
buffer,
user,
ip,
});
attachments[itemPath] = attachment;
continue;
}
console.log(`Skipped ${itemPath}`);
}
return {
documents,
collections,
attachments,
};
}