diff --git a/src/file/file.controller.ts b/src/file/file.controller.ts index e09539f..5799bcc 100644 --- a/src/file/file.controller.ts +++ b/src/file/file.controller.ts @@ -14,10 +14,13 @@ import { getFile, updateFile, uploadDone, + uploadDoneBatch, } from "./file.service"; import { CreateFileInput, + CreateFilesBatch, UpdateFileInput, + UploadDoneBatchInput, UploadMultiPartCompleteRequest, } from "./file.schema"; @@ -43,6 +46,31 @@ export async function createFileHandler( } } +export async function createFileBatchHandler( + req: FastifyRequest, + res: FastifyReply +) { + const input = req.body as CreateFilesBatch; + const resObj = []; + + try { + for (const file of input.files) { + const newFile = (await createFile(file, req.user)).toObject(); + + if (newFile.mimeType != "folder") { + const signedUrl = await getUploadUrl(newFile.pid); + newFile["signedUrl"] = signedUrl; + } + + resObj.push({ ...newFile }); + } + + return res.code(201).send(resObj); + } catch (err) { + return err; + } +} + export async function uploadDoneHandler( req: FastifyRequest, res: FastifyReply @@ -57,6 +85,20 @@ export async function uploadDoneHandler( } } +export async function uploadDoneBatchHandler( + req: FastifyRequest, + res: FastifyReply +) { + const input = req.body as UploadDoneBatchInput; + + try { + const updateRes = await uploadDoneBatch(input, req.user); + return res.code(200).send(); + } catch (err) { + return err; + } +} + export async function getFileHandler(req: FastifyRequest, res: FastifyReply) { const { fileId } = req.params as { fileId: string }; diff --git a/src/file/file.route.ts b/src/file/file.route.ts index c67d605..1286257 100644 --- a/src/file/file.route.ts +++ b/src/file/file.route.ts @@ -1,5 +1,6 @@ import { FastifyInstance } from "fastify"; import { + createFileBatchHandler, createFileHandler, deleteFileHandler, fileDownloadHandler, @@ -8,6 +9,7 @@ import { getChildrenHandler, getFileHandler, updateFileHandler, + uploadDoneBatchHandler, uploadDoneHandler, } from "./file.controller"; import { $file } from "./file.schema"; @@ -37,6 +39,30 @@ export async function fileRoutes(fastify: FastifyInstance) { uploadDoneHandler ); + fastify.post( + "/createBatch", + { + schema: { + body: $file("createFileBatch"), + }, + config: { requiredClaims: ["file:upload"] }, + preHandler: [fastify.authorize], + }, + createFileBatchHandler + ); + + fastify.post( + "/doneBatch", + { + schema: { + body: $file("uploadDoneBatchInput"), + }, + config: { requiredClaims: ["file:upload"] }, + preHandler: [fastify.authorize], + }, + uploadDoneBatchHandler + ); + fastify.get( "/:fileId", { diff --git a/src/file/file.schema.ts b/src/file/file.schema.ts index c698d64..df86a2b 100644 --- a/src/file/file.schema.ts +++ b/src/file/file.schema.ts @@ -47,6 +47,12 @@ const updateFileInput = z.object({ root: z.boolean().optional(), }); +const createFileBatch = z.object({ + files: z.array(createFileInput), +}); + +const uploadDoneBatchInput = z.array(z.string()); + const downloadFileResponse = z.object({ url: z.string().url(), }); @@ -95,12 +101,16 @@ export type UploadMultiPartCompleteRequest = z.infer< export type CreateFileInput = z.infer; export type UpdateFileInput = z.infer; +export type CreateFilesBatch = z.infer; +export type UploadDoneBatchInput = z.infer; export const { schemas: fileSchemas, $ref: $file } = buildJsonSchemas( { createFileInput, updateFileInput, downloadFileResponse, + createFileBatch, + uploadDoneBatchInput, uploadMultipartCompleteRequest, }, { $id: "file" } diff --git a/src/file/file.service.ts b/src/file/file.service.ts index f629c8e..787d669 100644 --- a/src/file/file.service.ts +++ b/src/file/file.service.ts @@ -1,7 +1,13 @@ import { AuthenticatedUser } from "../auth"; import { generateId } from "../utils/id"; import { deleteFileS3 } from "../utils/s3"; -import { CreateFileInput, fileModel, UpdateFileInput } from "./file.schema"; +import { + CreateFileInput, + CreateFilesBatch, + fileModel, + UpdateFileInput, + UploadDoneBatchInput, +} from "./file.schema"; export const ErrNotFound = "not_found"; export const ParentNotFound = "parent_not_found"; @@ -45,6 +51,18 @@ export async function uploadDone(fileId: string, tenantId: string) { ); } +export async function uploadDoneBatch( + input: UploadDoneBatchInput, + user: AuthenticatedUser +) { + return await fileModel.updateMany( + { + $and: [{ tenantId: user.tenantId }, { pid: { $in: input } }], + }, + { status: "done" } + ); +} + export async function getFile(fileId: string, tenantId: string) { return await fileModel.findOne({ $and: [{ tenantId: tenantId }, { pid: fileId }, { isDeleted: false }], diff --git a/src/utils/s3.ts b/src/utils/s3.ts index e02d1a2..3a33d68 100644 --- a/src/utils/s3.ts +++ b/src/utils/s3.ts @@ -36,7 +36,7 @@ export async function getUploadUrl(key: string) { Key: key, }); - return await getSignedUrl(client, command, { expiresIn: 300 }); + return await getSignedUrl(client, command, { expiresIn: 600 }); } export async function getUploadUrlMultiPart(key: string, fileSize: number) {