From 8cb99ff9fc88a72d826176bce28d743f6e0136c9 Mon Sep 17 00:00:00 2001 From: Soap Date: Mon, 11 Nov 2024 15:39:50 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refatcor:=20=EC=9C=A0=EC=A0=80=20enum,=20ty?= =?UTF-8?q?pe=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/user/{user-role.ts => role.enum.ts} | 0 backend/src/user/{userType.ts => user.type.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename backend/src/user/{user-role.ts => role.enum.ts} (100%) rename backend/src/user/{userType.ts => user.type.ts} (100%) diff --git a/backend/src/user/user-role.ts b/backend/src/user/role.enum.ts similarity index 100% rename from backend/src/user/user-role.ts rename to backend/src/user/role.enum.ts diff --git a/backend/src/user/userType.ts b/backend/src/user/user.type.ts similarity index 100% rename from backend/src/user/userType.ts rename to backend/src/user/user.type.ts From ec3f1f61bc7bcb54c54124b1b889407770a0bfe9 Mon Sep 17 00:00:00 2001 From: Soap Date: Mon, 11 Nov 2024 16:28:33 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=EC=9E=A5=EC=86=8C=EC=97=90=20?= =?UTF-8?q?=EC=83=89=EC=83=81=20=EC=B6=94=EA=B0=80,=20=EB=A7=B5=EC=97=90?= =?UTF-8?q?=20=EC=9E=A5=EC=86=8C=20=EB=93=B1=EB=A1=9D=EC=8B=9C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20#86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/resources/sql/DDL.sql | 5 +++-- backend/src/map/dto/AddPlaceToMapRequest.ts | 6 +++++- backend/src/map/dto/MapDetailResponse.ts | 4 +++- backend/src/map/entity/map-place.entity.ts | 7 ++++++- backend/src/map/entity/map.entity.ts | 6 ++++-- backend/src/map/map.controller.ts | 7 ++++--- backend/src/map/map.service.ts | 8 +++++--- backend/src/place/color.enum.ts | 8 ++++++++ backend/src/user/dto/CreateUserRequest.ts | 2 +- 9 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 backend/src/place/color.enum.ts diff --git a/backend/resources/sql/DDL.sql b/backend/resources/sql/DDL.sql index 014abd29..0b0404b3 100644 --- a/backend/resources/sql/DDL.sql +++ b/backend/resources/sql/DDL.sql @@ -67,8 +67,9 @@ CREATE TABLE MAP_PLACE place_id INT NOT NULL, map_id INT NOT NULL, description TEXT, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + color VARCHAR(20) DEFAULT 'RED', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deleted_at TIMESTAMP NULL, FOREIGN KEY (place_id) REFERENCES PLACE (id) ON DELETE CASCADE, FOREIGN KEY (map_id) REFERENCES MAP (id) ON DELETE CASCADE diff --git a/backend/src/map/dto/AddPlaceToMapRequest.ts b/backend/src/map/dto/AddPlaceToMapRequest.ts index 0d220b05..6daebe9a 100644 --- a/backend/src/map/dto/AddPlaceToMapRequest.ts +++ b/backend/src/map/dto/AddPlaceToMapRequest.ts @@ -1,4 +1,5 @@ -import { IsNumber, IsString } from 'class-validator'; +import { IsNumber, IsString, IsEnum } from 'class-validator'; +import { Color } from '../../place/color.enum'; export class AddPlaceToMapRequest { @IsNumber() @@ -6,4 +7,7 @@ export class AddPlaceToMapRequest { @IsString() comment?: string; + + @IsEnum(Color) + color: Color; } diff --git a/backend/src/map/dto/MapDetailResponse.ts b/backend/src/map/dto/MapDetailResponse.ts index 53c16401..056853d0 100644 --- a/backend/src/map/dto/MapDetailResponse.ts +++ b/backend/src/map/dto/MapDetailResponse.ts @@ -15,13 +15,15 @@ export class MapDetailResponse { readonly places: PlaceListResponse[], readonly createdAt: Date, readonly updatedAt: Date, - ) {} + ) { + } static async from(map: Map) { const places = (await map.getPlacesWithComment()).map((place) => { return { ...PlaceListResponse.from(place.place), comment: place.comment, + color: place.color, }; }); diff --git a/backend/src/map/entity/map-place.entity.ts b/backend/src/map/entity/map-place.entity.ts index 6b9c301f..dad38f23 100644 --- a/backend/src/map/entity/map-place.entity.ts +++ b/backend/src/map/entity/map-place.entity.ts @@ -2,6 +2,7 @@ import { Entity, Column, ManyToOne, JoinColumn } from 'typeorm'; import { BaseEntity } from '../../common/BaseEntity'; import { Place } from '../../place/entity/place.entity'; import { Map } from './map.entity'; +import { Color } from '../../place/color.enum'; @Entity() export class MapPlace extends BaseEntity { @@ -22,9 +23,13 @@ export class MapPlace extends BaseEntity { @Column('text', { nullable: true }) description?: string; - static of(placeId: number, map: Map, description?: string) { + @Column() + color: Color; + + static of(placeId: number, map: Map, color: Color, description?: string) { const place = new MapPlace(); place.map = map; + place.color = color; place.placeId = placeId; place.place = Promise.resolve({ id: placeId } as Place); place.description = description; diff --git a/backend/src/map/entity/map.entity.ts b/backend/src/map/entity/map.entity.ts index bc58ccda..a74b0334 100644 --- a/backend/src/map/entity/map.entity.ts +++ b/backend/src/map/entity/map.entity.ts @@ -2,6 +2,7 @@ import { Entity, Column, ManyToOne, JoinColumn, OneToMany } from 'typeorm'; import { BaseEntity } from '../../common/BaseEntity'; import { User } from '../../user/entity/user.entity'; import { MapPlace } from './map-place.entity'; +import { Color } from '../../place/color.enum'; @Entity() export class Map extends BaseEntity { @@ -46,8 +47,8 @@ export class Map extends BaseEntity { return this.mapPlaces.length; } - addPlace(placeId: number, description: string) { - this.mapPlaces.push(MapPlace.of(placeId, this, description)); + addPlace(placeId: number, color: Color, description: string) { + this.mapPlaces.push(MapPlace.of(placeId, this, color, description)); } async deletePlace(placeId: number) { @@ -63,6 +64,7 @@ export class Map extends BaseEntity { this.mapPlaces.map(async (mapPlace) => ({ place: await mapPlace.place, comment: mapPlace.description, + color: mapPlace.color, })), ); } diff --git a/backend/src/map/map.controller.ts b/backend/src/map/map.controller.ts index 82e44150..cb0cee9d 100644 --- a/backend/src/map/map.controller.ts +++ b/backend/src/map/map.controller.ts @@ -15,7 +15,8 @@ import { AddPlaceToMapRequest } from './dto/AddPlaceToMapRequest'; @Controller('/maps') export class MapController { - constructor(private readonly mapService: MapService) {} + constructor(private readonly mapService: MapService) { + } @Get() async getMapList( @@ -51,8 +52,8 @@ export class MapController { @Param('id') id: number, @Body() addPlaceToMapRequest: AddPlaceToMapRequest, ) { - const { placeId, comment } = addPlaceToMapRequest; - return await this.mapService.addPlace(id, placeId, comment); + const { placeId, color, comment } = addPlaceToMapRequest; + return await this.mapService.addPlace(id, placeId, color, comment); } @Delete('/:id/places/:placeId') diff --git a/backend/src/map/map.service.ts b/backend/src/map/map.service.ts index 6f93ed70..dad2bd0e 100644 --- a/backend/src/map/map.service.ts +++ b/backend/src/map/map.service.ts @@ -11,6 +11,7 @@ import { DuplicatePlaceToMapException } from './exception/DuplicatePlaceToMapExc import { PlaceRepository } from '../place/place.repository'; import { InvalidPlaceToMapException } from './exception/InvalidPlaceToMapException'; import { Map } from './entity/map.entity'; +import { Color } from '../place/color.enum'; @Injectable() export class MapService { @@ -103,17 +104,18 @@ export class MapService { throw new MapNotFoundException(id); } - async addPlace(id: number, placeId: number, comment?: string) { + async addPlace(id: number, placeId: number, color = Color.RED, comment?: string) { const map = await this.mapRepository.findById(id); if (!map) throw new MapNotFoundException(id); await this.checkPlaceCanAddToMap(placeId, map); - map.addPlace(placeId, comment); + map.addPlace(placeId, color, comment); await this.mapRepository.save(map); return { savedPlaceId: placeId, - comment: comment, + comment, + color, }; } diff --git a/backend/src/place/color.enum.ts b/backend/src/place/color.enum.ts new file mode 100644 index 00000000..02545dd7 --- /dev/null +++ b/backend/src/place/color.enum.ts @@ -0,0 +1,8 @@ +export enum Color { + RED = 'RED', + ORANGE = 'ORANGE', + YELLOW = 'YELLOW', + GREEN = 'GREEN', + BLUE = 'BLUE', + PURPLE = 'PURPLE' +} diff --git a/backend/src/user/dto/CreateUserRequest.ts b/backend/src/user/dto/CreateUserRequest.ts index e6e0a1a5..41485094 100644 --- a/backend/src/user/dto/CreateUserRequest.ts +++ b/backend/src/user/dto/CreateUserRequest.ts @@ -1,6 +1,6 @@ import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; import { User } from '../entity/user.entity'; -import { userInfoWithProvider } from '../userType'; +import { userInfoWithProvider } from '../user.type'; export class CreateUserRequest { @IsString() From 0ac057e9421a1d699e21c3746cd8ab6af46ed25e Mon Sep 17 00:00:00 2001 From: Soap Date: Mon, 11 Nov 2024 16:28:57 +0900 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20=EC=A0=84=EC=97=AD=EC=98=88?= =?UTF-8?q?=EC=99=B8=ED=95=84=ED=84=B0=20=ED=83=80=EC=9E=85=EB=B3=84?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/filter/GlobalExceptionFilter.ts | 91 +++++++++---------- backend/src/main.ts | 12 ++- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/backend/src/common/exception/filter/GlobalExceptionFilter.ts b/backend/src/common/exception/filter/GlobalExceptionFilter.ts index 1e97de0d..83d2c9b1 100644 --- a/backend/src/common/exception/filter/GlobalExceptionFilter.ts +++ b/backend/src/common/exception/filter/GlobalExceptionFilter.ts @@ -1,59 +1,58 @@ -import { - ArgumentsHost, - Catch, - ExceptionFilter, - HttpException, - HttpStatus, -} from '@nestjs/common'; +import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common'; import { Response } from 'express'; import { BaseException } from '../BaseException'; -@Catch() -export class GlobalExceptionFilter implements ExceptionFilter { - catch(exception: unknown, host: ArgumentsHost) { +@Catch(BaseException) +export class BaseExceptionFilter implements ExceptionFilter { + catch(exception: BaseException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); - if (exception instanceof BaseException) { - return this.sendErrorResponse( - response, - exception.getCode(), - exception.getStatus(), - exception.getMessage(), - ); - } - - if (exception instanceof HttpException) { - console.log(exception); - return this.sendErrorResponse( - response, - 9999, - exception.getStatus(), - exception.message, - ); - } + return response.status(exception.getStatus()).json({ + code: exception.getCode(), + message: exception.getMessage(), + }); + } +} - console.log(exception); - return this.sendErrorResponse( - response, - -1, - HttpStatus.INTERNAL_SERVER_ERROR, - this.getDefaultErrorMessage(exception), - ); +@Catch(HttpException) +export class HttpExceptionFilter implements ExceptionFilter { + catch(exception: HttpException, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + + const exceptionResponse = exception.getResponse(); + + const errorMessage = this.isValidationError(exceptionResponse) + ? (exceptionResponse as any).message.join(', ') + : exception.message; + + return response.status(exception.getStatus()).json({ + code: 9999, + message: errorMessage, + }); } - private sendErrorResponse( - response: Response, - code: number, - status: number, - message: string, - ) { - response.status(status).json({ code, message }); + private isValidationError(exceptionResponse: unknown): boolean { + return ( + typeof exceptionResponse === 'object' && + exceptionResponse !== null && + 'message' in exceptionResponse && + Array.isArray((exceptionResponse as any).message) + ); } +} - private getDefaultErrorMessage(exception: unknown) { - return exception instanceof Error - ? 'Internal server error: ' + exception.message - : 'Internal server error'; +@Catch() +export class UnknownExceptionFilter implements ExceptionFilter { + catch(exception: unknown, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + + console.log(exception); + return response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ + code: -1, + message: 'Internal server error', + }); } } diff --git a/backend/src/main.ts b/backend/src/main.ts index c00eefb0..2aa91c1e 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -1,11 +1,19 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { ValidationPipe } from '@nestjs/common'; -import { GlobalExceptionFilter } from './common/exception/filter/GlobalExceptionFilter'; +import { + BaseExceptionFilter, + HttpExceptionFilter, + UnknownExceptionFilter, +} from './common/exception/filter/GlobalExceptionFilter'; async function bootstrap() { const app = await NestFactory.create(AppModule); - app.useGlobalFilters(new GlobalExceptionFilter()); + app.useGlobalFilters( + new UnknownExceptionFilter(), + new HttpExceptionFilter(), + new BaseExceptionFilter(), + ); app.useGlobalPipes(new ValidationPipe({ transform: true })); await app.listen(8080); } From 40325e89b09b44ad74f4c5153c368bd7acd70bbe Mon Sep 17 00:00:00 2001 From: miensoap Date: Mon, 11 Nov 2024 18:03:55 +0900 Subject: [PATCH 4/8] =?UTF-8?q?fix:=20=EB=82=B4=EC=9A=A9=EC=9D=B4=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=EC=97=90=20=EB=8C=80=ED=95=B4=20=EB=B9=88=20=EB=B0=B0?= =?UTF-8?q?=EC=97=B4=20=EC=9D=91=EB=8B=B5=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/place/place.service.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/backend/src/place/place.service.ts b/backend/src/place/place.service.ts index 323c1761..54d564a4 100644 --- a/backend/src/place/place.service.ts +++ b/backend/src/place/place.service.ts @@ -7,7 +7,8 @@ import { PlaceSearchResponse } from './dto/PlaceSearchResponse'; @Injectable() export class PlaceService { - constructor(private readonly placeRepository: PlaceRepository) {} + constructor(private readonly placeRepository: PlaceRepository) { + } async addPlace(createPlaceRequest: CreatePlaceRequest) { const { googlePlaceId } = createPlaceRequest; @@ -23,15 +24,12 @@ export class PlaceService { async getPlaces(query?: string, page: number = 1, pageSize: number = 10) { const result = query ? await this.placeRepository.searchByNameOrAddressQuery( - query, - page, - pageSize, - ) + query, + page, + pageSize, + ) : await this.placeRepository.findAll(page, pageSize); - if (!result.length) { - throw new PlaceNotFoundException(); - } return result.map(PlaceSearchResponse.from); } From ad2ffb1726b78c7c43eff04c33e72060d66572b8 Mon Sep 17 00:00:00 2001 From: Soap Date: Mon, 11 Nov 2024 16:38:54 +0900 Subject: [PATCH 5/8] =?UTF-8?q?style:=20=EC=BD=94=EB=93=9C=20=ED=8F=AC?= =?UTF-8?q?=EB=A7=B7=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/exception/filter/GlobalExceptionFilter.ts | 8 +++++++- backend/src/map/dto/MapDetailResponse.ts | 3 +-- backend/src/map/map.controller.ts | 3 +-- backend/src/map/map.service.ts | 7 ++++++- backend/src/place/color.enum.ts | 2 +- backend/src/place/place.service.ts | 11 +++++------ 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/backend/src/common/exception/filter/GlobalExceptionFilter.ts b/backend/src/common/exception/filter/GlobalExceptionFilter.ts index 83d2c9b1..64c1831f 100644 --- a/backend/src/common/exception/filter/GlobalExceptionFilter.ts +++ b/backend/src/common/exception/filter/GlobalExceptionFilter.ts @@ -1,4 +1,10 @@ -import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common'; +import { + ArgumentsHost, + Catch, + ExceptionFilter, + HttpException, + HttpStatus, +} from '@nestjs/common'; import { Response } from 'express'; import { BaseException } from '../BaseException'; diff --git a/backend/src/map/dto/MapDetailResponse.ts b/backend/src/map/dto/MapDetailResponse.ts index 056853d0..4b7d30b6 100644 --- a/backend/src/map/dto/MapDetailResponse.ts +++ b/backend/src/map/dto/MapDetailResponse.ts @@ -15,8 +15,7 @@ export class MapDetailResponse { readonly places: PlaceListResponse[], readonly createdAt: Date, readonly updatedAt: Date, - ) { - } + ) {} static async from(map: Map) { const places = (await map.getPlacesWithComment()).map((place) => { diff --git a/backend/src/map/map.controller.ts b/backend/src/map/map.controller.ts index cb0cee9d..186168df 100644 --- a/backend/src/map/map.controller.ts +++ b/backend/src/map/map.controller.ts @@ -15,8 +15,7 @@ import { AddPlaceToMapRequest } from './dto/AddPlaceToMapRequest'; @Controller('/maps') export class MapController { - constructor(private readonly mapService: MapService) { - } + constructor(private readonly mapService: MapService) {} @Get() async getMapList( diff --git a/backend/src/map/map.service.ts b/backend/src/map/map.service.ts index dad2bd0e..3bfdcaf9 100644 --- a/backend/src/map/map.service.ts +++ b/backend/src/map/map.service.ts @@ -104,7 +104,12 @@ export class MapService { throw new MapNotFoundException(id); } - async addPlace(id: number, placeId: number, color = Color.RED, comment?: string) { + async addPlace( + id: number, + placeId: number, + color = Color.RED, + comment?: string, + ) { const map = await this.mapRepository.findById(id); if (!map) throw new MapNotFoundException(id); await this.checkPlaceCanAddToMap(placeId, map); diff --git a/backend/src/place/color.enum.ts b/backend/src/place/color.enum.ts index 02545dd7..95641cfd 100644 --- a/backend/src/place/color.enum.ts +++ b/backend/src/place/color.enum.ts @@ -4,5 +4,5 @@ export enum Color { YELLOW = 'YELLOW', GREEN = 'GREEN', BLUE = 'BLUE', - PURPLE = 'PURPLE' + PURPLE = 'PURPLE', } diff --git a/backend/src/place/place.service.ts b/backend/src/place/place.service.ts index 54d564a4..5cfe01b3 100644 --- a/backend/src/place/place.service.ts +++ b/backend/src/place/place.service.ts @@ -7,8 +7,7 @@ import { PlaceSearchResponse } from './dto/PlaceSearchResponse'; @Injectable() export class PlaceService { - constructor(private readonly placeRepository: PlaceRepository) { - } + constructor(private readonly placeRepository: PlaceRepository) {} async addPlace(createPlaceRequest: CreatePlaceRequest) { const { googlePlaceId } = createPlaceRequest; @@ -24,10 +23,10 @@ export class PlaceService { async getPlaces(query?: string, page: number = 1, pageSize: number = 10) { const result = query ? await this.placeRepository.searchByNameOrAddressQuery( - query, - page, - pageSize, - ) + query, + page, + pageSize, + ) : await this.placeRepository.findAll(page, pageSize); return result.map(PlaceSearchResponse.from); From 87a90837c390721333919e96ad9094c8ad1b8c94 Mon Sep 17 00:00:00 2001 From: miensoap Date: Tue, 12 Nov 2024 02:03:21 +0900 Subject: [PATCH 6/8] =?UTF-8?q?feat:=20=ED=95=80=20=EC=83=89=EC=83=81=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=BC=EC=97=90=20NOT=20NULL=20=EC=A0=9C=EC=95=BD?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EC=B6=94=EA=B0=80=20#86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/resources/sql/DDL.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/resources/sql/DDL.sql b/backend/resources/sql/DDL.sql index 0b0404b3..23db01fd 100644 --- a/backend/resources/sql/DDL.sql +++ b/backend/resources/sql/DDL.sql @@ -64,13 +64,13 @@ CREATE TABLE MAP CREATE TABLE MAP_PLACE ( id INT PRIMARY KEY AUTO_INCREMENT, - place_id INT NOT NULL, - map_id INT NOT NULL, + place_id INT NOT NULL, + map_id INT NOT NULL, description TEXT, - color VARCHAR(20) DEFAULT 'RED', + color VARCHAR(20) DEFAULT 'RED' NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - deleted_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, FOREIGN KEY (place_id) REFERENCES PLACE (id) ON DELETE CASCADE, FOREIGN KEY (map_id) REFERENCES MAP (id) ON DELETE CASCADE ); From 1020a662382674656b570100521eb803659f3e1f Mon Sep 17 00:00:00 2001 From: miensoap Date: Tue, 12 Nov 2024 02:06:00 +0900 Subject: [PATCH 7/8] =?UTF-8?q?refactor:=20=EC=BD=94=EC=8A=A4/=EC=A7=80?= =?UTF-8?q?=EB=8F=84=EC=97=90=20=EC=9E=A5=EC=86=8C=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EC=A0=84=20=ED=99=95=EC=9D=B8=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95=20#86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/course/course.service.ts | 4 ++-- backend/src/map/map.service.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/course/course.service.ts b/backend/src/course/course.service.ts index 8cec9aa2..572a36f9 100644 --- a/backend/src/course/course.service.ts +++ b/backend/src/course/course.service.ts @@ -118,7 +118,7 @@ export class CourseService { const course = await this.courseRepository.findById(id); if (!course) throw new CourseNotFoundException(id); - await this.checkPlacesExist( + await this.validatePlacesForCourse( setPlacesOfCourseRequest.places.map((p) => p.placeId), ); @@ -131,7 +131,7 @@ export class CourseService { }; } - private async checkPlacesExist(placeIds: number[]) { + private async validatePlacesForCourse(placeIds: number[]) { const notExistsPlaceIds = await Promise.all( placeIds.map(async (placeId) => { const exists = await this.placeRepository.existById(placeId); diff --git a/backend/src/map/map.service.ts b/backend/src/map/map.service.ts index 3bfdcaf9..da7c8b01 100644 --- a/backend/src/map/map.service.ts +++ b/backend/src/map/map.service.ts @@ -112,7 +112,7 @@ export class MapService { ) { const map = await this.mapRepository.findById(id); if (!map) throw new MapNotFoundException(id); - await this.checkPlaceCanAddToMap(placeId, map); + await this.validatePlacesForMap(placeId, map); map.addPlace(placeId, color, comment); await this.mapRepository.save(map); @@ -124,7 +124,7 @@ export class MapService { }; } - private async checkPlaceCanAddToMap(placeId: number, map: Map) { + private async validatePlacesForMap(placeId: number, map: Map) { if (!(await this.placeRepository.existById(placeId))) { throw new InvalidPlaceToMapException(placeId); } From 12a4b4a805e42889c7c8b7334f035b43374138f6 Mon Sep 17 00:00:00 2001 From: Soap Date: Mon, 11 Nov 2024 00:37:18 +0900 Subject: [PATCH 8/8] =?UTF-8?q?feat:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20=EA=B4=80=EB=A0=A8=20Cloud=20Func?= =?UTF-8?q?tions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scripts/get-presigned-post-function.js | 59 +++++++++++++++++++ .../scripts/get-presigned-url-function.js | 50 ++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 backend/resources/scripts/get-presigned-post-function.js create mode 100644 backend/resources/scripts/get-presigned-url-function.js diff --git a/backend/resources/scripts/get-presigned-post-function.js b/backend/resources/scripts/get-presigned-post-function.js new file mode 100644 index 00000000..93dd202b --- /dev/null +++ b/backend/resources/scripts/get-presigned-post-function.js @@ -0,0 +1,59 @@ +function main(params) { + const AWS = require('aws-sdk'); + + const ENDPOINT_URL = 'https://kr.object.ncloudstorage.com'; + const endpoint = new AWS.Endpoint('https://kr.object.ncloudstorage.com'); + const region = 'kr-standard'; + const accessKey = params.access; + const secretKey = params.secret; + + const bucketName = 'ogil-public'; + const baseDirname = 'uploads'; + + const objectName = path.join( + 'post', + baseDirname, + params.dirname, + getUUIDName(params.extension), + ); + + const signedUrlExpireSeconds = 300; + const contentType = 'image/*'; + const ACL = 'public-read'; + + const maxFileSize = 3 * 1024 * 1024; + + const S3 = new AWS.S3({ + endpoint: endpoint, + region: region, + credentials: { + accessKeyId: accessKey, + secretAccessKey: secretKey, + }, + signatureVersion: 'v4', + }); + + const post = S3.createPresignedPost({ + Bucket: bucketName, + Conditions: [['content-length-range', 0, maxFileSize]], + ContentType: contentType, + Expires: signedUrlExpireSeconds, + Fields: { + key: objectName, + 'Content-Type': contentType, + acl: ACL, + }, + }); + + const uploadedUrl = path.join(ENDPOINT_URL, bucketName, objectName); + + console.log(post); + console.log(`${uploadedUrl}에 업로드 됩니다`); + + return { ...post, uploadedUrl }; +} + +function getUUIDName(extension) { + const { v4: uuidv4 } = require('uuid'); + return uuidv4().substring(0, 13).replace('-', '') + '.' + extension; +} diff --git a/backend/resources/scripts/get-presigned-url-function.js b/backend/resources/scripts/get-presigned-url-function.js new file mode 100644 index 00000000..e7f0d08b --- /dev/null +++ b/backend/resources/scripts/get-presigned-url-function.js @@ -0,0 +1,50 @@ +function main(params) { + const AWS = require('aws-sdk'); + + const ENDPOINT_URL = 'https://kr.object.ncloudstorage.com'; + const endpoint = new AWS.Endpoint('https://kr.object.ncloudstorage.com'); + const region = 'kr-standard'; + const accessKey = params.access; + const secretKey = params.secret; + + const bucketName = 'ogil-public'; + const baseDirname = 'uploads'; + + const objectName = path.join( + baseDirname, + params.dirname, + getUUIDName(params.extension), + ); + + const signedUrlExpireSeconds = 300; + const contentType = 'image/*'; + const ACL = 'public-read'; + + const S3 = new AWS.S3({ + endpoint: endpoint, + region: region, + credentials: { + accessKeyId: accessKey, + secretAccessKey: secretKey, + }, + signatureVersion: 'v4', + }); + + const url = S3.getSignedUrl('putObject', { + Bucket: bucketName, + Key: objectName, + Expires: signedUrlExpireSeconds, + ContentType: contentType, + ACL, + }); + + const uploadedUrl = path.join(ENDPOINT_URL, bucketName, objectName); + + console.log({ url, uploadedUrl }); + return { url, uploadedUrl }; +} + +function getUUIDName(extension) { + const { v4: uuidv4 } = require('uuid'); + return uuidv4().substring(0, 13).replace('-', '') + '.' + extension; +}