refactor: Upload file to storage, and then pass attachmentId to collections.import

This avoids having large file uploads going directly to the server and allows us to fetch it async into a worker process
This commit is contained in:
Tom Moor
2021-02-18 22:36:07 -08:00
parent 568e271738
commit df233c95a9
12 changed files with 70 additions and 54 deletions

View File

@@ -38,7 +38,7 @@ router.post("attachments.create", auth(), async (ctx) => {
const key = `${bucket}/${user.id}/${s3Key}/${name}`;
const credential = makeCredential();
const longDate = format(new Date(), "YYYYMMDDTHHmmss\\Z");
const policy = makePolicy(credential, longDate, acl);
const policy = makePolicy(credential, longDate, acl, contentType);
const endpoint = publicS3Endpoint();
const url = `${endpoint}/${key}`;
@@ -85,6 +85,7 @@ router.post("attachments.create", auth(), async (ctx) => {
documentId,
contentType,
name,
id: attachment.id,
url: attachment.redirectUrl,
size,
},

View File

@@ -1,8 +1,10 @@
// @flow
import fs from "fs";
import os from "os";
import File from "formidable/lib/file";
import Router from "koa-router";
import collectionImporter from "../commands/collectionImporter";
import { ValidationError, InvalidRequestError } from "../errors";
import { ValidationError } from "../errors";
import { exportCollections } from "../logistics";
import auth from "../middlewares/authentication";
import {
@@ -13,6 +15,7 @@ import {
Event,
User,
Group,
Attachment,
} from "../models";
import policy from "../policies";
import {
@@ -100,23 +103,27 @@ router.post("collections.info", auth(), async (ctx) => {
});
router.post("collections.import", auth(), async (ctx) => {
const { type } = ctx.body;
const { type, attachmentId } = ctx.body;
ctx.assertIn(type, ["outline"], "type must be one of 'outline'");
if (!ctx.is("multipart/form-data")) {
throw new InvalidRequestError("Request type must be multipart/form-data");
}
const file: any = Object.values(ctx.request.files)[0];
ctx.assertPresent(file, "file is required");
if (file.type !== "application/zip") {
throw new InvalidRequestError("File type must be a zip");
}
ctx.assertUuid(attachmentId, "attachmentId is required");
const user = ctx.state.user;
authorize(user, "import", Collection);
const attachment = await Attachment.findByPk(attachmentId);
authorize(user, "read", attachment);
const buffer = await attachment.buffer;
const tmpDir = os.tmpdir();
const tmpFilePath = `${tmpDir}/upload-${attachmentId}`;
await fs.promises.writeFile(tmpFilePath, buffer);
const file = new File({
name: attachment.name,
type: attachment.type,
path: tmpFilePath,
});
const { documents, attachments, collections } = await collectionImporter({
file,
user,

View File

@@ -111,7 +111,7 @@ describe("#collections.list", () => {
});
describe("#collections.import", () => {
it("should error if no file is passed", async () => {
it("should error if no attachmentId is passed", async () => {
const user = await buildUser();
const res = await server.post("/api/collections.import", {
body: {