From ac8bdb73c8020973c485d6ac154f92a62e5a469c Mon Sep 17 00:00:00 2001 From: Andreas Date: Sun, 23 Jun 2024 23:02:33 +0200 Subject: [PATCH] Minor refactoring on the attachment api route --- src/app/api/attachment/route.ts | 109 ++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 42 deletions(-) diff --git a/src/app/api/attachment/route.ts b/src/app/api/attachment/route.ts index 18507e7..1f2488b 100644 --- a/src/app/api/attachment/route.ts +++ b/src/app/api/attachment/route.ts @@ -8,41 +8,48 @@ import { UUID, randomUUID } from "crypto"; import { mkdir, mkdirSync, writeFile } from "fs"; import { where } from "@sequelize/core"; +async function writeFilesToFS(uuid: UUID, files: any[]): Promise<{ success: boolean, filePaths: string[] }> { -async function writeFilesToBucket(uuid: UUID, files: any[]) { - - type FileArrayEntry = { - name:string; + type FileArrayEntryWithPromise = { + name: string; content: Promise> | ReadableStreamReadResult } + type FileArrayEntry = { + name: string; + content: ReadableStreamReadResult + }; - const fileArray:FileArrayEntry[] = await Promise.all(files.map((file: File) => { + // Resolve promises + const fileArray: FileArrayEntryWithPromise[] = await Promise.all(files.map((file: File) => { return { 'name': (() => file.name)(), 'content': file.stream().getReader().read() }; })); - let finalFileArray: { name: string, content: ReadableStreamReadResult }[] = await (async () => { - for (let file in fileArray) { - fileArray[file].content = await fileArray[file].content - } - return [...fileArray as { name: string, content: ReadableStreamReadResult }[]] - })(); - mkdirSync(`./bucket/${uuid}/`) + + let finalFileArray: FileArrayEntry[] = await ( + async () => { + for (let file in fileArray) { + fileArray[file].content = await fileArray[file].content + } + return [...fileArray as FileArrayEntry[]] + })(); + + // Make Bucket Directory + mkdirSync(`./bucket/${uuid}/`, { recursive: true }) + + // Write files to filesystem for (let file in finalFileArray) { - writeFile( - `./bucket/${uuid}/${finalFileArray[file].name}`, - Buffer.from(finalFileArray[file].content.value as Uint8Array), - (e) => { console.log(e) } - ); - const attachment = await Attachment.create( - { bucket_id: uuid, filename: finalFileArray[file].name }, - { include: Attachment.associations.bucket } - ); - console.log(attachment); + writeFile(`./bucket/${uuid}/${finalFileArray[file].name}` + , Buffer.from(finalFileArray[file].content.value as Uint8Array) + , (e) => { console.log(e) }); + } + return { + success: true, + filePaths: finalFileArray.map((e) => e.name) } } -async function addToPost(postid: number): Promise { +async function addToNewBucketForPost(postid: number): Promise { Post.sync(); const post = await Post.findOne({ where: { id: postid } }); @@ -50,9 +57,9 @@ async function addToPost(postid: number): Promise { const bucket = await post.createBucket({ id: randomUUID() }); return bucket; } -async function addToBucket(bucketid: number): Promise { - const bucket = await Bucket.findOne({ - where: { id: bucketid }, include: { association: Bucket.associations.posts } +async function addToExistingBucket(bucketid: number): Promise { + const bucket = await Bucket.findOne({ + where: { id: bucketid }, include: { association: Bucket.associations.posts } }); if (!bucket) throw new APIError({ status: 500, responseText: "invalid bucketid" }); return bucket; @@ -92,10 +99,11 @@ async function tryCreateAttachment(request: Request) { // Sanity check the auth and associated user for authorization - if (!auth || !auth.user) throw new APIError({ status: 401, responseText: "Authentication Error" }); - if (!auth.user.id) throw new APIError({ status: 500, responseText: "Missing user id" }); - if (!auth.user.perms || !auth.user.perms.isAdmin) - throw new APIError({ status: 401, responseText: `Unauthorized ${JSON.stringify(auth.user)}` }); + if (!auth + || !auth.user) throw new APIError({ status: 401, responseText: "Authentication Error" }); + if (!auth.user.id) throw new APIError({ status: 401, responseText: "Missing user id" }); + if (!auth.user.perms + || !auth.user.perms.isAdmin) throw new APIError({ status: 401, responseText: `Unauthorized` }); // Handle incomplete data or other problems if (!files) throw new APIError({ status: 500, responseText: "Missing file" }); if (!formData) throw new APIError({ status: 500, responseText: "Empty request body" }); @@ -103,23 +111,40 @@ async function tryCreateAttachment(request: Request) { if (!(typeof requestData == "string")) throw new APIError({ status: 500, responseText: "Malformed request data" }); - + // Parse JSON const data = JSON.parse(requestData); - let bucket:Bucket = (data.postid && !data.bucketid) ? await addToPost(data.postid) : await addToBucket(data.bucketid) - writeFilesToBucket(bucket.id, files); + // Get or create bucket + const bucket: Bucket = (data.postid && !data.bucketid) + ? await addToNewBucketForPost(data.postid) + : await addToExistingBucket(data.bucketid); + // Write files to bucket and store as attachments in DB + const writeResult = await writeFilesToFS(bucket.id, files); + // Handle failure + if (!writeResult.success) throw new APIError({ status: 500, responseText: "Error writing files to Bucket" }); - const bucket2 = await Bucket.findOne({ - where: { id: bucket.id }, - include: [Bucket.associations.posts, Bucket.associations.attachments] - }); - - - return new Response(JSON.stringify({ - bucket: bucket2 - }), { status: 200 }); + // Write attachments to db + const attachments = ((writeResult).filePaths.map(async (fp) => { + return (await Attachment.create( + { + bucket_id: bucket.id, + filename: fp + }, + { include: Attachment.associations.bucket } + )); + })) + attachments; + return new Response( + JSON.stringify({ + bucket: await Bucket.findOne({ + where: { id: bucket.id }, + include: [Bucket.associations.posts, Bucket.associations.attachments] + }) + }), + { status: 200 } + ); } export async function tryFetchAttachments(request: Request) {