From ca319a66979c9d792539f2ecd8a91b5b9a1173c3 Mon Sep 17 00:00:00 2001 From: PLJNS Date: Thu, 26 Oct 2023 21:20:57 -0400 Subject: [PATCH] 2.5.7 admin api for updating banner --- src/admin/admin.controller.ts | 95 +++++++++++++++++++++++++++++ src/moa-square/moa-square.module.ts | 2 +- 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/admin/admin.controller.ts b/src/admin/admin.controller.ts index 840c969b..6d7ca0ff 100644 --- a/src/admin/admin.controller.ts +++ b/src/admin/admin.controller.ts @@ -1,16 +1,25 @@ import { + BadRequestException, Body, Controller, HttpCode, HttpStatus, + Inject, + InternalServerErrorException, Logger, Post, Query, + UploadedFile, UseGuards, + UseInterceptors, } from '@nestjs/common'; +import { type ConfigType } from '@nestjs/config'; import { AuthGuard } from '@nestjs/passport'; +import { FileInterceptor } from '@nestjs/platform-express'; import { ApiBearerAuth, + ApiBody, + ApiConsumes, ApiOkResponse, ApiOperation, ApiQuery, @@ -18,10 +27,14 @@ import { ApiTags, ApiUnauthorizedResponse, } from '@nestjs/swagger'; +import { InjectS3, type S3 } from 'nestjs-s3'; +import path from 'path'; import { ApiKeyAuthGuard } from '../authentication/apikey-auth.guard.js'; import { AuthenticationService } from '../authentication/authentication.service.js'; import { AuthenticationEmailLoginRequestBody } from '../authentication/dto/authentication-email-login.dto.js'; import { AuthenticationResponse } from '../authentication/types/authentication-response.type.js'; +import { AwsS3Config } from '../configs/aws-s3.config.js'; +import { AppConfigService } from '../moa-square/services/app-config.service.js'; import { MerchantsSquareService } from '../moa-square/services/merchants.square.service.js'; import { ErrorResponse } from '../utils/error-response.js'; import { AdministratorsGuard } from './administrators.guard.js'; @@ -38,6 +51,11 @@ export class AdminController { constructor( private readonly authenticationService: AuthenticationService, private readonly merchantsSquareService: MerchantsSquareService, + private readonly appConfigService: AppConfigService, + @InjectS3() + private readonly s3: S3, + @Inject(AwsS3Config.KEY) + protected awsS3Config: ConfigType, ) { this.logger.verbose(this.constructor.name); } @@ -78,4 +96,81 @@ export class AdminController { merchantId, }); } + + @ApiBearerAuth() + @UseGuards(AuthGuard('jwt'), AdministratorsGuard) + @ApiUnauthorizedResponse({ + description: 'You need to be authenticated to access this endpoint.', + type: ErrorResponse, + }) + @Post('banner/upload') + @ApiConsumes('multipart/form-data') + @ApiBody({ + schema: { + type: 'object', + properties: { + file: { + type: 'string', + format: 'binary', + }, + }, + }, + }) + @UseInterceptors(FileInterceptor('file')) + @ApiOperation({ summary: 'Upload banner', operationId: 'postBannerUpload' }) + @ApiQuery({ name: 'merchantId', required: true, type: String }) + async postBannerUpload( + @Query('merchantId') merchantId: string, + @UploadedFile() file: Express.Multer.File, + ) { + this.logger.verbose(this.postBannerUpload.name); + + const fileExtension = path.extname(file.originalname).toLowerCase(); + let contentType: string; + + if (fileExtension === '.jpg' || fileExtension === '.jpeg') { + contentType = 'image/jpeg'; + } else if (fileExtension === '.png') { + contentType = 'image/png'; + } else { + throw new BadRequestException('Invalid file type'); // You can customize this message + } + + let appConfig = await this.appConfigService.findOne({ + where: { merchantId }, + }); + + if (!appConfig) { + appConfig = this.appConfigService.create({ + merchantId, + }); + } + + const sanitizedFilename = file.originalname.replace(/[^\w\s.-]/g, '_'); + const key = `${encodeURIComponent(Date.now())}-${encodeURIComponent( + sanitizedFilename, + )}`; + + const { defaultBucket, region } = this.awsS3Config; + + try { + await this.s3.putObject({ + Bucket: defaultBucket, + Key: key, + Body: file.buffer, + ContentType: contentType, + ContentDisposition: 'inline', + }); + } catch (error) { + this.logger.error(error); + throw new InternalServerErrorException(error); + } + + appConfig.bannerFileKey = key; + appConfig.bannerFileFullUrl = `https://${defaultBucket}.s3.${region}.amazonaws.com/${key}`; + appConfig.bannerFileDisplayName = file.originalname; + appConfig.bannerFileContentType = contentType; + + return this.appConfigService.save(appConfig); + } } diff --git a/src/moa-square/moa-square.module.ts b/src/moa-square/moa-square.module.ts index 0fcf291a..3eac0e4e 100644 --- a/src/moa-square/moa-square.module.ts +++ b/src/moa-square/moa-square.module.ts @@ -100,7 +100,7 @@ import { VariationsService } from './services/variations.service.js'; LineItemModifierEntity, ]), ], - exports: [MerchantsSquareService], + exports: [MerchantsSquareService, AppConfigService], providers: [ CatalogsService, ItemsService,