From 415e770228f4e0834aa9112e00021c3ce631b8ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sat, 28 Dec 2024 20:08:38 +0700 Subject: [PATCH 01/15] update: setup cloudinary & multer package --- backend/package.json | 4 +++ backend/pnpm-lock.yaml | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/backend/package.json b/backend/package.json index 4ee5e31..e2b661e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -29,10 +29,13 @@ "axios": "1.7.9", "class-transformer": "0.5.1", "class-validator": "0.14.1", + "cloudinary": "2.5.1", "date-fns": "4.1.0", "module-alias": "2.2.3", "mongoose": "8.9.1", "morgan": "1.10.0", + "multer": "1.4.5-lts.1", + "multer-storage-cloudinary": "4.0.0", "nodemailer": "6.9.16", "passport": "0.7.0", "passport-jwt": "4.0.1", @@ -46,6 +49,7 @@ "@trivago/prettier-plugin-sort-imports": "4.3.0", "@types/express": "4.17.21", "@types/morgan": "1.9.9", + "@types/multer": "1.4.12", "@types/node": "20.16.7", "@types/passport-jwt": "4.0.1", "@types/passport-local": "1.0.38", diff --git a/backend/pnpm-lock.yaml b/backend/pnpm-lock.yaml index ada2abe..bbd751f 100644 --- a/backend/pnpm-lock.yaml +++ b/backend/pnpm-lock.yaml @@ -47,6 +47,9 @@ importers: class-validator: specifier: 0.14.1 version: 0.14.1 + cloudinary: + specifier: 2.5.1 + version: 2.5.1 date-fns: specifier: 4.1.0 version: 4.1.0 @@ -59,6 +62,12 @@ importers: morgan: specifier: 1.10.0 version: 1.10.0 + multer: + specifier: 1.4.5-lts.1 + version: 1.4.5-lts.1 + multer-storage-cloudinary: + specifier: 4.0.0 + version: 4.0.0(cloudinary@2.5.1) nodemailer: specifier: 6.9.16 version: 6.9.16 @@ -93,6 +102,9 @@ importers: '@types/morgan': specifier: 1.9.9 version: 1.9.9 + '@types/multer': + specifier: 1.4.12 + version: 1.4.12 '@types/node': specifier: 20.16.7 version: 20.16.7 @@ -492,6 +504,9 @@ packages: '@types/morgan@1.9.9': resolution: {integrity: sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ==} + '@types/multer@1.4.12': + resolution: {integrity: sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==} + '@types/node@20.16.7': resolution: {integrity: sha512-QkDQjAY3gkvJNcZOWwzy3BN34RweT0OQ9zJyvLCU0kSK22dO2QYh/NHGfbEAYylPYzRB1/iXcojS79wOg5gFSw==} @@ -867,6 +882,10 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + cloudinary@2.5.1: + resolution: {integrity: sha512-CNg6uU53Hl4FEVynkTGpt5bQEAQWDHi3H+Sm62FzKf5uQHipSN2v7qVqS8GRVqeb0T1WNV+22+75DOJeRXYeSQ==} + engines: {node: '>=9'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1654,10 +1673,19 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + multer-storage-cloudinary@4.0.0: + resolution: {integrity: sha512-25lm9R6o5dWrHLqLvygNX+kBOxprzpmZdnVKH4+r68WcfCt8XV6xfQaMuAg+kUE5Xmr8mJNA4gE0AcBj9FJyWA==} + peerDependencies: + cloudinary: ^1.21.0 + multer@1.4.4-lts.1: resolution: {integrity: sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==} engines: {node: '>= 6.0.0'} + multer@1.4.5-lts.1: + resolution: {integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==} + engines: {node: '>= 6.0.0'} + mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} @@ -1857,6 +1885,14 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + q@1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + deprecated: |- + You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. + + (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) + qs@6.13.0: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} @@ -2760,6 +2796,10 @@ snapshots: dependencies: '@types/node': 20.16.7 + '@types/multer@1.4.12': + dependencies: + '@types/express': 4.17.21 + '@types/node@20.16.7': dependencies: undici-types: 6.19.8 @@ -3214,6 +3254,11 @@ snapshots: clone@1.0.4: {} + cloudinary@2.5.1: + dependencies: + lodash: 4.17.21 + q: 1.5.1 + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -4007,6 +4052,10 @@ snapshots: ms@2.1.3: {} + multer-storage-cloudinary@4.0.0(cloudinary@2.5.1): + dependencies: + cloudinary: 2.5.1 + multer@1.4.4-lts.1: dependencies: append-field: 1.0.0 @@ -4017,6 +4066,16 @@ snapshots: type-is: 1.6.18 xtend: 4.0.2 + multer@1.4.5-lts.1: + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 1.6.2 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + mute-stream@0.0.8: {} mute-stream@1.0.0: {} @@ -4178,6 +4237,8 @@ snapshots: punycode@2.3.1: {} + q@1.5.1: {} + qs@6.13.0: dependencies: side-channel: 1.1.0 From 5a447abe755d9a35ba0247b7fd20158861546de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 09:37:45 +0700 Subject: [PATCH 02/15] add: cloudinary config --- .../src/domains/upload/config/cloudinary.config.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 backend/src/domains/upload/config/cloudinary.config.ts diff --git a/backend/src/domains/upload/config/cloudinary.config.ts b/backend/src/domains/upload/config/cloudinary.config.ts new file mode 100644 index 0000000..50516f5 --- /dev/null +++ b/backend/src/domains/upload/config/cloudinary.config.ts @@ -0,0 +1,12 @@ +import { ConfigService } from '@nestjs/config'; +import { v2 as cloudinary } from 'cloudinary'; + +export const configureCloudinary = (configService: ConfigService) => { + cloudinary.config({ + cloud_name: configService.get('CLOUDINARY_CLOUD_NAME'), + api_key: configService.get('CLOUDINARY_API_KEY'), + api_secret: configService.get('CLOUDINARY_API_SECRET'), + }); +}; + +export { cloudinary }; From 7bf795ba4e8aab25a86cd1310fd0dac2acdb890b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 09:38:43 +0700 Subject: [PATCH 03/15] add: multer config --- .../src/domains/upload/config/multer.config.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 backend/src/domains/upload/config/multer.config.ts diff --git a/backend/src/domains/upload/config/multer.config.ts b/backend/src/domains/upload/config/multer.config.ts new file mode 100644 index 0000000..00855dd --- /dev/null +++ b/backend/src/domains/upload/config/multer.config.ts @@ -0,0 +1,15 @@ +import * as multer from 'multer'; + +export const multerOptions = { + storage: multer.memoryStorage(), + limits: { + fileSize: 5 * 1024 * 1024, + }, + fileFilter: (req, file, cb) => { + if (!file.mimetype.match(/\/(jpg|jpeg|png|gif)$/)) { + cb(new Error('Only image files are allowed!'), false); + } else { + cb(null, true); + } + }, +}; From e9c023c0c9af4b9c828e17c6ce5c56ac7f01e6db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 09:39:21 +0700 Subject: [PATCH 04/15] add: setup upload module --- backend/src/domains/domains.module.ts | 2 + .../src/domains/upload/upload.controller.ts | 61 +++++++++++++++++++ backend/src/domains/upload/upload.module.ts | 11 ++++ backend/src/domains/upload/upload.service.ts | 40 ++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 backend/src/domains/upload/upload.controller.ts create mode 100644 backend/src/domains/upload/upload.module.ts create mode 100644 backend/src/domains/upload/upload.service.ts diff --git a/backend/src/domains/domains.module.ts b/backend/src/domains/domains.module.ts index e660476..ca0097b 100644 --- a/backend/src/domains/domains.module.ts +++ b/backend/src/domains/domains.module.ts @@ -9,6 +9,7 @@ import { NotifiesModule } from '@/domains/notifies/notifies.module'; import { PartiesModule } from '@/domains/parties/parties.module'; import { PaymentsModule } from '@/domains/payments/payments.module'; import { ReviewsModule } from '@/domains/reviews/reviews.module'; +import { UploadModule } from '@/domains/upload/upload.module'; import { UsersModule } from '@/domains/users/users.module'; import { VouchersModule } from '@/domains/vouchers/vouchers.module'; @@ -21,6 +22,7 @@ import { VouchersModule } from '@/domains/vouchers/vouchers.module'; PaymentsModule, ReviewsModule, UsersModule, + UploadModule, VouchersModule, ], providers: [ diff --git a/backend/src/domains/upload/upload.controller.ts b/backend/src/domains/upload/upload.controller.ts new file mode 100644 index 0000000..e08016f --- /dev/null +++ b/backend/src/domains/upload/upload.controller.ts @@ -0,0 +1,61 @@ +import { + BadRequestException, + Controller, + Post, + UploadedFiles, + UseInterceptors, +} from '@nestjs/common'; +import { FilesInterceptor } from '@nestjs/platform-express'; +import { ApiBearerAuth, ApiBody, ApiConsumes, ApiTags } from '@nestjs/swagger'; + +import { multerOptions } from '@/domains/upload/config/multer.config'; +import { UploadService } from '@/domains/upload/upload.service'; + +@ApiTags('Upload') +@ApiBearerAuth() +@Controller('upload') +export class UploadController { + constructor(private readonly uploadService: UploadService) {} + + @Post() + @ApiConsumes('multipart/form-data') + @ApiBody({ + description: 'File upload (only image files are allowed)', + schema: { + type: 'object', + properties: { + files: { + type: 'array', + items: { + type: 'string', + format: 'binary', + }, + }, + }, + }, + }) + @UseInterceptors(FilesInterceptor('files', 20, multerOptions)) + async uploadFiles(@UploadedFiles() files: Express.Multer.File[]) { + if (!files || files.length === 0) { + throw new BadRequestException('At least one file is required'); + } + + try { + const uploadResults = await Promise.all( + files.map((file) => this.uploadService.uploadImage(file)), + ); + + return { + message: 'Files uploaded successfully', + uploads: uploadResults.map((result) => ({ + url: result.secure_url, + public_id: result.public_id, + })), + }; + } catch (error) { + throw new BadRequestException( + `Failed to upload files: ${error.message || 'Unknown error'}`, + ); + } + } +} diff --git a/backend/src/domains/upload/upload.module.ts b/backend/src/domains/upload/upload.module.ts new file mode 100644 index 0000000..a38edb2 --- /dev/null +++ b/backend/src/domains/upload/upload.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; + +import { UploadController } from '@/domains/upload/upload.controller'; +import { UploadService } from '@/domains/upload/upload.service'; + +@Module({ + controllers: [UploadController], + providers: [UploadService], + exports: [UploadService], +}) +export class UploadModule {} diff --git a/backend/src/domains/upload/upload.service.ts b/backend/src/domains/upload/upload.service.ts new file mode 100644 index 0000000..d668ad3 --- /dev/null +++ b/backend/src/domains/upload/upload.service.ts @@ -0,0 +1,40 @@ +import { Injectable, Logger } from '@nestjs/common'; + +import { cloudinary } from '@/domains/upload/config/cloudinary.config'; + +@Injectable() +export class UploadService { + private readonly logger = new Logger(UploadService.name); + + async uploadImage(file: Express.Multer.File): Promise { + try { + const result = await new Promise((resolve, reject) => { + const uploadStream = cloudinary.uploader.upload_stream( + { folder: process.env.CLOUDINARY_FOLDER_STORAGE || 'default_folder' }, + (error, result) => { + if (error) { + this.logger.error( + `Error uploading image to Cloudinary: ${error.message}`, + error.stack, + ); + reject(error); + } else { + this.logger.log('Image uploaded to Cloudinary successfully'); + resolve(result); + } + }, + ); + + uploadStream.end(file.buffer); + }); + + return result; + } catch (error) { + this.logger.error( + `Error uploading image to Cloudinary: ${error.message}`, + error.stack, + ); + throw error; + } + } +} From cecb47ddeeecce723c50e382f2337adff2dbaaf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 09:41:51 +0700 Subject: [PATCH 05/15] update: cloudinary config to app module --- backend/src/app.module.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index f40f21f..ae235bc 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -5,6 +5,7 @@ import { MongooseModule } from '@nestjs/mongoose'; import corsConfig from '@/config/cors.config'; import jwtConfig from '@/domains/auth/config/jwt.config'; import { DomainsModule } from '@/domains/domains.module'; +import { configureCloudinary } from '@/domains/upload/config/cloudinary.config'; import { MorganMiddleware } from '@/middlewares/morgan.middleware'; @Module({ @@ -24,4 +25,8 @@ export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(MorganMiddleware).forRoutes('*'); } + + constructor(private configService: ConfigService) { + configureCloudinary(this.configService); + } } From 1e24be6b7e917377067128021167cc6ae63c43f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 09:42:24 +0700 Subject: [PATCH 06/15] update: api version to 1.4.0 --- backend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/package.json b/backend/package.json index e2b661e..d6e0039 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "evora-backend", - "version": "1.3.2", + "version": "1.4.0", "description": "Evora connects customers with event organizers quickly through detailed online booking.", "repository": "https://github.com/bakaqc/evora-17c", "author": "Quốc Chương", From c1fb8ad8203a29438e4d919726667dd1ea216b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 10:00:28 +0700 Subject: [PATCH 07/15] update: user schema --- backend/src/schemas/user.schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/schemas/user.schema.ts b/backend/src/schemas/user.schema.ts index ee493bb..efedf36 100644 --- a/backend/src/schemas/user.schema.ts +++ b/backend/src/schemas/user.schema.ts @@ -23,7 +23,7 @@ export class User { @Prop({ required: true }) gender: 'male' | 'female'; - @Prop({ required: true }) + @Prop({ required: false, default: () => process.env.AVATAR_DEFAULT }) avatar: string; @Prop({ required: true, default: 'user' }) From a5de029bee416aee3666ef523ecffbb2e18e7a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 10:02:04 +0700 Subject: [PATCH 08/15] update: user create dto --- backend/src/domains/users/dto/createUser.dto.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/backend/src/domains/users/dto/createUser.dto.ts b/backend/src/domains/users/dto/createUser.dto.ts index f5b35c4..7afa981 100644 --- a/backend/src/domains/users/dto/createUser.dto.ts +++ b/backend/src/domains/users/dto/createUser.dto.ts @@ -43,9 +43,4 @@ export class CreateUserDto { @IsIn(['male', 'female']) @IsNotEmpty() gender: string; - - @ApiProperty({ description: 'User avatar' }) - @IsString() - @IsNotEmpty() - avatar: string; } From ced7062aac384ca922172116d7b6e7ac1c56b5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 10:02:39 +0700 Subject: [PATCH 09/15] update: auth service --- backend/src/domains/auth/auth.service.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/src/domains/auth/auth.service.ts b/backend/src/domains/auth/auth.service.ts index fe260ac..e887e5f 100644 --- a/backend/src/domains/auth/auth.service.ts +++ b/backend/src/domains/auth/auth.service.ts @@ -37,6 +37,15 @@ export class AuthService { async login(user: any) { const payload = { email: user.email, role: user.role, sub: user._id }; + + const findUser = await this.userModel.findOne({ email: user.email }); + + if (!findUser.isVerified) { + throw new UnauthorizedException( + 'Your account is not verified. Please verify your email.', + ); + } + return { access_token: this.jwtService.sign(payload), }; From 9f9efc0984da46480792bded1c6c887988bc8003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 10:03:20 +0700 Subject: [PATCH 10/15] update: otp service --- backend/src/domains/auth/otp.service.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/domains/auth/otp.service.ts b/backend/src/domains/auth/otp.service.ts index f735582..fc4645e 100644 --- a/backend/src/domains/auth/otp.service.ts +++ b/backend/src/domains/auth/otp.service.ts @@ -98,6 +98,9 @@ export class OtpService { user.verificationCode = null; user.verificationCodeExpires = null; + if (!user.isVerified) { + user.isVerified = true; + } await user.save(); From 24542d17f5878eaa8e2c49e993cf8a1269da2ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 10:03:43 +0700 Subject: [PATCH 11/15] update: api version to 1.4.1 --- backend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/package.json b/backend/package.json index d6e0039..a5ec672 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "evora-backend", - "version": "1.4.0", + "version": "1.4.1", "description": "Evora connects customers with event organizers quickly through detailed online booking.", "repository": "https://github.com/bakaqc/evora-17c", "author": "Quốc Chương", From 446166b94d4e85bafba15d9c47a7e51039bd91b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 10:14:23 +0700 Subject: [PATCH 12/15] fix: sonarcloud issue --- backend/src/app.module.ts | 2 +- backend/src/domains/upload/upload.service.ts | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index ae235bc..332bc47 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -26,7 +26,7 @@ export class AppModule implements NestModule { consumer.apply(MorganMiddleware).forRoutes('*'); } - constructor(private configService: ConfigService) { + constructor(private readonly configService: ConfigService) { configureCloudinary(this.configService); } } diff --git a/backend/src/domains/upload/upload.service.ts b/backend/src/domains/upload/upload.service.ts index d668ad3..d65443c 100644 --- a/backend/src/domains/upload/upload.service.ts +++ b/backend/src/domains/upload/upload.service.ts @@ -6,28 +6,27 @@ import { cloudinary } from '@/domains/upload/config/cloudinary.config'; export class UploadService { private readonly logger = new Logger(UploadService.name); - async uploadImage(file: Express.Multer.File): Promise { + async uploadImage(file: Express.Multer.File) { try { const result = await new Promise((resolve, reject) => { const uploadStream = cloudinary.uploader.upload_stream( { folder: process.env.CLOUDINARY_FOLDER_STORAGE || 'default_folder' }, (error, result) => { if (error) { - this.logger.error( + const err = new Error( `Error uploading image to Cloudinary: ${error.message}`, - error.stack, ); - reject(error); + + this.logger.error(err.message, error.stack); + reject(err); } else { this.logger.log('Image uploaded to Cloudinary successfully'); resolve(result); } }, ); - uploadStream.end(file.buffer); }); - return result; } catch (error) { this.logger.error( From d0805add15688ba562e6a6674bad42612b577ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 10:15:05 +0700 Subject: [PATCH 13/15] update: api version to 1.4.2 --- backend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/package.json b/backend/package.json index a5ec672..e654180 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "evora-backend", - "version": "1.4.1", + "version": "1.4.2", "description": "Evora connects customers with event organizers quickly through detailed online booking.", "repository": "https://github.com/bakaqc/evora-17c", "author": "Quốc Chương", From 656f8ec023dc60f4b38cad981b850779f5af00a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 10:18:29 +0700 Subject: [PATCH 14/15] fix: err build backend --- backend/src/domains/upload/upload.service.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/domains/upload/upload.service.ts b/backend/src/domains/upload/upload.service.ts index d65443c..6e4120a 100644 --- a/backend/src/domains/upload/upload.service.ts +++ b/backend/src/domains/upload/upload.service.ts @@ -6,7 +6,7 @@ import { cloudinary } from '@/domains/upload/config/cloudinary.config'; export class UploadService { private readonly logger = new Logger(UploadService.name); - async uploadImage(file: Express.Multer.File) { + async uploadImage(file: Express.Multer.File): Promise { try { const result = await new Promise((resolve, reject) => { const uploadStream = cloudinary.uploader.upload_stream( @@ -16,7 +16,6 @@ export class UploadService { const err = new Error( `Error uploading image to Cloudinary: ${error.message}`, ); - this.logger.error(err.message, error.stack); reject(err); } else { From 6dfa0e73f6ffebe1750c6d8513b47dad0f7854e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Ch=C6=B0=C6=A1ng?= Date: Sun, 29 Dec 2024 10:18:54 +0700 Subject: [PATCH 15/15] update: api version to 1.4.3 --- backend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/package.json b/backend/package.json index e654180..ca184b2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "evora-backend", - "version": "1.4.2", + "version": "1.4.3", "description": "Evora connects customers with event organizers quickly through detailed online booking.", "repository": "https://github.com/bakaqc/evora-17c", "author": "Quốc Chương",