From 0aba6f010d7a5454679f2bd6982bf829f328fd42 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 30 Nov 2023 01:06:29 +0900 Subject: [PATCH 01/37] feat/#66: create notice-boards module --- src/apis/api.module.ts | 3 ++- .../notice-boards.controller.spec.ts | 18 ++++++++++++++++++ .../controllers/notice-boards.controller.ts | 19 +++++++++++++++++++ .../notice-boards/notice-boards.module.ts | 9 +++++++++ .../services/notice-boards.service.spec.ts | 18 ++++++++++++++++++ .../services/notice-boards.service.ts | 4 ++++ 6 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/apis/notice-boards/controllers/notice-boards.controller.spec.ts create mode 100644 src/apis/notice-boards/controllers/notice-boards.controller.ts create mode 100644 src/apis/notice-boards/notice-boards.module.ts create mode 100644 src/apis/notice-boards/services/notice-boards.service.spec.ts create mode 100644 src/apis/notice-boards/services/notice-boards.service.ts diff --git a/src/apis/api.module.ts b/src/apis/api.module.ts index b95961dc..7af9080e 100644 --- a/src/apis/api.module.ts +++ b/src/apis/api.module.ts @@ -1,8 +1,9 @@ import { Module } from '@nestjs/common'; import { AuthModule } from './auth/auth.module'; import { UsersModule } from './users/users.module'; +import { NoticeBoardsModule } from './notice-boards/notice-boards.module'; @Module({ - imports: [AuthModule, UsersModule], + imports: [AuthModule, UsersModule, NoticeBoardsModule], }) export class ApiModule {} diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts b/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts new file mode 100644 index 00000000..85ae70e5 --- /dev/null +++ b/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { NoticeBoardsController } from './notice-boards.controller'; + +describe('NoticeBoardsController', () => { + let controller: NoticeBoardsController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [NoticeBoardsController], + }).compile(); + + controller = module.get(NoticeBoardsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.ts b/src/apis/notice-boards/controllers/notice-boards.controller.ts new file mode 100644 index 00000000..0e2a92a4 --- /dev/null +++ b/src/apis/notice-boards/controllers/notice-boards.controller.ts @@ -0,0 +1,19 @@ +import { Controller, Delete, Get, Patch, Post } from '@nestjs/common'; + +@Controller('notice-boards') +export class NoticeBoardsController { + @Post() + create() {} + + @Get() + findAll() {} + + @Get(':id') + findOne() {} + + @Patch(':id') + update() {} + + @Delete(':id') + remove() {} +} diff --git a/src/apis/notice-boards/notice-boards.module.ts b/src/apis/notice-boards/notice-boards.module.ts new file mode 100644 index 00000000..1aacc199 --- /dev/null +++ b/src/apis/notice-boards/notice-boards.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { NoticeBoardsController } from './controllers/notice-boards.controller'; +import { NoticeBoardsService } from './services/notice-boards.service'; + +@Module({ + controllers: [NoticeBoardsController], + providers: [NoticeBoardsService], +}) +export class NoticeBoardsModule {} diff --git a/src/apis/notice-boards/services/notice-boards.service.spec.ts b/src/apis/notice-boards/services/notice-boards.service.spec.ts new file mode 100644 index 00000000..1d679256 --- /dev/null +++ b/src/apis/notice-boards/services/notice-boards.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { NoticeBoardsService } from './notice-boards.service'; + +describe('NoticeBoardsService', () => { + let service: NoticeBoardsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [NoticeBoardsService], + }).compile(); + + service = module.get(NoticeBoardsService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/apis/notice-boards/services/notice-boards.service.ts b/src/apis/notice-boards/services/notice-boards.service.ts new file mode 100644 index 00000000..f1d8eb28 --- /dev/null +++ b/src/apis/notice-boards/services/notice-boards.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class NoticeBoardsService {} From 95436586d538f327cf798316483db7389b827263 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 30 Nov 2023 01:22:17 +0900 Subject: [PATCH 02/37] modify/#66: modifying entities related to the notice-board --- .../dto/create-notice-board.dto.ts | 0 .../notice-boards/dto/notice-board.dto.ts | 6 ++++++ src/entities/NoticeBoard.ts | 7 +++++++ src/entities/NoticeBoardComment.ts | 14 +++++++++++++ src/entities/NoticeBoardCommentReaction.ts | 14 +++++++++++++ src/entities/NoticeBoardReaction.ts | 14 +++++++++++++ src/entities/NoticeBoardReplyComment.ts | 21 +++++++++++++++++++ .../NoticeBoardReplyCommentReaction.ts | 14 +++++++++++++ 8 files changed, 90 insertions(+) create mode 100644 src/apis/notice-boards/dto/create-notice-board.dto.ts create mode 100644 src/apis/notice-boards/dto/notice-board.dto.ts diff --git a/src/apis/notice-boards/dto/create-notice-board.dto.ts b/src/apis/notice-boards/dto/create-notice-board.dto.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/apis/notice-boards/dto/notice-board.dto.ts b/src/apis/notice-boards/dto/notice-board.dto.ts new file mode 100644 index 00000000..54c0b125 --- /dev/null +++ b/src/apis/notice-boards/dto/notice-board.dto.ts @@ -0,0 +1,6 @@ +import { BaseDto } from '@src/dto/base.dto'; +import { NoticeBoard } from '@src/entities/NoticeBoard'; + +export class NoticeBoardDto + extends BaseDto + implements Pick {} diff --git a/src/entities/NoticeBoard.ts b/src/entities/NoticeBoard.ts index 7b1f509b..331fe1d0 100644 --- a/src/entities/NoticeBoard.ts +++ b/src/entities/NoticeBoard.ts @@ -57,6 +57,13 @@ export class NoticeBoard { }) updatedAt: Date; + @Column('int', { + name: 'user_id', + comment: '게시글 작성 유저 고유 ID', + unsigned: true, + }) + userId: number; + @ManyToOne(() => User, (user) => user.noticeBoards, { onDelete: 'CASCADE', onUpdate: 'CASCADE', diff --git a/src/entities/NoticeBoardComment.ts b/src/entities/NoticeBoardComment.ts index 5f53bff9..de7c2841 100644 --- a/src/entities/NoticeBoardComment.ts +++ b/src/entities/NoticeBoardComment.ts @@ -46,6 +46,13 @@ export class NoticeBoardComment { }) updatedAt: Date; + @Column('int', { + name: 'user_id', + comment: '게시글 작성 유저 고유 ID', + unsigned: true, + }) + userId: number; + @ManyToOne(() => User, (user) => user.noticeBoardComments, { onDelete: 'CASCADE', onUpdate: 'CASCADE', @@ -53,6 +60,13 @@ export class NoticeBoardComment { @JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }]) user: User; + @Column('int', { + name: 'notice_board_id', + comment: '공지 게시글 고유 ID', + unsigned: true, + }) + noticeBoardId: number; + @ManyToOne( () => NoticeBoard, (noticeBoard) => noticeBoard.noticeBoardComments, diff --git a/src/entities/NoticeBoardCommentReaction.ts b/src/entities/NoticeBoardCommentReaction.ts index 3ba9801d..9c475a2d 100644 --- a/src/entities/NoticeBoardCommentReaction.ts +++ b/src/entities/NoticeBoardCommentReaction.ts @@ -26,6 +26,13 @@ export class NoticeBoardCommentReaction { }) createdAt: Date; + @Column('int', { + name: 'notice_board_comment_id', + comment: '공지 게시판 댓글 고유 ID', + unsigned: true, + }) + noticeBoardCommentId: number; + @ManyToOne( () => NoticeBoardComment, (noticeBoardComment) => noticeBoardComment.noticeBoardCommentReactions, @@ -34,6 +41,13 @@ export class NoticeBoardCommentReaction { @JoinColumn([{ name: 'notice_board_comment_id', referencedColumnName: 'id' }]) noticeBoardComment: NoticeBoardComment; + @Column('int', { + name: 'user_id', + comment: '게시글 작성 유저 고유 ID', + unsigned: true, + }) + userId: number; + @ManyToOne(() => User, (user) => user.noticeBoardCommentReactions, { onDelete: 'CASCADE', onUpdate: 'CASCADE', diff --git a/src/entities/NoticeBoardReaction.ts b/src/entities/NoticeBoardReaction.ts index 97a5aa7c..c05c9bd3 100644 --- a/src/entities/NoticeBoardReaction.ts +++ b/src/entities/NoticeBoardReaction.ts @@ -26,6 +26,13 @@ export class NoticeBoardReaction { }) createdAt: Date; + @Column('int', { + name: 'user_id', + comment: '게시글 작성 유저 고유 ID', + unsigned: true, + }) + userId: number; + @ManyToOne(() => User, (user) => user.noticeBoardReactions, { onDelete: 'CASCADE', onUpdate: 'CASCADE', @@ -33,6 +40,13 @@ export class NoticeBoardReaction { @JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }]) user: User; + @Column('int', { + name: 'notice_board_id', + comment: '공지 게시글 고유 ID', + unsigned: true, + }) + noticeBoardId: number; + @ManyToOne( () => NoticeBoard, (noticeBoard) => noticeBoard.noticeBoardReactions, diff --git a/src/entities/NoticeBoardReplyComment.ts b/src/entities/NoticeBoardReplyComment.ts index e2503c86..9f3a8271 100644 --- a/src/entities/NoticeBoardReplyComment.ts +++ b/src/entities/NoticeBoardReplyComment.ts @@ -50,6 +50,13 @@ export class NoticeBoardReplyComment { }) updatedAt: Date; + @Column('int', { + name: 'notice_board_id', + comment: '공지 게시글 고유 ID', + unsigned: true, + }) + noticeBoardId: number; + @ManyToOne( () => NoticeBoard, (noticeBoard) => noticeBoard.noticeBoardReplyComments, @@ -58,6 +65,13 @@ export class NoticeBoardReplyComment { @JoinColumn([{ name: 'notice_board_id', referencedColumnName: 'id' }]) noticeBoard: NoticeBoard; + @Column('int', { + name: 'notice_board_comment_id', + comment: '공지 게시글 댓글 고유 ID', + unsigned: true, + }) + noticeBoardCommentId: number; + @ManyToOne( () => NoticeBoardComment, (noticeBoardComment) => noticeBoardComment.noticeBoardReplyComments, @@ -66,6 +80,13 @@ export class NoticeBoardReplyComment { @JoinColumn([{ name: 'notice_board_comment_id', referencedColumnName: 'id' }]) noticeBoardComment: NoticeBoardComment; + @Column('int', { + name: 'user_id', + comment: '게시글 작성 유저 고유 ID', + unsigned: true, + }) + userId: number; + @ManyToOne(() => User, (user) => user.noticeBoardReplyComments, { onDelete: 'CASCADE', onUpdate: 'CASCADE', diff --git a/src/entities/NoticeBoardReplyCommentReaction.ts b/src/entities/NoticeBoardReplyCommentReaction.ts index 3895edf7..54f1e847 100644 --- a/src/entities/NoticeBoardReplyCommentReaction.ts +++ b/src/entities/NoticeBoardReplyCommentReaction.ts @@ -34,6 +34,13 @@ export class NoticeBoardReplyCommentReaction { @JoinColumn([{ name: 'reaction_type_id', referencedColumnName: 'id' }]) reactionType: ReactionType; + @Column('int', { + name: 'notice_board_reply_comment_id', + comment: '공지 게시글 대댓글 고유 ID', + unsigned: true, + }) + noticeBoardReplyCommentId: number; + @ManyToOne( () => NoticeBoardReplyComment, (noticeBoardReplyComment) => @@ -45,6 +52,13 @@ export class NoticeBoardReplyCommentReaction { ]) noticeBoardReplyComment: NoticeBoardReplyComment; + @Column('int', { + name: 'user_id', + comment: '게시글 작성 유저 고유 ID', + unsigned: true, + }) + userId: number; + @ManyToOne(() => User, (user) => user.noticeBoardReplyCommentReactions, { onDelete: 'CASCADE', onUpdate: 'CASCADE', From cf1ab641a1398fe1cd98f06f959f70ba8d050323 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 30 Nov 2023 01:22:49 +0900 Subject: [PATCH 03/37] modify/#66: modifying entity related to the notice-board --- src/entities/NoticeBoardCommentReaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/NoticeBoardCommentReaction.ts b/src/entities/NoticeBoardCommentReaction.ts index 9c475a2d..efcdb99d 100644 --- a/src/entities/NoticeBoardCommentReaction.ts +++ b/src/entities/NoticeBoardCommentReaction.ts @@ -28,7 +28,7 @@ export class NoticeBoardCommentReaction { @Column('int', { name: 'notice_board_comment_id', - comment: '공지 게시판 댓글 고유 ID', + comment: '공지 게시글 댓글 고유 ID', unsigned: true, }) noticeBoardCommentId: number; From 37e1837ea89bccaca6f3dee5a58a74423843053f Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 30 Nov 2023 01:32:29 +0900 Subject: [PATCH 04/37] feat/#66: create dto, constant --- .../constants/notice-board.constant.ts | 4 ++++ .../notice-boards/dto/create-notice-board.dto.ts | 12 ++++++++++++ src/apis/notice-boards/dto/notice-board.dto.ts | 13 ++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/apis/notice-boards/constants/notice-board.constant.ts diff --git a/src/apis/notice-boards/constants/notice-board.constant.ts b/src/apis/notice-boards/constants/notice-board.constant.ts new file mode 100644 index 00000000..107bf785 --- /dev/null +++ b/src/apis/notice-boards/constants/notice-board.constant.ts @@ -0,0 +1,4 @@ +export const NOTICE_BOARD_TITLE_LENGTH = { + MIN: 1, + MAX: 255, +} as const; diff --git a/src/apis/notice-boards/dto/create-notice-board.dto.ts b/src/apis/notice-boards/dto/create-notice-board.dto.ts index e69de29b..6494645c 100644 --- a/src/apis/notice-boards/dto/create-notice-board.dto.ts +++ b/src/apis/notice-boards/dto/create-notice-board.dto.ts @@ -0,0 +1,12 @@ +import { IsNotEmpty, Length } from 'class-validator'; +import { NOTICE_BOARD_TITLE_LENGTH } from '../constants/notice-board.constant'; + +export class NoticeBoardDto + implements Pick +{ + @Length(NOTICE_BOARD_TITLE_LENGTH.MIN, NOTICE_BOARD_TITLE_LENGTH.MAX) + title: string; + + @IsNotEmpty() + description: string; +} diff --git a/src/apis/notice-boards/dto/notice-board.dto.ts b/src/apis/notice-boards/dto/notice-board.dto.ts index 54c0b125..17c40379 100644 --- a/src/apis/notice-boards/dto/notice-board.dto.ts +++ b/src/apis/notice-boards/dto/notice-board.dto.ts @@ -3,4 +3,15 @@ import { NoticeBoard } from '@src/entities/NoticeBoard'; export class NoticeBoardDto extends BaseDto - implements Pick {} + implements + Pick< + NoticeBoard, + 'title' | 'description' | 'hit' | 'allowComment' | 'userId' + > +{ + title: string; + description: string; + hit: number; + allowComment: number; + userId: number; +} From 7d80f29a9bcc8d7ccdeac8f4f5704aaca4d526ab Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 30 Nov 2023 01:54:39 +0900 Subject: [PATCH 05/37] feat/#66: feat post api, modify dto --- .../controllers/notice-boards.controller.ts | 25 +++++++-- .../dto/create-notice-board.dto.ts | 3 +- .../notice-boards/dto/notice-board.dto.ts | 6 +++ .../notice-boards/notice-boards.module.ts | 3 ++ .../services/notice-boards.service.ts | 51 ++++++++++++++++++- 5 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.ts b/src/apis/notice-boards/controllers/notice-boards.controller.ts index 0e2a92a4..2f5d3115 100644 --- a/src/apis/notice-boards/controllers/notice-boards.controller.ts +++ b/src/apis/notice-boards/controllers/notice-boards.controller.ts @@ -1,9 +1,28 @@ -import { Controller, Delete, Get, Patch, Post } from '@nestjs/common'; +import { + Body, + Controller, + Delete, + Get, + Param, + ParseIntPipe, + Patch, + Post, +} from '@nestjs/common'; +import { CreateNoticeBoardDto } from '../dto/create-notice-board.dto'; +import { NoticeBoardsService } from '../services/notice-boards.service'; @Controller('notice-boards') export class NoticeBoardsController { - @Post() - create() {} + constructor(private readonly noticeBoardService: NoticeBoardsService) {} + + @Post(':userId') + create( + // 추후 develop에 guard가 merge 될 시에 수정 + @Param('userId', ParseIntPipe) userId: number, + @Body() createNoticeBoardDto: CreateNoticeBoardDto, + ) { + return this.noticeBoardService.create(userId, createNoticeBoardDto); + } @Get() findAll() {} diff --git a/src/apis/notice-boards/dto/create-notice-board.dto.ts b/src/apis/notice-boards/dto/create-notice-board.dto.ts index 6494645c..71fdba1f 100644 --- a/src/apis/notice-boards/dto/create-notice-board.dto.ts +++ b/src/apis/notice-boards/dto/create-notice-board.dto.ts @@ -1,7 +1,8 @@ import { IsNotEmpty, Length } from 'class-validator'; import { NOTICE_BOARD_TITLE_LENGTH } from '../constants/notice-board.constant'; +import { NoticeBoardDto } from './notice-board.dto'; -export class NoticeBoardDto +export class CreateNoticeBoardDto implements Pick { @Length(NOTICE_BOARD_TITLE_LENGTH.MIN, NOTICE_BOARD_TITLE_LENGTH.MAX) diff --git a/src/apis/notice-boards/dto/notice-board.dto.ts b/src/apis/notice-boards/dto/notice-board.dto.ts index 17c40379..1e2e3ad9 100644 --- a/src/apis/notice-boards/dto/notice-board.dto.ts +++ b/src/apis/notice-boards/dto/notice-board.dto.ts @@ -14,4 +14,10 @@ export class NoticeBoardDto hit: number; allowComment: number; userId: number; + + constructor(noticeBoardDto: Partial = {}) { + super(); + + Object.assign(this, noticeBoardDto); + } } diff --git a/src/apis/notice-boards/notice-boards.module.ts b/src/apis/notice-boards/notice-boards.module.ts index 1aacc199..d7ab3111 100644 --- a/src/apis/notice-boards/notice-boards.module.ts +++ b/src/apis/notice-boards/notice-boards.module.ts @@ -1,8 +1,11 @@ import { Module } from '@nestjs/common'; import { NoticeBoardsController } from './controllers/notice-boards.controller'; import { NoticeBoardsService } from './services/notice-boards.service'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { NoticeBoard } from '@src/entities/NoticeBoard'; @Module({ + imports: [TypeOrmModule.forFeature([NoticeBoard])], controllers: [NoticeBoardsController], providers: [NoticeBoardsService], }) diff --git a/src/apis/notice-boards/services/notice-boards.service.ts b/src/apis/notice-boards/services/notice-boards.service.ts index f1d8eb28..2a49e686 100644 --- a/src/apis/notice-boards/services/notice-boards.service.ts +++ b/src/apis/notice-boards/services/notice-boards.service.ts @@ -1,4 +1,53 @@ import { Injectable } from '@nestjs/common'; +import { CreateNoticeBoardDto } from '../dto/create-notice-board.dto'; +import { DataSource, Repository } from 'typeorm'; +import { InjectRepository } from '@nestjs/typeorm'; +import { NoticeBoard } from '@src/entities/NoticeBoard'; +import { NoticeBoardDto } from '../dto/notice-board.dto'; +import { HttpInternalServerErrorException } from '@src/http-exceptions/exceptions/http-internal-server-error.exception'; +import { COMMON_ERROR_CODE } from '@src/constants/error/common/common-error-code.constant'; @Injectable() -export class NoticeBoardsService {} +export class NoticeBoardsService { + constructor( + private readonly dataSource: DataSource, + @InjectRepository(NoticeBoard) + private readonly noticeBoardRepository: Repository, + ) {} + async create(userId: number, createNoticeBoardDto: CreateNoticeBoardDto) { + const queryRunner = this.dataSource.createQueryRunner(); + + await queryRunner.connect(); + await queryRunner.startTransaction(); + + try { + const entityManager = queryRunner.manager; + + const newPost = await entityManager + .withRepository(this.noticeBoardRepository) + .save({ + userId, + ...createNoticeBoardDto, + }); + + await queryRunner.commitTransaction(); + + return new NoticeBoardDto(newPost); + } catch (error) { + if (queryRunner.isTransactionActive) { + await queryRunner.rollbackTransaction(); + } + + console.error(error); + throw new HttpInternalServerErrorException({ + code: COMMON_ERROR_CODE.SERVER_ERROR, + ctx: '공지게시글 생성 중 알 수 없는 에러', + stack: error.stack, + }); + } finally { + if (!queryRunner.isReleased) { + await queryRunner.release(); + } + } + } +} From 7a21900103c8b48cd9029980711c01d214ca5f58 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 30 Nov 2023 14:30:19 +0900 Subject: [PATCH 06/37] feat/#66: create swagger api docs and set response --- .../constants/notice-board.constant.ts | 5 ++ .../controllers/notice-boards.controller.ts | 29 +++++++----- .../controllers/notice-boards.swagger.ts | 47 +++++++++++++++++++ .../dto/create-notice-board.dto.ts | 27 +++++++++-- .../notice-boards/dto/notice-board.dto.ts | 32 +++++++++++++ 5 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 src/apis/notice-boards/controllers/notice-boards.swagger.ts diff --git a/src/apis/notice-boards/constants/notice-board.constant.ts b/src/apis/notice-boards/constants/notice-board.constant.ts index 107bf785..1255bf0e 100644 --- a/src/apis/notice-boards/constants/notice-board.constant.ts +++ b/src/apis/notice-boards/constants/notice-board.constant.ts @@ -2,3 +2,8 @@ export const NOTICE_BOARD_TITLE_LENGTH = { MIN: 1, MAX: 255, } as const; + +export const NOTICE_BOARD_ALLOW_COMMENT_LENGTH = { + MIN: 0, + MAX: 1, +}; diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.ts b/src/apis/notice-boards/controllers/notice-boards.controller.ts index 2f5d3115..166f86fc 100644 --- a/src/apis/notice-boards/controllers/notice-boards.controller.ts +++ b/src/apis/notice-boards/controllers/notice-boards.controller.ts @@ -1,20 +1,27 @@ import { Body, Controller, - Delete, - Get, + // Delete, + // Get, Param, ParseIntPipe, - Patch, + // Patch, Post, } from '@nestjs/common'; import { CreateNoticeBoardDto } from '../dto/create-notice-board.dto'; import { NoticeBoardsService } from '../services/notice-boards.service'; +import { SetResponse } from '@src/interceptors/success-interceptor/decorators/success-response.decorator'; +import { ResponseType } from '@src/interceptors/success-interceptor/constants/success-interceptor.enum'; +import { ApiNoticeBoard } from './notice-boards.swagger'; +import { ApiTags } from '@nestjs/swagger'; +@ApiTags('notice-boards') @Controller('notice-boards') export class NoticeBoardsController { constructor(private readonly noticeBoardService: NoticeBoardsService) {} + @ApiNoticeBoard.Create({ summary: 'notice-board 게시글 생성 API' }) + @SetResponse({ type: ResponseType.Detail, key: 'board' }) @Post(':userId') create( // 추후 develop에 guard가 merge 될 시에 수정 @@ -24,15 +31,15 @@ export class NoticeBoardsController { return this.noticeBoardService.create(userId, createNoticeBoardDto); } - @Get() - findAll() {} + // @Get() + // findAll() {} - @Get(':id') - findOne() {} + // @Get(':id') + // findOne() {} - @Patch(':id') - update() {} + // @Patch(':id') + // update() {} - @Delete(':id') - remove() {} + // @Delete(':id') + // remove() {} } diff --git a/src/apis/notice-boards/controllers/notice-boards.swagger.ts b/src/apis/notice-boards/controllers/notice-boards.swagger.ts new file mode 100644 index 00000000..b4d41a87 --- /dev/null +++ b/src/apis/notice-boards/controllers/notice-boards.swagger.ts @@ -0,0 +1,47 @@ +import { HttpStatus, applyDecorators } from '@nestjs/common'; +import { ApiOperation } from '@nestjs/swagger'; +import { OperationObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface'; + +import { AUTH_ERROR_CODE } from '@src/constants/error/auth/auth-error-code.constant'; +import { COMMON_ERROR_CODE } from '@src/constants/error/common/common-error-code.constant'; +import { HttpException } from '@src/http-exceptions/exceptions/http.exception'; +import { ApiOperator } from '@src/types/type'; +import { ValidationError } from '@src/types/validation-errors.type'; +import { NoticeBoardsController } from './notice-boards.controller'; +import { DetailResponseDto } from '@src/interceptors/success-interceptor/dto/detail-response.dto'; +import { NoticeBoardDto } from '../dto/notice-board.dto'; + +export const ApiNoticeBoard: ApiOperator = { + Create: ( + apiOperationOptions: Required, 'summary'>> & + Partial, + ): PropertyDecorator => { + return applyDecorators( + ApiOperation({ + operationId: 'NoticeBoardCreate', + ...apiOperationOptions, + }), + DetailResponseDto.swaggerBuilder( + HttpStatus.CREATED, + 'board', + NoticeBoardDto, + ), + HttpException.swaggerBuilder( + HttpStatus.BAD_REQUEST, + [ + COMMON_ERROR_CODE.INVALID_REQUEST_PARAMETER, + AUTH_ERROR_CODE.ACCOUNT_NOT_FOUND, + AUTH_ERROR_CODE.DIFFERENT_ACCOUNT_INFORMATION, + ], + { + description: + '해당 필드는 request parameter 가 잘못된 경우에만 리턴됩니다.', + type: ValidationError, + }, + ), + HttpException.swaggerBuilder(HttpStatus.INTERNAL_SERVER_ERROR, [ + COMMON_ERROR_CODE.SERVER_ERROR, + ]), + ); + }, +}; diff --git a/src/apis/notice-boards/dto/create-notice-board.dto.ts b/src/apis/notice-boards/dto/create-notice-board.dto.ts index 71fdba1f..9c48b2b6 100644 --- a/src/apis/notice-boards/dto/create-notice-board.dto.ts +++ b/src/apis/notice-boards/dto/create-notice-board.dto.ts @@ -1,13 +1,34 @@ -import { IsNotEmpty, Length } from 'class-validator'; -import { NOTICE_BOARD_TITLE_LENGTH } from '../constants/notice-board.constant'; +import { IsBoolean, IsNotEmpty, Length } from 'class-validator'; +import { + NOTICE_BOARD_ALLOW_COMMENT_LENGTH, + NOTICE_BOARD_TITLE_LENGTH, +} from '../constants/notice-board.constant'; import { NoticeBoardDto } from './notice-board.dto'; +import { ApiProperty } from '@nestjs/swagger'; export class CreateNoticeBoardDto - implements Pick + implements Pick { + @ApiProperty({ + description: '공지 게시글 제목', + minLength: NOTICE_BOARD_TITLE_LENGTH.MIN, + maxLength: NOTICE_BOARD_TITLE_LENGTH.MAX, + }) @Length(NOTICE_BOARD_TITLE_LENGTH.MIN, NOTICE_BOARD_TITLE_LENGTH.MAX) title: string; + @ApiProperty({ + description: '공지 게시글 본문', + }) @IsNotEmpty() description: string; + + @ApiProperty({ + description: '댓글 허용 여부 (0: 비활성화, 1: 허용)', + minimum: NOTICE_BOARD_ALLOW_COMMENT_LENGTH.MIN, + maximum: NOTICE_BOARD_ALLOW_COMMENT_LENGTH.MAX, + default: 1, + }) + @IsBoolean() + allowComment: number; } diff --git a/src/apis/notice-boards/dto/notice-board.dto.ts b/src/apis/notice-boards/dto/notice-board.dto.ts index 1e2e3ad9..435bbe23 100644 --- a/src/apis/notice-boards/dto/notice-board.dto.ts +++ b/src/apis/notice-boards/dto/notice-board.dto.ts @@ -1,5 +1,10 @@ +import { ApiProperty } from '@nestjs/swagger'; import { BaseDto } from '@src/dto/base.dto'; import { NoticeBoard } from '@src/entities/NoticeBoard'; +import { + NOTICE_BOARD_TITLE_LENGTH, + NOTICE_BOARD_ALLOW_COMMENT_LENGTH, +} from '../constants/notice-board.constant'; export class NoticeBoardDto extends BaseDto @@ -9,10 +14,37 @@ export class NoticeBoardDto 'title' | 'description' | 'hit' | 'allowComment' | 'userId' > { + @ApiProperty({ + description: '공지 게시글 제목', + minLength: NOTICE_BOARD_TITLE_LENGTH.MIN, + maxLength: NOTICE_BOARD_TITLE_LENGTH.MAX, + }) title: string; + + @ApiProperty({ + description: '공지 게시글 본문', + }) description: string; + + @ApiProperty({ + description: '공지 게시글 조회수', + default: 0, + format: 'integer', + }) hit: number; + + @ApiProperty({ + description: '댓글 허용 여부 (0: 비활성화, 1: 허용)', + minimum: NOTICE_BOARD_ALLOW_COMMENT_LENGTH.MIN, + maximum: NOTICE_BOARD_ALLOW_COMMENT_LENGTH.MAX, + default: 1, + }) allowComment: number; + + @ApiProperty({ + description: '게시글 작성자 고유 ID', + format: 'integer', + }) userId: number; constructor(noticeBoardDto: Partial = {}) { From c54f62ee793e6e92b11081167efb7d9d744e43c3 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Thu, 30 Nov 2023 16:31:14 +0900 Subject: [PATCH 07/37] feat/#66: feat findAll and notice-board-history migrate --- .../1701328900610-notice-board-history.ts | 247 ++++++++++++++++++ .../controllers/notice-boards.controller.ts | 9 +- .../controllers/notice-boards.swagger.ts | 32 +++ .../services/notice-boards.service.ts | 4 + 4 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 migrations/1701328900610-notice-board-history.ts diff --git a/migrations/1701328900610-notice-board-history.ts b/migrations/1701328900610-notice-board-history.ts new file mode 100644 index 00000000..5d6aa0fd --- /dev/null +++ b/migrations/1701328900610-notice-board-history.ts @@ -0,0 +1,247 @@ +import { + MigrationInterface, + QueryRunner, + Table, + TableColumnOptions, +} from 'typeorm'; + +const generatePrimaryColumn = ( + comment: string = '고유 ID', +): TableColumnOptions => { + return { + name: 'id', + type: 'int', + unsigned: true, + isPrimary: true, + isNullable: false, + isGenerated: true, + generationStrategy: 'increment', + comment, + }; +}; + +const generateCreatedAtColumn = ( + comment: string = '생성 일자', +): TableColumnOptions => { + return { + name: 'created_at', + type: 'timestamp', + isNullable: false, + default: 'CURRENT_TIMESTAMP', + comment, + }; +}; + +export class NoticeBoardHistory1701328900610 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + // 공지게시글 히스토리 + await queryRunner.createTable( + new Table({ + name: 'notice_board_history', + columns: [ + generatePrimaryColumn('공지 게시글 히스토리 고유 ID'), + { + name: 'notice_board_id', + type: 'int', + unsigned: true, + isNullable: false, + comment: '공지 게시글 고유 ID', + }, + { + name: 'user_id', + type: 'int', + unsigned: true, + isNullable: false, + comment: '게시글 작성 유저 고유 ID', + }, + { + name: 'title', + type: 'varchar', + length: '255', + isNullable: false, + comment: '공지게시글 제목', + }, + { + name: 'description', + type: 'text', + isNullable: false, + comment: '공지게시글 내용', + }, + { + name: 'allow_comment', + type: 'tinyint', + length: '1', + unsigned: true, + default: 1, + isNullable: false, + comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', + }, + generateCreatedAtColumn(), + ], + foreignKeys: [ + { + referencedTableName: 'notice_board', + referencedColumnNames: ['id'], + columnNames: ['notice_board_id'], + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }, + { + referencedTableName: 'user', + referencedColumnNames: ['id'], + columnNames: ['user_id'], + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }, + ], + }), + ); + await queryRunner.query( + 'ALTER TABLE notice_board_history COMMENT = "공지 게시판 수정이력"', + ); + + // 공지게시글 댓글 수정이력 + await queryRunner.createTable( + new Table({ + name: 'notice_board_comment_history', + columns: [ + generatePrimaryColumn('공지게시글 댓글 수정이력 고유 ID'), + { + name: 'user_id', + type: 'int', + unsigned: true, + isNullable: false, + comment: '댓글 작성 유저 고유 ID', + }, + { + name: 'notice_board_history_id', + type: 'int', + unsigned: true, + isNullable: false, + comment: '게시글 고유 ID', + }, + { + name: 'description', + type: 'varchar', + length: '255', + isNullable: false, + comment: '댓글 본문', + }, + { + name: 'isAnonymous', + type: 'tinyint', + length: '1', + default: 0, + unsigned: true, + isNullable: false, + comment: '작성자 익명 여부 (0: 실명, 1: 익명)', + }, + generateCreatedAtColumn(), + ], + foreignKeys: [ + { + referencedTableName: 'user', + referencedColumnNames: ['id'], + columnNames: ['user_id'], + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }, + { + referencedTableName: 'notice_board_history', + referencedColumnNames: ['id'], + columnNames: ['notice_board_history_id'], + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }, + ], + }), + ); + await queryRunner.query( + 'ALTER TABLE notice_board_comment_history COMMENT = "공지 게시글 댓글 수정이력"', + ); + + // 공지 게시글 대댓글 + await queryRunner.createTable( + new Table({ + name: 'notice_board_reply_comment_history', + columns: [ + generatePrimaryColumn('공지 게시글 대댓글 고유 ID'), + { + name: 'notice_board_history_id', + type: 'int', + unsigned: true, + isNullable: false, + comment: '게시글 고유 ID', + }, + { + name: 'notice_board_comment_history_id', + type: 'int', + unsigned: true, + isNullable: false, + comment: '공지 게시글 댓글 고유 ID', + }, + { + name: 'user_id', + type: 'int', + unsigned: true, + isNullable: false, + comment: '대댓글 작성 유저 고유 ID', + }, + { + name: 'description', + type: 'varchar', + length: '255', + isNullable: false, + comment: '대댓글 본문', + }, + { + name: 'isAnonymous', + type: 'tinyint', + length: '1', + default: 0, + unsigned: true, + isNullable: false, + comment: '작성자 익명 여부 (0: 실명, 1: 익명)', + }, + generateCreatedAtColumn(), + ], + foreignKeys: [ + { + referencedTableName: 'user', + referencedColumnNames: ['id'], + columnNames: ['user_id'], + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }, + { + referencedTableName: 'notice_board_history', + referencedColumnNames: ['id'], + columnNames: ['notice_board_history_id'], + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }, + { + referencedTableName: 'notice_board_comment_history', + referencedColumnNames: ['id'], + columnNames: ['notice_board_comment_history_id'], + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }, + ], + }), + ); + await queryRunner.query( + 'ALTER TABLE notice_board_reply_comment_history COMMENT = "공지 게시판 대댓글 수정이력"', + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable( + new Table({ name: 'notice_board_reply_comment_history' }), + ); + await queryRunner.dropTable( + new Table({ name: 'notice_board_comment_history' }), + ); + await queryRunner.dropTable(new Table({ name: 'notice_board_history' })); + } +} diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.ts b/src/apis/notice-boards/controllers/notice-boards.controller.ts index 166f86fc..2345b9eb 100644 --- a/src/apis/notice-boards/controllers/notice-boards.controller.ts +++ b/src/apis/notice-boards/controllers/notice-boards.controller.ts @@ -1,6 +1,7 @@ import { Body, Controller, + Get, // Delete, // Get, Param, @@ -31,8 +32,12 @@ export class NoticeBoardsController { return this.noticeBoardService.create(userId, createNoticeBoardDto); } - // @Get() - // findAll() {} + @ApiNoticeBoard.FindAll({ summary: 'notice-board 전체 조회 ' }) + @SetResponse({ type: ResponseType.Common, key: 'boards' }) + @Get() + findAll() { + return this.noticeBoardService.findAll(); + } // @Get(':id') // findOne() {} diff --git a/src/apis/notice-boards/controllers/notice-boards.swagger.ts b/src/apis/notice-boards/controllers/notice-boards.swagger.ts index b4d41a87..888cf77d 100644 --- a/src/apis/notice-boards/controllers/notice-boards.swagger.ts +++ b/src/apis/notice-boards/controllers/notice-boards.swagger.ts @@ -44,4 +44,36 @@ export const ApiNoticeBoard: ApiOperator = { ]), ); }, + FindAll: ( + apiOperationOptions: Required, 'summary'>> & + Partial, + ): PropertyDecorator => { + return applyDecorators( + ApiOperation({ + operationId: 'NoticeBoardFindAll', + ...apiOperationOptions, + }), + DetailResponseDto.swaggerBuilder( + HttpStatus.CREATED, + 'boards', + NoticeBoardDto, + ), + HttpException.swaggerBuilder( + HttpStatus.BAD_REQUEST, + [ + COMMON_ERROR_CODE.INVALID_REQUEST_PARAMETER, + AUTH_ERROR_CODE.ACCOUNT_NOT_FOUND, + AUTH_ERROR_CODE.DIFFERENT_ACCOUNT_INFORMATION, + ], + { + description: + '해당 필드는 request parameter 가 잘못된 경우에만 리턴됩니다.', + type: ValidationError, + }, + ), + HttpException.swaggerBuilder(HttpStatus.INTERNAL_SERVER_ERROR, [ + COMMON_ERROR_CODE.SERVER_ERROR, + ]), + ); + }, }; diff --git a/src/apis/notice-boards/services/notice-boards.service.ts b/src/apis/notice-boards/services/notice-boards.service.ts index 2a49e686..a85c47fb 100644 --- a/src/apis/notice-boards/services/notice-boards.service.ts +++ b/src/apis/notice-boards/services/notice-boards.service.ts @@ -50,4 +50,8 @@ export class NoticeBoardsService { } } } + + async findAll() { + return this.noticeBoardRepository.find(); + } } From 3865fece06b5af85a6fce902f62a320bb17e3440 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 3 Dec 2023 20:44:28 +0900 Subject: [PATCH 08/37] feat/#66: create dto, add and modify entities --- .../constants/notice-board.constant.ts | 12 ++++ .../controllers/notice-boards.controller.ts | 11 ++- .../controllers/notice-boards.swagger.ts | 2 +- .../dto/find-notice-board-query.dto.ts | 55 ++++++++++++++ .../dto/notice-boards-item.dto.ts | 6 ++ .../notice-boards/notice-boards.module.ts | 3 +- src/entities/NoticeBoard.ts | 7 ++ src/entities/NoticeBoardCommentHistory.ts | 62 ++++++++++++++++ src/entities/NoticeBoardHistory.ts | 72 +++++++++++++++++++ .../NoticeBoardReplyCommentHistory.ts | 70 ++++++++++++++++++ src/entities/User.ts | 21 ++++++ 11 files changed, 313 insertions(+), 8 deletions(-) create mode 100644 src/apis/notice-boards/dto/find-notice-board-query.dto.ts create mode 100644 src/apis/notice-boards/dto/notice-boards-item.dto.ts create mode 100644 src/entities/NoticeBoardCommentHistory.ts create mode 100644 src/entities/NoticeBoardHistory.ts create mode 100644 src/entities/NoticeBoardReplyCommentHistory.ts diff --git a/src/apis/notice-boards/constants/notice-board.constant.ts b/src/apis/notice-boards/constants/notice-board.constant.ts index 1255bf0e..9140baed 100644 --- a/src/apis/notice-boards/constants/notice-board.constant.ts +++ b/src/apis/notice-boards/constants/notice-board.constant.ts @@ -1,3 +1,15 @@ +import { NoticeBoardDto } from '../dto/notice-board.dto'; + +export const NOTICE_BOARD_ORDER_FIELD: readonly (keyof NoticeBoardDto)[] = [ + 'id', + 'userId', + 'title', + 'hit', + 'allowComment', + 'createdAt', + 'updatedAt', +] as const; + export const NOTICE_BOARD_TITLE_LENGTH = { MIN: 1, MAX: 255, diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.ts b/src/apis/notice-boards/controllers/notice-boards.controller.ts index 2345b9eb..4390baf2 100644 --- a/src/apis/notice-boards/controllers/notice-boards.controller.ts +++ b/src/apis/notice-boards/controllers/notice-boards.controller.ts @@ -8,6 +8,7 @@ import { ParseIntPipe, // Patch, Post, + Query, } from '@nestjs/common'; import { CreateNoticeBoardDto } from '../dto/create-notice-board.dto'; import { NoticeBoardsService } from '../services/notice-boards.service'; @@ -15,6 +16,7 @@ import { SetResponse } from '@src/interceptors/success-interceptor/decorators/su import { ResponseType } from '@src/interceptors/success-interceptor/constants/success-interceptor.enum'; import { ApiNoticeBoard } from './notice-boards.swagger'; import { ApiTags } from '@nestjs/swagger'; +import { NOTICE_BOARD_ORDER_FIELD } from '../constants/notice-board.constant'; @ApiTags('notice-boards') @Controller('notice-boards') @@ -32,13 +34,10 @@ export class NoticeBoardsController { return this.noticeBoardService.create(userId, createNoticeBoardDto); } - @ApiNoticeBoard.FindAll({ summary: 'notice-board 전체 조회 ' }) - @SetResponse({ type: ResponseType.Common, key: 'boards' }) @Get() - findAll() { - return this.noticeBoardService.findAll(); - } - + async findAllAndCount( + @Query() findNoticeBoardQueryDto: FindNoticeBoardQueryDto, + ) {} // @Get(':id') // findOne() {} diff --git a/src/apis/notice-boards/controllers/notice-boards.swagger.ts b/src/apis/notice-boards/controllers/notice-boards.swagger.ts index 888cf77d..070d9de0 100644 --- a/src/apis/notice-boards/controllers/notice-boards.swagger.ts +++ b/src/apis/notice-boards/controllers/notice-boards.swagger.ts @@ -44,7 +44,7 @@ export const ApiNoticeBoard: ApiOperator = { ]), ); }, - FindAll: ( + FindAllAndCount: ( apiOperationOptions: Required, 'summary'>> & Partial, ): PropertyDecorator => { diff --git a/src/apis/notice-boards/dto/find-notice-board-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-query.dto.ts new file mode 100644 index 00000000..c176ddf4 --- /dev/null +++ b/src/apis/notice-boards/dto/find-notice-board-query.dto.ts @@ -0,0 +1,55 @@ +import { PageDto } from '@src/dto/page.dto'; +import { NoticeBoardDto } from './notice-board.dto'; +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { IsBooleanString, IsOptional } from 'class-validator'; +import { IsPositiveInt } from '@src/dto/validator/is-positive-int.decorator'; +import { + NOTICE_BOARD_ORDER_FIELD, + NOTICE_BOARD_TITLE_LENGTH, +} from '../constants/notice-board.constant'; +import { Type } from 'class-transformer'; +import { ApiPropertyOrder } from '@src/dto/swagger/api-property-order.decorator'; +import { CsvToOrder, Order } from '@src/dto/transformer/csv-to-order.decorator'; +import { FREE_BOARD_ORDER_FIELD } from '@src/apis/free-boards/constants/free-board.constant'; +import { SortOrder } from '@src/constants/enum'; + +export class FindNoticeBoardQueryDto + extends PageDto + implements Partial +{ + @ApiPropertyOptional({ + description: '공지게시글 고유 ID 필터링', + format: 'integer', + }) + @IsOptional() + @IsPositiveInt() + id?: number; + + @ApiPropertyOptional({ + description: '공지게시글 작성자 고유 ID 필터링', + format: 'integer', + }) + @IsOptional() + @IsPositiveInt() + userId?: number; + + @ApiPropertyOptional({ + description: 'title 필터링', + maxLength: NOTICE_BOARD_TITLE_LENGTH.MAX, + }) + title?: string; + + @ApiPropertyOptional({ + description: '댓글 허용 여부', + enum: ['true', 'false', '0', '1'], + }) + @IsBooleanString() + @IsOptional() + @Type(() => Boolean) + allowComment?: boolean; + + @ApiPropertyOrder(NOTICE_BOARD_ORDER_FIELD) + @CsvToOrder([...NOTICE_BOARD_ORDER_FIELD]) + @IsOptional() + order: Order = { id: SortOrder.Desc }; +} diff --git a/src/apis/notice-boards/dto/notice-boards-item.dto.ts b/src/apis/notice-boards/dto/notice-boards-item.dto.ts new file mode 100644 index 00000000..118c1c5e --- /dev/null +++ b/src/apis/notice-boards/dto/notice-boards-item.dto.ts @@ -0,0 +1,6 @@ +import { OmitType } from '@nestjs/swagger'; +import { NoticeBoardDto } from './notice-board.dto'; + +export class NoticeBoardsItemDto extends OmitType(NoticeBoardDto, [ + 'description', +] as const) {} diff --git a/src/apis/notice-boards/notice-boards.module.ts b/src/apis/notice-boards/notice-boards.module.ts index d7ab3111..fca147fc 100644 --- a/src/apis/notice-boards/notice-boards.module.ts +++ b/src/apis/notice-boards/notice-boards.module.ts @@ -3,10 +3,11 @@ import { NoticeBoardsController } from './controllers/notice-boards.controller'; import { NoticeBoardsService } from './services/notice-boards.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { NoticeBoard } from '@src/entities/NoticeBoard'; +import { QueryHelper } from '@src/helpers/query.helper'; @Module({ imports: [TypeOrmModule.forFeature([NoticeBoard])], controllers: [NoticeBoardsController], - providers: [NoticeBoardsService], + providers: [NoticeBoardsService, QueryHelper], }) export class NoticeBoardsModule {} diff --git a/src/entities/NoticeBoard.ts b/src/entities/NoticeBoard.ts index 331fe1d0..cf25eccf 100644 --- a/src/entities/NoticeBoard.ts +++ b/src/entities/NoticeBoard.ts @@ -10,6 +10,7 @@ import { NoticeBoardComment } from './NoticeBoardComment'; import { NoticeBoardReaction } from './NoticeBoardReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { User } from './User'; +import { NoticeBoardHistory } from './NoticeBoardHistory'; @Entity('notice_board', { schema: 'dongurami_local_db' }) export class NoticeBoard { @@ -88,4 +89,10 @@ export class NoticeBoard { (noticeBoardReplyComment) => noticeBoardReplyComment.noticeBoard, ) noticeBoardReplyComments: NoticeBoardReplyComment[]; + + @OneToMany( + () => NoticeBoardHistory, + (noticeBoardHistories) => noticeBoardHistories.noticeBoard, + ) + noticeBoardHistories: NoticeBoardHistory[]; } diff --git a/src/entities/NoticeBoardCommentHistory.ts b/src/entities/NoticeBoardCommentHistory.ts new file mode 100644 index 00000000..ad5c23f2 --- /dev/null +++ b/src/entities/NoticeBoardCommentHistory.ts @@ -0,0 +1,62 @@ +import { + Column, + Entity, + JoinColumn, + ManyToOne, + OneToMany, + PrimaryGeneratedColumn, +} from 'typeorm'; +import { NoticeBoardHistory } from './NoticeBoardHistory'; +import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; +import { User } from './User'; + +@Entity('notice_board_comment_history', { schema: 'dongurami_local_db' }) +export class NoticeBoardCommentHistory { + @PrimaryGeneratedColumn({ + type: 'int', + name: 'id', + comment: '공지게시글 댓글 수정이력 고유 ID', + unsigned: true, + }) + id: number; + + @Column('varchar', { name: 'description', comment: '댓글 본문', length: 255 }) + description: string; + + @Column('tinyint', { + name: 'isAnonymous', + comment: '작성자 익명 여부 (0: 실명, 1: 익명)', + unsigned: true, + default: () => "'0'", + }) + isAnonymous: number; + + @Column('timestamp', { + name: 'created_at', + comment: '생성 일자', + default: () => 'CURRENT_TIMESTAMP', + }) + createdAt: Date; + + @ManyToOne(() => User, (user) => user.noticeBoardCommentHistories, { + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }) + @JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }]) + user: User; + + @ManyToOne( + () => NoticeBoardHistory, + (noticeBoardHistory) => noticeBoardHistory.noticeBoardCommentHistories, + { onDelete: 'NO ACTION', onUpdate: 'NO ACTION' }, + ) + @JoinColumn([{ name: 'notice_board_history_id', referencedColumnName: 'id' }]) + noticeBoardHistory: NoticeBoardHistory; + + @OneToMany( + () => NoticeBoardReplyCommentHistory, + (noticeBoardReplyCommentHistory) => + noticeBoardReplyCommentHistory.noticeBoardCommentHistory, + ) + noticeBoardReplyCommentHistories: NoticeBoardReplyCommentHistory[]; +} diff --git a/src/entities/NoticeBoardHistory.ts b/src/entities/NoticeBoardHistory.ts new file mode 100644 index 00000000..1d18ea5e --- /dev/null +++ b/src/entities/NoticeBoardHistory.ts @@ -0,0 +1,72 @@ +import { + Column, + Entity, + JoinColumn, + ManyToOne, + OneToMany, + PrimaryGeneratedColumn, +} from 'typeorm'; +import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; +import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; +import { User } from './User'; +import { NoticeBoard } from './NoticeBoard'; + +@Entity('notice_board_history', { schema: 'dongurami_local_db' }) +export class NoticeBoardHistory { + @PrimaryGeneratedColumn({ + type: 'int', + name: 'id', + comment: '공지 게시글 히스토리 고유 ID', + unsigned: true, + }) + id: number; + + @Column('varchar', { name: 'title', comment: '공지게시글 제목', length: 255 }) + title: string; + + @Column('text', { name: 'description', comment: '공지게시글 내용' }) + description: string; + + @Column('tinyint', { + name: 'allow_comment', + comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', + unsigned: true, + default: () => "'1'", + }) + allowComment: number; + + @Column('timestamp', { + name: 'created_at', + comment: '생성 일자', + default: () => 'CURRENT_TIMESTAMP', + }) + createdAt: Date; + + @OneToMany( + () => NoticeBoardCommentHistory, + (noticeBoardCommentHistory) => noticeBoardCommentHistory.noticeBoardHistory, + ) + noticeBoardCommentHistories: NoticeBoardCommentHistory[]; + + @ManyToOne(() => User, (user) => user.noticeBoardHistories, { + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }) + @JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }]) + user: User; + + @ManyToOne( + () => NoticeBoard, + (noticeBoard) => noticeBoard.noticeBoardHistories, + { onDelete: 'NO ACTION', onUpdate: 'NO ACTION' }, + ) + @JoinColumn([{ name: 'notice_board_id', referencedColumnName: 'id' }]) + noticeBoard: NoticeBoard; + + @OneToMany( + () => NoticeBoardReplyCommentHistory, + (noticeBoardReplyCommentHistory) => + noticeBoardReplyCommentHistory.noticeBoardHistory, + ) + noticeBoardReplyCommentHistories: NoticeBoardReplyCommentHistory[]; +} diff --git a/src/entities/NoticeBoardReplyCommentHistory.ts b/src/entities/NoticeBoardReplyCommentHistory.ts new file mode 100644 index 00000000..51812554 --- /dev/null +++ b/src/entities/NoticeBoardReplyCommentHistory.ts @@ -0,0 +1,70 @@ +import { + Column, + Entity, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, +} from 'typeorm'; + +import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; +import { NoticeBoardHistory } from './NoticeBoardHistory'; +import { User } from './User'; + +@Entity('notice_board_reply_comment_history', { schema: 'dongurami_local_db' }) +export class NoticeBoardReplyCommentHistory { + @PrimaryGeneratedColumn({ + type: 'int', + name: 'id', + comment: '공지 게시글 대댓글 고유 ID', + unsigned: true, + }) + id: number; + + @Column('varchar', { + name: 'description', + comment: '대댓글 본문', + length: 255, + }) + description: string; + + @Column('tinyint', { + name: 'isAnonymous', + comment: '작성자 익명 여부 (0: 실명, 1: 익명)', + unsigned: true, + default: () => "'0'", + }) + isAnonymous: number; + + @Column('timestamp', { + name: 'created_at', + comment: '생성 일자', + default: () => 'CURRENT_TIMESTAMP', + }) + createdAt: Date; + + @ManyToOne(() => User, (user) => user.noticeBoardReplyCommentHistories, { + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + }) + @JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }]) + user: User; + + @ManyToOne( + () => NoticeBoardCommentHistory, + (noticeBoardCommentHistory) => + noticeBoardCommentHistory.noticeBoardReplyCommentHistories, + { onDelete: 'NO ACTION', onUpdate: 'NO ACTION' }, + ) + @JoinColumn([ + { name: 'notice_board_comment_history_id', referencedColumnName: 'id' }, + ]) + noticeBoardCommentHistory: NoticeBoardCommentHistory; + + @ManyToOne( + () => NoticeBoardHistory, + (noticeBoardHistory) => noticeBoardHistory.noticeBoardReplyCommentHistories, + { onDelete: 'NO ACTION', onUpdate: 'NO ACTION' }, + ) + @JoinColumn([{ name: 'notice_board_history_id', referencedColumnName: 'id' }]) + noticeBoardHistory: NoticeBoardHistory; +} diff --git a/src/entities/User.ts b/src/entities/User.ts index 725dde2b..0ae6b845 100644 --- a/src/entities/User.ts +++ b/src/entities/User.ts @@ -29,6 +29,9 @@ import { NoticeBoardCommentReaction } from './NoticeBoardCommentReaction'; import { NoticeBoardReaction } from './NoticeBoardReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { NoticeBoardReplyCommentReaction } from './NoticeBoardReplyCommentReaction'; +import { NoticeBoardHistory } from './NoticeBoardHistory'; +import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; +import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; @Entity('user', { schema: 'dongurami_v2' }) export class User { @@ -185,12 +188,24 @@ export class User { @OneToMany(() => NoticeBoard, (noticeBoard) => noticeBoard.user) noticeBoards: NoticeBoard[]; + @OneToMany( + () => NoticeBoardHistory, + (noticeBoardHistories) => noticeBoardHistories.user, + ) + noticeBoardHistories: NoticeBoardHistory[]; + @OneToMany( () => NoticeBoardComment, (noticeBoardComment) => noticeBoardComment.user, ) noticeBoardComments: NoticeBoardComment[]; + @OneToMany( + () => NoticeBoardCommentHistory, + (noticeBoardCommentHistories) => noticeBoardCommentHistories.user, + ) + noticeBoardCommentHistories: NoticeBoardCommentHistory[]; + @OneToMany( () => NoticeBoardCommentReaction, (noticeBoardCommentReaction) => noticeBoardCommentReaction.user, @@ -209,6 +224,12 @@ export class User { ) noticeBoardReplyComments: NoticeBoardReplyComment[]; + @OneToMany( + () => NoticeBoardReplyCommentHistory, + (noticeBoardReplyCommentHistories) => noticeBoardReplyCommentHistories.user, + ) + noticeBoardReplyCommentHistories: NoticeBoardReplyCommentHistory[]; + @OneToMany( () => NoticeBoardReplyCommentReaction, (noticeBoardReplyCommentReaction) => noticeBoardReplyCommentReaction.user, From 96831599495ff084fc315f76ccd490f6f32b94d0 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 3 Dec 2023 20:51:03 +0900 Subject: [PATCH 09/37] modify/#66: modify entity --- src/entities/NoticeBoard.ts | 4 +++- src/entities/NoticeBoardHistory.ts | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/entities/NoticeBoard.ts b/src/entities/NoticeBoard.ts index cf25eccf..440a1667 100644 --- a/src/entities/NoticeBoard.ts +++ b/src/entities/NoticeBoard.ts @@ -11,6 +11,7 @@ import { NoticeBoardReaction } from './NoticeBoardReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { User } from './User'; import { NoticeBoardHistory } from './NoticeBoardHistory'; +import { BooleanTransformer } from './transfomers/boolean.transfomer'; @Entity('notice_board', { schema: 'dongurami_local_db' }) export class NoticeBoard { @@ -41,8 +42,9 @@ export class NoticeBoard { comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', unsigned: true, default: () => "'1'", + transformer: new BooleanTransformer(), }) - allowComment: number; + allowComment: boolean; @Column('timestamp', { name: 'created_at', diff --git a/src/entities/NoticeBoardHistory.ts b/src/entities/NoticeBoardHistory.ts index 1d18ea5e..87c8a24c 100644 --- a/src/entities/NoticeBoardHistory.ts +++ b/src/entities/NoticeBoardHistory.ts @@ -10,6 +10,7 @@ import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; import { User } from './User'; import { NoticeBoard } from './NoticeBoard'; +import { BooleanTransformer } from './transfomers/boolean.transfomer'; @Entity('notice_board_history', { schema: 'dongurami_local_db' }) export class NoticeBoardHistory { @@ -32,8 +33,9 @@ export class NoticeBoardHistory { comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', unsigned: true, default: () => "'1'", + transformer: new BooleanTransformer(), }) - allowComment: number; + allowComment: boolean; @Column('timestamp', { name: 'created_at', @@ -48,6 +50,20 @@ export class NoticeBoardHistory { ) noticeBoardCommentHistories: NoticeBoardCommentHistory[]; + @Column('int', { + name: 'notice_board_id', + comment: '공지 게시글 고유 ID', + unsigned: true, + }) + noticeBoardId: number; + + @Column('int', { + name: 'user_id', + comment: '게시글 작성 유저 고유 ID', + unsigned: true, + }) + userId: number; + @ManyToOne(() => User, (user) => user.noticeBoardHistories, { onDelete: 'NO ACTION', onUpdate: 'NO ACTION', From 0d324e12af0c6c3ac37bbebd8aeb2699cfd98551 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 3 Dec 2023 21:47:25 +0900 Subject: [PATCH 10/37] feat/#66: create api for post, getAll --- .../controllers/notice-boards.controller.ts | 34 +++++++++---- .../controllers/notice-boards.swagger.ts | 32 +++++------- .../dto/create-notice-board.dto.ts | 2 +- ...ts => find-notice-board-list-query.dto.ts} | 2 +- .../notice-boards/dto/notice-board.dto.ts | 11 ++++- .../dto/create-notice-board-history.dto.ts | 15 ++++++ .../notice-board-history.module.ts | 11 +++++ .../services/notice-board-history.service.ts | 27 ++++++++++ .../notice-boards/notice-boards.module.ts | 3 +- .../services/notice-boards.service.ts | 49 ++++++++++++++++++- 10 files changed, 149 insertions(+), 37 deletions(-) rename src/apis/notice-boards/dto/{find-notice-board-query.dto.ts => find-notice-board-list-query.dto.ts} (97%) create mode 100644 src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts create mode 100644 src/apis/notice-boards/notice-board-history/notice-board-history.module.ts create mode 100644 src/apis/notice-boards/notice-board-history/services/notice-board-history.service.ts diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.ts b/src/apis/notice-boards/controllers/notice-boards.controller.ts index 4390baf2..a32ad4fc 100644 --- a/src/apis/notice-boards/controllers/notice-boards.controller.ts +++ b/src/apis/notice-boards/controllers/notice-boards.controller.ts @@ -4,11 +4,10 @@ import { Get, // Delete, // Get, - Param, - ParseIntPipe, // Patch, Post, Query, + UseGuards, } from '@nestjs/common'; import { CreateNoticeBoardDto } from '../dto/create-notice-board.dto'; import { NoticeBoardsService } from '../services/notice-boards.service'; @@ -16,28 +15,43 @@ import { SetResponse } from '@src/interceptors/success-interceptor/decorators/su import { ResponseType } from '@src/interceptors/success-interceptor/constants/success-interceptor.enum'; import { ApiNoticeBoard } from './notice-boards.swagger'; import { ApiTags } from '@nestjs/swagger'; -import { NOTICE_BOARD_ORDER_FIELD } from '../constants/notice-board.constant'; +import { FindNoticeBoardListQueryDto } from '../dto/find-notice-board-list-query.dto'; +import { NoticeBoardsItemDto } from '../dto/notice-boards-item.dto'; +import { plainToInstance } from 'class-transformer'; +import { JwtAuthGuard } from '@src/apis/auth/jwt/jwt.guard'; +import { UserDto } from '@src/apis/users/dto/user.dto'; +import { User } from '@src/decorators/user.decorator'; @ApiTags('notice-boards') @Controller('notice-boards') export class NoticeBoardsController { constructor(private readonly noticeBoardService: NoticeBoardsService) {} - @ApiNoticeBoard.Create({ summary: 'notice-board 게시글 생성 API' }) + @ApiNoticeBoard.Create({ summary: '공지 게시글 생성 API' }) + @UseGuards(JwtAuthGuard) @SetResponse({ type: ResponseType.Detail, key: 'board' }) - @Post(':userId') + @Post() create( - // 추후 develop에 guard가 merge 될 시에 수정 - @Param('userId', ParseIntPipe) userId: number, + @User() user: UserDto, @Body() createNoticeBoardDto: CreateNoticeBoardDto, ) { - return this.noticeBoardService.create(userId, createNoticeBoardDto); + return this.noticeBoardService.create(user.id, createNoticeBoardDto); } + @ApiNoticeBoard.FindAllAndCount({ + summary: '공지 게시글 전체조회(pagination)', + }) + @SetResponse({ type: ResponseType.Pagination, key: 'noticeBoards' }) @Get() async findAllAndCount( - @Query() findNoticeBoardQueryDto: FindNoticeBoardQueryDto, - ) {} + @Query() findNoticeBoardListQueryDto: FindNoticeBoardListQueryDto, + ): Promise<[NoticeBoardsItemDto[], number]> { + const [noticeBoards, count] = await this.noticeBoardService.findAllAndCount( + findNoticeBoardListQueryDto, + ); + + return [plainToInstance(NoticeBoardsItemDto, noticeBoards), count]; + } // @Get(':id') // findOne() {} diff --git a/src/apis/notice-boards/controllers/notice-boards.swagger.ts b/src/apis/notice-boards/controllers/notice-boards.swagger.ts index 070d9de0..3ef12773 100644 --- a/src/apis/notice-boards/controllers/notice-boards.swagger.ts +++ b/src/apis/notice-boards/controllers/notice-boards.swagger.ts @@ -1,8 +1,6 @@ import { HttpStatus, applyDecorators } from '@nestjs/common'; import { ApiOperation } from '@nestjs/swagger'; import { OperationObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface'; - -import { AUTH_ERROR_CODE } from '@src/constants/error/auth/auth-error-code.constant'; import { COMMON_ERROR_CODE } from '@src/constants/error/common/common-error-code.constant'; import { HttpException } from '@src/http-exceptions/exceptions/http.exception'; import { ApiOperator } from '@src/types/type'; @@ -10,6 +8,8 @@ import { ValidationError } from '@src/types/validation-errors.type'; import { NoticeBoardsController } from './notice-boards.controller'; import { DetailResponseDto } from '@src/interceptors/success-interceptor/dto/detail-response.dto'; import { NoticeBoardDto } from '../dto/notice-board.dto'; +import { NoticeBoardsItemDto } from '../dto/notice-boards-item.dto'; +import { PaginationResponseDto } from '@src/interceptors/success-interceptor/dto/pagination-response.dto'; export const ApiNoticeBoard: ApiOperator = { Create: ( @@ -28,17 +28,16 @@ export const ApiNoticeBoard: ApiOperator = { ), HttpException.swaggerBuilder( HttpStatus.BAD_REQUEST, - [ - COMMON_ERROR_CODE.INVALID_REQUEST_PARAMETER, - AUTH_ERROR_CODE.ACCOUNT_NOT_FOUND, - AUTH_ERROR_CODE.DIFFERENT_ACCOUNT_INFORMATION, - ], + [COMMON_ERROR_CODE.INVALID_REQUEST_PARAMETER], { description: '해당 필드는 request parameter 가 잘못된 경우에만 리턴됩니다.', type: ValidationError, }, ), + HttpException.swaggerBuilder(HttpStatus.UNAUTHORIZED, [ + COMMON_ERROR_CODE.INVALID_TOKEN, + ]), HttpException.swaggerBuilder(HttpStatus.INTERNAL_SERVER_ERROR, [ COMMON_ERROR_CODE.SERVER_ERROR, ]), @@ -50,30 +49,23 @@ export const ApiNoticeBoard: ApiOperator = { ): PropertyDecorator => { return applyDecorators( ApiOperation({ - operationId: 'NoticeBoardFindAll', + operationId: 'NoticeBoardFindAllAndCount', ...apiOperationOptions, }), - DetailResponseDto.swaggerBuilder( - HttpStatus.CREATED, - 'boards', - NoticeBoardDto, + PaginationResponseDto.swaggerBuilder( + HttpStatus.OK, + 'noticeBoards', + NoticeBoardsItemDto, ), HttpException.swaggerBuilder( HttpStatus.BAD_REQUEST, - [ - COMMON_ERROR_CODE.INVALID_REQUEST_PARAMETER, - AUTH_ERROR_CODE.ACCOUNT_NOT_FOUND, - AUTH_ERROR_CODE.DIFFERENT_ACCOUNT_INFORMATION, - ], + [COMMON_ERROR_CODE.INVALID_REQUEST_PARAMETER], { description: '해당 필드는 request parameter 가 잘못된 경우에만 리턴됩니다.', type: ValidationError, }, ), - HttpException.swaggerBuilder(HttpStatus.INTERNAL_SERVER_ERROR, [ - COMMON_ERROR_CODE.SERVER_ERROR, - ]), ); }, }; diff --git a/src/apis/notice-boards/dto/create-notice-board.dto.ts b/src/apis/notice-boards/dto/create-notice-board.dto.ts index 9c48b2b6..53cec89f 100644 --- a/src/apis/notice-boards/dto/create-notice-board.dto.ts +++ b/src/apis/notice-boards/dto/create-notice-board.dto.ts @@ -30,5 +30,5 @@ export class CreateNoticeBoardDto default: 1, }) @IsBoolean() - allowComment: number; + allowComment: boolean; } diff --git a/src/apis/notice-boards/dto/find-notice-board-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts similarity index 97% rename from src/apis/notice-boards/dto/find-notice-board-query.dto.ts rename to src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index c176ddf4..c229a060 100644 --- a/src/apis/notice-boards/dto/find-notice-board-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -13,7 +13,7 @@ import { CsvToOrder, Order } from '@src/dto/transformer/csv-to-order.decorator'; import { FREE_BOARD_ORDER_FIELD } from '@src/apis/free-boards/constants/free-board.constant'; import { SortOrder } from '@src/constants/enum'; -export class FindNoticeBoardQueryDto +export class FindNoticeBoardListQueryDto extends PageDto implements Partial { diff --git a/src/apis/notice-boards/dto/notice-board.dto.ts b/src/apis/notice-boards/dto/notice-board.dto.ts index 435bbe23..aeaacee0 100644 --- a/src/apis/notice-boards/dto/notice-board.dto.ts +++ b/src/apis/notice-boards/dto/notice-board.dto.ts @@ -11,7 +11,14 @@ export class NoticeBoardDto implements Pick< NoticeBoard, - 'title' | 'description' | 'hit' | 'allowComment' | 'userId' + | 'id' + | 'title' + | 'description' + | 'hit' + | 'allowComment' + | 'userId' + | 'createdAt' + | 'updatedAt' > { @ApiProperty({ @@ -39,7 +46,7 @@ export class NoticeBoardDto maximum: NOTICE_BOARD_ALLOW_COMMENT_LENGTH.MAX, default: 1, }) - allowComment: number; + allowComment: boolean; @ApiProperty({ description: '게시글 작성자 고유 ID', diff --git a/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts b/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts new file mode 100644 index 00000000..677cf8a7 --- /dev/null +++ b/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts @@ -0,0 +1,15 @@ +import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; + +export class CreateNoticeBoardHistoryDto + implements Pick +{ + title: string; + description: string; + allowComment: boolean; + + constructor(createNoticeBoardHistoryDto: CreateNoticeBoardHistoryDto) { + this.title = createNoticeBoardHistoryDto.title; + this.description = createNoticeBoardHistoryDto.description; + this.allowComment = createNoticeBoardHistoryDto.allowComment; + } +} diff --git a/src/apis/notice-boards/notice-board-history/notice-board-history.module.ts b/src/apis/notice-boards/notice-board-history/notice-board-history.module.ts new file mode 100644 index 00000000..d37e537a --- /dev/null +++ b/src/apis/notice-boards/notice-board-history/notice-board-history.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { NoticeBoardHistoryService } from './services/notice-board-history.service'; +import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; + +@Module({ + imports: [TypeOrmModule.forFeature([NoticeBoardHistory])], + providers: [NoticeBoardHistoryService], + exports: [NoticeBoardHistoryService], +}) +export class NoticeBoardHistoryModule {} diff --git a/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.ts b/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.ts new file mode 100644 index 00000000..9ab7e9ff --- /dev/null +++ b/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; +import { EntityManager, Repository } from 'typeorm'; +import { CreateNoticeBoardHistoryDto } from '../dto/create-notice-board-history.dto'; + +@Injectable() +export class NoticeBoardHistoryService { + constructor( + @InjectRepository(NoticeBoardHistory) + private readonly noticeBoardHistoryRepository: Repository, + ) {} + create( + entityManager: EntityManager, + userId: number, + noticeBoardId: number, + createNoticeBoardHistoryDto: CreateNoticeBoardHistoryDto, + ) { + return entityManager + .withRepository(this.noticeBoardHistoryRepository) + .save({ + userId, + noticeBoardId, + ...new CreateNoticeBoardHistoryDto(createNoticeBoardHistoryDto), + }); + } +} diff --git a/src/apis/notice-boards/notice-boards.module.ts b/src/apis/notice-boards/notice-boards.module.ts index fca147fc..ce4c64b0 100644 --- a/src/apis/notice-boards/notice-boards.module.ts +++ b/src/apis/notice-boards/notice-boards.module.ts @@ -4,9 +4,10 @@ import { NoticeBoardsService } from './services/notice-boards.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { NoticeBoard } from '@src/entities/NoticeBoard'; import { QueryHelper } from '@src/helpers/query.helper'; +import { NoticeBoardHistoryModule } from './notice-board-history/notice-board-history.module'; @Module({ - imports: [TypeOrmModule.forFeature([NoticeBoard])], + imports: [TypeOrmModule.forFeature([NoticeBoard]), NoticeBoardHistoryModule], controllers: [NoticeBoardsController], providers: [NoticeBoardsService, QueryHelper], }) diff --git a/src/apis/notice-boards/services/notice-boards.service.ts b/src/apis/notice-boards/services/notice-boards.service.ts index a85c47fb..b1027a06 100644 --- a/src/apis/notice-boards/services/notice-boards.service.ts +++ b/src/apis/notice-boards/services/notice-boards.service.ts @@ -6,10 +6,21 @@ import { NoticeBoard } from '@src/entities/NoticeBoard'; import { NoticeBoardDto } from '../dto/notice-board.dto'; import { HttpInternalServerErrorException } from '@src/http-exceptions/exceptions/http-internal-server-error.exception'; import { COMMON_ERROR_CODE } from '@src/constants/error/common/common-error-code.constant'; +import { QueryHelper } from '@src/helpers/query.helper'; +import { FindNoticeBoardListQueryDto } from '../dto/find-notice-board-list-query.dto'; +import { NoticeBoardsItemDto } from '../dto/notice-boards-item.dto'; +import { NoticeBoardHistoryService } from '../notice-board-history/services/notice-board-history.service'; @Injectable() export class NoticeBoardsService { + private readonly LIKE_SEARCH_FIELD: readonly (keyof Pick< + NoticeBoardDto, + 'title' + >)[] = ['title']; + constructor( + private readonly queryHelper: QueryHelper, + private readonly noticeBoardHistoryService: NoticeBoardHistoryService, private readonly dataSource: DataSource, @InjectRepository(NoticeBoard) private readonly noticeBoardRepository: Repository, @@ -30,6 +41,17 @@ export class NoticeBoardsService { ...createNoticeBoardDto, }); + await this.noticeBoardHistoryService.create( + entityManager, + newPost.userId, + newPost.id, + { + title: newPost.title, + description: newPost.description, + allowComment: newPost.allowComment, + }, + ); + await queryRunner.commitTransaction(); return new NoticeBoardDto(newPost); @@ -51,7 +73,30 @@ export class NoticeBoardsService { } } - async findAll() { - return this.noticeBoardRepository.find(); + async findAllAndCount( + findNoticeBoardListQueryDto: FindNoticeBoardListQueryDto, + ): Promise<[NoticeBoardsItemDto[], number]> { + const { page, pageSize, order, ...filter } = findNoticeBoardListQueryDto; + + const where = this.queryHelper.buildWherePropForFind( + filter, + this.LIKE_SEARCH_FIELD, + ); + + return this.noticeBoardRepository.findAndCount({ + select: { + id: true, + userId: true, + title: true, + hit: true, + allowComment: true, + createdAt: true, + updatedAt: true, + }, + where, + order, + skip: page * pageSize, + take: pageSize, + }); } } From 4d5f325894916a4075daa67dba156eea4cad8bf5 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 3 Dec 2023 22:46:50 +0900 Subject: [PATCH 11/37] feat/#66: create test code --- src/apis/auth/jwt/jwt.guard.ts | 1 + .../notice-boards.controller.spec.ts | 59 +++++++++- .../dto/find-notice-board-list-query.dto.ts | 1 + .../notice-boards/dto/notice-board.dto.ts | 14 +-- .../notice-board-history.service.spec.ts | 65 +++++++++++ .../services/notice-boards.service.spec.ts | 104 +++++++++++++++++- .../services/notice-boards.service.ts | 1 + test/mock/mock.repository.ts | 13 +++ test/mock/mock.service.ts | 12 ++ 9 files changed, 260 insertions(+), 10 deletions(-) create mode 100644 src/apis/notice-boards/notice-board-history/services/notice-board-history.service.spec.ts diff --git a/src/apis/auth/jwt/jwt.guard.ts b/src/apis/auth/jwt/jwt.guard.ts index c487393d..933019d7 100644 --- a/src/apis/auth/jwt/jwt.guard.ts +++ b/src/apis/auth/jwt/jwt.guard.ts @@ -7,6 +7,7 @@ import { HttpUnauthorizedException } from '@src/http-exceptions/exceptions/http- export class JwtAuthGuard extends AuthGuard('jwt') { handleRequest(err, user) { if (err || !user) { + console.log(err, user); throw new HttpUnauthorizedException({ code: COMMON_ERROR_CODE.INVALID_TOKEN, }); diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts b/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts index 85ae70e5..730d0164 100644 --- a/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts +++ b/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts @@ -1,18 +1,75 @@ +import { faker } from '@faker-js/faker'; import { Test, TestingModule } from '@nestjs/testing'; +import { UserDto } from '@src/apis/users/dto/user.dto'; +import { mockNoticeBoardsService } from '@test/mock/mock.service'; +import { CreateNoticeBoardDto } from '../dto/create-notice-board.dto'; +import { FindNoticeBoardListQueryDto } from '../dto/find-notice-board-list-query.dto'; +import { NoticeBoardDto } from '../dto/notice-board.dto'; +import { NoticeBoardsService } from '../services/notice-boards.service'; import { NoticeBoardsController } from './notice-boards.controller'; -describe('NoticeBoardsController', () => { +describe(NoticeBoardsController.name, () => { let controller: NoticeBoardsController; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ controllers: [NoticeBoardsController], + providers: [ + { + provide: NoticeBoardsService, + useValue: mockNoticeBoardsService, + }, + ], }).compile(); controller = module.get(NoticeBoardsController); }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('should be defined', () => { expect(controller).toBeDefined(); }); + + describe(NoticeBoardsController.prototype.create.name, () => { + let user: UserDto; + let createNoticeBoardDto: CreateNoticeBoardDto; + + let newNoticeBoard: NoticeBoardDto; + + beforeEach(() => { + user = new UserDto(); + createNoticeBoardDto = new CreateNoticeBoardDto(); + + newNoticeBoard = new NoticeBoardDto(); + }); + + it('create Notice board', async () => { + user.id = faker.number.int(); + + mockNoticeBoardsService.create.mockResolvedValue(newNoticeBoard); + + await expect( + controller.create(user, createNoticeBoardDto), + ).resolves.toEqual(newNoticeBoard); + }); + }); + + describe(NoticeBoardsController.prototype.findAllAndCount.name, () => { + let findNoticeBoardListQueryDto: FindNoticeBoardListQueryDto; + + beforeEach(() => { + findNoticeBoardListQueryDto = new FindNoticeBoardListQueryDto(); + }); + + it('find all and count', async () => { + mockNoticeBoardsService.findAllAndCount.mockResolvedValue([[], 0]); + + await expect( + controller.findAllAndCount(findNoticeBoardListQueryDto), + ).resolves.toEqual([[], 0]); + }); + }); }); diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index c229a060..3413b7eb 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -37,6 +37,7 @@ export class FindNoticeBoardListQueryDto description: 'title 필터링', maxLength: NOTICE_BOARD_TITLE_LENGTH.MAX, }) + @IsOptional() title?: string; @ApiPropertyOptional({ diff --git a/src/apis/notice-boards/dto/notice-board.dto.ts b/src/apis/notice-boards/dto/notice-board.dto.ts index aeaacee0..b14faba2 100644 --- a/src/apis/notice-boards/dto/notice-board.dto.ts +++ b/src/apis/notice-boards/dto/notice-board.dto.ts @@ -14,9 +14,9 @@ export class NoticeBoardDto | 'id' | 'title' | 'description' + | 'userId' | 'hit' | 'allowComment' - | 'userId' | 'createdAt' | 'updatedAt' > @@ -33,6 +33,12 @@ export class NoticeBoardDto }) description: string; + @ApiProperty({ + description: '게시글 작성자 고유 ID', + format: 'integer', + }) + userId: number; + @ApiProperty({ description: '공지 게시글 조회수', default: 0, @@ -48,12 +54,6 @@ export class NoticeBoardDto }) allowComment: boolean; - @ApiProperty({ - description: '게시글 작성자 고유 ID', - format: 'integer', - }) - userId: number; - constructor(noticeBoardDto: Partial = {}) { super(); diff --git a/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.spec.ts b/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.spec.ts new file mode 100644 index 00000000..a7eaf475 --- /dev/null +++ b/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.spec.ts @@ -0,0 +1,65 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { + mockEntityManager, + mockNoticeBoardHistoryRepository, +} from '@test/mock/mock.repository'; + +import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; +import { CreateNoticeBoardHistoryDto } from '../dto/create-notice-board-history.dto'; +import { NoticeBoardHistoryService } from './notice-board-history.service'; + +describe(NoticeBoardHistoryService.name, () => { + let service: NoticeBoardHistoryService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + NoticeBoardHistoryService, + { + provide: getRepositoryToken(NoticeBoardHistory), + useValue: mockNoticeBoardHistoryRepository, + }, + ], + }).compile(); + + service = module.get(NoticeBoardHistoryService); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); + + describe(NoticeBoardHistoryService.prototype.create.name, () => { + let entityManager: any; + let userId: number; + let noticeBoardId: number; + let createNoticeBoardHistoryDto: CreateNoticeBoardHistoryDto; + + beforeEach(() => { + entityManager = mockEntityManager; + userId = NaN; + noticeBoardId = NaN; + createNoticeBoardHistoryDto = new CreateNoticeBoardHistoryDto({} as any); + }); + + it('create notice board history', async () => { + mockNoticeBoardHistoryRepository.save.mockResolvedValue( + createNoticeBoardHistoryDto, + ); + + await expect( + service.create( + entityManager, + userId, + noticeBoardId, + createNoticeBoardHistoryDto, + ), + ).resolves.toEqual({}); + }); + }); +}); diff --git a/src/apis/notice-boards/services/notice-boards.service.spec.ts b/src/apis/notice-boards/services/notice-boards.service.spec.ts index 1d679256..cd9a2e7f 100644 --- a/src/apis/notice-boards/services/notice-boards.service.spec.ts +++ b/src/apis/notice-boards/services/notice-boards.service.spec.ts @@ -1,18 +1,118 @@ +import { faker } from '@faker-js/faker'; import { Test, TestingModule } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { SortOrder } from '@src/constants/enum'; +import { QueryHelper } from '@src/helpers/query.helper'; +import { mockQueryHelper } from '@test/mock/mock.helper'; +import { + mockDataSource, + mockNoticeBoardRepository, +} from '@test/mock/mock.repository'; +import { mockNoticeBoardHistoryService } from '@test/mock/mock.service'; +import { DataSource } from 'typeorm'; import { NoticeBoardsService } from './notice-boards.service'; +import { NoticeBoardDto } from '../dto/notice-board.dto'; +import { CreateNoticeBoardDto } from '../dto/create-notice-board.dto'; +import { NoticeBoardHistoryService } from '../notice-board-history/services/notice-board-history.service'; +import { NoticeBoard } from '@src/entities/NoticeBoard'; +import { FindNoticeBoardListQueryDto } from '../dto/find-notice-board-list-query.dto'; -describe('NoticeBoardsService', () => { +describe(NoticeBoardsService.name, () => { let service: NoticeBoardsService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [NoticeBoardsService], + providers: [ + NoticeBoardsService, + { + provide: NoticeBoardHistoryService, + useValue: mockNoticeBoardHistoryService, + }, + { + provide: QueryHelper, + useValue: mockQueryHelper, + }, + { + provide: DataSource, + useValue: mockDataSource, + }, + { + provide: getRepositoryToken(NoticeBoard), + useValue: mockNoticeBoardRepository, + }, + ], }).compile(); service = module.get(NoticeBoardsService); }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('should be defined', () => { expect(service).toBeDefined(); }); + + describe(NoticeBoardsService.prototype.create.name, () => { + let userId: number; + let createNoticeBoardDto: CreateNoticeBoardDto; + + beforeEach(() => { + userId = NaN; + createNoticeBoardDto = new CreateNoticeBoardDto(); + }); + + it('create notice board', async () => { + userId = faker.number.int(); + + mockNoticeBoardRepository.save.mockResolvedValue({ id: 1 }); + + await expect( + service.create(userId, createNoticeBoardDto), + ).resolves.toEqual({ + id: 1, + }); + + expect(mockNoticeBoardHistoryService.create).toHaveBeenCalled(); + }); + }); + + describe(NoticeBoardsService.prototype.findAllAndCount.name, () => { + let findNoticeBoardListQueryDto: FindNoticeBoardListQueryDto; + + let noticeBoards: NoticeBoardDto[]; + let count: number; + + beforeEach(() => { + findNoticeBoardListQueryDto = new FindNoticeBoardListQueryDto(); + + noticeBoards = []; + count = NaN; + }); + + it('default option findAllAndCount', async () => { + findNoticeBoardListQueryDto.page = 0; + findNoticeBoardListQueryDto.pageSize = 20; + findNoticeBoardListQueryDto.order = { id: SortOrder.Desc }; + + mockQueryHelper.buildWherePropForFind.mockReturnValue({}); + mockNoticeBoardRepository.findAndCount.mockResolvedValue([ + noticeBoards, + count, + ]); + + await expect( + service.findAllAndCount(findNoticeBoardListQueryDto), + ).resolves.toEqual([noticeBoards, count]); + + expect(mockNoticeBoardRepository.findAndCount).toHaveBeenCalledWith({ + select: expect.anything(), + where: {}, + order: { id: SortOrder.Desc }, + skip: 0, + take: 20, + }); + }); + }); }); diff --git a/src/apis/notice-boards/services/notice-boards.service.ts b/src/apis/notice-boards/services/notice-boards.service.ts index b1027a06..83c7ae4e 100644 --- a/src/apis/notice-boards/services/notice-boards.service.ts +++ b/src/apis/notice-boards/services/notice-boards.service.ts @@ -77,6 +77,7 @@ export class NoticeBoardsService { findNoticeBoardListQueryDto: FindNoticeBoardListQueryDto, ): Promise<[NoticeBoardsItemDto[], number]> { const { page, pageSize, order, ...filter } = findNoticeBoardListQueryDto; + console.log(findNoticeBoardListQueryDto); const where = this.queryHelper.buildWherePropForFind( filter, diff --git a/test/mock/mock.repository.ts b/test/mock/mock.repository.ts index 2aee560e..4ab41438 100644 --- a/test/mock/mock.repository.ts +++ b/test/mock/mock.repository.ts @@ -1,6 +1,8 @@ import { UserRepository } from '@src/apis/users/repositories/user.repository'; import { FreeBoard } from '@src/entities/FreeBoard'; import { FreeBoardHistory } from '@src/entities/FreeBoardHistory'; +import { NoticeBoard } from '@src/entities/NoticeBoard'; +import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; import { MockProvider } from '@test/mock/mock.type'; import { Repository } from 'typeorm'; @@ -87,3 +89,14 @@ export const mockFreeBoardHistoryRepository: MockProvider< > = { ...getDefaultRepositoryMethod(), }; + +export const mockNoticeBoardRepository: MockProvider> = + { + ...getDefaultRepositoryMethod(), + }; + +export const mockNoticeBoardHistoryRepository: MockProvider< + Repository +> = { + ...getDefaultRepositoryMethod(), +}; diff --git a/test/mock/mock.service.ts b/test/mock/mock.service.ts index c3e88769..caf48531 100644 --- a/test/mock/mock.service.ts +++ b/test/mock/mock.service.ts @@ -2,6 +2,8 @@ import { JwtService } from '@nestjs/jwt'; import { AuthService } from '@src/apis/auth/services/auth.service'; import { FreeBoardHistoryService } from '@src/apis/free-boards/free-board-history/services/free-board-history.service'; import { FreeBoardsService } from '@src/apis/free-boards/services/free-board.service'; +import { NoticeBoardHistoryService } from '@src/apis/notice-boards/notice-board-history/services/notice-board-history.service'; +import { NoticeBoardsService } from '@src/apis/notice-boards/services/notice-boards.service'; import { UsersService } from '@src/apis/users/services/users.service'; import { AppConfigService } from '@src/core/app-config/services/app-config.service'; import { EncryptionService } from '@src/libs/encryption/services/encryption.service'; @@ -50,3 +52,13 @@ export const mockFreeBoardHistoryService: MockProvider { create: jest.fn(), }; + +export const mockNoticeBoardsService: MockProvider = { + create: jest.fn(), + findAllAndCount: jest.fn(), +}; + +export const mockNoticeBoardHistoryService: MockProvider = + { + create: jest.fn(), + }; From b600416236025d2803063f89afa86ca7218a0596 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 3 Dec 2023 22:52:18 +0900 Subject: [PATCH 12/37] refactor/#66: delete console.log --- src/apis/auth/jwt/jwt.guard.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/apis/auth/jwt/jwt.guard.ts b/src/apis/auth/jwt/jwt.guard.ts index 933019d7..c487393d 100644 --- a/src/apis/auth/jwt/jwt.guard.ts +++ b/src/apis/auth/jwt/jwt.guard.ts @@ -7,7 +7,6 @@ import { HttpUnauthorizedException } from '@src/http-exceptions/exceptions/http- export class JwtAuthGuard extends AuthGuard('jwt') { handleRequest(err, user) { if (err || !user) { - console.log(err, user); throw new HttpUnauthorizedException({ code: COMMON_ERROR_CODE.INVALID_TOKEN, }); From 941b402b38831ff12eee8c44eb30819cb95681b1 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 3 Dec 2023 22:53:22 +0900 Subject: [PATCH 13/37] refactor/#66: modify string --- .../notice-boards/controllers/notice-boards.controller.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts b/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts index 730d0164..811e2630 100644 --- a/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts +++ b/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts @@ -46,7 +46,7 @@ describe(NoticeBoardsController.name, () => { newNoticeBoard = new NoticeBoardDto(); }); - it('create Notice board', async () => { + it('create notice board', async () => { user.id = faker.number.int(); mockNoticeBoardsService.create.mockResolvedValue(newNoticeBoard); From 782865b64064b2bc4f201f1dcbb8640e6dbdc16e Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 3 Dec 2023 22:54:45 +0900 Subject: [PATCH 14/37] modify/#66: modify Order type --- src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index 3413b7eb..4ea19802 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -52,5 +52,5 @@ export class FindNoticeBoardListQueryDto @ApiPropertyOrder(NOTICE_BOARD_ORDER_FIELD) @CsvToOrder([...NOTICE_BOARD_ORDER_FIELD]) @IsOptional() - order: Order = { id: SortOrder.Desc }; + order: Order = { id: SortOrder.Desc }; } From b3a035f47cf52401c597a02435957536b506853f Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 3 Dec 2023 22:55:32 +0900 Subject: [PATCH 15/37] modify/#66: modify Order type --- src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index 4ea19802..9a54bd13 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -10,7 +10,6 @@ import { import { Type } from 'class-transformer'; import { ApiPropertyOrder } from '@src/dto/swagger/api-property-order.decorator'; import { CsvToOrder, Order } from '@src/dto/transformer/csv-to-order.decorator'; -import { FREE_BOARD_ORDER_FIELD } from '@src/apis/free-boards/constants/free-board.constant'; import { SortOrder } from '@src/constants/enum'; export class FindNoticeBoardListQueryDto From 62b4bd35288557d2d5f67079a3687ac18f1161f6 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Sun, 3 Dec 2023 22:57:40 +0900 Subject: [PATCH 16/37] refactor/#66: modify NoticeBoard Create's key for swaggerBuilder --- src/apis/notice-boards/controllers/notice-boards.swagger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apis/notice-boards/controllers/notice-boards.swagger.ts b/src/apis/notice-boards/controllers/notice-boards.swagger.ts index 3ef12773..796c6c77 100644 --- a/src/apis/notice-boards/controllers/notice-boards.swagger.ts +++ b/src/apis/notice-boards/controllers/notice-boards.swagger.ts @@ -23,7 +23,7 @@ export const ApiNoticeBoard: ApiOperator = { }), DetailResponseDto.swaggerBuilder( HttpStatus.CREATED, - 'board', + 'noticeBoard', NoticeBoardDto, ), HttpException.swaggerBuilder( From ebd5e47dca49e7775df8f059a524fbf1adde8450 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 14:27:59 +0900 Subject: [PATCH 17/37] feat/#66: add ApiBearerAuth --- src/apis/notice-boards/controllers/notice-boards.swagger.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/apis/notice-boards/controllers/notice-boards.swagger.ts b/src/apis/notice-boards/controllers/notice-boards.swagger.ts index 796c6c77..b4ab218a 100644 --- a/src/apis/notice-boards/controllers/notice-boards.swagger.ts +++ b/src/apis/notice-boards/controllers/notice-boards.swagger.ts @@ -1,5 +1,5 @@ import { HttpStatus, applyDecorators } from '@nestjs/common'; -import { ApiOperation } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { OperationObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface'; import { COMMON_ERROR_CODE } from '@src/constants/error/common/common-error-code.constant'; import { HttpException } from '@src/http-exceptions/exceptions/http.exception'; @@ -21,6 +21,7 @@ export const ApiNoticeBoard: ApiOperator = { operationId: 'NoticeBoardCreate', ...apiOperationOptions, }), + ApiBearerAuth(), DetailResponseDto.swaggerBuilder( HttpStatus.CREATED, 'noticeBoard', From d266d562e8a015199e838ad40aec3805efa382e1 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 16:56:31 +0900 Subject: [PATCH 18/37] modify/#66: modify string --- migrations/1701328900610-notice-board-history.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrations/1701328900610-notice-board-history.ts b/migrations/1701328900610-notice-board-history.ts index 5d6aa0fd..930aaebd 100644 --- a/migrations/1701328900610-notice-board-history.ts +++ b/migrations/1701328900610-notice-board-history.ts @@ -160,7 +160,7 @@ export class NoticeBoardHistory1701328900610 implements MigrationInterface { 'ALTER TABLE notice_board_comment_history COMMENT = "공지 게시글 댓글 수정이력"', ); - // 공지 게시글 대댓글 + // 공지 게시글 대댓글 수정이력 await queryRunner.createTable( new Table({ name: 'notice_board_reply_comment_history', From 8eae7275ff2a2c88cb64bfc0f461b7dc834efd05 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 16:58:52 +0900 Subject: [PATCH 19/37] modify/#66: remove test code --- .../notice-boards.controller.spec.ts | 75 ----------- .../notice-board-history.service.spec.ts | 65 ---------- .../services/notice-boards.service.spec.ts | 118 ------------------ test/mock/mock.repository.ts | 13 -- test/mock/mock.service.ts | 12 -- 5 files changed, 283 deletions(-) delete mode 100644 src/apis/notice-boards/controllers/notice-boards.controller.spec.ts delete mode 100644 src/apis/notice-boards/notice-board-history/services/notice-board-history.service.spec.ts delete mode 100644 src/apis/notice-boards/services/notice-boards.service.spec.ts diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts b/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts deleted file mode 100644 index 811e2630..00000000 --- a/src/apis/notice-boards/controllers/notice-boards.controller.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { faker } from '@faker-js/faker'; -import { Test, TestingModule } from '@nestjs/testing'; -import { UserDto } from '@src/apis/users/dto/user.dto'; -import { mockNoticeBoardsService } from '@test/mock/mock.service'; -import { CreateNoticeBoardDto } from '../dto/create-notice-board.dto'; -import { FindNoticeBoardListQueryDto } from '../dto/find-notice-board-list-query.dto'; -import { NoticeBoardDto } from '../dto/notice-board.dto'; -import { NoticeBoardsService } from '../services/notice-boards.service'; -import { NoticeBoardsController } from './notice-boards.controller'; - -describe(NoticeBoardsController.name, () => { - let controller: NoticeBoardsController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [NoticeBoardsController], - providers: [ - { - provide: NoticeBoardsService, - useValue: mockNoticeBoardsService, - }, - ], - }).compile(); - - controller = module.get(NoticeBoardsController); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); - - describe(NoticeBoardsController.prototype.create.name, () => { - let user: UserDto; - let createNoticeBoardDto: CreateNoticeBoardDto; - - let newNoticeBoard: NoticeBoardDto; - - beforeEach(() => { - user = new UserDto(); - createNoticeBoardDto = new CreateNoticeBoardDto(); - - newNoticeBoard = new NoticeBoardDto(); - }); - - it('create notice board', async () => { - user.id = faker.number.int(); - - mockNoticeBoardsService.create.mockResolvedValue(newNoticeBoard); - - await expect( - controller.create(user, createNoticeBoardDto), - ).resolves.toEqual(newNoticeBoard); - }); - }); - - describe(NoticeBoardsController.prototype.findAllAndCount.name, () => { - let findNoticeBoardListQueryDto: FindNoticeBoardListQueryDto; - - beforeEach(() => { - findNoticeBoardListQueryDto = new FindNoticeBoardListQueryDto(); - }); - - it('find all and count', async () => { - mockNoticeBoardsService.findAllAndCount.mockResolvedValue([[], 0]); - - await expect( - controller.findAllAndCount(findNoticeBoardListQueryDto), - ).resolves.toEqual([[], 0]); - }); - }); -}); diff --git a/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.spec.ts b/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.spec.ts deleted file mode 100644 index a7eaf475..00000000 --- a/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; -import { - mockEntityManager, - mockNoticeBoardHistoryRepository, -} from '@test/mock/mock.repository'; - -import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; -import { CreateNoticeBoardHistoryDto } from '../dto/create-notice-board-history.dto'; -import { NoticeBoardHistoryService } from './notice-board-history.service'; - -describe(NoticeBoardHistoryService.name, () => { - let service: NoticeBoardHistoryService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - NoticeBoardHistoryService, - { - provide: getRepositoryToken(NoticeBoardHistory), - useValue: mockNoticeBoardHistoryRepository, - }, - ], - }).compile(); - - service = module.get(NoticeBoardHistoryService); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); - - describe(NoticeBoardHistoryService.prototype.create.name, () => { - let entityManager: any; - let userId: number; - let noticeBoardId: number; - let createNoticeBoardHistoryDto: CreateNoticeBoardHistoryDto; - - beforeEach(() => { - entityManager = mockEntityManager; - userId = NaN; - noticeBoardId = NaN; - createNoticeBoardHistoryDto = new CreateNoticeBoardHistoryDto({} as any); - }); - - it('create notice board history', async () => { - mockNoticeBoardHistoryRepository.save.mockResolvedValue( - createNoticeBoardHistoryDto, - ); - - await expect( - service.create( - entityManager, - userId, - noticeBoardId, - createNoticeBoardHistoryDto, - ), - ).resolves.toEqual({}); - }); - }); -}); diff --git a/src/apis/notice-boards/services/notice-boards.service.spec.ts b/src/apis/notice-boards/services/notice-boards.service.spec.ts deleted file mode 100644 index cd9a2e7f..00000000 --- a/src/apis/notice-boards/services/notice-boards.service.spec.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { faker } from '@faker-js/faker'; -import { Test, TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; -import { SortOrder } from '@src/constants/enum'; -import { QueryHelper } from '@src/helpers/query.helper'; -import { mockQueryHelper } from '@test/mock/mock.helper'; -import { - mockDataSource, - mockNoticeBoardRepository, -} from '@test/mock/mock.repository'; -import { mockNoticeBoardHistoryService } from '@test/mock/mock.service'; -import { DataSource } from 'typeorm'; -import { NoticeBoardsService } from './notice-boards.service'; -import { NoticeBoardDto } from '../dto/notice-board.dto'; -import { CreateNoticeBoardDto } from '../dto/create-notice-board.dto'; -import { NoticeBoardHistoryService } from '../notice-board-history/services/notice-board-history.service'; -import { NoticeBoard } from '@src/entities/NoticeBoard'; -import { FindNoticeBoardListQueryDto } from '../dto/find-notice-board-list-query.dto'; - -describe(NoticeBoardsService.name, () => { - let service: NoticeBoardsService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - NoticeBoardsService, - { - provide: NoticeBoardHistoryService, - useValue: mockNoticeBoardHistoryService, - }, - { - provide: QueryHelper, - useValue: mockQueryHelper, - }, - { - provide: DataSource, - useValue: mockDataSource, - }, - { - provide: getRepositoryToken(NoticeBoard), - useValue: mockNoticeBoardRepository, - }, - ], - }).compile(); - - service = module.get(NoticeBoardsService); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); - - describe(NoticeBoardsService.prototype.create.name, () => { - let userId: number; - let createNoticeBoardDto: CreateNoticeBoardDto; - - beforeEach(() => { - userId = NaN; - createNoticeBoardDto = new CreateNoticeBoardDto(); - }); - - it('create notice board', async () => { - userId = faker.number.int(); - - mockNoticeBoardRepository.save.mockResolvedValue({ id: 1 }); - - await expect( - service.create(userId, createNoticeBoardDto), - ).resolves.toEqual({ - id: 1, - }); - - expect(mockNoticeBoardHistoryService.create).toHaveBeenCalled(); - }); - }); - - describe(NoticeBoardsService.prototype.findAllAndCount.name, () => { - let findNoticeBoardListQueryDto: FindNoticeBoardListQueryDto; - - let noticeBoards: NoticeBoardDto[]; - let count: number; - - beforeEach(() => { - findNoticeBoardListQueryDto = new FindNoticeBoardListQueryDto(); - - noticeBoards = []; - count = NaN; - }); - - it('default option findAllAndCount', async () => { - findNoticeBoardListQueryDto.page = 0; - findNoticeBoardListQueryDto.pageSize = 20; - findNoticeBoardListQueryDto.order = { id: SortOrder.Desc }; - - mockQueryHelper.buildWherePropForFind.mockReturnValue({}); - mockNoticeBoardRepository.findAndCount.mockResolvedValue([ - noticeBoards, - count, - ]); - - await expect( - service.findAllAndCount(findNoticeBoardListQueryDto), - ).resolves.toEqual([noticeBoards, count]); - - expect(mockNoticeBoardRepository.findAndCount).toHaveBeenCalledWith({ - select: expect.anything(), - where: {}, - order: { id: SortOrder.Desc }, - skip: 0, - take: 20, - }); - }); - }); -}); diff --git a/test/mock/mock.repository.ts b/test/mock/mock.repository.ts index 4ab41438..2aee560e 100644 --- a/test/mock/mock.repository.ts +++ b/test/mock/mock.repository.ts @@ -1,8 +1,6 @@ import { UserRepository } from '@src/apis/users/repositories/user.repository'; import { FreeBoard } from '@src/entities/FreeBoard'; import { FreeBoardHistory } from '@src/entities/FreeBoardHistory'; -import { NoticeBoard } from '@src/entities/NoticeBoard'; -import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; import { MockProvider } from '@test/mock/mock.type'; import { Repository } from 'typeorm'; @@ -89,14 +87,3 @@ export const mockFreeBoardHistoryRepository: MockProvider< > = { ...getDefaultRepositoryMethod(), }; - -export const mockNoticeBoardRepository: MockProvider> = - { - ...getDefaultRepositoryMethod(), - }; - -export const mockNoticeBoardHistoryRepository: MockProvider< - Repository -> = { - ...getDefaultRepositoryMethod(), -}; diff --git a/test/mock/mock.service.ts b/test/mock/mock.service.ts index caf48531..c3e88769 100644 --- a/test/mock/mock.service.ts +++ b/test/mock/mock.service.ts @@ -2,8 +2,6 @@ import { JwtService } from '@nestjs/jwt'; import { AuthService } from '@src/apis/auth/services/auth.service'; import { FreeBoardHistoryService } from '@src/apis/free-boards/free-board-history/services/free-board-history.service'; import { FreeBoardsService } from '@src/apis/free-boards/services/free-board.service'; -import { NoticeBoardHistoryService } from '@src/apis/notice-boards/notice-board-history/services/notice-board-history.service'; -import { NoticeBoardsService } from '@src/apis/notice-boards/services/notice-boards.service'; import { UsersService } from '@src/apis/users/services/users.service'; import { AppConfigService } from '@src/core/app-config/services/app-config.service'; import { EncryptionService } from '@src/libs/encryption/services/encryption.service'; @@ -52,13 +50,3 @@ export const mockFreeBoardHistoryService: MockProvider { create: jest.fn(), }; - -export const mockNoticeBoardsService: MockProvider = { - create: jest.fn(), - findAllAndCount: jest.fn(), -}; - -export const mockNoticeBoardHistoryService: MockProvider = - { - create: jest.fn(), - }; From 75cf9e73711086e3f9242b4466e58965890490b7 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 17:08:33 +0900 Subject: [PATCH 20/37] modify/#66: modify notice-board.constants --- src/apis/notice-boards/constants/notice-board.constant.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/apis/notice-boards/constants/notice-board.constant.ts b/src/apis/notice-boards/constants/notice-board.constant.ts index 9140baed..d17dd027 100644 --- a/src/apis/notice-boards/constants/notice-board.constant.ts +++ b/src/apis/notice-boards/constants/notice-board.constant.ts @@ -15,7 +15,7 @@ export const NOTICE_BOARD_TITLE_LENGTH = { MAX: 255, } as const; -export const NOTICE_BOARD_ALLOW_COMMENT_LENGTH = { - MIN: 0, - MAX: 1, -}; +export const NOTICE_BOARD_ALLOW_COMMENT = { + TRUE: true, + FALSE: false, +} as const; From 66da11a62a6b9ce53e143ba97109ac406766a9ff Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 17:27:44 +0900 Subject: [PATCH 21/37] modify/#66: modify entity --- src/apis/notice-boards/constants/notice-board.constant.ts | 5 ----- src/entities/NoticeBoard.ts | 7 +++---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/apis/notice-boards/constants/notice-board.constant.ts b/src/apis/notice-boards/constants/notice-board.constant.ts index d17dd027..c69d17c9 100644 --- a/src/apis/notice-boards/constants/notice-board.constant.ts +++ b/src/apis/notice-boards/constants/notice-board.constant.ts @@ -14,8 +14,3 @@ export const NOTICE_BOARD_TITLE_LENGTH = { MIN: 1, MAX: 255, } as const; - -export const NOTICE_BOARD_ALLOW_COMMENT = { - TRUE: true, - FALSE: false, -} as const; diff --git a/src/entities/NoticeBoard.ts b/src/entities/NoticeBoard.ts index 440a1667..37e4a145 100644 --- a/src/entities/NoticeBoard.ts +++ b/src/entities/NoticeBoard.ts @@ -37,11 +37,10 @@ export class NoticeBoard { }) hit: number; - @Column('tinyint', { + @Column('bool', { name: 'allow_comment', - comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', - unsigned: true, - default: () => "'1'", + comment: '댓글 허용 여부 (false: 비활성화, true: 허용)', + default: () => true, transformer: new BooleanTransformer(), }) allowComment: boolean; From bbd65bffc61672e4b94f89c0a56bb1dff855495d Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 17:54:11 +0900 Subject: [PATCH 22/37] modify/#66: modify migration file --- migrations/1701328900610-notice-board-history.ts | 12 +++--------- src/entities/NoticeBoardCommentHistory.ts | 9 ++++----- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/migrations/1701328900610-notice-board-history.ts b/migrations/1701328900610-notice-board-history.ts index 930aaebd..5f3efc6f 100644 --- a/migrations/1701328900610-notice-board-history.ts +++ b/migrations/1701328900610-notice-board-history.ts @@ -69,9 +69,7 @@ export class NoticeBoardHistory1701328900610 implements MigrationInterface { }, { name: 'allow_comment', - type: 'tinyint', - length: '1', - unsigned: true, + type: 'boolean', default: 1, isNullable: false, comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', @@ -129,10 +127,8 @@ export class NoticeBoardHistory1701328900610 implements MigrationInterface { }, { name: 'isAnonymous', - type: 'tinyint', - length: '1', + type: 'boolean', default: 0, - unsigned: true, isNullable: false, comment: '작성자 익명 여부 (0: 실명, 1: 익명)', }, @@ -196,10 +192,8 @@ export class NoticeBoardHistory1701328900610 implements MigrationInterface { }, { name: 'isAnonymous', - type: 'tinyint', - length: '1', + type: 'boolean', default: 0, - unsigned: true, isNullable: false, comment: '작성자 익명 여부 (0: 실명, 1: 익명)', }, diff --git a/src/entities/NoticeBoardCommentHistory.ts b/src/entities/NoticeBoardCommentHistory.ts index ad5c23f2..0d1bae00 100644 --- a/src/entities/NoticeBoardCommentHistory.ts +++ b/src/entities/NoticeBoardCommentHistory.ts @@ -23,13 +23,12 @@ export class NoticeBoardCommentHistory { @Column('varchar', { name: 'description', comment: '댓글 본문', length: 255 }) description: string; - @Column('tinyint', { + @Column('bool', { name: 'isAnonymous', - comment: '작성자 익명 여부 (0: 실명, 1: 익명)', - unsigned: true, - default: () => "'0'", + comment: '작성자 익명 여부 (false: 실명, true: 익명)', + default: () => true, }) - isAnonymous: number; + isAnonymous: boolean; @Column('timestamp', { name: 'created_at', From 10915d0fe8566a3a966a8bf5b86326965fb4915c Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 20:34:32 +0900 Subject: [PATCH 23/37] modify/#66: modify entities and migration --- migrations/1701328900610-notice-board-history.ts | 2 +- src/entities/NoticeBoardComment.ts | 9 +++++---- src/entities/NoticeBoardCommentHistory.ts | 6 ++++-- src/entities/NoticeBoardHistory.ts | 5 ++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/migrations/1701328900610-notice-board-history.ts b/migrations/1701328900610-notice-board-history.ts index 5f3efc6f..bd47e38c 100644 --- a/migrations/1701328900610-notice-board-history.ts +++ b/migrations/1701328900610-notice-board-history.ts @@ -161,7 +161,7 @@ export class NoticeBoardHistory1701328900610 implements MigrationInterface { new Table({ name: 'notice_board_reply_comment_history', columns: [ - generatePrimaryColumn('공지 게시글 대댓글 고유 ID'), + generatePrimaryColumn('공지 게시글 대댓글 수정이력 고유 ID'), { name: 'notice_board_history_id', type: 'int', diff --git a/src/entities/NoticeBoardComment.ts b/src/entities/NoticeBoardComment.ts index de7c2841..2a088f2a 100644 --- a/src/entities/NoticeBoardComment.ts +++ b/src/entities/NoticeBoardComment.ts @@ -10,6 +10,7 @@ import { NoticeBoard } from './NoticeBoard'; import { NoticeBoardCommentReaction } from './NoticeBoardCommentReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { User } from './User'; +import { BooleanTransformer } from './transfomers/boolean.transfomer'; @Entity('notice_board_comment', { schema: 'dongurami_local_db' }) export class NoticeBoardComment { @@ -24,13 +25,13 @@ export class NoticeBoardComment { @Column('varchar', { name: 'description', comment: '댓글 본문', length: 255 }) description: string; - @Column('tinyint', { + @Column('boolean', { name: 'isAnonymous', comment: '작성자 익명 여부 (0: 실명, 1: 익명)', - unsigned: true, - default: () => "'0'", + default: () => false, + transformer: new BooleanTransformer(), }) - isAnonymous: number; + isAnonymous: boolean; @Column('timestamp', { name: 'created_at', diff --git a/src/entities/NoticeBoardCommentHistory.ts b/src/entities/NoticeBoardCommentHistory.ts index 0d1bae00..fafe1bfa 100644 --- a/src/entities/NoticeBoardCommentHistory.ts +++ b/src/entities/NoticeBoardCommentHistory.ts @@ -9,6 +9,7 @@ import { import { NoticeBoardHistory } from './NoticeBoardHistory'; import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; import { User } from './User'; +import { BooleanTransformer } from './transfomers/boolean.transfomer'; @Entity('notice_board_comment_history', { schema: 'dongurami_local_db' }) export class NoticeBoardCommentHistory { @@ -23,10 +24,11 @@ export class NoticeBoardCommentHistory { @Column('varchar', { name: 'description', comment: '댓글 본문', length: 255 }) description: string; - @Column('bool', { + @Column('boolean', { name: 'isAnonymous', comment: '작성자 익명 여부 (false: 실명, true: 익명)', - default: () => true, + default: () => false, + transformer: new BooleanTransformer(), }) isAnonymous: boolean; diff --git a/src/entities/NoticeBoardHistory.ts b/src/entities/NoticeBoardHistory.ts index 87c8a24c..183c5396 100644 --- a/src/entities/NoticeBoardHistory.ts +++ b/src/entities/NoticeBoardHistory.ts @@ -28,11 +28,10 @@ export class NoticeBoardHistory { @Column('text', { name: 'description', comment: '공지게시글 내용' }) description: string; - @Column('tinyint', { + @Column('boolean', { name: 'allow_comment', comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', - unsigned: true, - default: () => "'1'", + default: () => true, transformer: new BooleanTransformer(), }) allowComment: boolean; From 1fe7fd1a7d1b07c8724d354e791fc7d532c1ed0e Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 20:37:32 +0900 Subject: [PATCH 24/37] modify/#66: modify entities --- src/entities/NoticeBoardReplyComment.ts | 7 +++---- src/entities/NoticeBoardReplyCommentHistory.ts | 9 +++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/entities/NoticeBoardReplyComment.ts b/src/entities/NoticeBoardReplyComment.ts index 9f3a8271..06fe6ff8 100644 --- a/src/entities/NoticeBoardReplyComment.ts +++ b/src/entities/NoticeBoardReplyComment.ts @@ -28,13 +28,12 @@ export class NoticeBoardReplyComment { }) description: string; - @Column('tinyint', { + @Column('boolean', { name: 'isAnonymous', comment: '작성자 익명 여부 (0: 실명, 1: 익명)', - unsigned: true, - default: () => "'0'", + default: () => false, }) - isAnonymous: number; + isAnonymous: boolean; @Column('timestamp', { name: 'created_at', diff --git a/src/entities/NoticeBoardReplyCommentHistory.ts b/src/entities/NoticeBoardReplyCommentHistory.ts index 51812554..8ce82671 100644 --- a/src/entities/NoticeBoardReplyCommentHistory.ts +++ b/src/entities/NoticeBoardReplyCommentHistory.ts @@ -9,6 +9,7 @@ import { import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; import { NoticeBoardHistory } from './NoticeBoardHistory'; import { User } from './User'; +import { BooleanTransformer } from './transfomers/boolean.transfomer'; @Entity('notice_board_reply_comment_history', { schema: 'dongurami_local_db' }) export class NoticeBoardReplyCommentHistory { @@ -27,13 +28,13 @@ export class NoticeBoardReplyCommentHistory { }) description: string; - @Column('tinyint', { + @Column('boolean', { name: 'isAnonymous', comment: '작성자 익명 여부 (0: 실명, 1: 익명)', - unsigned: true, - default: () => "'0'", + default: () => false, + transformer: new BooleanTransformer(), }) - isAnonymous: number; + isAnonymous: boolean; @Column('timestamp', { name: 'created_at', From 9a7b052fad7337947ab28b233f46792e68567f4f Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 20:45:05 +0900 Subject: [PATCH 25/37] refactor/#66: modify typo --- src/entities/FreeBoard.ts | 2 +- src/entities/FreeBoardHistory.ts | 2 +- src/entities/NoticeBoard.ts | 2 +- src/entities/NoticeBoardComment.ts | 2 +- src/entities/NoticeBoardCommentHistory.ts | 2 +- src/entities/NoticeBoardHistory.ts | 2 +- src/entities/NoticeBoardReplyCommentHistory.ts | 2 +- .../boolean.transformer.ts} | 0 8 files changed, 7 insertions(+), 7 deletions(-) rename src/entities/{transfomers/boolean.transfomer.ts => transformers/boolean.transformer.ts} (100%) diff --git a/src/entities/FreeBoard.ts b/src/entities/FreeBoard.ts index a0ce6337..6d97fb7a 100644 --- a/src/entities/FreeBoard.ts +++ b/src/entities/FreeBoard.ts @@ -1,5 +1,5 @@ import { FreeBoardHistory } from '@src/entities/FreeBoardHistory'; -import { BooleanTransformer } from '@src/entities/transfomers/boolean.transfomer'; +import { BooleanTransformer } from '@src/entities/transformers/boolean.transformer'; import { Column, Entity, diff --git a/src/entities/FreeBoardHistory.ts b/src/entities/FreeBoardHistory.ts index 7333999f..44c35508 100644 --- a/src/entities/FreeBoardHistory.ts +++ b/src/entities/FreeBoardHistory.ts @@ -1,4 +1,4 @@ -import { BooleanTransformer } from '@src/entities/transfomers/boolean.transfomer'; +import { BooleanTransformer } from '@src/entities/transformers/boolean.transformer'; import { Column, Entity, diff --git a/src/entities/NoticeBoard.ts b/src/entities/NoticeBoard.ts index 37e4a145..50803a6c 100644 --- a/src/entities/NoticeBoard.ts +++ b/src/entities/NoticeBoard.ts @@ -11,7 +11,7 @@ import { NoticeBoardReaction } from './NoticeBoardReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { User } from './User'; import { NoticeBoardHistory } from './NoticeBoardHistory'; -import { BooleanTransformer } from './transfomers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; @Entity('notice_board', { schema: 'dongurami_local_db' }) export class NoticeBoard { diff --git a/src/entities/NoticeBoardComment.ts b/src/entities/NoticeBoardComment.ts index 2a088f2a..47a7726e 100644 --- a/src/entities/NoticeBoardComment.ts +++ b/src/entities/NoticeBoardComment.ts @@ -10,7 +10,7 @@ import { NoticeBoard } from './NoticeBoard'; import { NoticeBoardCommentReaction } from './NoticeBoardCommentReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { User } from './User'; -import { BooleanTransformer } from './transfomers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; @Entity('notice_board_comment', { schema: 'dongurami_local_db' }) export class NoticeBoardComment { diff --git a/src/entities/NoticeBoardCommentHistory.ts b/src/entities/NoticeBoardCommentHistory.ts index fafe1bfa..3e9acf98 100644 --- a/src/entities/NoticeBoardCommentHistory.ts +++ b/src/entities/NoticeBoardCommentHistory.ts @@ -9,7 +9,7 @@ import { import { NoticeBoardHistory } from './NoticeBoardHistory'; import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; import { User } from './User'; -import { BooleanTransformer } from './transfomers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; @Entity('notice_board_comment_history', { schema: 'dongurami_local_db' }) export class NoticeBoardCommentHistory { diff --git a/src/entities/NoticeBoardHistory.ts b/src/entities/NoticeBoardHistory.ts index 183c5396..d884df53 100644 --- a/src/entities/NoticeBoardHistory.ts +++ b/src/entities/NoticeBoardHistory.ts @@ -10,7 +10,7 @@ import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; import { User } from './User'; import { NoticeBoard } from './NoticeBoard'; -import { BooleanTransformer } from './transfomers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; @Entity('notice_board_history', { schema: 'dongurami_local_db' }) export class NoticeBoardHistory { diff --git a/src/entities/NoticeBoardReplyCommentHistory.ts b/src/entities/NoticeBoardReplyCommentHistory.ts index 8ce82671..5a0443d3 100644 --- a/src/entities/NoticeBoardReplyCommentHistory.ts +++ b/src/entities/NoticeBoardReplyCommentHistory.ts @@ -9,7 +9,7 @@ import { import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; import { NoticeBoardHistory } from './NoticeBoardHistory'; import { User } from './User'; -import { BooleanTransformer } from './transfomers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; @Entity('notice_board_reply_comment_history', { schema: 'dongurami_local_db' }) export class NoticeBoardReplyCommentHistory { diff --git a/src/entities/transfomers/boolean.transfomer.ts b/src/entities/transformers/boolean.transformer.ts similarity index 100% rename from src/entities/transfomers/boolean.transfomer.ts rename to src/entities/transformers/boolean.transformer.ts From 8a206fe34ad1b67c2c5f9defe8294ea0bfc44372 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 20:50:40 +0900 Subject: [PATCH 26/37] modify/#66: modify dtos --- src/apis/notice-boards/dto/create-notice-board.dto.ts | 11 +++-------- .../dto/find-notice-board-list-query.dto.ts | 3 ++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/apis/notice-boards/dto/create-notice-board.dto.ts b/src/apis/notice-boards/dto/create-notice-board.dto.ts index 53cec89f..bb75c6a3 100644 --- a/src/apis/notice-boards/dto/create-notice-board.dto.ts +++ b/src/apis/notice-boards/dto/create-notice-board.dto.ts @@ -1,8 +1,5 @@ import { IsBoolean, IsNotEmpty, Length } from 'class-validator'; -import { - NOTICE_BOARD_ALLOW_COMMENT_LENGTH, - NOTICE_BOARD_TITLE_LENGTH, -} from '../constants/notice-board.constant'; +import { NOTICE_BOARD_TITLE_LENGTH } from '../constants/notice-board.constant'; import { NoticeBoardDto } from './notice-board.dto'; import { ApiProperty } from '@nestjs/swagger'; @@ -24,10 +21,8 @@ export class CreateNoticeBoardDto description: string; @ApiProperty({ - description: '댓글 허용 여부 (0: 비활성화, 1: 허용)', - minimum: NOTICE_BOARD_ALLOW_COMMENT_LENGTH.MIN, - maximum: NOTICE_BOARD_ALLOW_COMMENT_LENGTH.MAX, - default: 1, + description: '댓글 허용 여부 (false: 비활성화, true: 허용)', + default: true, }) @IsBoolean() allowComment: boolean; diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index 9a54bd13..20fb161c 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -1,7 +1,7 @@ import { PageDto } from '@src/dto/page.dto'; import { NoticeBoardDto } from './notice-board.dto'; import { ApiPropertyOptional } from '@nestjs/swagger'; -import { IsBooleanString, IsOptional } from 'class-validator'; +import { IsBooleanString, IsOptional, Length } from 'class-validator'; import { IsPositiveInt } from '@src/dto/validator/is-positive-int.decorator'; import { NOTICE_BOARD_ORDER_FIELD, @@ -36,6 +36,7 @@ export class FindNoticeBoardListQueryDto description: 'title 필터링', maxLength: NOTICE_BOARD_TITLE_LENGTH.MAX, }) + @Length(NOTICE_BOARD_TITLE_LENGTH.MIN - 1, NOTICE_BOARD_TITLE_LENGTH.MAX) @IsOptional() title?: string; From 0114f8942e927bba6b3e01b4d264094ac672af83 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 20:54:39 +0900 Subject: [PATCH 27/37] modify/#66: modify dtos --- .../dto/find-notice-board-list-query.dto.ts | 6 +++--- src/apis/notice-boards/dto/notice-board.dto.ts | 11 +++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index 20fb161c..81bb18ec 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -1,7 +1,7 @@ import { PageDto } from '@src/dto/page.dto'; import { NoticeBoardDto } from './notice-board.dto'; import { ApiPropertyOptional } from '@nestjs/swagger'; -import { IsBooleanString, IsOptional, Length } from 'class-validator'; +import { IsBoolean, IsOptional, Length } from 'class-validator'; import { IsPositiveInt } from '@src/dto/validator/is-positive-int.decorator'; import { NOTICE_BOARD_ORDER_FIELD, @@ -42,9 +42,9 @@ export class FindNoticeBoardListQueryDto @ApiPropertyOptional({ description: '댓글 허용 여부', - enum: ['true', 'false', '0', '1'], + enum: ['true', 'false'], }) - @IsBooleanString() + @IsBoolean() @IsOptional() @Type(() => Boolean) allowComment?: boolean; diff --git a/src/apis/notice-boards/dto/notice-board.dto.ts b/src/apis/notice-boards/dto/notice-board.dto.ts index b14faba2..42bdbb21 100644 --- a/src/apis/notice-boards/dto/notice-board.dto.ts +++ b/src/apis/notice-boards/dto/notice-board.dto.ts @@ -1,10 +1,7 @@ import { ApiProperty } from '@nestjs/swagger'; import { BaseDto } from '@src/dto/base.dto'; import { NoticeBoard } from '@src/entities/NoticeBoard'; -import { - NOTICE_BOARD_TITLE_LENGTH, - NOTICE_BOARD_ALLOW_COMMENT_LENGTH, -} from '../constants/notice-board.constant'; +import { NOTICE_BOARD_TITLE_LENGTH } from '../constants/notice-board.constant'; export class NoticeBoardDto extends BaseDto @@ -47,10 +44,8 @@ export class NoticeBoardDto hit: number; @ApiProperty({ - description: '댓글 허용 여부 (0: 비활성화, 1: 허용)', - minimum: NOTICE_BOARD_ALLOW_COMMENT_LENGTH.MIN, - maximum: NOTICE_BOARD_ALLOW_COMMENT_LENGTH.MAX, - default: 1, + description: '댓글 허용 여부 (false: 비활성화, true: 허용)', + default: true, }) allowComment: boolean; From a293353a6120edec5b7f1f1e4e58180cf464ea16 Mon Sep 17 00:00:00 2001 From: hobiJeong <137868493+hobiJeong@users.noreply.github.com> Date: Mon, 4 Dec 2023 20:55:19 +0900 Subject: [PATCH 28/37] Update src/apis/notice-boards/services/notice-boards.service.ts Co-authored-by: Lee seok ho --- src/apis/notice-boards/services/notice-boards.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/apis/notice-boards/services/notice-boards.service.ts b/src/apis/notice-boards/services/notice-boards.service.ts index 83c7ae4e..f5e251c9 100644 --- a/src/apis/notice-boards/services/notice-boards.service.ts +++ b/src/apis/notice-boards/services/notice-boards.service.ts @@ -25,6 +25,7 @@ export class NoticeBoardsService { @InjectRepository(NoticeBoard) private readonly noticeBoardRepository: Repository, ) {} + async create(userId: number, createNoticeBoardDto: CreateNoticeBoardDto) { const queryRunner = this.dataSource.createQueryRunner(); From d4139d446de4f9f8d4cca4c1c5a96c623e32a288 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 21:00:26 +0900 Subject: [PATCH 29/37] refactor/#66: use snake case --- src/apis/notice-boards/services/notice-boards.service.ts | 4 ++-- src/entities/NoticeBoard.ts | 4 ++-- src/entities/NoticeBoardComment.ts | 2 +- src/entities/NoticeBoardCommentHistory.ts | 4 ++-- src/entities/NoticeBoardReplyComment.ts | 2 +- src/entities/NoticeBoardReplyCommentHistory.ts | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/apis/notice-boards/services/notice-boards.service.ts b/src/apis/notice-boards/services/notice-boards.service.ts index f5e251c9..00a2ebe5 100644 --- a/src/apis/notice-boards/services/notice-boards.service.ts +++ b/src/apis/notice-boards/services/notice-boards.service.ts @@ -25,7 +25,7 @@ export class NoticeBoardsService { @InjectRepository(NoticeBoard) private readonly noticeBoardRepository: Repository, ) {} - + async create(userId: number, createNoticeBoardDto: CreateNoticeBoardDto) { const queryRunner = this.dataSource.createQueryRunner(); @@ -62,6 +62,7 @@ export class NoticeBoardsService { } console.error(error); + throw new HttpInternalServerErrorException({ code: COMMON_ERROR_CODE.SERVER_ERROR, ctx: '공지게시글 생성 중 알 수 없는 에러', @@ -78,7 +79,6 @@ export class NoticeBoardsService { findNoticeBoardListQueryDto: FindNoticeBoardListQueryDto, ): Promise<[NoticeBoardsItemDto[], number]> { const { page, pageSize, order, ...filter } = findNoticeBoardListQueryDto; - console.log(findNoticeBoardListQueryDto); const where = this.queryHelper.buildWherePropForFind( filter, diff --git a/src/entities/NoticeBoard.ts b/src/entities/NoticeBoard.ts index 50803a6c..e7b68b9b 100644 --- a/src/entities/NoticeBoard.ts +++ b/src/entities/NoticeBoard.ts @@ -37,9 +37,9 @@ export class NoticeBoard { }) hit: number; - @Column('bool', { + @Column('boolean', { name: 'allow_comment', - comment: '댓글 허용 여부 (false: 비활성화, true: 허용)', + comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', default: () => true, transformer: new BooleanTransformer(), }) diff --git a/src/entities/NoticeBoardComment.ts b/src/entities/NoticeBoardComment.ts index 47a7726e..ee962cd7 100644 --- a/src/entities/NoticeBoardComment.ts +++ b/src/entities/NoticeBoardComment.ts @@ -26,7 +26,7 @@ export class NoticeBoardComment { description: string; @Column('boolean', { - name: 'isAnonymous', + name: 'is_anonymous', comment: '작성자 익명 여부 (0: 실명, 1: 익명)', default: () => false, transformer: new BooleanTransformer(), diff --git a/src/entities/NoticeBoardCommentHistory.ts b/src/entities/NoticeBoardCommentHistory.ts index 3e9acf98..307da064 100644 --- a/src/entities/NoticeBoardCommentHistory.ts +++ b/src/entities/NoticeBoardCommentHistory.ts @@ -25,8 +25,8 @@ export class NoticeBoardCommentHistory { description: string; @Column('boolean', { - name: 'isAnonymous', - comment: '작성자 익명 여부 (false: 실명, true: 익명)', + name: 'is_anonymous', + comment: '작성자 익명 여부 (0: 실명, 1: 익명)', default: () => false, transformer: new BooleanTransformer(), }) diff --git a/src/entities/NoticeBoardReplyComment.ts b/src/entities/NoticeBoardReplyComment.ts index 06fe6ff8..1bbe49df 100644 --- a/src/entities/NoticeBoardReplyComment.ts +++ b/src/entities/NoticeBoardReplyComment.ts @@ -29,7 +29,7 @@ export class NoticeBoardReplyComment { description: string; @Column('boolean', { - name: 'isAnonymous', + name: 'is_anonymous', comment: '작성자 익명 여부 (0: 실명, 1: 익명)', default: () => false, }) diff --git a/src/entities/NoticeBoardReplyCommentHistory.ts b/src/entities/NoticeBoardReplyCommentHistory.ts index 5a0443d3..9f883632 100644 --- a/src/entities/NoticeBoardReplyCommentHistory.ts +++ b/src/entities/NoticeBoardReplyCommentHistory.ts @@ -29,7 +29,7 @@ export class NoticeBoardReplyCommentHistory { description: string; @Column('boolean', { - name: 'isAnonymous', + name: 'is_anonymous', comment: '작성자 익명 여부 (0: 실명, 1: 익명)', default: () => false, transformer: new BooleanTransformer(), From 4b10111597741b57108278026efb1d5e1299e9c2 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 21:04:59 +0900 Subject: [PATCH 30/37] refactor/#66: modify entity comment --- src/entities/NoticeBoardReplyCommentHistory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/NoticeBoardReplyCommentHistory.ts b/src/entities/NoticeBoardReplyCommentHistory.ts index 9f883632..01eed198 100644 --- a/src/entities/NoticeBoardReplyCommentHistory.ts +++ b/src/entities/NoticeBoardReplyCommentHistory.ts @@ -16,7 +16,7 @@ export class NoticeBoardReplyCommentHistory { @PrimaryGeneratedColumn({ type: 'int', name: 'id', - comment: '공지 게시글 대댓글 고유 ID', + comment: '공지 게시글 대댓글 수정이력 고유 ID', unsigned: true, }) id: number; From 6da5f5921ddb35b92ffbbccc06d5bb1c3aa42092 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 22:20:29 +0900 Subject: [PATCH 31/37] modify/#66: modify column name and dtos --- migrations/1700634679995-notice-board.ts | 6 +++--- migrations/1701328900610-notice-board-history.ts | 6 +++--- .../notice-boards/constants/notice-board.constant.ts | 2 +- .../controllers/notice-boards.controller.ts | 2 +- src/apis/notice-boards/dto/create-notice-board.dto.ts | 5 ++--- .../dto/find-notice-board-list-query.dto.ts | 11 +++++------ src/apis/notice-boards/dto/notice-board.dto.ts | 4 ++-- .../dto/create-notice-board-history.dto.ts | 7 ++++--- .../notice-boards/services/notice-boards.service.ts | 4 ++-- src/entities/FreeBoard.ts | 2 +- src/entities/FreeBoardHistory.ts | 2 +- src/entities/NoticeBoard.ts | 6 +++--- src/entities/NoticeBoardComment.ts | 2 +- src/entities/NoticeBoardCommentHistory.ts | 2 +- src/entities/NoticeBoardHistory.ts | 6 +++--- src/entities/NoticeBoardReplyCommentHistory.ts | 2 +- .../{boolean.transformer.ts => boolean.transfomer.ts} | 0 17 files changed, 34 insertions(+), 35 deletions(-) rename src/entities/transformers/{boolean.transformer.ts => boolean.transfomer.ts} (100%) diff --git a/migrations/1700634679995-notice-board.ts b/migrations/1700634679995-notice-board.ts index a22cac6c..4b4e1879 100644 --- a/migrations/1700634679995-notice-board.ts +++ b/migrations/1700634679995-notice-board.ts @@ -80,7 +80,7 @@ export class NoticeBoard1700634679995 implements MigrationInterface { comment: '조회수', }, { - name: 'allow_comment', + name: 'is_allow_comment', type: 'tinyint', length: '1', unsigned: true, @@ -190,7 +190,7 @@ export class NoticeBoard1700634679995 implements MigrationInterface { comment: '댓글 본문', }, { - name: 'isAnonymous', + name: 'is_anonymous', type: 'tinyint', length: '1', default: 0, @@ -316,7 +316,7 @@ export class NoticeBoard1700634679995 implements MigrationInterface { comment: '대댓글 본문', }, { - name: 'isAnonymous', + name: 'is_anonymous', type: 'tinyint', length: '1', default: 0, diff --git a/migrations/1701328900610-notice-board-history.ts b/migrations/1701328900610-notice-board-history.ts index bd47e38c..8aedd993 100644 --- a/migrations/1701328900610-notice-board-history.ts +++ b/migrations/1701328900610-notice-board-history.ts @@ -68,7 +68,7 @@ export class NoticeBoardHistory1701328900610 implements MigrationInterface { comment: '공지게시글 내용', }, { - name: 'allow_comment', + name: 'is_allow_comment', type: 'boolean', default: 1, isNullable: false, @@ -126,7 +126,7 @@ export class NoticeBoardHistory1701328900610 implements MigrationInterface { comment: '댓글 본문', }, { - name: 'isAnonymous', + name: 'is_anonymous', type: 'boolean', default: 0, isNullable: false, @@ -191,7 +191,7 @@ export class NoticeBoardHistory1701328900610 implements MigrationInterface { comment: '대댓글 본문', }, { - name: 'isAnonymous', + name: 'is_anonymous', type: 'boolean', default: 0, isNullable: false, diff --git a/src/apis/notice-boards/constants/notice-board.constant.ts b/src/apis/notice-boards/constants/notice-board.constant.ts index c69d17c9..81513dc5 100644 --- a/src/apis/notice-boards/constants/notice-board.constant.ts +++ b/src/apis/notice-boards/constants/notice-board.constant.ts @@ -5,7 +5,7 @@ export const NOTICE_BOARD_ORDER_FIELD: readonly (keyof NoticeBoardDto)[] = [ 'userId', 'title', 'hit', - 'allowComment', + 'isAllowComment', 'createdAt', 'updatedAt', ] as const; diff --git a/src/apis/notice-boards/controllers/notice-boards.controller.ts b/src/apis/notice-boards/controllers/notice-boards.controller.ts index a32ad4fc..9761811b 100644 --- a/src/apis/notice-boards/controllers/notice-boards.controller.ts +++ b/src/apis/notice-boards/controllers/notice-boards.controller.ts @@ -29,7 +29,7 @@ export class NoticeBoardsController { @ApiNoticeBoard.Create({ summary: '공지 게시글 생성 API' }) @UseGuards(JwtAuthGuard) - @SetResponse({ type: ResponseType.Detail, key: 'board' }) + @SetResponse({ type: ResponseType.Detail, key: 'noticeBoard' }) @Post() create( @User() user: UserDto, diff --git a/src/apis/notice-boards/dto/create-notice-board.dto.ts b/src/apis/notice-boards/dto/create-notice-board.dto.ts index bb75c6a3..a2f391a4 100644 --- a/src/apis/notice-boards/dto/create-notice-board.dto.ts +++ b/src/apis/notice-boards/dto/create-notice-board.dto.ts @@ -4,7 +4,7 @@ import { NoticeBoardDto } from './notice-board.dto'; import { ApiProperty } from '@nestjs/swagger'; export class CreateNoticeBoardDto - implements Pick + implements Pick { @ApiProperty({ description: '공지 게시글 제목', @@ -22,8 +22,7 @@ export class CreateNoticeBoardDto @ApiProperty({ description: '댓글 허용 여부 (false: 비활성화, true: 허용)', - default: true, }) @IsBoolean() - allowComment: boolean; + isAllowComment: boolean; } diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index 81bb18ec..4069fd68 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -1,13 +1,12 @@ import { PageDto } from '@src/dto/page.dto'; import { NoticeBoardDto } from './notice-board.dto'; import { ApiPropertyOptional } from '@nestjs/swagger'; -import { IsBoolean, IsOptional, Length } from 'class-validator'; +import { IsBooleanString, IsOptional, Length } from 'class-validator'; import { IsPositiveInt } from '@src/dto/validator/is-positive-int.decorator'; import { NOTICE_BOARD_ORDER_FIELD, NOTICE_BOARD_TITLE_LENGTH, } from '../constants/notice-board.constant'; -import { Type } from 'class-transformer'; import { ApiPropertyOrder } from '@src/dto/swagger/api-property-order.decorator'; import { CsvToOrder, Order } from '@src/dto/transformer/csv-to-order.decorator'; import { SortOrder } from '@src/constants/enum'; @@ -34,9 +33,10 @@ export class FindNoticeBoardListQueryDto @ApiPropertyOptional({ description: 'title 필터링', + minLength: NOTICE_BOARD_TITLE_LENGTH.MIN, maxLength: NOTICE_BOARD_TITLE_LENGTH.MAX, }) - @Length(NOTICE_BOARD_TITLE_LENGTH.MIN - 1, NOTICE_BOARD_TITLE_LENGTH.MAX) + @Length(NOTICE_BOARD_TITLE_LENGTH.MIN, NOTICE_BOARD_TITLE_LENGTH.MAX) @IsOptional() title?: string; @@ -44,10 +44,9 @@ export class FindNoticeBoardListQueryDto description: '댓글 허용 여부', enum: ['true', 'false'], }) - @IsBoolean() + @IsBooleanString() @IsOptional() - @Type(() => Boolean) - allowComment?: boolean; + isAllowComment?: boolean; @ApiPropertyOrder(NOTICE_BOARD_ORDER_FIELD) @CsvToOrder([...NOTICE_BOARD_ORDER_FIELD]) diff --git a/src/apis/notice-boards/dto/notice-board.dto.ts b/src/apis/notice-boards/dto/notice-board.dto.ts index 42bdbb21..10a6e24c 100644 --- a/src/apis/notice-boards/dto/notice-board.dto.ts +++ b/src/apis/notice-boards/dto/notice-board.dto.ts @@ -13,7 +13,7 @@ export class NoticeBoardDto | 'description' | 'userId' | 'hit' - | 'allowComment' + | 'isAllowComment' | 'createdAt' | 'updatedAt' > @@ -47,7 +47,7 @@ export class NoticeBoardDto description: '댓글 허용 여부 (false: 비활성화, true: 허용)', default: true, }) - allowComment: boolean; + isAllowComment: boolean; constructor(noticeBoardDto: Partial = {}) { super(); diff --git a/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts b/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts index 677cf8a7..48af0c42 100644 --- a/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts +++ b/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts @@ -1,15 +1,16 @@ import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; export class CreateNoticeBoardHistoryDto - implements Pick + implements + Pick { title: string; description: string; - allowComment: boolean; + isAllowComment: boolean; constructor(createNoticeBoardHistoryDto: CreateNoticeBoardHistoryDto) { this.title = createNoticeBoardHistoryDto.title; this.description = createNoticeBoardHistoryDto.description; - this.allowComment = createNoticeBoardHistoryDto.allowComment; + this.isAllowComment = createNoticeBoardHistoryDto.isAllowComment; } } diff --git a/src/apis/notice-boards/services/notice-boards.service.ts b/src/apis/notice-boards/services/notice-boards.service.ts index 00a2ebe5..b4393a62 100644 --- a/src/apis/notice-boards/services/notice-boards.service.ts +++ b/src/apis/notice-boards/services/notice-boards.service.ts @@ -49,7 +49,7 @@ export class NoticeBoardsService { { title: newPost.title, description: newPost.description, - allowComment: newPost.allowComment, + isAllowComment: newPost.isAllowComment, }, ); @@ -91,7 +91,7 @@ export class NoticeBoardsService { userId: true, title: true, hit: true, - allowComment: true, + isAllowComment: true, createdAt: true, updatedAt: true, }, diff --git a/src/entities/FreeBoard.ts b/src/entities/FreeBoard.ts index 6d97fb7a..310e9db7 100644 --- a/src/entities/FreeBoard.ts +++ b/src/entities/FreeBoard.ts @@ -1,5 +1,5 @@ import { FreeBoardHistory } from '@src/entities/FreeBoardHistory'; -import { BooleanTransformer } from '@src/entities/transformers/boolean.transformer'; +import { BooleanTransformer } from '@src/entities/transformers/boolean.transfomer'; import { Column, Entity, diff --git a/src/entities/FreeBoardHistory.ts b/src/entities/FreeBoardHistory.ts index 44c35508..9688d79f 100644 --- a/src/entities/FreeBoardHistory.ts +++ b/src/entities/FreeBoardHistory.ts @@ -1,4 +1,4 @@ -import { BooleanTransformer } from '@src/entities/transformers/boolean.transformer'; +import { BooleanTransformer } from '@src/entities/transformers/boolean.transfomer'; import { Column, Entity, diff --git a/src/entities/NoticeBoard.ts b/src/entities/NoticeBoard.ts index e7b68b9b..ffc8dfcd 100644 --- a/src/entities/NoticeBoard.ts +++ b/src/entities/NoticeBoard.ts @@ -11,7 +11,7 @@ import { NoticeBoardReaction } from './NoticeBoardReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { User } from './User'; import { NoticeBoardHistory } from './NoticeBoardHistory'; -import { BooleanTransformer } from './transformers/boolean.transformer'; +import { BooleanTransformer } from './transformers/boolean.transfomer'; @Entity('notice_board', { schema: 'dongurami_local_db' }) export class NoticeBoard { @@ -38,12 +38,12 @@ export class NoticeBoard { hit: number; @Column('boolean', { - name: 'allow_comment', + name: 'is_allow_comment', comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', default: () => true, transformer: new BooleanTransformer(), }) - allowComment: boolean; + isAllowComment: boolean; @Column('timestamp', { name: 'created_at', diff --git a/src/entities/NoticeBoardComment.ts b/src/entities/NoticeBoardComment.ts index ee962cd7..ec515e14 100644 --- a/src/entities/NoticeBoardComment.ts +++ b/src/entities/NoticeBoardComment.ts @@ -10,7 +10,7 @@ import { NoticeBoard } from './NoticeBoard'; import { NoticeBoardCommentReaction } from './NoticeBoardCommentReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { User } from './User'; -import { BooleanTransformer } from './transformers/boolean.transformer'; +import { BooleanTransformer } from './transformers/boolean.transfomer'; @Entity('notice_board_comment', { schema: 'dongurami_local_db' }) export class NoticeBoardComment { diff --git a/src/entities/NoticeBoardCommentHistory.ts b/src/entities/NoticeBoardCommentHistory.ts index 307da064..6786186e 100644 --- a/src/entities/NoticeBoardCommentHistory.ts +++ b/src/entities/NoticeBoardCommentHistory.ts @@ -9,7 +9,7 @@ import { import { NoticeBoardHistory } from './NoticeBoardHistory'; import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; import { User } from './User'; -import { BooleanTransformer } from './transformers/boolean.transformer'; +import { BooleanTransformer } from './transformers/boolean.transfomer'; @Entity('notice_board_comment_history', { schema: 'dongurami_local_db' }) export class NoticeBoardCommentHistory { diff --git a/src/entities/NoticeBoardHistory.ts b/src/entities/NoticeBoardHistory.ts index d884df53..dc4fd5fa 100644 --- a/src/entities/NoticeBoardHistory.ts +++ b/src/entities/NoticeBoardHistory.ts @@ -10,7 +10,7 @@ import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; import { User } from './User'; import { NoticeBoard } from './NoticeBoard'; -import { BooleanTransformer } from './transformers/boolean.transformer'; +import { BooleanTransformer } from './transformers/boolean.transfomer'; @Entity('notice_board_history', { schema: 'dongurami_local_db' }) export class NoticeBoardHistory { @@ -29,12 +29,12 @@ export class NoticeBoardHistory { description: string; @Column('boolean', { - name: 'allow_comment', + name: 'is_allow_comment', comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', default: () => true, transformer: new BooleanTransformer(), }) - allowComment: boolean; + isAllowComment: boolean; @Column('timestamp', { name: 'created_at', diff --git a/src/entities/NoticeBoardReplyCommentHistory.ts b/src/entities/NoticeBoardReplyCommentHistory.ts index 01eed198..33cfb3a7 100644 --- a/src/entities/NoticeBoardReplyCommentHistory.ts +++ b/src/entities/NoticeBoardReplyCommentHistory.ts @@ -9,7 +9,7 @@ import { import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; import { NoticeBoardHistory } from './NoticeBoardHistory'; import { User } from './User'; -import { BooleanTransformer } from './transformers/boolean.transformer'; +import { BooleanTransformer } from './transformers/boolean.transfomer'; @Entity('notice_board_reply_comment_history', { schema: 'dongurami_local_db' }) export class NoticeBoardReplyCommentHistory { diff --git a/src/entities/transformers/boolean.transformer.ts b/src/entities/transformers/boolean.transfomer.ts similarity index 100% rename from src/entities/transformers/boolean.transformer.ts rename to src/entities/transformers/boolean.transfomer.ts From cc357182e774bf660c1a22d75536ba8092ff8e51 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 23:02:38 +0900 Subject: [PATCH 32/37] feat/#66: notice_board , notice_board_history migration --- ...6068699-notice-board-change-column-name.ts | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 migrations/1701696068699-notice-board-change-column-name.ts diff --git a/migrations/1701696068699-notice-board-change-column-name.ts b/migrations/1701696068699-notice-board-change-column-name.ts new file mode 100644 index 00000000..7030372e --- /dev/null +++ b/migrations/1701696068699-notice-board-change-column-name.ts @@ -0,0 +1,123 @@ +import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; + +export class NoticeBoardChangeColumnName1701696068699 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.changeColumn( + 'notice_board', + 'allow_comment', + new TableColumn({ + name: 'is_allow_comment', + type: 'boolean', + default: true, + isNullable: false, + comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_comment', + 'isAnonymous', + new TableColumn({ + name: 'is_anonymous', + type: 'tinyint', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_reply_comment', + 'isAnonymous', + new TableColumn({ + name: 'is_anonymous', + type: 'tinyint', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_history', + 'allow_comment', + new TableColumn({ + name: 'is_allow_comment', + type: 'boolean', + default: true, + isNullable: false, + comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_comment_history', + 'isAnonymous', + new TableColumn({ + name: 'is_anonymous', + type: 'tinyint', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_reply_comment_history', + 'isAnonymous', + new TableColumn({ + name: 'is_anonymous', + type: 'tinyint', + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.changeColumn( + 'notice_board', + 'is_allow_comment', + new TableColumn({ + name: 'allow_comment', + type: 'boolean', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_comment', + 'is_anonymous', + new TableColumn({ + name: 'isAnonymous', + type: 'tinyint', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_reply_comment', + 'is_anonymous', + new TableColumn({ + name: 'isAnonymous', + type: 'tinyint', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_history', + 'is_allow_comment', + new TableColumn({ + name: 'allow_comment', + type: 'boolean', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_comment_history', + 'is_anonymous', + new TableColumn({ + name: 'isAnonymous', + type: 'tinyint', + }), + ); + + await queryRunner.changeColumn( + 'notice_board_reply_comment_history', + 'is_anonymous', + new TableColumn({ + name: 'isAnonymous', + type: 'tinyint', + }), + ); + } +} From db84c464112cdf252cbff8f9ab08694ff3b4b4ae Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Mon, 4 Dec 2023 23:04:58 +0900 Subject: [PATCH 33/37] =?UTF-8?q?modify/#66:=20=EC=A3=BC=EC=84=9D=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...6068699-notice-board-change-column-name.ts | 222 +++++++++--------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/migrations/1701696068699-notice-board-change-column-name.ts b/migrations/1701696068699-notice-board-change-column-name.ts index 7030372e..11b979de 100644 --- a/migrations/1701696068699-notice-board-change-column-name.ts +++ b/migrations/1701696068699-notice-board-change-column-name.ts @@ -1,123 +1,123 @@ -import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; +// import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; -export class NoticeBoardChangeColumnName1701696068699 - implements MigrationInterface -{ - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.changeColumn( - 'notice_board', - 'allow_comment', - new TableColumn({ - name: 'is_allow_comment', - type: 'boolean', - default: true, - isNullable: false, - comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', - }), - ); +// export class NoticeBoardChangeColumnName1701696068699 +// implements MigrationInterface +// { +// public async up(queryRunner: QueryRunner): Promise { +// await queryRunner.changeColumn( +// 'notice_board', +// 'allow_comment', +// new TableColumn({ +// name: 'is_allow_comment', +// type: 'boolean', +// default: true, +// isNullable: false, +// comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_comment', - 'isAnonymous', - new TableColumn({ - name: 'is_anonymous', - type: 'tinyint', - }), - ); +// await queryRunner.changeColumn( +// 'notice_board_comment', +// 'isAnonymous', +// new TableColumn({ +// name: 'is_anonymous', +// type: 'tinyint', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_reply_comment', - 'isAnonymous', - new TableColumn({ - name: 'is_anonymous', - type: 'tinyint', - }), - ); +// await queryRunner.changeColumn( +// 'notice_board_reply_comment', +// 'isAnonymous', +// new TableColumn({ +// name: 'is_anonymous', +// type: 'tinyint', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_history', - 'allow_comment', - new TableColumn({ - name: 'is_allow_comment', - type: 'boolean', - default: true, - isNullable: false, - comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', - }), - ); +// await queryRunner.changeColumn( +// 'notice_board_history', +// 'allow_comment', +// new TableColumn({ +// name: 'is_allow_comment', +// type: 'boolean', +// default: true, +// isNullable: false, +// comment: '댓글 허용 여부 (0: 비활성화, 1: 허용)', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_comment_history', - 'isAnonymous', - new TableColumn({ - name: 'is_anonymous', - type: 'tinyint', - }), - ); +// await queryRunner.changeColumn( +// 'notice_board_comment_history', +// 'isAnonymous', +// new TableColumn({ +// name: 'is_anonymous', +// type: 'tinyint', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_reply_comment_history', - 'isAnonymous', - new TableColumn({ - name: 'is_anonymous', - type: 'tinyint', - }), - ); - } +// await queryRunner.changeColumn( +// 'notice_board_reply_comment_history', +// 'isAnonymous', +// new TableColumn({ +// name: 'is_anonymous', +// type: 'tinyint', +// }), +// ); +// } - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.changeColumn( - 'notice_board', - 'is_allow_comment', - new TableColumn({ - name: 'allow_comment', - type: 'boolean', - }), - ); +// public async down(queryRunner: QueryRunner): Promise { +// await queryRunner.changeColumn( +// 'notice_board', +// 'is_allow_comment', +// new TableColumn({ +// name: 'allow_comment', +// type: 'boolean', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_comment', - 'is_anonymous', - new TableColumn({ - name: 'isAnonymous', - type: 'tinyint', - }), - ); +// await queryRunner.changeColumn( +// 'notice_board_comment', +// 'is_anonymous', +// new TableColumn({ +// name: 'isAnonymous', +// type: 'tinyint', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_reply_comment', - 'is_anonymous', - new TableColumn({ - name: 'isAnonymous', - type: 'tinyint', - }), - ); +// await queryRunner.changeColumn( +// 'notice_board_reply_comment', +// 'is_anonymous', +// new TableColumn({ +// name: 'isAnonymous', +// type: 'tinyint', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_history', - 'is_allow_comment', - new TableColumn({ - name: 'allow_comment', - type: 'boolean', - }), - ); +// await queryRunner.changeColumn( +// 'notice_board_history', +// 'is_allow_comment', +// new TableColumn({ +// name: 'allow_comment', +// type: 'boolean', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_comment_history', - 'is_anonymous', - new TableColumn({ - name: 'isAnonymous', - type: 'tinyint', - }), - ); +// await queryRunner.changeColumn( +// 'notice_board_comment_history', +// 'is_anonymous', +// new TableColumn({ +// name: 'isAnonymous', +// type: 'tinyint', +// }), +// ); - await queryRunner.changeColumn( - 'notice_board_reply_comment_history', - 'is_anonymous', - new TableColumn({ - name: 'isAnonymous', - type: 'tinyint', - }), - ); - } -} +// await queryRunner.changeColumn( +// 'notice_board_reply_comment_history', +// 'is_anonymous', +// new TableColumn({ +// name: 'isAnonymous', +// type: 'tinyint', +// }), +// ); +// } +// } From 39c7ba210035ea16ec357d2206cd09a1c54feb8d Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Tue, 5 Dec 2023 00:04:05 +0900 Subject: [PATCH 34/37] feat/#66: reflect #81 PR --- .../1701700089002-notice-board-soft-delete.ts | 67 +++++++++++++++++++ .../constants/notice-board.enum.ts | 4 ++ .../dto/find-notice-board-list-query.dto.ts | 11 ++- .../notice-boards/dto/notice-board.dto.ts | 10 +++ .../dto/create-notice-board-history.dto.ts | 8 ++- .../services/notice-board-history.service.ts | 3 + .../services/notice-boards.service.ts | 7 +- src/constants/enum.ts | 6 ++ src/entities/FreeBoard.ts | 2 +- src/entities/FreeBoardHistory.ts | 2 +- src/entities/NoticeBoard.ts | 17 ++++- src/entities/NoticeBoardComment.ts | 2 +- src/entities/NoticeBoardCommentHistory.ts | 2 +- src/entities/NoticeBoardHistory.ts | 18 ++++- .../NoticeBoardReplyCommentHistory.ts | 2 +- ...n.transfomer.ts => boolean.transformer.ts} | 0 16 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 migrations/1701700089002-notice-board-soft-delete.ts create mode 100644 src/apis/notice-boards/constants/notice-board.enum.ts rename src/entities/transformers/{boolean.transfomer.ts => boolean.transformer.ts} (100%) diff --git a/migrations/1701700089002-notice-board-soft-delete.ts b/migrations/1701700089002-notice-board-soft-delete.ts new file mode 100644 index 00000000..54fcf500 --- /dev/null +++ b/migrations/1701700089002-notice-board-soft-delete.ts @@ -0,0 +1,67 @@ +import { NoticeBoardStatus } from '@src/apis/notice-boards/constants/notice-board.enum'; +import { HistoryAction } from '@src/constants/enum'; +import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; + +export class NoticeBoardSoftDelete1701700089002 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.addColumns('notice_board', [ + new TableColumn({ + name: 'deleted_at', + type: 'timestamp', + isNullable: true, + comment: '삭제 일자', + }), + new TableColumn({ + name: 'status', + type: 'enum', + enum: [NoticeBoardStatus.Posting, NoticeBoardStatus.Remove], + isNullable: false, + default: `"${NoticeBoardStatus.Posting}"`, + comment: '공지게시글 상태', + }), + ]); + queryRunner.query( + 'ALTER TABLE notice_board ALTER COLUMN status DROP DEFAULT', + ); + + await queryRunner.addColumns('notice_board_history', [ + new TableColumn({ + name: 'action', + type: 'enum', + enum: [ + HistoryAction.Insert, + HistoryAction.Update, + HistoryAction.Delete, + ], + isNullable: false, + default: `"${HistoryAction.Insert}"`, + comment: 'history 를 쌓는 action', + }), + new TableColumn({ + name: 'status', + type: 'enum', + enum: [NoticeBoardStatus.Posting, NoticeBoardStatus.Remove], + default: `"${NoticeBoardStatus.Posting}"`, + isNullable: false, + comment: '공지게시글 상태', + }), + ]); + queryRunner.query( + 'ALTER TABLE notice_board_history ALTER COLUMN action DROP DEFAULT', + ); + queryRunner.query( + 'ALTER TABLE notice_board_history ALTER COLUMN status DROP DEFAULT', + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropColumns('notice_board', [ + new TableColumn({ name: 'deleted_at', type: 'timestamp' }), + new TableColumn({ name: 'status', type: 'enum' }), + ]); + await queryRunner.dropColumns('notice_board_history', [ + new TableColumn({ name: 'action', type: 'enum' }), + new TableColumn({ name: 'status', type: 'enum' }), + ]); + } +} diff --git a/src/apis/notice-boards/constants/notice-board.enum.ts b/src/apis/notice-boards/constants/notice-board.enum.ts new file mode 100644 index 00000000..c2a91b35 --- /dev/null +++ b/src/apis/notice-boards/constants/notice-board.enum.ts @@ -0,0 +1,4 @@ +export enum NoticeBoardStatus { + Posting = 'posting', + Remove = 'remove', +} diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index 4069fd68..2549a41c 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -1,7 +1,12 @@ import { PageDto } from '@src/dto/page.dto'; import { NoticeBoardDto } from './notice-board.dto'; import { ApiPropertyOptional } from '@nestjs/swagger'; -import { IsBooleanString, IsOptional, Length } from 'class-validator'; +import { + IsBooleanString, + IsDefined, + IsOptional, + Length, +} from 'class-validator'; import { IsPositiveInt } from '@src/dto/validator/is-positive-int.decorator'; import { NOTICE_BOARD_ORDER_FIELD, @@ -10,6 +15,7 @@ import { import { ApiPropertyOrder } from '@src/dto/swagger/api-property-order.decorator'; import { CsvToOrder, Order } from '@src/dto/transformer/csv-to-order.decorator'; import { SortOrder } from '@src/constants/enum'; +import { NoticeBoardStatus } from '../constants/notice-board.enum'; export class FindNoticeBoardListQueryDto extends PageDto @@ -52,4 +58,7 @@ export class FindNoticeBoardListQueryDto @CsvToOrder([...NOTICE_BOARD_ORDER_FIELD]) @IsOptional() order: Order = { id: SortOrder.Desc }; + + @IsDefined() + status: NoticeBoardStatus.Posting; } diff --git a/src/apis/notice-boards/dto/notice-board.dto.ts b/src/apis/notice-boards/dto/notice-board.dto.ts index 10a6e24c..83d2a8aa 100644 --- a/src/apis/notice-boards/dto/notice-board.dto.ts +++ b/src/apis/notice-boards/dto/notice-board.dto.ts @@ -2,6 +2,8 @@ import { ApiProperty } from '@nestjs/swagger'; import { BaseDto } from '@src/dto/base.dto'; import { NoticeBoard } from '@src/entities/NoticeBoard'; import { NOTICE_BOARD_TITLE_LENGTH } from '../constants/notice-board.constant'; +import { Exclude } from 'class-transformer'; +import { NoticeBoardStatus } from '../constants/notice-board.enum'; export class NoticeBoardDto extends BaseDto @@ -14,8 +16,10 @@ export class NoticeBoardDto | 'userId' | 'hit' | 'isAllowComment' + | 'status' | 'createdAt' | 'updatedAt' + | 'deletedAt' > { @ApiProperty({ @@ -49,6 +53,12 @@ export class NoticeBoardDto }) isAllowComment: boolean; + @Exclude() + status: NoticeBoardStatus; + + @Exclude() + deletedAt: Date; + constructor(noticeBoardDto: Partial = {}) { super(); diff --git a/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts b/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts index 48af0c42..308637d6 100644 --- a/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts +++ b/src/apis/notice-boards/notice-board-history/dto/create-notice-board-history.dto.ts @@ -1,16 +1,22 @@ import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; +import { NoticeBoardStatus } from '../../constants/notice-board.enum'; export class CreateNoticeBoardHistoryDto implements - Pick + Pick< + NoticeBoardHistory, + 'title' | 'description' | 'isAllowComment' | 'status' + > { title: string; description: string; isAllowComment: boolean; + status: NoticeBoardStatus; constructor(createNoticeBoardHistoryDto: CreateNoticeBoardHistoryDto) { this.title = createNoticeBoardHistoryDto.title; this.description = createNoticeBoardHistoryDto.description; this.isAllowComment = createNoticeBoardHistoryDto.isAllowComment; + this.status = createNoticeBoardHistoryDto.status; } } diff --git a/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.ts b/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.ts index 9ab7e9ff..285cd875 100644 --- a/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.ts +++ b/src/apis/notice-boards/notice-board-history/services/notice-board-history.service.ts @@ -3,6 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { NoticeBoardHistory } from '@src/entities/NoticeBoardHistory'; import { EntityManager, Repository } from 'typeorm'; import { CreateNoticeBoardHistoryDto } from '../dto/create-notice-board-history.dto'; +import { HistoryAction } from '@src/constants/enum'; @Injectable() export class NoticeBoardHistoryService { @@ -14,6 +15,7 @@ export class NoticeBoardHistoryService { entityManager: EntityManager, userId: number, noticeBoardId: number, + action: HistoryAction, createNoticeBoardHistoryDto: CreateNoticeBoardHistoryDto, ) { return entityManager @@ -21,6 +23,7 @@ export class NoticeBoardHistoryService { .save({ userId, noticeBoardId, + action, ...new CreateNoticeBoardHistoryDto(createNoticeBoardHistoryDto), }); } diff --git a/src/apis/notice-boards/services/notice-boards.service.ts b/src/apis/notice-boards/services/notice-boards.service.ts index b4393a62..85a91a60 100644 --- a/src/apis/notice-boards/services/notice-boards.service.ts +++ b/src/apis/notice-boards/services/notice-boards.service.ts @@ -10,6 +10,7 @@ import { QueryHelper } from '@src/helpers/query.helper'; import { FindNoticeBoardListQueryDto } from '../dto/find-notice-board-list-query.dto'; import { NoticeBoardsItemDto } from '../dto/notice-boards-item.dto'; import { NoticeBoardHistoryService } from '../notice-board-history/services/notice-board-history.service'; +import { HistoryAction } from '@src/constants/enum'; @Injectable() export class NoticeBoardsService { @@ -41,15 +42,15 @@ export class NoticeBoardsService { userId, ...createNoticeBoardDto, }); + console.log(newPost); await this.noticeBoardHistoryService.create( entityManager, newPost.userId, newPost.id, + HistoryAction.Insert, { - title: newPost.title, - description: newPost.description, - isAllowComment: newPost.isAllowComment, + ...newPost, }, ); diff --git a/src/constants/enum.ts b/src/constants/enum.ts index 33f874e1..1697b36c 100644 --- a/src/constants/enum.ts +++ b/src/constants/enum.ts @@ -2,3 +2,9 @@ export enum SortOrder { Desc = 'DESC', Asc = 'ASC', } + +export enum HistoryAction { + Insert = 'insert', + Update = 'update', + Delete = 'delete', +} diff --git a/src/entities/FreeBoard.ts b/src/entities/FreeBoard.ts index 310e9db7..6d97fb7a 100644 --- a/src/entities/FreeBoard.ts +++ b/src/entities/FreeBoard.ts @@ -1,5 +1,5 @@ import { FreeBoardHistory } from '@src/entities/FreeBoardHistory'; -import { BooleanTransformer } from '@src/entities/transformers/boolean.transfomer'; +import { BooleanTransformer } from '@src/entities/transformers/boolean.transformer'; import { Column, Entity, diff --git a/src/entities/FreeBoardHistory.ts b/src/entities/FreeBoardHistory.ts index 9688d79f..44c35508 100644 --- a/src/entities/FreeBoardHistory.ts +++ b/src/entities/FreeBoardHistory.ts @@ -1,4 +1,4 @@ -import { BooleanTransformer } from '@src/entities/transformers/boolean.transfomer'; +import { BooleanTransformer } from '@src/entities/transformers/boolean.transformer'; import { Column, Entity, diff --git a/src/entities/NoticeBoard.ts b/src/entities/NoticeBoard.ts index ffc8dfcd..18fdf0a9 100644 --- a/src/entities/NoticeBoard.ts +++ b/src/entities/NoticeBoard.ts @@ -11,7 +11,8 @@ import { NoticeBoardReaction } from './NoticeBoardReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { User } from './User'; import { NoticeBoardHistory } from './NoticeBoardHistory'; -import { BooleanTransformer } from './transformers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; +import { NoticeBoardStatus } from '@src/apis/notice-boards/constants/notice-board.enum'; @Entity('notice_board', { schema: 'dongurami_local_db' }) export class NoticeBoard { @@ -45,6 +46,13 @@ export class NoticeBoard { }) isAllowComment: boolean; + @Column('enum', { + name: 'status', + comment: '공지게시글 상태', + enum: NoticeBoardStatus, + }) + status: NoticeBoardStatus; + @Column('timestamp', { name: 'created_at', comment: '생성 일자', @@ -59,6 +67,13 @@ export class NoticeBoard { }) updatedAt: Date; + @Column('timestamp', { + name: 'deleted_at', + nullable: true, + comment: '삭제 일자', + }) + deletedAt: Date | null; + @Column('int', { name: 'user_id', comment: '게시글 작성 유저 고유 ID', diff --git a/src/entities/NoticeBoardComment.ts b/src/entities/NoticeBoardComment.ts index ec515e14..ee962cd7 100644 --- a/src/entities/NoticeBoardComment.ts +++ b/src/entities/NoticeBoardComment.ts @@ -10,7 +10,7 @@ import { NoticeBoard } from './NoticeBoard'; import { NoticeBoardCommentReaction } from './NoticeBoardCommentReaction'; import { NoticeBoardReplyComment } from './NoticeBoardReplyComment'; import { User } from './User'; -import { BooleanTransformer } from './transformers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; @Entity('notice_board_comment', { schema: 'dongurami_local_db' }) export class NoticeBoardComment { diff --git a/src/entities/NoticeBoardCommentHistory.ts b/src/entities/NoticeBoardCommentHistory.ts index 6786186e..307da064 100644 --- a/src/entities/NoticeBoardCommentHistory.ts +++ b/src/entities/NoticeBoardCommentHistory.ts @@ -9,7 +9,7 @@ import { import { NoticeBoardHistory } from './NoticeBoardHistory'; import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; import { User } from './User'; -import { BooleanTransformer } from './transformers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; @Entity('notice_board_comment_history', { schema: 'dongurami_local_db' }) export class NoticeBoardCommentHistory { diff --git a/src/entities/NoticeBoardHistory.ts b/src/entities/NoticeBoardHistory.ts index dc4fd5fa..5d3a795b 100644 --- a/src/entities/NoticeBoardHistory.ts +++ b/src/entities/NoticeBoardHistory.ts @@ -10,7 +10,9 @@ import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; import { NoticeBoardReplyCommentHistory } from './NoticeBoardReplyCommentHistory'; import { User } from './User'; import { NoticeBoard } from './NoticeBoard'; -import { BooleanTransformer } from './transformers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; +import { HistoryAction } from '@src/constants/enum'; +import { NoticeBoardStatus } from '@src/apis/notice-boards/constants/notice-board.enum'; @Entity('notice_board_history', { schema: 'dongurami_local_db' }) export class NoticeBoardHistory { @@ -36,6 +38,20 @@ export class NoticeBoardHistory { }) isAllowComment: boolean; + @Column('enum', { + name: 'action', + comment: 'history 를 쌓는 action', + enum: HistoryAction, + }) + action: HistoryAction; + + @Column('enum', { + name: 'status', + comment: '공지게시글 상태', + enum: NoticeBoardStatus, + }) + status: NoticeBoardStatus; + @Column('timestamp', { name: 'created_at', comment: '생성 일자', diff --git a/src/entities/NoticeBoardReplyCommentHistory.ts b/src/entities/NoticeBoardReplyCommentHistory.ts index 33cfb3a7..01eed198 100644 --- a/src/entities/NoticeBoardReplyCommentHistory.ts +++ b/src/entities/NoticeBoardReplyCommentHistory.ts @@ -9,7 +9,7 @@ import { import { NoticeBoardCommentHistory } from './NoticeBoardCommentHistory'; import { NoticeBoardHistory } from './NoticeBoardHistory'; import { User } from './User'; -import { BooleanTransformer } from './transformers/boolean.transfomer'; +import { BooleanTransformer } from './transformers/boolean.transformer'; @Entity('notice_board_reply_comment_history', { schema: 'dongurami_local_db' }) export class NoticeBoardReplyCommentHistory { diff --git a/src/entities/transformers/boolean.transfomer.ts b/src/entities/transformers/boolean.transformer.ts similarity index 100% rename from src/entities/transformers/boolean.transfomer.ts rename to src/entities/transformers/boolean.transformer.ts From 4c58c8541bae8a7fe45583bd0cb0269644f9c1b8 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Tue, 5 Dec 2023 16:17:03 +0900 Subject: [PATCH 35/37] feat/#66: add default value --- .../notice-boards/dto/find-notice-board-list-query.dto.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index 2549a41c..ea927a7b 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -1,6 +1,6 @@ import { PageDto } from '@src/dto/page.dto'; import { NoticeBoardDto } from './notice-board.dto'; -import { ApiPropertyOptional } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsBooleanString, IsDefined, @@ -59,6 +59,11 @@ export class FindNoticeBoardListQueryDto @IsOptional() order: Order = { id: SortOrder.Desc }; + @ApiProperty({ + description: + '게시글 상태(posting: 게시글 작성된 상태, remove: 게시글 삭제된 상태)', + default: NoticeBoardStatus.Posting, + }) @IsDefined() status: NoticeBoardStatus.Posting; } From 6fba066303622517c7dc3723be3d1bdf665a8e6d Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Tue, 5 Dec 2023 17:56:11 +0900 Subject: [PATCH 36/37] modify/#66: set default value --- src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index ea927a7b..fc5c9c71 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -65,5 +65,5 @@ export class FindNoticeBoardListQueryDto default: NoticeBoardStatus.Posting, }) @IsDefined() - status: NoticeBoardStatus.Posting; + status: NoticeBoardStatus.Posting = NoticeBoardStatus.Posting; } From 11403a3a3b35579efa54cff7f25a597a8803e0f4 Mon Sep 17 00:00:00 2001 From: hobiJeong Date: Tue, 5 Dec 2023 19:26:54 +0900 Subject: [PATCH 37/37] modify/#66: delete ApiProperty --- .../notice-boards/dto/find-notice-board-list-query.dto.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts index fc5c9c71..5b585de1 100644 --- a/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts +++ b/src/apis/notice-boards/dto/find-notice-board-list-query.dto.ts @@ -59,11 +59,6 @@ export class FindNoticeBoardListQueryDto @IsOptional() order: Order = { id: SortOrder.Desc }; - @ApiProperty({ - description: - '게시글 상태(posting: 게시글 작성된 상태, remove: 게시글 삭제된 상태)', - default: NoticeBoardStatus.Posting, - }) @IsDefined() status: NoticeBoardStatus.Posting = NoticeBoardStatus.Posting; }