feat: Bulk HTML export (#4620)
* wip * Working bulk html export * Refactor * test * test
This commit is contained in:
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user