feat: Bulk HTML export (#4620)

* wip

* Working bulk html export

* Refactor

* test

* test
This commit is contained in:
Tom Moor
2022-12-30 17:42:20 +00:00
committed by GitHub
parent 1b8dd9399c
commit f3469d25fe
32 changed files with 485 additions and 258 deletions

View File

@@ -1,4 +1,4 @@
export const uploadToS3FromBuffer = jest.fn().mockReturnValue("/endpoint/key");
export const uploadToS3 = jest.fn().mockReturnValue("/endpoint/key");
export const publicS3Endpoint = jest.fn().mockReturnValue("http://mock");

View File

@@ -85,21 +85,28 @@ export const publicS3Endpoint = (isServerUpload?: boolean) => {
}${AWS_S3_UPLOAD_BUCKET_NAME}`;
};
export const uploadToS3FromBuffer = async (
buffer: Buffer,
contentType: string,
key: string,
acl: string
) => {
export const uploadToS3 = async ({
body,
contentLength,
contentType,
key,
acl,
}: {
body: S3.Body;
contentLength: number;
contentType: string;
key: string;
acl: string;
}) => {
await s3
.putObject({
ACL: acl,
Bucket: AWS_S3_UPLOAD_BUCKET_NAME,
Key: key,
ContentType: contentType,
ContentLength: buffer.length,
ContentLength: contentLength,
ContentDisposition: "attachment",
Body: buffer,
Body: body,
})
.promise();
const endpoint = publicS3Endpoint(true);

View File

@@ -3,6 +3,7 @@ import path from "path";
import JSZip, { JSZipObject } from "jszip";
import { find } from "lodash";
import tmp from "tmp";
import { FileOperationFormat } from "@shared/types";
import { ValidationError } from "@server/errors";
import Logger from "@server/logging/Logger";
import Attachment from "@server/models/Attachment";
@@ -26,9 +27,21 @@ export type Item = {
item: JSZipObject;
};
export type FileTreeNode = {
/** The title, extracted from the file name */
title: string;
/** The file name including extension */
name: string;
/** The full path to within the zip file */
path: string;
/** The nested children */
children: FileTreeNode[];
};
async function addDocumentTreeToArchive(
zip: JSZip,
documents: NavigationNode[]
documents: NavigationNode[],
format = FileOperationFormat.MarkdownZip
) {
for (const doc of documents) {
const document = await Document.findByPk(doc.id);
@@ -37,7 +50,10 @@ async function addDocumentTreeToArchive(
continue;
}
let text = DocumentHelper.toMarkdown(document);
let text =
format === FileOperationFormat.HTMLZip
? await DocumentHelper.toHTML(document)
: await DocumentHelper.toMarkdown(document);
const attachments = await Attachment.findAll({
where: {
teamId: document.teamId,
@@ -52,7 +68,9 @@ async function addDocumentTreeToArchive(
let title = serializeFilename(document.title) || "Untitled";
title = safeAddFileToArchive(zip, `${title}.md`, text, {
const extension = format === FileOperationFormat.HTMLZip ? "html" : "md";
title = safeAddFileToArchive(zip, `${title}.${extension}`, text, {
date: document.updatedAt,
comment: JSON.stringify({
createdAt: document.createdAt,
@@ -161,7 +179,10 @@ async function archiveToPath(zip: JSZip): Promise<string> {
});
}
export async function archiveCollections(collections: Collection[]) {
export async function archiveCollections(
collections: Collection[],
format: FileOperationFormat
) {
const zip = new JSZip();
for (const collection of collections) {
@@ -169,7 +190,11 @@ export async function archiveCollections(collections: Collection[]) {
const folder = zip.folder(serializeFilename(collection.name));
if (folder) {
await addDocumentTreeToArchive(folder, collection.documentStructure);
await addDocumentTreeToArchive(
folder,
collection.documentStructure,
format
);
}
}
}
@@ -177,17 +202,6 @@ export async function archiveCollections(collections: Collection[]) {
return archiveToPath(zip);
}
export type FileTreeNode = {
/** The title, extracted from the file name */
title: string;
/** The file name including extension */
name: string;
/** The full path to within the zip file */
path: string;
/** The nested children */
children: FileTreeNode[];
};
/**
* Converts the flat structure returned by JSZIP into a nested file structure
* for easier processing.