From fd6e0a69aadbfe170de2202c6679f6581ff006cd Mon Sep 17 00:00:00 2001 From: KishenKumarrrrr Date: Thu, 8 Feb 2024 15:35:31 +0800 Subject: [PATCH] feat: add endpoint in backend to upload file --- .../middlewares/file-attachment.middleware.ts | 35 +++++++++++++++++++ .../core/routes/common-attachment.routes.ts | 8 +++++ frontend/src/services/upload.service.ts | 14 ++++---- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/backend/src/core/middlewares/file-attachment.middleware.ts b/backend/src/core/middlewares/file-attachment.middleware.ts index 62d4f1818..a0e7d7baf 100644 --- a/backend/src/core/middlewares/file-attachment.middleware.ts +++ b/backend/src/core/middlewares/file-attachment.middleware.ts @@ -14,6 +14,8 @@ import { configureEndpoint } from '@core/utils/aws-endpoint' import { CommonAttachment } from '@email/models/common-attachment' import { v4 as uuidv4 } from 'uuid' import { Readable } from 'stream' +import axios from 'axios' +import { UploadService } from '@core/services' const TOTAL_ATTACHMENT_SIZE_LIMIT = config.get( 'file.maxCumulativeAttachmentsSize' @@ -156,6 +158,38 @@ async function streamCampaignEmbed( return res } +async function uploadFileToPresignedUrl( + req: Request, + res: Response +): Promise { + // 1. Get uploaded file from request + const uploadedFile = req.files?.file as fileUpload.UploadedFile + if (!uploadedFile) { + return res + } + // 2. Get presigned URL for file upload + const { presignedUrl, signedKey } = await UploadService.getUploadParameters( + uploadedFile.mimetype + ) + try { + // 3. Upload file to presigned URL + const response = await axios.put(presignedUrl, uploadedFile, { + headers: { + 'Content-Type': uploadedFile.mimetype, + }, + withCredentials: false, + timeout: 30 * 1000, // 30 Seconds + }) + // 4. Return the etag and transactionId to the FE + return res.json({ + etag: response.headers.etag, + transactionId: signedKey, + }) + } catch (err) { + return res.status(500).json({ error: err }) + } +} + export const FileAttachmentMiddleware = { checkAttachmentValidity, getFileUploadHandler, @@ -163,4 +197,5 @@ export const FileAttachmentMiddleware = { transformAttachmentsFieldToArray, storeCampaignEmbed, streamCampaignEmbed, + uploadFileToPresignedUrl, } diff --git a/backend/src/core/routes/common-attachment.routes.ts b/backend/src/core/routes/common-attachment.routes.ts index bf410ae99..93b88746e 100644 --- a/backend/src/core/routes/common-attachment.routes.ts +++ b/backend/src/core/routes/common-attachment.routes.ts @@ -6,6 +6,7 @@ import { } from '@core/middlewares' import { Joi, Segments, celebrate } from 'celebrate' import { Router } from 'express' +import fileUpload from 'express-fileupload' export const InitCommonAttachmentRoute = ( authMiddleware: AuthMiddleware @@ -35,6 +36,13 @@ export const InitCommonAttachmentRoute = ( FileAttachmentMiddleware.storeCampaignEmbed ) + router.post( + '/csv-upload', + authMiddleware.getAuthMiddleware([AuthType.Cookie]), + fileUpload(), + FileAttachmentMiddleware.uploadFileToPresignedUrl + ) + router.get( '/:attachmentId/:fileName', celebrate({ diff --git a/frontend/src/services/upload.service.ts b/frontend/src/services/upload.service.ts index 201742ef2..d85128685 100644 --- a/frontend/src/services/upload.service.ts +++ b/frontend/src/services/upload.service.ts @@ -63,19 +63,17 @@ async function getMd5(blob: Blob): Promise { export async function uploadFileWithPresignedUrl( uploadedFile: File, - presignedUrl: string + _presignedUrl: string // Making this unused because the endpoint below generates its own presignedUrl and uploads the file ): Promise { try { - const md5 = await getMd5(uploadedFile) - const response = await axios.put(presignedUrl, uploadedFile, { + const formData = new FormData() + formData.append('file', uploadedFile) + const response = await axios.post(`/attachments/csv-upload`, formData, { headers: { - 'Content-Type': uploadedFile.type, - 'Content-MD5': md5, + 'Content-Type': 'multipart/form-data', }, - withCredentials: false, - timeout: 0, }) - return response.headers.etag + return response.data.etag } catch (e) { errorHandler( e,