From b8de3175c1f3083e494f010181e2b5fadc24d757 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Fri, 7 Mar 2025 12:11:47 +0900 Subject: [PATCH 01/29] =?UTF-8?q?Hotfix:=20=EB=9E=AD=ED=82=B9=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/request/FilteredRankListRequest.ts | 26 ++++++++++++++----- .../entity/dao/request/RankListRequest.ts | 1 - src/rank/repository/rankListRepository.ts | 6 ++--- src/rank/service/rankListService.ts | 21 +++------------ 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/rank/entity/dao/request/FilteredRankListRequest.ts b/src/rank/entity/dao/request/FilteredRankListRequest.ts index 342e604..5044bb5 100644 --- a/src/rank/entity/dao/request/FilteredRankListRequest.ts +++ b/src/rank/entity/dao/request/FilteredRankListRequest.ts @@ -12,15 +12,27 @@ export default class FilteredRankListRequest { public current: number public nickname: string constructor(params: FilteredRankListRequestParams) { - if ( - !new RegExp(Regex.TIER).test(params.tier) || - !params.nickname || - params.nickname.length > 100 - ) { + if (params.tier && !new RegExp(Regex.TIER).test(params.tier)) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (!params.tier) { + this.tier = '%' + } else { + this.tier = params.tier + } + + if (!params.current) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - this.tier = params.tier this.current = Number(params.current) - this.nickname = params.nickname + + if (params.nickname && params.nickname.length > 100) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (!params.nickname) { + this.nickname = '%' + } else { + this.nickname = params.nickname + } } } diff --git a/src/rank/entity/dao/request/RankListRequest.ts b/src/rank/entity/dao/request/RankListRequest.ts index d10da31..2dc7858 100644 --- a/src/rank/entity/dao/request/RankListRequest.ts +++ b/src/rank/entity/dao/request/RankListRequest.ts @@ -8,4 +8,3 @@ export default class RankListRequest { this.current = Number(params.current) } } -;`` diff --git a/src/rank/repository/rankListRepository.ts b/src/rank/repository/rankListRepository.ts index 9ce9ece..365f7df 100644 --- a/src/rank/repository/rankListRepository.ts +++ b/src/rank/repository/rankListRepository.ts @@ -86,7 +86,7 @@ export default class RankListRepository { ), ranked_tiers AS ( SELECT - ROW_NUMBER() OVER (ORDER BY score DESC) AS new_rank, + ROW_NUMBER() OVER (ORDER BY score DESC) AS rank, tier, nickname, score @@ -95,8 +95,8 @@ export default class RankListRepository { ) SELECT * FROM ranked_tiers - WHERE new_rank > $2 AND nickname LIKE $3 - ORDER BY new_rank + WHERE rank > $2 AND nickname LIKE $3 + ORDER BY rank LIMIT 10; `, [tier, current, nickname], diff --git a/src/rank/service/rankListService.ts b/src/rank/service/rankListService.ts index 1f69f25..c6d07ca 100644 --- a/src/rank/service/rankListService.ts +++ b/src/rank/service/rankListService.ts @@ -13,28 +13,13 @@ export default class RankListService { filteredRankListRequest: FilteredRankListRequest, ) { const { tier, current, nickname } = filteredRankListRequest - if (!nickname) { - const result: any = await RankListRepository.getFilteredRankListFromDb( - tier, - current, - '%', - ) - return new RankListResponse(result) - } - if (!tier) { - const result: any = await RankListRepository.getFilteredRankListFromDb( - '%', - current, - nickname, - ) - return new RankListResponse(result) - } const result: any = await RankListRepository.getFilteredRankListFromDb( - tier, + '%' + tier + '%', current, - nickname, + '%' + nickname + '%', ) + return new RankListResponse(result) } } From a32180cbcfc508c99bd7784781e4a3d70904c0e8 Mon Sep 17 00:00:00 2001 From: taegyun Date: Fri, 7 Mar 2025 15:40:39 +0900 Subject: [PATCH 02/29] Hotfix:title_ regex_edit --- src/core/util/Regex/index.ts | 13 +++++++------ src/notice/router/writeRouter.ts | 2 +- src/notice/service/WriteService.ts | 9 +++++++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/core/util/Regex/index.ts b/src/core/util/Regex/index.ts index 47d6f41..0889756 100644 --- a/src/core/util/Regex/index.ts +++ b/src/core/util/Regex/index.ts @@ -2,21 +2,22 @@ export default class Regex { public static readonly ID = /^(?=.*[a-zA-Z])[a-zA-Z0-9]{5,16}$/ public static readonly EMAIL = /^[a-zA-Z0-9._%+-]{1,20}@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ + public static readonly NICKNAME = /^(?=.*[가-힣a-zA-Z])[가-힣a-zA-Z0-9]{2,12}$/ - public static readonly TITLE = /^[가-힣a-zA-Z0-9]{2,50}$/ + + public static readonly TITLE = /^[ㄱ-ㅎ가-힣a-zA-Z0-9\s]{2,50}$/ public static readonly DESCRIPTION = /^[가-힣a-zA-Z0-9]{2,500}$/ public static readonly SUBJECT = /^(?=.*[가-힣a-zA-Z])[가-힣a-zA-Z0-9]{2,50}$/ public static readonly QUIZ_COUNT = /^(10|[1-9])$/ - public static readonly CONTENT = /^[가-힣a-zA-Z0-9]{2,500}$/ + public static readonly CONTENT = /^[가-힣a-zA-Z0-9\s]{2,500}$/ public static readonly TEXT_ANSWER = - /^[가-힣a-zA-Z0-9!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{1,100}$/ - public static readonly SEARCH = /^[가-힣a-zA-Z0-9]{2,100}$/ + /^[ㄱ-ㅎ가-힣a-zA-Z0-9\s!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{1,100}$/ + public static readonly TIER = /^(DIAMOND|PLATINUM|GOLD|SILVER|BRONZE)$/ - public static readonly FILE = - /^(?:[^\s]+\.jpg|[^\s]+\.png)(,(?:[^\s]+\.jpg|[^\s]+\.png)){0,4}$/ public static readonly PASSWORD = /^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z0-9!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{8,16}$/ + public static readonly UUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/ } diff --git a/src/notice/router/writeRouter.ts b/src/notice/router/writeRouter.ts index 3e1788f..fefe2a8 100644 --- a/src/notice/router/writeRouter.ts +++ b/src/notice/router/writeRouter.ts @@ -16,6 +16,6 @@ writeRouter.post( WriteRequest, WriteResponse, )(async (req, res) => { - return res.send(await WriteService.writeNotice(req.body)) + return res.send(await WriteService.writeNotice(req.memberIdx, req.body)) }), ) diff --git a/src/notice/service/WriteService.ts b/src/notice/service/WriteService.ts index 5fd7f90..8d5ea7c 100644 --- a/src/notice/service/WriteService.ts +++ b/src/notice/service/WriteService.ts @@ -3,12 +3,17 @@ import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' import NoticeRepository from '../repository/NoticeRepository.js' export default class WriteService { - static async writeNotice(writeRequest: WriteRequest) { + static async writeNotice(memberIdx: number, writeRequest: WriteRequest) { const { title, content, uploadUrls } = writeRequest // 멤버 인덱스 return new WriteResponse( - await NoticeRepository.insertNoticeToDb(2, title, content, uploadUrls), + await NoticeRepository.insertNoticeToDb( + memberIdx, + title, + content, + uploadUrls, + ), ) } } From 2caeab2a6eb2715414e90f684a3db2ed8a9b2c2a Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Fri, 7 Mar 2025 16:28:49 +0900 Subject: [PATCH 03/29] =?UTF-8?q?Hotfix:=20=EB=AA=A8=EC=9D=98=EA=B3=A0?= =?UTF-8?q?=EC=82=AC=20=EB=AC=B8=EC=A0=9C=20=ED=92=80=EC=9D=B4=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20=EC=9E=85=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../frontend/request/body/MockEditRequest.ts | 2 +- .../dao/frontend/request/body/SolveRequest.ts | 25 +++++++++++-------- .../dao/frontend/request/body/WriteRequest.ts | 2 +- .../frontend/request/NoticeEditBodyRequest.ts | 2 +- .../dao/frontend/request/WriteRequest.ts | 2 +- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts index 5303b0a..8e9a869 100644 --- a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts @@ -15,7 +15,7 @@ export default class MockEditRequest { constructor(params: MockEditRequestParams) { if ( !new RegExp(Regex.TITLE).test(params.title) || - !new RegExp(Regex.DESCRIPTION).test(params.description) + (params.description && params.description.length > 1000) ) { throw ErrorRegistry.INVALID_INPUT_FORMAT } diff --git a/src/mock/entity/dao/frontend/request/body/SolveRequest.ts b/src/mock/entity/dao/frontend/request/body/SolveRequest.ts index 4630f93..0a404fd 100644 --- a/src/mock/entity/dao/frontend/request/body/SolveRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/SolveRequest.ts @@ -1,5 +1,4 @@ import ErrorRegistry from '#error/ErrorRegistry' -import Regex from '#util/Regex' interface SolveRequestParams { singleChoiceAnswer?: number @@ -10,17 +9,21 @@ export default class SolveRequest { singleChoiceAnswer?: number textAnswer?: string - constructor(public params: SolveRequestParams) { - if ( - (typeof params.textAnswer === 'string' && - !new RegExp(Regex.TEXT_ANSWER).test(params.textAnswer)) || - (typeof params.singleChoiceAnswer === 'number' && - (params.singleChoiceAnswer > 3 || params.singleChoiceAnswer < 0)) - ) { + constructor(params: SolveRequestParams) { + if (typeof params.singleChoiceAnswer === 'number') { + if (params.singleChoiceAnswer > 3 || params.singleChoiceAnswer < 0) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + this.singleChoiceAnswer = Number(params.singleChoiceAnswer) + } + if (typeof params.textAnswer === 'string') { + if (params.textAnswer.length > 100) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + this.textAnswer = params.textAnswer + } + if (params.singleChoiceAnswer === null && params.textAnswer === null) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - - this.singleChoiceAnswer = params.singleChoiceAnswer - this.textAnswer = params.textAnswer } } diff --git a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts index 6d59cf9..d02ba55 100644 --- a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts @@ -20,7 +20,7 @@ export default class WriteRequest { if ( !new RegExp(Regex.SUBJECT).test(params.subject) || !new RegExp(Regex.TITLE).test(params.title) || - !new RegExp(Regex.DESCRIPTION).test(params.description) || + (params.description && params.description.length > 1000) || params.quizCount > 10 || params.quizCount < 0 ) { diff --git a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts index 867a14c..50f59a7 100644 --- a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts +++ b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts @@ -14,7 +14,7 @@ export default class NoticeEditBodyRequest { constructor(params: NoticeEditBodyRequestParams) { if ( !new RegExp(Regex.TITLE).test(params.title) || - !new RegExp(Regex.CONTENT).test(params.content) + (params.content && params.content.length > 1000) ) { throw ErrorRegistry.INVALID_INPUT_FORMAT } diff --git a/src/notice/entity/dao/frontend/request/WriteRequest.ts b/src/notice/entity/dao/frontend/request/WriteRequest.ts index 9a5284e..571a9e7 100644 --- a/src/notice/entity/dao/frontend/request/WriteRequest.ts +++ b/src/notice/entity/dao/frontend/request/WriteRequest.ts @@ -14,7 +14,7 @@ export default class WriteRequest { constructor(params: WriteRequestParams) { if ( !new RegExp(Regex.TITLE).test(params.title) || - !new RegExp(Regex.CONTENT).test(params.content) + (params.content && params.content.length > 10000) ) { throw ErrorRegistry.INVALID_INPUT_FORMAT } From b9a0ed4a8ec157fb5ebed87b3002c918fdf0244b Mon Sep 17 00:00:00 2001 From: taegyun Date: Sat, 8 Mar 2025 20:13:11 +0900 Subject: [PATCH 04/29] Hotfix: password_change_logic_edit --- src/core/util/Regex/index.ts | 3 ++- src/member/service/ChangeService.ts | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/core/util/Regex/index.ts b/src/core/util/Regex/index.ts index 0889756..f32ab70 100644 --- a/src/core/util/Regex/index.ts +++ b/src/core/util/Regex/index.ts @@ -10,7 +10,8 @@ export default class Regex { public static readonly DESCRIPTION = /^[가-힣a-zA-Z0-9]{2,500}$/ public static readonly SUBJECT = /^(?=.*[가-힣a-zA-Z])[가-힣a-zA-Z0-9]{2,50}$/ public static readonly QUIZ_COUNT = /^(10|[1-9])$/ - public static readonly CONTENT = /^[가-힣a-zA-Z0-9\s]{2,500}$/ + public static readonly CONTENT = + /^[가-힣a-zA-Z0-9\s!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{2,500}$/ public static readonly TEXT_ANSWER = /^[ㄱ-ㅎ가-힣a-zA-Z0-9\s!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{1,100}$/ diff --git a/src/member/service/ChangeService.ts b/src/member/service/ChangeService.ts index f956710..02f37e7 100644 --- a/src/member/service/ChangeService.ts +++ b/src/member/service/ChangeService.ts @@ -1,6 +1,7 @@ import ErrorRegistry from '#error/ErrorRegistry' import EmailSender from '#util/EmailSender' import Token from '#util/Token' +import CryptoJS from 'crypto-js' import { Request } from 'express' import jwt from 'jsonwebtoken' import NicknameChangeRequest from '../entity/dao/frontend/request/NicknameChangeRequest.js' @@ -30,7 +31,14 @@ export default class ChangeService { } const secretKey = process.env.JWT_SIGNATURE_KEY const data: any = jwt.verify(token, secretKey) - await MemberChangeRepository.updateMemberPassword(password, data.userId) + const salt = process.env.ENCRYPT_SALT_STRING + const changePassword = CryptoJS.SHA256(password + salt).toString() + console.log(changePassword) + await MemberChangeRepository.updateMemberPassword( + changePassword, + data.userId, + ) + console.log(data) await RedisEmailChangeRepository.resetFindPasswordEmailDataFromRedis( data.email, ) @@ -46,6 +54,7 @@ export default class ChangeService { sendFindPasswordEmailRequest: SendFindPasswordEmailRequest, ) { const { id, email } = sendFindPasswordEmailRequest + console.log(id) const token = Token.generateVerifyToken(id, email) await RedisEmailChangeRepository.checkFindPasswordEmailDataFromRedis( email, From 19d031d7f15fa6a9c013fbff26e0f815f7f835d9 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Sun, 9 Mar 2025 15:22:56 +0900 Subject: [PATCH 05/29] =?UTF-8?q?[SUS-76]=20notice=EA=B9=8C=EC=A7=80=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/like/router/addRouter.ts | 21 --------- src/like/router/index.ts | 6 +-- .../{deleteRouter.ts => likeItemRouter.ts} | 21 +++++++-- .../dao/frontend/request/ListRequest.ts | 15 ++++--- .../dao/frontend/response/ListResponse.ts | 39 ++++++----------- src/notice/entity/dto/NoticeList.ts | 42 ------------------ src/notice/router/index.ts | 4 +- src/notice/router/listRouter.ts | 15 ------- src/notice/router/noticeItemRouter.ts | 24 +++++++++-- src/notice/router/writeRouter.ts | 21 --------- src/notice/service/ListService.ts | 43 ++++++------------- src/notice/service/NoticeItemService.ts | 16 +++++++ src/notice/service/WriteService.ts | 19 -------- 13 files changed, 96 insertions(+), 190 deletions(-) delete mode 100644 src/like/router/addRouter.ts rename src/like/router/{deleteRouter.ts => likeItemRouter.ts} (56%) delete mode 100644 src/notice/entity/dto/NoticeList.ts delete mode 100644 src/notice/router/writeRouter.ts delete mode 100644 src/notice/service/WriteService.ts diff --git a/src/like/router/addRouter.ts b/src/like/router/addRouter.ts deleted file mode 100644 index 5b264f0..0000000 --- a/src/like/router/addRouter.ts +++ /dev/null @@ -1,21 +0,0 @@ -import controller from '#controller' -import express from 'express' -import ArticleIdxPath from '../entity/dao/frontend/request/path/ArticleIdxPath.js' -import LikeService from '../service/LikeService.js' - -export const addRouter = express.Router() - -addRouter.post( - '/:idx', - controller( - 'login', - null, - ArticleIdxPath, - null, - null, - )(async (req, res) => { - return res.send( - await LikeService.addLikeToArticle(req.memberIdx, req.params.idx), - ) - }), -) diff --git a/src/like/router/index.ts b/src/like/router/index.ts index 0f17186..db22471 100644 --- a/src/like/router/index.ts +++ b/src/like/router/index.ts @@ -1,8 +1,6 @@ import express from 'express' -import { addRouter } from './addRouter.js' -import { deleteRouter } from './deleteRouter.js' +import { likeItemRouter } from './likeItemRouter.js' export const likeRouter = express.Router() -likeRouter.use('/add', addRouter) -likeRouter.use('/delete', deleteRouter) +likeRouter.use('/:idx', likeItemRouter) diff --git a/src/like/router/deleteRouter.ts b/src/like/router/likeItemRouter.ts similarity index 56% rename from src/like/router/deleteRouter.ts rename to src/like/router/likeItemRouter.ts index 392d093..ae8f32f 100644 --- a/src/like/router/deleteRouter.ts +++ b/src/like/router/likeItemRouter.ts @@ -3,10 +3,25 @@ import express from 'express' import ArticleIdxPath from '../entity/dao/frontend/request/path/ArticleIdxPath.js' import LikeService from '../service/LikeService.js' -export const deleteRouter = express.Router() +export const likeItemRouter = express.Router() -deleteRouter.delete( - '/:idx', +likeItemRouter.post( + '/', + controller( + 'login', + null, + ArticleIdxPath, + null, + null, + )(async (req, res) => { + return res.send( + await LikeService.addLikeToArticle(req.memberIdx, req.params.idx), + ) + }), +) + +likeItemRouter.delete( + '/', controller( 'login', null, diff --git a/src/notice/entity/dao/frontend/request/ListRequest.ts b/src/notice/entity/dao/frontend/request/ListRequest.ts index 3b7e363..d380ba0 100644 --- a/src/notice/entity/dao/frontend/request/ListRequest.ts +++ b/src/notice/entity/dao/frontend/request/ListRequest.ts @@ -1,24 +1,29 @@ import ErrorRegistry from '#error/ErrorRegistry' interface ListRequestParams { - current: number + title: string display: number + current: number } export default class ListRequest { + public title: string public current: number public display: number constructor(params: ListRequestParams) { + if (params.title && params.title.length > 100) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + + this.title = params.title if (!params.current) { throw ErrorRegistry.INVALID_INPUT_FORMAT - } else { - this.current = Number(params.current) } + this.display = Number(params.display) if (!params.display) { throw ErrorRegistry.INVALID_INPUT_FORMAT - } else { - this.display = Number(params.display) } + this.current = Number(params.current) } } diff --git a/src/notice/entity/dao/frontend/response/ListResponse.ts b/src/notice/entity/dao/frontend/response/ListResponse.ts index 787e3e4..c9e8634 100644 --- a/src/notice/entity/dao/frontend/response/ListResponse.ts +++ b/src/notice/entity/dao/frontend/response/ListResponse.ts @@ -1,5 +1,3 @@ -import NoticeList from 'src/notice/entity/dto/NoticeList.js' - export default class NoticeListResponse { firstPageNumber: number currentPageNumber: number @@ -13,39 +11,30 @@ export default class NoticeListResponse { createdAt: string }[] - public static of(noticeList: NoticeList): NoticeListResponse { - return new NoticeListResponse( - noticeList.firstPageNumber, - noticeList.currentPageNumber, - noticeList.lastPageNumber, - noticeList.prevPageExist, - noticeList.nextPageExist, - noticeList.notices, - ) - } - - public static createEmpty(): NoticeListResponse { - return new NoticeListResponse(1, 1, 1, false, false, []) - } - constructor( - firstPageNumber: number, currentPageNumber: number, - lastPageNumber: number, - prevPageExist: boolean, - nextPageExist: boolean, + displayCount: number, + totalCount: number, notices: { idx: number title: string writerNickname: string createdAt: string + totalCount: number }[], ) { - this.firstPageNumber = firstPageNumber this.currentPageNumber = currentPageNumber - this.lastPageNumber = lastPageNumber - this.prevPageExist = prevPageExist - this.nextPageExist = nextPageExist + this.firstPageNumber = Math.floor((currentPageNumber - 1) / 10) * 10 + 1 + const pageOffset = Math.min( + 9, + Math.floor( + (totalCount - (this.firstPageNumber - 1) * displayCount) / displayCount, + ), + ) + this.lastPageNumber = this.firstPageNumber + pageOffset + this.prevPageExist = this.firstPageNumber > 1 + this.nextPageExist = + this.lastPageNumber < Math.floor((totalCount - 1) / displayCount) + 1 this.notices = notices } } diff --git a/src/notice/entity/dto/NoticeList.ts b/src/notice/entity/dto/NoticeList.ts deleted file mode 100644 index e58bbfa..0000000 --- a/src/notice/entity/dto/NoticeList.ts +++ /dev/null @@ -1,42 +0,0 @@ -export default class NoticeList { - firstPageNumber: number - currentPageNumber: number - lastPageNumber: number - prevPageExist: boolean - nextPageExist: boolean - totalCount: number - notices: { - idx: number - title: string - writerNickname: string - createdAt: string - }[] - - constructor( - currentPageNumber: number, - displayCount: number, - totalCount: number, - notices: { - idx: number - title: string - writerNickname: string - createdAt: string - totalCount: number - }[], - ) { - this.totalCount = totalCount - this.currentPageNumber = currentPageNumber - this.firstPageNumber = Math.floor((currentPageNumber - 1) / 10) * 10 + 1 - const pageOffset = Math.min( - 9, - Math.floor( - (totalCount - (this.firstPageNumber - 1) * displayCount) / displayCount, - ), - ) - this.lastPageNumber = this.firstPageNumber + pageOffset - this.prevPageExist = this.firstPageNumber > 1 - this.nextPageExist = - this.lastPageNumber < Math.floor((totalCount - 1) / displayCount) + 1 - this.notices = notices - } -} diff --git a/src/notice/router/index.ts b/src/notice/router/index.ts index 734f9f7..3e54564 100644 --- a/src/notice/router/index.ts +++ b/src/notice/router/index.ts @@ -1,10 +1,8 @@ import express from 'express' import { listRouter } from './listRouter.js' import { noticeItemRouter } from './noticeItemRouter.js' -import { writeRouter } from './writeRouter.js' export const noticeRouter = express.Router() noticeRouter.use('/list', listRouter) -noticeRouter.use('/write', writeRouter) -noticeRouter.use('/', noticeItemRouter) +noticeRouter.use('/:idx', noticeItemRouter) diff --git a/src/notice/router/listRouter.ts b/src/notice/router/listRouter.ts index d7a584d..7e4f29b 100644 --- a/src/notice/router/listRouter.ts +++ b/src/notice/router/listRouter.ts @@ -1,9 +1,7 @@ import controller from '#controller' import express from 'express' import ListRequest from '../entity/dao/frontend/request/ListRequest.js' -import ListSearchRequest from '../entity/dao/frontend/request/ListSearchRequest.js' import ListResponse from '../entity/dao/frontend/response/ListResponse.js' -import ListSearchResponse from '../entity/dao/frontend/response/ListSearchResponse.js' import ListService from '../service/ListService.js' export const listRouter = express.Router() @@ -19,16 +17,3 @@ listRouter.get( return res.send(await ListService.getList(req.query)) }), ) - -listRouter.get( - '/search', - controller( - 'login', - ListSearchRequest, - null, - null, - ListSearchResponse, - )(async (req, res) => { - return res.send(await ListService.searchList(req.query)) - }), -) diff --git a/src/notice/router/noticeItemRouter.ts b/src/notice/router/noticeItemRouter.ts index 61b3bbf..f5eea5c 100644 --- a/src/notice/router/noticeItemRouter.ts +++ b/src/notice/router/noticeItemRouter.ts @@ -3,12 +3,30 @@ import multipartParser from '#util/multipartParser' import express from 'express' import NoticeEditBodyRequest from '../entity/dao/frontend/request/NoticeEditBodyRequest.js' import NoticePathRequest from '../entity/dao/frontend/request/NoticePathRequest.js' +import WriteRequest from '../entity/dao/frontend/request/WriteRequest.js' import NoticeResponse from '../entity/dao/frontend/response/NoticeResponse.js' +import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' import NoticeItemService from '../service/NoticeItemService.js' export const noticeItemRouter = express.Router() +noticeItemRouter.post( + '/', + multipartParser('image', 5), + controller( + 'admin', + null, + null, + WriteRequest, + WriteResponse, + )(async (req, res) => { + return res.send( + await NoticeItemService.writeNotice(req.memberIdx, req.body), + ) + }), +) + noticeItemRouter.get( - '/:idx', + '/', controller( 'login', null, @@ -21,7 +39,7 @@ noticeItemRouter.get( ) noticeItemRouter.delete( - '/:idx', + '/', controller( 'admin', null, @@ -35,7 +53,7 @@ noticeItemRouter.delete( ) noticeItemRouter.patch( - '/:idx', + '/', multipartParser('image', 5), controller( 'admin', diff --git a/src/notice/router/writeRouter.ts b/src/notice/router/writeRouter.ts deleted file mode 100644 index fefe2a8..0000000 --- a/src/notice/router/writeRouter.ts +++ /dev/null @@ -1,21 +0,0 @@ -import controller from '#controller' -import multipartParser from '#util/multipartParser' -import express from 'express' -import WriteRequest from '../entity/dao/frontend/request/WriteRequest.js' -import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' -import WriteService from '../service/WriteService.js' -export const writeRouter = express.Router() - -writeRouter.post( - '/', - multipartParser('image', 5), - controller( - 'admin', - null, - null, - WriteRequest, - WriteResponse, - )(async (req, res) => { - return res.send(await WriteService.writeNotice(req.memberIdx, req.body)) - }), -) diff --git a/src/notice/service/ListService.ts b/src/notice/service/ListService.ts index 2628763..548afe6 100644 --- a/src/notice/service/ListService.ts +++ b/src/notice/service/ListService.ts @@ -1,44 +1,29 @@ import ListRequest from '../entity/dao/frontend/request/ListRequest.js' -import ListSearchRequest from '../entity/dao/frontend/request/ListSearchRequest.js' import ListResponse from '../entity/dao/frontend/response/ListResponse.js' -import ListSearchResponse from '../entity/dao/frontend/response/ListSearchResponse.js' -import NoticeList from '../entity/dto/NoticeList.js' import NoticeRepository from '../repository/NoticeRepository.js' export default class ListService { static async getList(listRequest: ListRequest) { - const { current, display } = listRequest + const { current, display, title } = listRequest const offset = (current - 1) * display - const listData: any = await NoticeRepository.getPagedListFromDb( - display, - offset, - ) - const noticeList = new NoticeList( + let listData + if (title) { + const titleToSearch = '%' + title + '%' + listData = await NoticeRepository.getSearchListFromDb( + titleToSearch, + display, + offset, + ) + } else { + listData = await NoticeRepository.getPagedListFromDb(display, offset) + } + + return new ListResponse( current, display, listData.totalCountResult, listData.listResult, ) - - return ListResponse.of(noticeList) - } - - static async searchList(listSearchRequest: ListSearchRequest) { - const { title, display, current } = listSearchRequest - const offset = (current - 1) * display - const titleToSearch = '%' + title + '%' - const searchData: any = await NoticeRepository.getSearchListFromDb( - titleToSearch, - display, - offset, - ) - const noticeList = new NoticeList( - current, - display, - searchData.totalCountResult, - searchData.listResult, - ) - return ListSearchResponse.of(noticeList) } } diff --git a/src/notice/service/NoticeItemService.ts b/src/notice/service/NoticeItemService.ts index 3827039..984b8af 100644 --- a/src/notice/service/NoticeItemService.ts +++ b/src/notice/service/NoticeItemService.ts @@ -1,10 +1,26 @@ import ErrorRegistry from '#error/ErrorRegistry' import NoticeEditBodyRequest from '../entity/dao/frontend/request/NoticeEditBodyRequest.js' import NoticePathRequest from '../entity/dao/frontend/request/NoticePathRequest.js' +import WriteRequest from '../entity/dao/frontend/request/WriteRequest.js' import NoticeResponse from '../entity/dao/frontend/response/NoticeResponse.js' +import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' import NoticeRepository from '../repository/NoticeRepository.js' export default class NoticeItemService { + static async writeNotice(memberIdx: number, writeRequest: WriteRequest) { + const { title, content, uploadUrls } = writeRequest + // 멤버 인덱스 + + return new WriteResponse( + await NoticeRepository.insertNoticeToDb( + memberIdx, + title, + content, + uploadUrls, + ), + ) + } + static async getNotice(noticePathRequest: NoticePathRequest) { const { idx } = noticePathRequest const result = await NoticeRepository.getNoticeInfoFromDb(idx) diff --git a/src/notice/service/WriteService.ts b/src/notice/service/WriteService.ts deleted file mode 100644 index 8d5ea7c..0000000 --- a/src/notice/service/WriteService.ts +++ /dev/null @@ -1,19 +0,0 @@ -import WriteRequest from '../entity/dao/frontend/request/WriteRequest.js' -import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' -import NoticeRepository from '../repository/NoticeRepository.js' - -export default class WriteService { - static async writeNotice(memberIdx: number, writeRequest: WriteRequest) { - const { title, content, uploadUrls } = writeRequest - // 멤버 인덱스 - - return new WriteResponse( - await NoticeRepository.insertNoticeToDb( - memberIdx, - title, - content, - uploadUrls, - ), - ) - } -} From 4a8960484eee7035a0f4ff2b929cef6fdc4b8640 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Sun, 9 Mar 2025 15:28:36 +0900 Subject: [PATCH 06/29] =?UTF-8?q?[SUS-76]=20tier=EA=B9=8C=EC=A7=80=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/dao/request/RankListRequest.ts | 20 ++++++++++ src/rank/router/rankListRouter.ts | 14 ------- src/rank/service/rankListService.ts | 39 ++++++++++++------- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/rank/entity/dao/request/RankListRequest.ts b/src/rank/entity/dao/request/RankListRequest.ts index 2dc7858..4dafe82 100644 --- a/src/rank/entity/dao/request/RankListRequest.ts +++ b/src/rank/entity/dao/request/RankListRequest.ts @@ -1,10 +1,30 @@ +import ErrorRegistry from '#error/ErrorRegistry' +import Regex from '#util/Regex' + interface RankListRequestParams { + tier: string current: number + nickname: string } export default class RankListRequest { + public tier: string public current: number + public nickname: string constructor(params: RankListRequestParams) { + if (!params.current) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } this.current = Number(params.current) + + if (params.tier && !new RegExp(Regex.TIER).test(params.tier)) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + this.tier = params.tier + + if (params.nickname && params.nickname.length > 100) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + this.nickname = params.nickname } } diff --git a/src/rank/router/rankListRouter.ts b/src/rank/router/rankListRouter.ts index b9e2813..625e2e0 100644 --- a/src/rank/router/rankListRouter.ts +++ b/src/rank/router/rankListRouter.ts @@ -1,6 +1,5 @@ import controller from '#controller' import express from 'express' -import FilteredRankListRequest from '../entity/dao/request/FilteredRankListRequest.js' import RankListRequest from '../entity/dao/request/RankListRequest.js' import RankListResponse from '../entity/dao/response/RankListResponse.js' import RankListService from '../service/rankListService.js' @@ -19,16 +18,3 @@ rankListRouter.get( return res.send(await RankListService.getRankList(req.query)) }), ) - -rankListRouter.get( - '/search', - controller( - 'login', - FilteredRankListRequest, - null, - null, - RankListResponse, - )(async (req, res) => { - return res.send(await RankListService.getFilteredRankList(req.query)) - }), -) diff --git a/src/rank/service/rankListService.ts b/src/rank/service/rankListService.ts index c6d07ca..40adf14 100644 --- a/src/rank/service/rankListService.ts +++ b/src/rank/service/rankListService.ts @@ -1,24 +1,35 @@ -import FilteredRankListRequest from '../entity/dao/request/FilteredRankListRequest.js' import RankListRequest from '../entity/dao/request/RankListRequest.js' import RankListResponse from '../entity/dao/response/RankListResponse.js' import RankListRepository from '../repository/rankListRepository.js' export default class RankListService { static async getRankList(rankListRequest: RankListRequest) { - const { current } = rankListRequest - const result: any = await RankListRepository.getRankListFromDb(current) - return new RankListResponse(result) - } - static async getFilteredRankList( - filteredRankListRequest: FilteredRankListRequest, - ) { - const { tier, current, nickname } = filteredRankListRequest + const { current, tier, nickname } = rankListRequest + + let result + if (!tier && !nickname) { + result = await RankListRepository.getRankListFromDb(current) + } else { + let tierQuery: string + if (!tier) { + tierQuery = '%' + } else { + tierQuery = tier + } + + let nicknameQuery: string + if (!nickname) { + nicknameQuery = '%' + } else { + nicknameQuery = nickname + } - const result: any = await RankListRepository.getFilteredRankListFromDb( - '%' + tier + '%', - current, - '%' + nickname + '%', - ) + result = await RankListRepository.getFilteredRankListFromDb( + tierQuery, + current, + nicknameQuery, + ) + } return new RankListResponse(result) } From 9cc836aee0bb3529aab20f46b93c4ae06a19816d Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Sun, 9 Mar 2025 16:03:54 +0900 Subject: [PATCH 07/29] =?UTF-8?q?[SUS-76]=20:idx=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/util/Regex/index.ts | 2 +- .../dao/frontend/request/query/ListRequest.ts | 29 ++++-- src/mock/router/index.ts | 2 - src/mock/router/listRouter.ts | 18 +--- src/mock/router/mockItemRouter.ts | 71 ++++++++------ src/mock/router/writeRouter.ts | 22 ----- src/mock/service/ListService.ts | 94 ++++++++----------- .../frontend/response/ListSearchResponse.ts | 50 ---------- src/notice/router/noticeItemRouter.ts | 11 +-- src/notice/service/NoticeItemService.ts | 18 +--- src/notice/service/WriteService.ts | 18 ++++ src/rank/service/rankListService.ts | 4 +- 12 files changed, 137 insertions(+), 202 deletions(-) delete mode 100644 src/mock/router/writeRouter.ts delete mode 100644 src/notice/entity/dao/frontend/response/ListSearchResponse.ts create mode 100644 src/notice/service/WriteService.ts diff --git a/src/core/util/Regex/index.ts b/src/core/util/Regex/index.ts index f32ab70..592495f 100644 --- a/src/core/util/Regex/index.ts +++ b/src/core/util/Regex/index.ts @@ -20,5 +20,5 @@ export default class Regex { /^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z0-9!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{8,16}$/ public static readonly UUID = - /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/ + /^[0-9a-f]{8}-[0-9]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ } diff --git a/src/mock/entity/dao/frontend/request/query/ListRequest.ts b/src/mock/entity/dao/frontend/request/query/ListRequest.ts index 8c9dd1f..a41b8f0 100644 --- a/src/mock/entity/dao/frontend/request/query/ListRequest.ts +++ b/src/mock/entity/dao/frontend/request/query/ListRequest.ts @@ -1,19 +1,36 @@ import ErrorRegistry from '#error/ErrorRegistry' -interface ListQueryParams { +interface ListRequestParams { current: number display: number + sort: 'like' + title: string } -export default class ListQuery { +export default class ListRequest { current: number display: number + sort: 'new' | 'like' + title: string - constructor(params: ListQueryParams) { - if (!params.current || !params.display) { + constructor(params: ListRequestParams) { + if (!params.current) { throw ErrorRegistry.INVALID_INPUT_FORMAT + } else { + this.current = Number(params.current) } - this.current = Number(params.current) - this.display = Number(params.display) + + if (!params.display) { + this.display = 10 + } else { + this.display = Number(params.display) + } + + this.sort = params.sort + + if (params.title && params.title.length > 100) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + this.title = params.title } } diff --git a/src/mock/router/index.ts b/src/mock/router/index.ts index 2b88eb9..652a2de 100644 --- a/src/mock/router/index.ts +++ b/src/mock/router/index.ts @@ -2,11 +2,9 @@ import express from 'express' import { listRouter } from './listRouter.js' import { mockItemRouter } from './mockItemRouter.js' import { quizRouter } from './quizRouter.js' -import { writeRouter } from './writeRouter.js' export const mockRouter = express.Router() mockRouter.use('/list', listRouter) -mockRouter.use('/write', writeRouter) mockRouter.use('/quiz', quizRouter) mockRouter.use('/', mockItemRouter) diff --git a/src/mock/router/listRouter.ts b/src/mock/router/listRouter.ts index 223a943..7723af4 100644 --- a/src/mock/router/listRouter.ts +++ b/src/mock/router/listRouter.ts @@ -1,8 +1,7 @@ import controller from '#controller' import express from 'express' -import ListQuery from '../entity/dao/frontend/request/query/ListRequest.js' -import SearchQuery from '../entity/dao/frontend/request/query/SearchRequest.js' +import ListRequest from '../entity/dao/frontend/request/query/ListRequest.js' import ListResponse from '../entity/dao/frontend/response/ListResponse.js' import ListService from '../service/ListService.js' @@ -12,7 +11,7 @@ listRouter.get( '/', controller( 'login', - ListQuery, + ListRequest, null, null, ListResponse, @@ -20,16 +19,3 @@ listRouter.get( return res.send(await ListService.getMockList(req.query)) }), ) - -listRouter.get( - '/search', - controller( - 'login', - SearchQuery, - null, - null, - ListResponse, - )(async (req, res) => { - return res.send(await ListService.searchMock(req.query)) - }), -) diff --git a/src/mock/router/mockItemRouter.ts b/src/mock/router/mockItemRouter.ts index 2ace21f..7a08a11 100644 --- a/src/mock/router/mockItemRouter.ts +++ b/src/mock/router/mockItemRouter.ts @@ -3,14 +3,31 @@ import express from 'express' import multipartParser from '#util/multipartParser' import MockEditRequest from '../entity/dao/frontend/request/body/MockEditRequest.js' +import WriteRequest from '../entity/dao/frontend/request/body/WriteRequest.js' import MockIdxPath from '../entity/dao/frontend/request/path/MockIdxPath.js' import DetailResponse from '../entity/dao/frontend/response/DetailResponse.js' import IndividualMockInfoResponse from '../entity/dao/frontend/response/IndividualDetailResponse.js' import ResultResponse from '../entity/dao/frontend/response/ResultResponse.js' +import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' import MockItemService from '../service/MockItemService.js' +import WriteService from '../service/WriteService.js' export const mockItemRouter = express.Router() +mockItemRouter.post( + '/', + multipartParser('image', 1), + controller( + 'login', + null, + null, + WriteRequest, + WriteResponse, + )(async (req, res) => { + return res.send(await WriteService.writeMock(req.memberIdx, req.body)) + }), +) + mockItemRouter.get( '/:idx', controller( @@ -24,55 +41,52 @@ mockItemRouter.get( }), ) -mockItemRouter.get( - '/:idx/result', +mockItemRouter.delete( + '/:idx', controller( 'login', null, MockIdxPath, null, - ResultResponse, + null, )(async (req, res) => { - return res.send( - await MockItemService.getMockResult(req.memberIdx, req.params), - ) + await MockItemService.deleteMock(req.memberIdx, req.params) + res.sendStatus(200) }), ) -mockItemRouter.post( - '/:idx/result', +mockItemRouter.patch( + '/:idx', + multipartParser('image', 1), controller( 'login', null, MockIdxPath, - null, + MockEditRequest, null, )(async (req, res) => { - await MockItemService.saveMockResult(req.memberIdx, req.params) - res.sendStatus(201) + await MockItemService.editMock(req.memberIdx, req.params, req.body) + res.sendStatus(200) }), ) mockItemRouter.get( - '/:idx/individual', + '/:idx/result', controller( 'login', null, MockIdxPath, null, - IndividualMockInfoResponse, + ResultResponse, )(async (req, res) => { return res.send( - await MockItemService.getIndividualMockDetail({ - memberIdx: req.memberIdx, - path: req.params, - }), + await MockItemService.getMockResult(req.memberIdx, req.params), ) }), ) -mockItemRouter.delete( - '/:idx/delete', +mockItemRouter.post( + '/:idx/result', controller( 'login', null, @@ -80,22 +94,25 @@ mockItemRouter.delete( null, null, )(async (req, res) => { - await MockItemService.deleteMock(req.memberIdx, req.params) - res.sendStatus(200) + await MockItemService.saveMockResult(req.memberIdx, req.params) + res.sendStatus(201) }), ) -mockItemRouter.patch( - '/:idx/edit', - multipartParser('image', 1), +mockItemRouter.get( + '/:idx/individual', controller( 'login', null, MockIdxPath, - MockEditRequest, null, + IndividualMockInfoResponse, )(async (req, res) => { - await MockItemService.editMock(req.memberIdx, req.params, req.body) - res.sendStatus(200) + return res.send( + await MockItemService.getIndividualMockDetail({ + memberIdx: req.memberIdx, + path: req.params, + }), + ) }), ) diff --git a/src/mock/router/writeRouter.ts b/src/mock/router/writeRouter.ts deleted file mode 100644 index 37e3cb8..0000000 --- a/src/mock/router/writeRouter.ts +++ /dev/null @@ -1,22 +0,0 @@ -import controller from '#controller' -import multipartParser from '#util/multipartParser' -import express from 'express' -import WriteRequest from '../entity/dao/frontend/request/body/WriteRequest.js' -import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' -import WriteService from '../service/WriteService.js' - -export const writeRouter = express.Router() - -writeRouter.post( - '/', - multipartParser('image', 1), - controller( - 'login', - null, - null, - WriteRequest, - WriteResponse, - )(async (req, res) => { - return res.send(await WriteService.writeMock(req.memberIdx, req.body)) - }), -) diff --git a/src/mock/service/ListService.ts b/src/mock/service/ListService.ts index 1b23490..ea55b0d 100644 --- a/src/mock/service/ListService.ts +++ b/src/mock/service/ListService.ts @@ -1,69 +1,55 @@ import ErrorRegistry from '#error/ErrorRegistry' -import ListQuery from '../entity/dao/frontend/request/query/ListRequest.js' -import SearchQuery from '../entity/dao/frontend/request/query/SearchRequest.js' +import ListRequest from '../entity/dao/frontend/request/query/ListRequest.js' import ListResponse from '../entity/dao/frontend/response/ListResponse.js' import MockList from '../entity/dto/MockList.js' import MockRepository from '../repository/MockRepository.js' export default class ListService { - static async getMockList(query: ListQuery): Promise { - const currentPageNumber = query.current - const displayCount = query.display - const offset = (currentPageNumber - 1) * displayCount - - const dbResult = await MockRepository.getPaginatedMockList( - displayCount, - offset, - ) + static async getMockList(listRequest: ListRequest): Promise { + const { current, display, sort, title } = listRequest + const offset = (current - 1) * display + + let dbResult + if (!listRequest.sort && !listRequest.title) { + dbResult = await MockRepository.getPaginatedMockList(display, offset) + } else { + let titleQuery + if (!title) { + titleQuery = '%%%' + } else { + titleQuery = '%' + title + '%' + } + + if (!sort) { + dbResult = await MockRepository.getFilteredLikeDescMockList( + title, + display, + offset, + ) + } else if (sort === 'new') { + dbResult = await MockRepository.getFilteredLikeDescMockList( + title, + display, + offset, + ) + } else if (sort === 'like') { + dbResult = await MockRepository.getFilteredLikeDescMockList( + title, + display, + offset, + ) + } else { + throw ErrorRegistry.INTERNAL_SERVER_ERROR + } + } const mockList = new MockList( - currentPageNumber, - displayCount, + current, + display, dbResult.totalCount, dbResult.mocks, ) return ListResponse.of(mockList) } - - static async searchMock(query: SearchQuery): Promise { - const currentPageNumber = query.current - const displayCount = query.display - const offset = (currentPageNumber - 1) * displayCount - const title = '%' + query.title + '%' - - const dbResult = await this.getDBResultBySortType( - query.sort, - title, - displayCount, - offset, - ) - - const mockList = new MockList( - currentPageNumber, - displayCount, - dbResult.totalCount, - dbResult.mocks, - ) - return ListResponse.of(mockList) - } - - private static getDBResultBySortType = ( - sortType: 'new' | 'like', - title: string, - displayCount: number, - offset: number, - ) => { - if (sortType === 'new') { - return MockRepository.getFilteredNewMockList(title, displayCount, offset) - } - if (sortType === 'like') { - return MockRepository.getFilteredLikeDescMockList( - title, - displayCount, - offset, - ) - } - throw ErrorRegistry.INTERNAL_SERVER_ERROR - } } diff --git a/src/notice/entity/dao/frontend/response/ListSearchResponse.ts b/src/notice/entity/dao/frontend/response/ListSearchResponse.ts deleted file mode 100644 index dc088d2..0000000 --- a/src/notice/entity/dao/frontend/response/ListSearchResponse.ts +++ /dev/null @@ -1,50 +0,0 @@ -import NoticeList from 'src/notice/entity/dto/NoticeList.js' -export default class NoticeSearchListResponse { - firstPageNumber: number - currentPageNumber: number - lastPageNumber: number - prevPageExist: boolean - nextPageExist: boolean - notices: { - idx: number - title: string - writerNickname: string - createdAt: string - }[] - - public static of(noticeList: NoticeList): NoticeSearchListResponse { - return new NoticeSearchListResponse( - noticeList.firstPageNumber, - noticeList.currentPageNumber, - noticeList.lastPageNumber, - noticeList.prevPageExist, - noticeList.nextPageExist, - noticeList.notices, - ) - } - - public static createEmpty(): NoticeSearchListResponse { - return new NoticeSearchListResponse(1, 1, 1, false, false, []) - } - - constructor( - firstPageNumber: number, - currentPageNumber: number, - lastPageNumber: number, - prevPageExist: boolean, - nextPageExist: boolean, - notices: { - idx: number - title: string - writerNickname: string - createdAt: string - }[], - ) { - this.firstPageNumber = firstPageNumber - this.currentPageNumber = currentPageNumber - this.lastPageNumber = lastPageNumber - this.prevPageExist = prevPageExist - this.nextPageExist = nextPageExist - this.notices = notices - } -} diff --git a/src/notice/router/noticeItemRouter.ts b/src/notice/router/noticeItemRouter.ts index f5eea5c..89009f3 100644 --- a/src/notice/router/noticeItemRouter.ts +++ b/src/notice/router/noticeItemRouter.ts @@ -7,6 +7,7 @@ import WriteRequest from '../entity/dao/frontend/request/WriteRequest.js' import NoticeResponse from '../entity/dao/frontend/response/NoticeResponse.js' import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' import NoticeItemService from '../service/NoticeItemService.js' +import WriteService from '../service/WriteService.js' export const noticeItemRouter = express.Router() noticeItemRouter.post( @@ -19,14 +20,12 @@ noticeItemRouter.post( WriteRequest, WriteResponse, )(async (req, res) => { - return res.send( - await NoticeItemService.writeNotice(req.memberIdx, req.body), - ) + return res.send(await WriteService.writeNotice(req.memberIdx, req.body)) }), ) noticeItemRouter.get( - '/', + '/:idx', controller( 'login', null, @@ -39,7 +38,7 @@ noticeItemRouter.get( ) noticeItemRouter.delete( - '/', + '/:idx', controller( 'admin', null, @@ -53,7 +52,7 @@ noticeItemRouter.delete( ) noticeItemRouter.patch( - '/', + '/:idx', multipartParser('image', 5), controller( 'admin', diff --git a/src/notice/service/NoticeItemService.ts b/src/notice/service/NoticeItemService.ts index 984b8af..5ea8366 100644 --- a/src/notice/service/NoticeItemService.ts +++ b/src/notice/service/NoticeItemService.ts @@ -1,26 +1,10 @@ import ErrorRegistry from '#error/ErrorRegistry' import NoticeEditBodyRequest from '../entity/dao/frontend/request/NoticeEditBodyRequest.js' import NoticePathRequest from '../entity/dao/frontend/request/NoticePathRequest.js' -import WriteRequest from '../entity/dao/frontend/request/WriteRequest.js' import NoticeResponse from '../entity/dao/frontend/response/NoticeResponse.js' -import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' import NoticeRepository from '../repository/NoticeRepository.js' export default class NoticeItemService { - static async writeNotice(memberIdx: number, writeRequest: WriteRequest) { - const { title, content, uploadUrls } = writeRequest - // 멤버 인덱스 - - return new WriteResponse( - await NoticeRepository.insertNoticeToDb( - memberIdx, - title, - content, - uploadUrls, - ), - ) - } - static async getNotice(noticePathRequest: NoticePathRequest) { const { idx } = noticePathRequest const result = await NoticeRepository.getNoticeInfoFromDb(idx) @@ -29,10 +13,12 @@ export default class NoticeItemService { } return new NoticeResponse(result) } + static async deleteNotice(noticePathRequest: NoticePathRequest) { const { idx } = noticePathRequest await NoticeRepository.deleteNoticeFromDb(idx) } + static async editNotice( noticePathRequest: NoticePathRequest, noticeEditBodyRequest: NoticeEditBodyRequest, diff --git a/src/notice/service/WriteService.ts b/src/notice/service/WriteService.ts new file mode 100644 index 0000000..6f7ae07 --- /dev/null +++ b/src/notice/service/WriteService.ts @@ -0,0 +1,18 @@ +import WriteRequest from '../entity/dao/frontend/request/WriteRequest.js' +import WriteResponse from '../entity/dao/frontend/response/WriteResponse.js' +import NoticeRepository from '../repository/NoticeRepository.js' + +export default class WriteService { + static async writeNotice(memberIdx: number, writeRequest: WriteRequest) { + const { title, content, uploadUrls } = writeRequest + + return new WriteResponse( + await NoticeRepository.insertNoticeToDb( + memberIdx, + title, + content, + uploadUrls, + ), + ) + } +} diff --git a/src/rank/service/rankListService.ts b/src/rank/service/rankListService.ts index 40adf14..d8f2ddd 100644 --- a/src/rank/service/rankListService.ts +++ b/src/rank/service/rankListService.ts @@ -12,14 +12,14 @@ export default class RankListService { } else { let tierQuery: string if (!tier) { - tierQuery = '%' + tierQuery = '%%%' } else { tierQuery = tier } let nicknameQuery: string if (!nickname) { - nicknameQuery = '%' + nicknameQuery = '%%%' } else { nicknameQuery = nickname } From 4a295e0ec0505dc2a389ff2a34951bb1dfd9793a Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Sun, 9 Mar 2025 16:17:08 +0900 Subject: [PATCH 08/29] =?UTF-8?q?[SUS-76]=20=EB=A6=AC=ED=8C=A9=ED=84=B0?= =?UTF-8?q?=EB=A7=81=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/util/Regex/index.ts | 2 +- src/mock/service/ListService.ts | 10 +++++----- src/notice/entity/dao/frontend/request/ListRequest.ts | 2 +- src/notice/router/index.ts | 2 +- src/notice/service/ListService.ts | 10 +++++----- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/core/util/Regex/index.ts b/src/core/util/Regex/index.ts index 592495f..3ead57f 100644 --- a/src/core/util/Regex/index.ts +++ b/src/core/util/Regex/index.ts @@ -20,5 +20,5 @@ export default class Regex { /^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z0-9!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{8,16}$/ public static readonly UUID = - /^[0-9a-f]{8}-[0-9]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ } diff --git a/src/mock/service/ListService.ts b/src/mock/service/ListService.ts index ea55b0d..5c86d1e 100644 --- a/src/mock/service/ListService.ts +++ b/src/mock/service/ListService.ts @@ -21,20 +21,20 @@ export default class ListService { } if (!sort) { - dbResult = await MockRepository.getFilteredLikeDescMockList( - title, + dbResult = await MockRepository.getFilteredNewMockList( + titleQuery, display, offset, ) } else if (sort === 'new') { - dbResult = await MockRepository.getFilteredLikeDescMockList( - title, + dbResult = await MockRepository.getFilteredNewMockList( + titleQuery, display, offset, ) } else if (sort === 'like') { dbResult = await MockRepository.getFilteredLikeDescMockList( - title, + titleQuery, display, offset, ) diff --git a/src/notice/entity/dao/frontend/request/ListRequest.ts b/src/notice/entity/dao/frontend/request/ListRequest.ts index d380ba0..0b428cc 100644 --- a/src/notice/entity/dao/frontend/request/ListRequest.ts +++ b/src/notice/entity/dao/frontend/request/ListRequest.ts @@ -14,8 +14,8 @@ export default class ListRequest { if (params.title && params.title.length > 100) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - this.title = params.title + if (!params.current) { throw ErrorRegistry.INVALID_INPUT_FORMAT } diff --git a/src/notice/router/index.ts b/src/notice/router/index.ts index 3e54564..56a7622 100644 --- a/src/notice/router/index.ts +++ b/src/notice/router/index.ts @@ -5,4 +5,4 @@ import { noticeItemRouter } from './noticeItemRouter.js' export const noticeRouter = express.Router() noticeRouter.use('/list', listRouter) -noticeRouter.use('/:idx', noticeItemRouter) +noticeRouter.use('/', noticeItemRouter) diff --git a/src/notice/service/ListService.ts b/src/notice/service/ListService.ts index 548afe6..e55f444 100644 --- a/src/notice/service/ListService.ts +++ b/src/notice/service/ListService.ts @@ -8,15 +8,15 @@ export default class ListService { const offset = (current - 1) * display let listData - if (title) { - const titleToSearch = '%' + title + '%' + if (!title) { + listData = await NoticeRepository.getPagedListFromDb(display, offset) + } else { + const titleQuery = '%' + title + '%' listData = await NoticeRepository.getSearchListFromDb( - titleToSearch, + titleQuery, display, offset, ) - } else { - listData = await NoticeRepository.getPagedListFromDb(display, offset) } return new ListResponse( From 6fbf1c15896b1296cf3807e090bdb4bd1e69267b Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Sun, 9 Mar 2025 16:22:00 +0900 Subject: [PATCH 09/29] =?UTF-8?q?[SUS-76]=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 10 ++++++---- package.json | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1632935..3c030c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,11 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@types/crypto-js": "^4.2.2", "@upstash/redis": "1.34.4", "cookie-parser": "1.4.7", "cors": "2.8.5", - "crypto-js": "^4.2.0", - "crypto-ts": "^1.0.2", + "crypto-js": "4.2.0", + "crypto-ts": "1.0.2", "dotenv": "16.4.7", "express": "4.21.2", "jsonwebtoken": "9.0.2", @@ -26,6 +25,7 @@ "devDependencies": { "@types/cookie-parser": "1.4.8", "@types/cors": "2.8.17", + "@types/crypto-js": "^4.2.2", "@types/express": "5.0.0", "@types/jsonwebtoken": "9.0.8", "@types/multer": "1.4.12", @@ -1900,7 +1900,9 @@ "node_modules/@types/crypto-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", - "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==" + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/express": { "version": "5.0.0", diff --git a/package.json b/package.json index 49bd55e..6993389 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "#error/*": "./dist/src/core/error/*.js" }, "dependencies": { - "@types/crypto-js": "4.2.2", "@upstash/redis": "1.34.4", "cookie-parser": "1.4.7", "cors": "2.8.5", @@ -40,6 +39,7 @@ "devDependencies": { "@types/cookie-parser": "1.4.8", "@types/cors": "2.8.17", + "@types/crypto-js": "^4.2.2", "@types/express": "5.0.0", "@types/jsonwebtoken": "9.0.8", "@types/multer": "1.4.12", From 45e60a828c7bdf9bfe3c5fe91dde0ce6551f719b Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Sun, 9 Mar 2025 16:23:28 +0900 Subject: [PATCH 10/29] =?UTF-8?q?[SUS-76]=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 65 ----------------------------------------------- package.json | 1 - 2 files changed, 66 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3c030c6..2c7995b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "cookie-parser": "1.4.7", "cors": "2.8.5", "crypto-js": "4.2.0", - "crypto-ts": "1.0.2", "dotenv": "16.4.7", "express": "4.21.2", "jsonwebtoken": "9.0.2", @@ -44,38 +43,6 @@ "typescript": "5.7.3" } }, - "node_modules/@angular/common": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-19.2.0.tgz", - "integrity": "sha512-dm8PR94QY3DucXxltdV5p2Yxyr5bfPlmjOElwLhiTvxWbwCZJTVhPc8dw0TCKzCEu+tKafT48u4BLIB34a0A/g==", - "peer": true, - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" - }, - "peerDependencies": { - "@angular/core": "19.2.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/core": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-19.2.0.tgz", - "integrity": "sha512-WKTRltOt3MMWWuhRX7Y9RonKxIYjZeBDE6XRwceHMgaEDS2d8I2D3AIuqizRsgHpJqDPnQnH+vxcek4FivcSGA==", - "peer": true, - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" - }, - "peerDependencies": { - "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.15.0" - } - }, "node_modules/@aws-crypto/crc32": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", @@ -2786,23 +2753,6 @@ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, - "node_modules/crypto-ts": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/crypto-ts/-/crypto-ts-1.0.2.tgz", - "integrity": "sha512-TcBWwF8ghYhVd/qPSwvY4nsbDZRN/PVxQ1Uc8ryRLiX4M4C5XSPyIhVgR4M5mIhrQEnWIktLcrv+FIqhKk2t3g==", - "dependencies": { - "tslib": "^1.7.1" - }, - "peerDependencies": { - "@angular/common": ">= 5.0.0", - "@angular/core": ">= 5.0.0" - } - }, - "node_modules/crypto-ts/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -5767,15 +5717,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "peer": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -6824,12 +6765,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zone.js": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.0.tgz", - "integrity": "sha512-9oxn0IIjbCZkJ67L+LkhYWRyAy7axphb3VgE2MBDlOqnmHMPWGYMxJxBYFueFq/JGY2GMwS0rU+UCLunEmy5UA==", - "peer": true } } } diff --git a/package.json b/package.json index 6993389..14e7247 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "cookie-parser": "1.4.7", "cors": "2.8.5", "crypto-js": "4.2.0", - "crypto-ts": "1.0.2", "dotenv": "16.4.7", "express": "4.21.2", "jsonwebtoken": "9.0.2", From 758ff08eefca9253d4a6d7fea3caf7f354900056 Mon Sep 17 00:00:00 2001 From: taegyun Date: Sun, 9 Mar 2025 21:30:11 +0900 Subject: [PATCH 11/29] [SUS-75]Feat/member_data_check_query_edit --- .../repository/MemberLoginRepository.ts | 14 +++++++---- src/member/service/LoginService.ts | 24 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/member/repository/MemberLoginRepository.ts b/src/member/repository/MemberLoginRepository.ts index 283ea71..670c1c3 100644 --- a/src/member/repository/MemberLoginRepository.ts +++ b/src/member/repository/MemberLoginRepository.ts @@ -15,10 +15,16 @@ export default class MemberLoginRepository { /**소셜로그인 * 계정 존재 여부 확인 */ - static async checkMemberDataFromDb(socialId: string) { - return ( - await postgres.query('SELECT * FROM member WHERE id = $1', [socialId]) - ).rows[0] + static async checkMemberDataFromDb(socialId: string, email: string) { + return await postgres.query( + `SELECT + CASE + WHEN EXISTS (SELECT 1 FROM member WHERE id = $1 AND email = $2) THEN true + WHEN EXISTS (SELECT 1 FROM users WHERE email = $2) THEN false + ELSE NULL + END AS result`, + [socialId, email], + ) } /** 카카오 소셜로그인 회원가입 */ diff --git a/src/member/service/LoginService.ts b/src/member/service/LoginService.ts index 38fe524..add46e5 100644 --- a/src/member/service/LoginService.ts +++ b/src/member/service/LoginService.ts @@ -45,8 +45,10 @@ export default class LoginService { kakaoToken, kakaoOauthUserInfoUrl, ) + const kakaoEmail = `${userData.id}@kakao.com` const checkResult: any = await MemberLoginRepository.checkMemberDataFromDb( userData.id, + kakaoEmail, ) if (!checkResult) { @@ -55,7 +57,10 @@ export default class LoginService { userData.properties.nickname, ) const checkResult: any = - await MemberLoginRepository.checkMemberDataFromDb(userData.id) + await MemberLoginRepository.checkMemberDataFromDb( + userData.id, + kakaoEmail, + ) const token = Token.generateLoginToken( checkResult.idx, checkResult.email, @@ -80,22 +85,33 @@ export default class LoginService { res: Response, ): Promise { const googleLoginToken = await LoginAdapter.getGoogleToken(code) + console.log(1) const userData = await LoginAdapter.getUserDataByToken( googleLoginToken, googleOauthUserInfoUrl, ) + console.log(2) + console.log(userData) const checkResult: any = await MemberLoginRepository.checkMemberDataFromDb( userData.id, + userData.email, ) - + console.log(3) + console.log(checkResult) + if (checkResult == false) { + throw ErrorRegistry.DUPLICATED_EMAIL + } if (!checkResult) { - await MemberLoginRepository.insertGoogleLoginMemberData( + await await MemberLoginRepository.insertGoogleLoginMemberData( userData.id, userData.name, userData.email, ) const checkResult: any = - await MemberLoginRepository.checkMemberDataFromDb(userData.id) + await MemberLoginRepository.checkMemberDataFromDb( + userData.id, + userData.email, + ) const token = Token.generateLoginToken( checkResult.idx, checkResult.email, From a56d2e029cbcd1e3529dac7080553f193e430345 Mon Sep 17 00:00:00 2001 From: taegyun Date: Mon, 10 Mar 2025 17:26:35 +0900 Subject: [PATCH 12/29] [SUS-75]Feat/checkEmail_query_added --- .../repository/MemberLoginRepository.ts | 28 +++++++++++-------- src/member/service/LoginService.ts | 28 +++++++------------ 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/member/repository/MemberLoginRepository.ts b/src/member/repository/MemberLoginRepository.ts index 670c1c3..d28b033 100644 --- a/src/member/repository/MemberLoginRepository.ts +++ b/src/member/repository/MemberLoginRepository.ts @@ -15,18 +15,24 @@ export default class MemberLoginRepository { /**소셜로그인 * 계정 존재 여부 확인 */ - static async checkMemberDataFromDb(socialId: string, email: string) { - return await postgres.query( - `SELECT - CASE - WHEN EXISTS (SELECT 1 FROM member WHERE id = $1 AND email = $2) THEN true - WHEN EXISTS (SELECT 1 FROM users WHERE email = $2) THEN false - ELSE NULL - END AS result`, - [socialId, email], - ) + static async checkMemberDataFromDb(socialId: string) { + return ( + await postgres.query('SELECT * FROM member WHERE id =$1', [socialId]) + ).rows[0] + } + static async checkGoogleMailAvailable(socialId: string, email: string) { + return ( + await postgres.query( + `SELECT + CASE + WHEN EXISTS (SELECT 1 FROM member WHERE id = $1 AND email = $2) THEN true + WHEN EXISTS (SELECT 1 FROM member WHERE email = $2) THEN false + ELSE NULL + END AS result`, + [socialId, email], + ) + ).rows[0].result } - /** 카카오 소셜로그인 회원가입 */ static async insertKakaoLoginMemberData(socialId: string, nickname: string) { let dateTime = new Date() diff --git a/src/member/service/LoginService.ts b/src/member/service/LoginService.ts index add46e5..2b7ec89 100644 --- a/src/member/service/LoginService.ts +++ b/src/member/service/LoginService.ts @@ -45,10 +45,9 @@ export default class LoginService { kakaoToken, kakaoOauthUserInfoUrl, ) - const kakaoEmail = `${userData.id}@kakao.com` + // const kakaoEmail = `${userData.id}@kakao.com` const checkResult: any = await MemberLoginRepository.checkMemberDataFromDb( userData.id, - kakaoEmail, ) if (!checkResult) { @@ -57,10 +56,7 @@ export default class LoginService { userData.properties.nickname, ) const checkResult: any = - await MemberLoginRepository.checkMemberDataFromDb( - userData.id, - kakaoEmail, - ) + await MemberLoginRepository.checkMemberDataFromDb(userData.id) const token = Token.generateLoginToken( checkResult.idx, checkResult.email, @@ -85,33 +81,29 @@ export default class LoginService { res: Response, ): Promise { const googleLoginToken = await LoginAdapter.getGoogleToken(code) - console.log(1) const userData = await LoginAdapter.getUserDataByToken( googleLoginToken, googleOauthUserInfoUrl, ) - console.log(2) - console.log(userData) const checkResult: any = await MemberLoginRepository.checkMemberDataFromDb( userData.id, - userData.email, ) - console.log(3) - console.log(checkResult) - if (checkResult == false) { + const checkEmail: any = + await MemberLoginRepository.checkGoogleMailAvailable( + userData.id, + userData.email, + ) + if (checkEmail == false) { throw ErrorRegistry.DUPLICATED_EMAIL } if (!checkResult) { - await await MemberLoginRepository.insertGoogleLoginMemberData( + await MemberLoginRepository.insertGoogleLoginMemberData( userData.id, userData.name, userData.email, ) const checkResult: any = - await MemberLoginRepository.checkMemberDataFromDb( - userData.id, - userData.email, - ) + await MemberLoginRepository.checkMemberDataFromDb(userData.id) const token = Token.generateLoginToken( checkResult.idx, checkResult.email, From afa07bd8c4b61a70345898cc7e1f4f49b3397c88 Mon Sep 17 00:00:00 2001 From: taegyun Date: Mon, 10 Mar 2025 21:34:59 +0900 Subject: [PATCH 13/29] [SUS-78]Feat/Regexp_class_delete --- src/member/entity/dao/frontend/request/SignupRequest.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/member/entity/dao/frontend/request/SignupRequest.ts b/src/member/entity/dao/frontend/request/SignupRequest.ts index a5b1641..9ed1907 100644 --- a/src/member/entity/dao/frontend/request/SignupRequest.ts +++ b/src/member/entity/dao/frontend/request/SignupRequest.ts @@ -16,10 +16,10 @@ export default class SignupRequest { constructor(params: SignupRequestParams) { if ( - !new RegExp(Regex.ID).test(params.id) || - !new RegExp(Regex.PASSWORD).test(params.password) || - !new RegExp(Regex.PASSWORD).test(params.passwordCheck) || - !new RegExp(Regex.EMAIL).test(params.email) + !Regex.ID.test(params.id) || + !Regex.PASSWORD.test(params.password) || + !Regex.PASSWORD.test(params.passwordCheck) || + !Regex.EMAIL.test(params.email) ) { throw ErrorRegistry.INVALID_INPUT_FORMAT } From 70266214730bb835628a9be5b8d11e07435b764e Mon Sep 17 00:00:00 2001 From: taegyun Date: Mon, 10 Mar 2025 21:52:45 +0900 Subject: [PATCH 14/29] [SUS-78]Feat/request_input_regex_delete --- .../entity/dao/frontend/request/NicknameChangeRequest.ts | 2 +- .../entity/dao/frontend/request/PasswordChangeRequest.ts | 2 +- .../dao/frontend/request/SendFindPasswordEmailRequest.ts | 5 +---- .../entity/dao/frontend/request/SendVerifyEmailRequest.ts | 2 +- src/mock/entity/dao/frontend/request/body/MockEditRequest.ts | 2 +- src/mock/entity/dao/frontend/request/body/QuizRequest.ts | 2 +- src/mock/entity/dao/frontend/request/body/WriteRequest.ts | 4 ++-- src/mock/entity/dao/frontend/request/path/MockIdxPath.ts | 2 +- src/mock/entity/dao/frontend/request/path/QuizIdxPath.ts | 2 +- .../entity/dao/frontend/request/NoticeEditBodyRequest.ts | 2 +- src/notice/entity/dao/frontend/request/NoticePathRequest.ts | 2 +- src/notice/entity/dao/frontend/request/WriteRequest.ts | 2 +- src/rank/entity/dao/request/FilteredRankListRequest.ts | 2 +- src/rank/entity/dao/request/RankListRequest.ts | 2 +- 14 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts b/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts index 23031ec..53e827f 100644 --- a/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts +++ b/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts @@ -9,7 +9,7 @@ export default class NicknameChangeRequest { public nickname: string constructor(params: NicknameChangeRequestParams) { - if (!new RegExp(Regex.NICKNAME).test(params.nickname)) { + if (!Regex.NICKNAME.test(params.nickname)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.nickname = params.nickname diff --git a/src/member/entity/dao/frontend/request/PasswordChangeRequest.ts b/src/member/entity/dao/frontend/request/PasswordChangeRequest.ts index bc4b306..125a9d1 100644 --- a/src/member/entity/dao/frontend/request/PasswordChangeRequest.ts +++ b/src/member/entity/dao/frontend/request/PasswordChangeRequest.ts @@ -12,7 +12,7 @@ export default class PasswordChangeRequest { public token: string constructor(params: PasswordChangeRequestParams) { - if (!new RegExp(Regex.PASSWORD).test(params.password)) { + if (!Regex.PASSWORD.test(params.password)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } if (params.password != params.passwordCheck) { diff --git a/src/member/entity/dao/frontend/request/SendFindPasswordEmailRequest.ts b/src/member/entity/dao/frontend/request/SendFindPasswordEmailRequest.ts index 0224081..d01d2c7 100644 --- a/src/member/entity/dao/frontend/request/SendFindPasswordEmailRequest.ts +++ b/src/member/entity/dao/frontend/request/SendFindPasswordEmailRequest.ts @@ -11,10 +11,7 @@ export default class SendFindPasswordEmailRequest { public email: string constructor(params: SendFindPasswordEmailRequestParams) { - if ( - !new RegExp(Regex.ID).test(params.id) || - !new RegExp(Regex.EMAIL).test(params.email) - ) { + if (!Regex.ID.test(params.id) || !Regex.EMAIL.test(params.email)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.id = params.id diff --git a/src/member/entity/dao/frontend/request/SendVerifyEmailRequest.ts b/src/member/entity/dao/frontend/request/SendVerifyEmailRequest.ts index be467e2..9780acc 100644 --- a/src/member/entity/dao/frontend/request/SendVerifyEmailRequest.ts +++ b/src/member/entity/dao/frontend/request/SendVerifyEmailRequest.ts @@ -9,7 +9,7 @@ export default class SendVerifyEmailRequest { public email: string constructor(params: SendVerifyEmailRequestParams) { - if (!new RegExp(Regex.EMAIL).test(params.email)) { + if (!Regex.EMAIL.test(params.email)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.email = params.email diff --git a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts index 8e9a869..6595b97 100644 --- a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts @@ -14,7 +14,7 @@ export default class MockEditRequest { constructor(params: MockEditRequestParams) { if ( - !new RegExp(Regex.TITLE).test(params.title) || + !Regex.TITLE.test(params.title) || (params.description && params.description.length > 1000) ) { throw ErrorRegistry.INVALID_INPUT_FORMAT diff --git a/src/mock/entity/dao/frontend/request/body/QuizRequest.ts b/src/mock/entity/dao/frontend/request/body/QuizRequest.ts index 5cedc12..9a0b1f8 100644 --- a/src/mock/entity/dao/frontend/request/body/QuizRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/QuizRequest.ts @@ -10,7 +10,7 @@ export default class QuizRequest { public idx: UUID constructor(params: QuizRequestParams) { - if (!new RegExp(Regex.UUID).test(params.idx)) { + if (!Regex.UUID.test(params.idx)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.idx = params.idx diff --git a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts index d02ba55..93c9413 100644 --- a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts @@ -18,8 +18,8 @@ export default class WriteRequest { constructor(params: WriteRequestParams) { if ( - !new RegExp(Regex.SUBJECT).test(params.subject) || - !new RegExp(Regex.TITLE).test(params.title) || + !Regex.SUBJECT.test(params.subject) || + !Regex.TITLE.test(params.title) || (params.description && params.description.length > 1000) || params.quizCount > 10 || params.quizCount < 0 diff --git a/src/mock/entity/dao/frontend/request/path/MockIdxPath.ts b/src/mock/entity/dao/frontend/request/path/MockIdxPath.ts index 126e1e1..51ccee3 100644 --- a/src/mock/entity/dao/frontend/request/path/MockIdxPath.ts +++ b/src/mock/entity/dao/frontend/request/path/MockIdxPath.ts @@ -10,7 +10,7 @@ export default class MockIdxPath { public idx: UUID constructor(params: MockIdxPathParams) { - if (!new RegExp(Regex.UUID).test(params.idx)) { + if (!Regex.UUID.test(params.idx)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.idx = params.idx diff --git a/src/mock/entity/dao/frontend/request/path/QuizIdxPath.ts b/src/mock/entity/dao/frontend/request/path/QuizIdxPath.ts index fafb431..d01dc08 100644 --- a/src/mock/entity/dao/frontend/request/path/QuizIdxPath.ts +++ b/src/mock/entity/dao/frontend/request/path/QuizIdxPath.ts @@ -10,7 +10,7 @@ export default class QuizIdxPath { public idx: UUID constructor(params: QuizIdxPathParams) { - if (!new RegExp(Regex.UUID).test(params.idx)) { + if (Regex.UUID.test(params.idx)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.idx = params.idx diff --git a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts index 50f59a7..65ab4ab 100644 --- a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts +++ b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts @@ -13,7 +13,7 @@ export default class NoticeEditBodyRequest { public uploadUrls: string[] constructor(params: NoticeEditBodyRequestParams) { if ( - !new RegExp(Regex.TITLE).test(params.title) || + !Regex.TITLE.test(params.title) || (params.content && params.content.length > 1000) ) { throw ErrorRegistry.INVALID_INPUT_FORMAT diff --git a/src/notice/entity/dao/frontend/request/NoticePathRequest.ts b/src/notice/entity/dao/frontend/request/NoticePathRequest.ts index 6339f88..961d46d 100644 --- a/src/notice/entity/dao/frontend/request/NoticePathRequest.ts +++ b/src/notice/entity/dao/frontend/request/NoticePathRequest.ts @@ -9,7 +9,7 @@ interface NoticePathRequestParams { export default class NoticePathRequest { public idx: UUID constructor(params: NoticePathRequestParams) { - if (!new RegExp(Regex.UUID).test(params.idx)) { + if (!Regex.UUID.test(params.idx)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.idx = params.idx diff --git a/src/notice/entity/dao/frontend/request/WriteRequest.ts b/src/notice/entity/dao/frontend/request/WriteRequest.ts index 571a9e7..37d9d8e 100644 --- a/src/notice/entity/dao/frontend/request/WriteRequest.ts +++ b/src/notice/entity/dao/frontend/request/WriteRequest.ts @@ -13,7 +13,7 @@ export default class WriteRequest { public uploadUrls: string[] constructor(params: WriteRequestParams) { if ( - !new RegExp(Regex.TITLE).test(params.title) || + !Regex.TITLE.test(params.title) || (params.content && params.content.length > 10000) ) { throw ErrorRegistry.INVALID_INPUT_FORMAT diff --git a/src/rank/entity/dao/request/FilteredRankListRequest.ts b/src/rank/entity/dao/request/FilteredRankListRequest.ts index 5044bb5..a9262d5 100644 --- a/src/rank/entity/dao/request/FilteredRankListRequest.ts +++ b/src/rank/entity/dao/request/FilteredRankListRequest.ts @@ -12,7 +12,7 @@ export default class FilteredRankListRequest { public current: number public nickname: string constructor(params: FilteredRankListRequestParams) { - if (params.tier && !new RegExp(Regex.TIER).test(params.tier)) { + if (params.tier && !Regex.TIER.test(params.tier)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } if (!params.tier) { diff --git a/src/rank/entity/dao/request/RankListRequest.ts b/src/rank/entity/dao/request/RankListRequest.ts index 4dafe82..11fe035 100644 --- a/src/rank/entity/dao/request/RankListRequest.ts +++ b/src/rank/entity/dao/request/RankListRequest.ts @@ -17,7 +17,7 @@ export default class RankListRequest { } this.current = Number(params.current) - if (params.tier && !new RegExp(Regex.TIER).test(params.tier)) { + if (params.tier && !Regex.TIER.test(params.tier)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.tier = params.tier From c6afa32c07b906dc213516dad48476fc4a10fdf2 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Wed, 12 Mar 2025 14:28:59 +0900 Subject: [PATCH 15/29] =?UTF-8?q?[SUS-82]=20=EC=B2=B4=ED=81=AC=20=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .sql/.sql | 1 - src/core/util/multipartParser/index.ts | 24 +++++++++-- .../frontend/request/path/ArticleIdxPath.ts | 2 +- src/like/router/index.ts | 2 +- src/like/router/likeItemRouter.ts | 4 +- .../entity/dao/db/ProfileResultFromDB.ts | 2 + .../dao/frontend/response/ProfileResponse.ts | 6 ++- src/member/repository/MemberInfoRepository.ts | 7 ++-- src/member/service/MeService.ts | 2 +- .../dao/frontend/request/path/QuizIdxPath.ts | 2 +- .../dao/frontend/response/DetailResponse.ts | 3 ++ .../dao/frontend/response/ListResponse.ts | 38 ++++++----------- src/mock/entity/dto/MockList.ts | 41 ------------------- src/mock/repository/MockRepository.ts | 32 ++++++++------- src/mock/service/ListService.ts | 5 +-- src/mock/service/MockItemService.ts | 1 + .../frontend/request/NoticeEditBodyRequest.ts | 1 + .../dao/request/FilteredRankListRequest.ts | 38 ----------------- src/rank/repository/rankListRepository.ts | 10 ++--- src/rank/service/rankListService.ts | 2 +- 20 files changed, 79 insertions(+), 144 deletions(-) delete mode 100644 src/mock/entity/dto/MockList.ts delete mode 100644 src/rank/entity/dao/request/FilteredRankListRequest.ts diff --git a/.sql/.sql b/.sql/.sql index 7c04285..a96e77a 100644 --- a/.sql/.sql +++ b/.sql/.sql @@ -26,7 +26,6 @@ CREATE TABLE "mock" ( "title" TEXT NOT NULL, "description" TEXT NOT NULL, "quiz_count" INTEGER NOT NULL, - "like_count" INTEGER DEFAULT 0 NOT NULL, "created_at" TIMESTAMP NOT NULL, "updated_at" TIMESTAMP DEFAULT NOW() NOT NULL, "is_deleted" BOOLEAN DEFAULT FALSE NOT NULL diff --git a/src/core/util/multipartParser/index.ts b/src/core/util/multipartParser/index.ts index 2d9f6c5..11c6d95 100644 --- a/src/core/util/multipartParser/index.ts +++ b/src/core/util/multipartParser/index.ts @@ -40,10 +40,26 @@ const multipartParser = (contentType: string, limit: number) => { } } - const uploadUrls = req.files.map((file) => { - const multerFile = file as Express.MulterS3.File - return replaceBaseUrl(multerFile.location) - }) + const uploadUrls = [] + const existingUrls = req.body.existingUrls + if (existingUrls) { + existingUrls.forEach((url: string) => { + if (!url.startsWith(newBaseUrl)) { + return next(ErrorRegistry.INVALID_INPUT_FORMAT) + } + }) + if (existingUrls.length + req.files.length > limit) { + return next(ErrorRegistry.INVALID_INPUT_FORMAT) + } + uploadUrls.push(...existingUrls) + } + + uploadUrls.push( + req.files.map((file) => { + const multerFile = file as Express.MulterS3.File + return replaceBaseUrl(multerFile.location) + }), + ) req.body = { ...req.body, uploadUrls } next() diff --git a/src/like/entity/dao/frontend/request/path/ArticleIdxPath.ts b/src/like/entity/dao/frontend/request/path/ArticleIdxPath.ts index bf6d771..dd80f48 100644 --- a/src/like/entity/dao/frontend/request/path/ArticleIdxPath.ts +++ b/src/like/entity/dao/frontend/request/path/ArticleIdxPath.ts @@ -10,7 +10,7 @@ export default class ArticleIdxPath { public idx: UUID constructor(params: ArticleIdxPathParams) { - if (!new RegExp(Regex.UUID).test(params.idx)) { + if (!Regex.UUID.test(params.idx)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.idx = params.idx diff --git a/src/like/router/index.ts b/src/like/router/index.ts index db22471..036f347 100644 --- a/src/like/router/index.ts +++ b/src/like/router/index.ts @@ -3,4 +3,4 @@ import { likeItemRouter } from './likeItemRouter.js' export const likeRouter = express.Router() -likeRouter.use('/:idx', likeItemRouter) +likeRouter.use('/', likeItemRouter) diff --git a/src/like/router/likeItemRouter.ts b/src/like/router/likeItemRouter.ts index ae8f32f..612a0b1 100644 --- a/src/like/router/likeItemRouter.ts +++ b/src/like/router/likeItemRouter.ts @@ -6,7 +6,7 @@ import LikeService from '../service/LikeService.js' export const likeItemRouter = express.Router() likeItemRouter.post( - '/', + '/:idx', controller( 'login', null, @@ -21,7 +21,7 @@ likeItemRouter.post( ) likeItemRouter.delete( - '/', + '/:idx', controller( 'login', null, diff --git a/src/member/entity/dao/db/ProfileResultFromDB.ts b/src/member/entity/dao/db/ProfileResultFromDB.ts index c1cc1e6..ba82154 100644 --- a/src/member/entity/dao/db/ProfileResultFromDB.ts +++ b/src/member/entity/dao/db/ProfileResultFromDB.ts @@ -1,3 +1,5 @@ export default interface ProfileResultFromDB { nickname: string + role: string + idx: number } diff --git a/src/member/entity/dao/frontend/response/ProfileResponse.ts b/src/member/entity/dao/frontend/response/ProfileResponse.ts index 8d5c8e8..0547935 100644 --- a/src/member/entity/dao/frontend/response/ProfileResponse.ts +++ b/src/member/entity/dao/frontend/response/ProfileResponse.ts @@ -1,7 +1,11 @@ export default class ProfileResponse { public nickname: string + public role: string + public idx: number - constructor(nickname: string) { + constructor(nickname: string, role: string, idx: number) { this.nickname = nickname + this.role = role + this.idx = idx } } diff --git a/src/member/repository/MemberInfoRepository.ts b/src/member/repository/MemberInfoRepository.ts index 83086f6..9b5b2c9 100644 --- a/src/member/repository/MemberInfoRepository.ts +++ b/src/member/repository/MemberInfoRepository.ts @@ -5,9 +5,10 @@ export default class MemberInfoRepository { /** 내 정보 가져오기 */ static async getProfile(memberIdx: number) { return ( - await postgres.query('SELECT nickname FROM member WHERE idx = $1', [ - memberIdx, - ]) + await postgres.query( + 'SELECT nickname, role, idx FROM member WHERE idx = $1', + [memberIdx], + ) ).rows[0] as ProfileResultFromDB } } diff --git a/src/member/service/MeService.ts b/src/member/service/MeService.ts index ceaecef..68921fb 100644 --- a/src/member/service/MeService.ts +++ b/src/member/service/MeService.ts @@ -5,6 +5,6 @@ export default class MeService { /** 로그아웃 */ static async getProfile(memberIdx: number) { const result = await MemberInfoRepository.getProfile(memberIdx) - return new ProfileResponse(result.nickname) + return new ProfileResponse(result.nickname, result.role, result.idx) } } diff --git a/src/mock/entity/dao/frontend/request/path/QuizIdxPath.ts b/src/mock/entity/dao/frontend/request/path/QuizIdxPath.ts index d01dc08..f25668f 100644 --- a/src/mock/entity/dao/frontend/request/path/QuizIdxPath.ts +++ b/src/mock/entity/dao/frontend/request/path/QuizIdxPath.ts @@ -10,7 +10,7 @@ export default class QuizIdxPath { public idx: UUID constructor(params: QuizIdxPathParams) { - if (Regex.UUID.test(params.idx)) { + if (!Regex.UUID.test(params.idx)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.idx = params.idx diff --git a/src/mock/entity/dao/frontend/response/DetailResponse.ts b/src/mock/entity/dao/frontend/response/DetailResponse.ts index cfa4832..9179d0a 100644 --- a/src/mock/entity/dao/frontend/response/DetailResponse.ts +++ b/src/mock/entity/dao/frontend/response/DetailResponse.ts @@ -8,6 +8,7 @@ export default class DetailResponse { writerNickname: string images: string[] firstQuizIdx: UUID + likeCount: number ranks: { rank: number nickName: string @@ -22,6 +23,7 @@ export default class DetailResponse { writerNickname: string, images: string[], firstQuizIdx: UUID, + likeCount: number, ranks: { rank: number nickName: string @@ -35,6 +37,7 @@ export default class DetailResponse { this.writerNickname = writerNickname this.images = images this.firstQuizIdx = firstQuizIdx + this.likeCount = likeCount this.ranks = ranks } } diff --git a/src/mock/entity/dao/frontend/response/ListResponse.ts b/src/mock/entity/dao/frontend/response/ListResponse.ts index 6ac205d..58f6a1f 100644 --- a/src/mock/entity/dao/frontend/response/ListResponse.ts +++ b/src/mock/entity/dao/frontend/response/ListResponse.ts @@ -1,5 +1,3 @@ -import MockList from 'src/mock/entity/dto/MockList.js' - export default class ListResponse { firstPageNumber: number currentPageNumber: number @@ -14,16 +12,10 @@ export default class ListResponse { likeCount: number }[] - public static createEmpty(): ListResponse { - return new ListResponse(1, 1, 1, false, false, []) - } - constructor( - firstPageNumber: number, currentPageNumber: number, - lastPageNumber: number, - prevPageExist: boolean, - nextPageExist: boolean, + displayCount: number, + totalCount: number, mocks: { idx: number title: string @@ -32,22 +24,18 @@ export default class ListResponse { likeCount: number }[], ) { - this.firstPageNumber = firstPageNumber this.currentPageNumber = currentPageNumber - this.lastPageNumber = lastPageNumber - this.prevPageExist = prevPageExist - this.nextPageExist = nextPageExist - this.mocks = mocks - } - - static of(mockList: MockList): ListResponse { - return new ListResponse( - mockList.firstPageNumber, - mockList.currentPageNumber, - mockList.lastPageNumber, - mockList.prevPageExist, - mockList.nextPageExist, - mockList.mocks, + this.firstPageNumber = Math.floor((currentPageNumber - 1) / 10) * 10 + 1 + const pageOffset = Math.min( + 9, + Math.floor( + (totalCount - (this.firstPageNumber - 1) * displayCount) / displayCount, + ), ) + this.lastPageNumber = this.firstPageNumber + pageOffset + this.prevPageExist = this.firstPageNumber > 1 + this.nextPageExist = + this.lastPageNumber < Math.floor((totalCount - 1) / displayCount) + 1 + this.mocks = mocks } } diff --git a/src/mock/entity/dto/MockList.ts b/src/mock/entity/dto/MockList.ts deleted file mode 100644 index 6b3bd65..0000000 --- a/src/mock/entity/dto/MockList.ts +++ /dev/null @@ -1,41 +0,0 @@ -export default class MockList { - firstPageNumber: number - currentPageNumber: number - lastPageNumber: number - prevPageExist: boolean - nextPageExist: boolean - mocks: { - idx: number - title: string - writerNickname: string - createdAt: string - likeCount: number - }[] - - constructor( - currentPageNumber: number, - displayCount: number, - totalCount: number, - mocks: { - idx: number - title: string - writerNickname: string - createdAt: string - likeCount: number - }[], - ) { - this.currentPageNumber = currentPageNumber - this.firstPageNumber = Math.floor((currentPageNumber - 1) / 10) * 10 + 1 - const pageOffset = Math.min( - 9, - Math.floor( - (totalCount - (this.firstPageNumber - 1) * displayCount) / displayCount, - ), - ) - this.lastPageNumber = this.firstPageNumber + pageOffset - this.prevPageExist = this.firstPageNumber > 1 - this.nextPageExist = - this.lastPageNumber < Math.floor((totalCount - 1) / displayCount) + 1 - this.mocks = mocks - } -} diff --git a/src/mock/repository/MockRepository.ts b/src/mock/repository/MockRepository.ts index ff978aa..3d9cc2f 100644 --- a/src/mock/repository/MockRepository.ts +++ b/src/mock/repository/MockRepository.ts @@ -28,6 +28,10 @@ export default class MockRepository { FROM first_score ORDER BY score DESC LIMIT 15 + ), + like_count AS ( + SELECT COUNT(*)::integer as count FROM like_history + WHERE article_idx = $1 ) SELECT mock.idx, @@ -35,7 +39,7 @@ export default class MockRepository { mock.description, mock.created_at as "createdAt", mock.quiz_count as "quizCount", - mock.like_count as "likeCount", + like_count.count as "likeCount", member.nickname as "writerNickname", image.urls as images, ( @@ -57,7 +61,8 @@ export default class MockRepository { ) AS "ranks" FROM mock JOIN member ON member.idx = mock.member_idx - JOIN image ON image.article_idx = mock.idx + JOIN image ON image.article_idx = mock.idx, + like_count WHERE mock.idx = $1 AND mock.is_deleted = false `, [idx], @@ -74,8 +79,7 @@ export default class MockRepository { idx, title, member_idx, - created_at, - like_count + created_at FROM mock WHERE is_deleted = false ), @@ -90,8 +94,8 @@ export default class MockRepository { new_paginated.idx, new_paginated.title, new_paginated.created_at as "createdAt", - new_paginated.like_count as "likeCount", - member.nickname as "writerNickname" + member.nickname as "writerNickname", + (SELECT COUNT(*) FROM like_history lh WHERE lh.article_idx = new_paginated.idx) AS "likeCount" FROM new_paginated JOIN member ON member.idx = new_paginated.member_idx ) @@ -121,24 +125,23 @@ export default class MockRepository { idx, title, member_idx, - created_at, - like_count + created_at FROM mock WHERE title LIKE $1 AND is_deleted = false ), like_count_paginated AS ( SELECT * FROM filtered - ORDER BY like_count DESC, created_at DESC + ORDER BY created_at DESC LIMIT $2 OFFSET $3 ), nickname_added AS ( SELECT like_count_paginated.idx, like_count_paginated.title, - like_count_paginated.like_count as "likeCount", like_count_paginated.created_at as "createdAt", - member.nickname as "writerNickname" + member.nickname as "writerNickname", + (SELECT COUNT(*) FROM like_history lc WHERE lc.article_idx = like_count_paginated.idx) AS "likeCount" FROM like_count_paginated JOIN member ON member.idx = like_count_paginated.member_idx ) @@ -168,8 +171,7 @@ export default class MockRepository { idx, title, member_idx, - created_at, - like_count + created_at FROM mock WHERE title LIKE $1 AND is_deleted = false ), @@ -184,8 +186,8 @@ export default class MockRepository { new_paginated.idx, new_paginated.title, new_paginated.created_at as "createdAt", - new_paginated.like_count as "likeCount", - member.nickname as "writerNickname" + member.nickname as "writerNickname", + (SELECT COUNT(*) FROM like_history lh WHERE lh.article_idx = new_paginated.idx) AS "likeCount" FROM new_paginated JOIN member ON member.idx = new_paginated.member_idx ) diff --git a/src/mock/service/ListService.ts b/src/mock/service/ListService.ts index 5c86d1e..ab749aa 100644 --- a/src/mock/service/ListService.ts +++ b/src/mock/service/ListService.ts @@ -1,7 +1,6 @@ import ErrorRegistry from '#error/ErrorRegistry' import ListRequest from '../entity/dao/frontend/request/query/ListRequest.js' import ListResponse from '../entity/dao/frontend/response/ListResponse.js' -import MockList from '../entity/dto/MockList.js' import MockRepository from '../repository/MockRepository.js' export default class ListService { @@ -43,13 +42,11 @@ export default class ListService { } } - const mockList = new MockList( + return new ListResponse( current, display, dbResult.totalCount, dbResult.mocks, ) - - return ListResponse.of(mockList) } } diff --git a/src/mock/service/MockItemService.ts b/src/mock/service/MockItemService.ts index 52e512d..748af5a 100644 --- a/src/mock/service/MockItemService.ts +++ b/src/mock/service/MockItemService.ts @@ -22,6 +22,7 @@ export default class MockItemService { result.writerNickname, result.images, result.firstQuizIdx, + result.likeCount, result.ranks, ) } diff --git a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts index 65ab4ab..70e266a 100644 --- a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts +++ b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts @@ -4,6 +4,7 @@ import Regex from '#util/Regex' interface NoticeEditBodyRequestParams { title: string content: string + existingUrls: string[] uploadUrls: string[] } diff --git a/src/rank/entity/dao/request/FilteredRankListRequest.ts b/src/rank/entity/dao/request/FilteredRankListRequest.ts deleted file mode 100644 index a9262d5..0000000 --- a/src/rank/entity/dao/request/FilteredRankListRequest.ts +++ /dev/null @@ -1,38 +0,0 @@ -import ErrorRegistry from '#error/ErrorRegistry' -import Regex from '#util/Regex' - -interface FilteredRankListRequestParams { - tier: string - current: number - nickname: string -} - -export default class FilteredRankListRequest { - public tier: string - public current: number - public nickname: string - constructor(params: FilteredRankListRequestParams) { - if (params.tier && !Regex.TIER.test(params.tier)) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (!params.tier) { - this.tier = '%' - } else { - this.tier = params.tier - } - - if (!params.current) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - this.current = Number(params.current) - - if (params.nickname && params.nickname.length > 100) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (!params.nickname) { - this.nickname = '%' - } else { - this.nickname = params.nickname - } - } -} diff --git a/src/rank/repository/rankListRepository.ts b/src/rank/repository/rankListRepository.ts index 365f7df..ff282fd 100644 --- a/src/rank/repository/rankListRepository.ts +++ b/src/rank/repository/rankListRepository.ts @@ -72,7 +72,7 @@ export default class RankListRepository { WHEN rank BETWEEN 3 AND 5 THEN 'GOLD' WHEN rank BETWEEN 6 AND 8 THEN 'SILVER' ELSE 'BRONZE' - END + END WHEN score = 0 THEN 'BRONZE' WHEN rank BETWEEN 1 AND total_count * 0.06 THEN 'DIAMOND' WHEN rank BETWEEN total_count * 0.06 + 1 AND total_count * 0.12 THEN 'PLATINUM' @@ -87,16 +87,16 @@ export default class RankListRepository { ranked_tiers AS ( SELECT ROW_NUMBER() OVER (ORDER BY score DESC) AS rank, - tier, + tier, nickname, score FROM ranked_with_tiers - WHERE tier LIKE $1 + WHERE tier LIKE $1 AND nickname LIKE $3 ) SELECT * FROM ranked_tiers - WHERE rank > $2 AND nickname LIKE $3 - ORDER BY rank + WHERE rank > $2 + ORDER BY rank LIMIT 10; `, [tier, current, nickname], diff --git a/src/rank/service/rankListService.ts b/src/rank/service/rankListService.ts index d8f2ddd..a6daa7b 100644 --- a/src/rank/service/rankListService.ts +++ b/src/rank/service/rankListService.ts @@ -21,7 +21,7 @@ export default class RankListService { if (!nickname) { nicknameQuery = '%%%' } else { - nicknameQuery = nickname + nicknameQuery = '%' + nickname + '%' } result = await RankListRepository.getFilteredRankListFromDb( From f593d77f26a9fc2dd22b01eb5c71212a8ce7e56b Mon Sep 17 00:00:00 2001 From: taegyun Date: Wed, 12 Mar 2025 14:54:44 +0900 Subject: [PATCH 16/29] [SUS-81]Feat/modify_date_format_from_query_result --- src/notice/repository/NoticeRepository.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/notice/repository/NoticeRepository.ts b/src/notice/repository/NoticeRepository.ts index 962bad2..03ce9df 100644 --- a/src/notice/repository/NoticeRepository.ts +++ b/src/notice/repository/NoticeRepository.ts @@ -10,7 +10,7 @@ export default class NoticeRepository { SELECT notice.idx AS idx, notice.title AS title, mem.nickname AS "writerNickname", - notice.created_at AS "createdAt" + TO_CHAR(notice.created_at,'YYYY-MM-DD') AS "createdAt" FROM notice AS notice LEFT JOIN member AS mem ON notice.member_idx = mem.idx WHERE notice.is_deleted = 'f' @@ -41,7 +41,7 @@ export default class NoticeRepository { SELECT notice.idx AS idx, notice.title AS title, mem.nickname AS "writerNickname", - notice.created_at AS "createdAt" + TO_CHAR(notice.created_at,'YYYY-MM-DD') AS "createdAt" FROM notice AS notice LEFT JOIN member AS mem ON notice.member_idx = mem.idx WHERE notice.is_deleted = 'f' AND title LIKE $1 @@ -98,7 +98,7 @@ export default class NoticeRepository { `SELECT n.title, mem.nickname AS "writerNickname", n.content, - n.created_at AS "createdAt", + TO_CHAR(n.created_at,'YYYY-MM-DD') AS "createdAt", i.urls AS "images" FROM notice AS n LEFT JOIN image AS i ON n.idx = i.article_idx From c0657f4836c9c259e8c7f87f201b072c8adec941 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Wed, 12 Mar 2025 16:50:15 +0900 Subject: [PATCH 17/29] =?UTF-8?q?[SUS-82]=20=EC=B2=B4=ED=81=AC=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/util/multipartParser/index.ts | 6 +++--- src/member/service/ChangeService.ts | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/core/util/multipartParser/index.ts b/src/core/util/multipartParser/index.ts index 11c6d95..3efa1d2 100644 --- a/src/core/util/multipartParser/index.ts +++ b/src/core/util/multipartParser/index.ts @@ -41,8 +41,8 @@ const multipartParser = (contentType: string, limit: number) => { } const uploadUrls = [] - const existingUrls = req.body.existingUrls - if (existingUrls) { + if (req.body.existingUrls) { + const existingUrls = req.body.existingUrls.split(',') existingUrls.forEach((url: string) => { if (!url.startsWith(newBaseUrl)) { return next(ErrorRegistry.INVALID_INPUT_FORMAT) @@ -55,7 +55,7 @@ const multipartParser = (contentType: string, limit: number) => { } uploadUrls.push( - req.files.map((file) => { + ...req.files.map((file) => { const multerFile = file as Express.MulterS3.File return replaceBaseUrl(multerFile.location) }), diff --git a/src/member/service/ChangeService.ts b/src/member/service/ChangeService.ts index 02f37e7..6a5a8b2 100644 --- a/src/member/service/ChangeService.ts +++ b/src/member/service/ChangeService.ts @@ -33,12 +33,10 @@ export default class ChangeService { const data: any = jwt.verify(token, secretKey) const salt = process.env.ENCRYPT_SALT_STRING const changePassword = CryptoJS.SHA256(password + salt).toString() - console.log(changePassword) await MemberChangeRepository.updateMemberPassword( changePassword, data.userId, ) - console.log(data) await RedisEmailChangeRepository.resetFindPasswordEmailDataFromRedis( data.email, ) @@ -54,7 +52,6 @@ export default class ChangeService { sendFindPasswordEmailRequest: SendFindPasswordEmailRequest, ) { const { id, email } = sendFindPasswordEmailRequest - console.log(id) const token = Token.generateVerifyToken(id, email) await RedisEmailChangeRepository.checkFindPasswordEmailDataFromRedis( email, From 8b11203676c34e2b38e7430eb7da5466a7e3bfe7 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Wed, 12 Mar 2025 18:12:19 +0900 Subject: [PATCH 18/29] =?UTF-8?q?[SUS-82]=20=EA=B8=80=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=20=EC=82=AC=EC=96=91=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/util/Regex/index.ts | 1 - .../dao/frontend/request/body/MockEditRequest.ts | 12 +++++++----- .../entity/dao/frontend/request/body/WriteRequest.ts | 7 ++++++- .../dao/frontend/request/NoticeEditBodyRequest.ts | 12 +++++++----- .../entity/dao/frontend/request/WriteRequest.ts | 12 +++++++----- src/notice/repository/NoticeRepository.ts | 2 +- src/notice/service/NoticeItemService.ts | 1 + 7 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/core/util/Regex/index.ts b/src/core/util/Regex/index.ts index 3ead57f..971b5b1 100644 --- a/src/core/util/Regex/index.ts +++ b/src/core/util/Regex/index.ts @@ -6,7 +6,6 @@ export default class Regex { public static readonly NICKNAME = /^(?=.*[가-힣a-zA-Z])[가-힣a-zA-Z0-9]{2,12}$/ - public static readonly TITLE = /^[ㄱ-ㅎ가-힣a-zA-Z0-9\s]{2,50}$/ public static readonly DESCRIPTION = /^[가-힣a-zA-Z0-9]{2,500}$/ public static readonly SUBJECT = /^(?=.*[가-힣a-zA-Z])[가-힣a-zA-Z0-9]{2,50}$/ public static readonly QUIZ_COUNT = /^(10|[1-9])$/ diff --git a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts index 6595b97..91c193e 100644 --- a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts @@ -1,5 +1,4 @@ import ErrorRegistry from '#error/ErrorRegistry' -import Regex from '#util/Regex' interface MockEditRequestParams { title: string @@ -13,10 +12,13 @@ export default class MockEditRequest { uploadUrls: string[] constructor(params: MockEditRequestParams) { - if ( - !Regex.TITLE.test(params.title) || - (params.description && params.description.length > 1000) - ) { + if (!params.title) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.title.length > 50 && params.title.length < 2) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.description && params.description.length > 1000) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.title = params.title diff --git a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts index 93c9413..30a717d 100644 --- a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts @@ -17,9 +17,14 @@ export default class WriteRequest { public uploadUrls: string[] constructor(params: WriteRequestParams) { + if (!params.title) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.title.length > 50 && params.title.length < 2) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } if ( !Regex.SUBJECT.test(params.subject) || - !Regex.TITLE.test(params.title) || (params.description && params.description.length > 1000) || params.quizCount > 10 || params.quizCount < 0 diff --git a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts index 70e266a..de74d4c 100644 --- a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts +++ b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts @@ -1,5 +1,4 @@ import ErrorRegistry from '#error/ErrorRegistry' -import Regex from '#util/Regex' interface NoticeEditBodyRequestParams { title: string @@ -13,10 +12,13 @@ export default class NoticeEditBodyRequest { public content: string public uploadUrls: string[] constructor(params: NoticeEditBodyRequestParams) { - if ( - !Regex.TITLE.test(params.title) || - (params.content && params.content.length > 1000) - ) { + if (!params.title) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.title.length > 50 && params.title.length < 2) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.content && params.content.length > 1000) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.title = params.title diff --git a/src/notice/entity/dao/frontend/request/WriteRequest.ts b/src/notice/entity/dao/frontend/request/WriteRequest.ts index 37d9d8e..edc0c7d 100644 --- a/src/notice/entity/dao/frontend/request/WriteRequest.ts +++ b/src/notice/entity/dao/frontend/request/WriteRequest.ts @@ -1,5 +1,4 @@ import ErrorRegistry from '#error/ErrorRegistry' -import Regex from '#util/Regex' interface WriteRequestParams { title: string @@ -12,10 +11,13 @@ export default class WriteRequest { public content: string public uploadUrls: string[] constructor(params: WriteRequestParams) { - if ( - !Regex.TITLE.test(params.title) || - (params.content && params.content.length > 10000) - ) { + if (!params.title) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.title.length > 50 && params.title.length < 2) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.content && params.content.length > 10000) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.title = params.title diff --git a/src/notice/repository/NoticeRepository.ts b/src/notice/repository/NoticeRepository.ts index 962bad2..c23a622 100644 --- a/src/notice/repository/NoticeRepository.ts +++ b/src/notice/repository/NoticeRepository.ts @@ -119,7 +119,7 @@ export default class NoticeRepository { idx: UUID, title: string, content: string, - uploadUrls: string[], // uploadUrls는 null 또는 undefined일 수 있음 + uploadUrls: string[], ) { await postgres.query( ` diff --git a/src/notice/service/NoticeItemService.ts b/src/notice/service/NoticeItemService.ts index 5ea8366..0c81d50 100644 --- a/src/notice/service/NoticeItemService.ts +++ b/src/notice/service/NoticeItemService.ts @@ -25,6 +25,7 @@ export default class NoticeItemService { ) { const { idx } = noticePathRequest const { title, content, uploadUrls } = noticeEditBodyRequest + console.log(noticeEditBodyRequest) await NoticeRepository.editNoticeFromDb(idx, title, content, uploadUrls) } } From 88af6b35068a286622f4c2171b58ed18c1effab4 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Thu, 13 Mar 2025 00:23:05 +0900 Subject: [PATCH 19/29] =?UTF-8?q?[SUS-82]=20=EC=88=98=EC=A0=95=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/index.ts b/index.ts index 966512c..921829e 100644 --- a/index.ts +++ b/index.ts @@ -13,6 +13,7 @@ import express from 'express' configDotenv() const app = express() + app.use( cors({ origin: process.env.FRONTEND_SERVER_URL, From f55e68022339f01372d9aed509e886a7c9b0b216 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Thu, 13 Mar 2025 00:33:17 +0900 Subject: [PATCH 20/29] =?UTF-8?q?[SUS-82]=20mock=20rank=20=EC=A1=B4?= =?UTF-8?q?=EC=9E=AC=ED=95=98=EC=A7=80=20=EC=95=8A=EC=9D=84=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EB=B9=88=20=EB=B0=B0=EC=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mock/repository/MockRepository.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/mock/repository/MockRepository.ts b/src/mock/repository/MockRepository.ts index 3d9cc2f..8a5a4e4 100644 --- a/src/mock/repository/MockRepository.ts +++ b/src/mock/repository/MockRepository.ts @@ -49,15 +49,18 @@ export default class MockRepository { ORDER BY quiz.created_at ASC LIMIT 1 ) AS "firstQuizIdx", - ( - SELECT json_agg( - json_build_object( + COALESCE( + ( + SELECT json_agg( + json_build_object( 'rank', mr.rank, 'nickname', mr.nickname, 'score', mr.score + ) ) - ) - FROM mock_rank mr + FROM mock_rank mr + ), + '[]'::json ) AS "ranks" FROM mock JOIN member ON member.idx = mock.member_idx From 820011d138fdea967fbd20c840ff5bd17de8dd70 Mon Sep 17 00:00:00 2001 From: taegyun Date: Wed, 12 Mar 2025 21:38:41 +0900 Subject: [PATCH 21/29] [SUS-83]Feat/dao_added --- src/notice/entity/dao/db/NoticeInfoFromDB.ts | 7 +++++++ src/notice/entity/dao/db/NoticeListFromDB.ts | 12 ++++++++++++ src/notice/repository/NoticeRepository.ts | 19 ++++++++++++------- 3 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 src/notice/entity/dao/db/NoticeInfoFromDB.ts create mode 100644 src/notice/entity/dao/db/NoticeListFromDB.ts diff --git a/src/notice/entity/dao/db/NoticeInfoFromDB.ts b/src/notice/entity/dao/db/NoticeInfoFromDB.ts new file mode 100644 index 0000000..8a44c4c --- /dev/null +++ b/src/notice/entity/dao/db/NoticeInfoFromDB.ts @@ -0,0 +1,7 @@ +export interface NoticeInfoFromDB { + title: string + writerNickname: string + content: string + createdAt: string + images: string[] +} diff --git a/src/notice/entity/dao/db/NoticeListFromDB.ts b/src/notice/entity/dao/db/NoticeListFromDB.ts new file mode 100644 index 0000000..4dea803 --- /dev/null +++ b/src/notice/entity/dao/db/NoticeListFromDB.ts @@ -0,0 +1,12 @@ +import { UUID } from 'crypto' + +export interface NoticeListFromDB { + totalCount: number + list: { + idx: UUID + title: string + writerNickname: string + content: string + createdAt: string + }[] +} diff --git a/src/notice/repository/NoticeRepository.ts b/src/notice/repository/NoticeRepository.ts index 8572c4a..02ce095 100644 --- a/src/notice/repository/NoticeRepository.ts +++ b/src/notice/repository/NoticeRepository.ts @@ -1,6 +1,8 @@ import { postgres } from '#config/postgres' import ErrorRegistry from '#error/ErrorRegistry' import { UUID } from 'crypto' +import { NoticeInfoFromDB } from '../entity/dao/db/NoticeInfoFromDB.js' +import { NoticeListFromDB } from '../entity/dao/db/NoticeListFromDB.js' export default class NoticeRepository { static async getPagedListFromDb(display: number, offset: number) { @@ -26,10 +28,11 @@ export default class NoticeRepository { ) ).rows[0].totalCount return { - listResult, - totalCountResult, - } + list: listResult, + totalCount: totalCountResult, + } as NoticeListFromDB } + static async getSearchListFromDb( titleToSearch: string, display: number, @@ -51,16 +54,18 @@ export default class NoticeRepository { [titleToSearch, display, offset], ) ).rows + const totalCountResult = ( await postgres.query( `SELECT COUNT(*) AS "totalCount" FROM notice WHERE is_deleted = 'f' AND title LIKE $1`, [titleToSearch], ) ).rows[0].totalCount + return { - listResult, - totalCountResult, - } + totalCount: totalCountResult, + list: listResult, + } as NoticeListFromDB } static async insertNoticeToDb( memberIdx: number, @@ -106,7 +111,7 @@ export default class NoticeRepository { WHERE n.idx = $1 AND n.is_deleted = 'f'`, [idx], ) - ).rows[0] + ).rows[0] as NoticeInfoFromDB } static async deleteNoticeFromDb(idx: UUID) { return await postgres.query( From 56126a0a83e2add6f8cf1f1dc43ac29adce0ce38 Mon Sep 17 00:00:00 2001 From: taegyun Date: Wed, 12 Mar 2025 21:50:41 +0900 Subject: [PATCH 22/29] [SUS-83]Feat/modify_types_of_frontend_dao --- src/notice/entity/dao/frontend/response/ListResponse.ts | 8 +++++--- src/notice/service/ListService.ts | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/notice/entity/dao/frontend/response/ListResponse.ts b/src/notice/entity/dao/frontend/response/ListResponse.ts index c9e8634..b77d96b 100644 --- a/src/notice/entity/dao/frontend/response/ListResponse.ts +++ b/src/notice/entity/dao/frontend/response/ListResponse.ts @@ -1,3 +1,5 @@ +import { UUID } from 'crypto' + export default class NoticeListResponse { firstPageNumber: number currentPageNumber: number @@ -5,7 +7,7 @@ export default class NoticeListResponse { prevPageExist: boolean nextPageExist: boolean notices: { - idx: number + idx: UUID title: string writerNickname: string createdAt: string @@ -16,11 +18,11 @@ export default class NoticeListResponse { displayCount: number, totalCount: number, notices: { - idx: number + idx: UUID title: string writerNickname: string + content: string createdAt: string - totalCount: number }[], ) { this.currentPageNumber = currentPageNumber diff --git a/src/notice/service/ListService.ts b/src/notice/service/ListService.ts index e55f444..61986ce 100644 --- a/src/notice/service/ListService.ts +++ b/src/notice/service/ListService.ts @@ -22,8 +22,8 @@ export default class ListService { return new ListResponse( current, display, - listData.totalCountResult, - listData.listResult, + listData.totalCount, + listData.list, ) } } From 18c482870a7b823abcbf022822be6ec7f5c23015 Mon Sep 17 00:00:00 2001 From: taegyun Date: Thu, 13 Mar 2025 16:36:27 +0900 Subject: [PATCH 23/29] Hotfix: reset_redis_after_signup_approved --- src/member/repository/RedisEmailSignupRepository.ts | 6 ++++++ src/member/service/SignupService.ts | 1 + 2 files changed, 7 insertions(+) diff --git a/src/member/repository/RedisEmailSignupRepository.ts b/src/member/repository/RedisEmailSignupRepository.ts index 4761dc0..e69c26b 100644 --- a/src/member/repository/RedisEmailSignupRepository.ts +++ b/src/member/repository/RedisEmailSignupRepository.ts @@ -50,4 +50,10 @@ export default class RedisSignupRepository { } await redis.hincrby(email, 'send_count', 1) } + + /** 가입이 완료되고 나면 redis 데이터를 삭제합니다. + */ + static async resetEmailDataFromRedis(email: string) { + await redis.del(email) + } } diff --git a/src/member/service/SignupService.ts b/src/member/service/SignupService.ts index 15a93cb..1cc7b1e 100644 --- a/src/member/service/SignupService.ts +++ b/src/member/service/SignupService.ts @@ -58,6 +58,7 @@ export default class SignupService { result.email, result.role, ) + await RedisEmailSignupRepository.resetEmailDataFromRedis(data.email) Token.generateCookie('loginToken', token, res) } /** 회원가입 인증 이메일 재전송 서비스 로직 */ From a9946d2c31694b770deb7b5b051d842cb399fe0c Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Fri, 14 Mar 2025 11:24:58 +0900 Subject: [PATCH 24/29] =?UTF-8?q?[SUS-84]=20=ED=86=B5=EC=9D=BC=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/util/Regex/index.ts | 18 ++--------- .../dao/frontend/request/FindIdRequest.ts | 4 +-- .../frontend/request/FindPasswordRequest.ts | 15 +++++---- .../frontend/request/NormalLoginRequest.ts | 18 +++++++---- .../frontend/request/body/MockEditRequest.ts | 11 +++++-- .../dao/frontend/request/body/SolveRequest.ts | 2 ++ .../dao/frontend/request/body/WriteRequest.ts | 32 ++++++++++++------- .../dao/frontend/request/WriteRequest.ts | 9 ++++-- .../entity/dao/request/RankListRequest.ts | 2 +- 9 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/core/util/Regex/index.ts b/src/core/util/Regex/index.ts index 971b5b1..81c3206 100644 --- a/src/core/util/Regex/index.ts +++ b/src/core/util/Regex/index.ts @@ -1,23 +1,11 @@ export default class Regex { public static readonly ID = /^(?=.*[a-zA-Z])[a-zA-Z0-9]{5,16}$/ + public static readonly PASSWORD = + /^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z0-9!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{8,16}$/ public static readonly EMAIL = - /^[a-zA-Z0-9._%+-]{1,20}@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ - - public static readonly NICKNAME = - /^(?=.*[가-힣a-zA-Z])[가-힣a-zA-Z0-9]{2,12}$/ - - public static readonly DESCRIPTION = /^[가-힣a-zA-Z0-9]{2,500}$/ - public static readonly SUBJECT = /^(?=.*[가-힣a-zA-Z])[가-힣a-zA-Z0-9]{2,50}$/ + /^[a-zA-Z0-9._%+-]{1,20}@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,100}$/ public static readonly QUIZ_COUNT = /^(10|[1-9])$/ - public static readonly CONTENT = - /^[가-힣a-zA-Z0-9\s!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{2,500}$/ - public static readonly TEXT_ANSWER = - /^[ㄱ-ㅎ가-힣a-zA-Z0-9\s!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{1,100}$/ - public static readonly TIER = /^(DIAMOND|PLATINUM|GOLD|SILVER|BRONZE)$/ - public static readonly PASSWORD = - /^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z0-9!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{8,16}$/ - public static readonly UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ } diff --git a/src/member/entity/dao/frontend/request/FindIdRequest.ts b/src/member/entity/dao/frontend/request/FindIdRequest.ts index 057ac37..b797625 100644 --- a/src/member/entity/dao/frontend/request/FindIdRequest.ts +++ b/src/member/entity/dao/frontend/request/FindIdRequest.ts @@ -1,4 +1,5 @@ import ErrorRegistry from '#error/ErrorRegistry' +import Regex from '#util/Regex' interface FindIdRequestParams { email: string } @@ -7,10 +8,9 @@ export default class FindIdRequest { public email: string constructor(params: FindIdRequestParams) { - if (!params.email || params.email.length > 100) { + if (!Regex.EMAIL.test(params.email)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.email = params.email } } -;`` diff --git a/src/member/entity/dao/frontend/request/FindPasswordRequest.ts b/src/member/entity/dao/frontend/request/FindPasswordRequest.ts index 813d58f..c939c13 100644 --- a/src/member/entity/dao/frontend/request/FindPasswordRequest.ts +++ b/src/member/entity/dao/frontend/request/FindPasswordRequest.ts @@ -1,4 +1,5 @@ import ErrorRegistry from '#error/ErrorRegistry' +import Regex from '#util/Regex' interface FindPasswordRequestParams { id: string email: string @@ -9,15 +10,17 @@ export default class FindPasswordRequest { public email: string constructor(params: FindPasswordRequestParams) { - if ( - !params.id || - !params.email || - params.id.length > 100 || - params.email.length > 100 - ) { + if (!params.id) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.id.length > 16) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.id = params.id + + if (!Regex.EMAIL.test(params.email)) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } this.email = params.email } } diff --git a/src/member/entity/dao/frontend/request/NormalLoginRequest.ts b/src/member/entity/dao/frontend/request/NormalLoginRequest.ts index 30efefa..b5119f2 100644 --- a/src/member/entity/dao/frontend/request/NormalLoginRequest.ts +++ b/src/member/entity/dao/frontend/request/NormalLoginRequest.ts @@ -9,16 +9,20 @@ export default class NormalLoginRequest { public id: string public password: string constructor(params: NormalLoginRequestParams) { - if ( - !params.id || - !params.password || - params.id.length > 100 || - params.password.length > 100 - ) { + if (!params.id) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.id.length > 16) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - this.id = params.id + + if (!params.password) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.password.length > 16) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } this.password = params.password } } diff --git a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts index 91c193e..6a2c0ed 100644 --- a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts @@ -15,14 +15,19 @@ export default class MockEditRequest { if (!params.title) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - if (params.title.length > 50 && params.title.length < 2) { + if (params.title.length > 50 || params.title.length < 2) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - if (params.description && params.description.length > 1000) { + this.title = params.title + + if (!params.description) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.description.length > 1000) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - this.title = params.title this.description = params.description + this.uploadUrls = params.uploadUrls } } diff --git a/src/mock/entity/dao/frontend/request/body/SolveRequest.ts b/src/mock/entity/dao/frontend/request/body/SolveRequest.ts index 0a404fd..6799a17 100644 --- a/src/mock/entity/dao/frontend/request/body/SolveRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/SolveRequest.ts @@ -16,12 +16,14 @@ export default class SolveRequest { } this.singleChoiceAnswer = Number(params.singleChoiceAnswer) } + if (typeof params.textAnswer === 'string') { if (params.textAnswer.length > 100) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.textAnswer = params.textAnswer } + if (params.singleChoiceAnswer === null && params.textAnswer === null) { throw ErrorRegistry.INVALID_INPUT_FORMAT } diff --git a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts index 30a717d..3fbd28d 100644 --- a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts @@ -1,5 +1,4 @@ import ErrorRegistry from '#error/ErrorRegistry' -import Regex from '#util/Regex' interface WriteRequestParams { subject: string @@ -17,24 +16,35 @@ export default class WriteRequest { public uploadUrls: string[] constructor(params: WriteRequestParams) { - if (!params.title) { + if (!params.subject) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - if (params.title.length > 50 && params.title.length < 2) { + if (params.subject.length > 50 || params.subject.length < 2) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - if ( - !Regex.SUBJECT.test(params.subject) || - (params.description && params.description.length > 1000) || - params.quizCount > 10 || - params.quizCount < 0 - ) { + this.subject = params.subject + + if (!params.title) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.title.length > 50 || params.title.length < 2) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - this.subject = params.subject - this.quizCount = params.quizCount this.title = params.title + + if (!params.description) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.description.length > 1000) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } this.description = params.description + + if (params.quizCount > 10 || params.quizCount < 0) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + this.quizCount = params.quizCount + this.uploadUrls = params.uploadUrls } } diff --git a/src/notice/entity/dao/frontend/request/WriteRequest.ts b/src/notice/entity/dao/frontend/request/WriteRequest.ts index edc0c7d..73463d8 100644 --- a/src/notice/entity/dao/frontend/request/WriteRequest.ts +++ b/src/notice/entity/dao/frontend/request/WriteRequest.ts @@ -17,11 +17,16 @@ export default class WriteRequest { if (params.title.length > 50 && params.title.length < 2) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - if (params.content && params.content.length > 10000) { + this.title = params.title + + if (!params.content) { + throw ErrorRegistry.INVALID_INPUT_FORMAT + } + if (params.content.length > 10000) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - this.title = params.title this.content = params.content + this.uploadUrls = params.uploadUrls } } diff --git a/src/rank/entity/dao/request/RankListRequest.ts b/src/rank/entity/dao/request/RankListRequest.ts index 11fe035..e242e77 100644 --- a/src/rank/entity/dao/request/RankListRequest.ts +++ b/src/rank/entity/dao/request/RankListRequest.ts @@ -22,7 +22,7 @@ export default class RankListRequest { } this.tier = params.tier - if (params.nickname && params.nickname.length > 100) { + if (params.nickname && params.nickname.length > 12) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.nickname = params.nickname From b6b8aad257caedbe72720267e67ad4c09d46a8f8 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Fri, 14 Mar 2025 12:39:44 +0900 Subject: [PATCH 25/29] =?UTF-8?q?[SUS-84]=20=EB=8B=89=EB=84=A4=EC=9E=84=20?= =?UTF-8?q?dao=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/dao/frontend/request/NicknameChangeRequest.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts b/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts index 53e827f..22855ec 100644 --- a/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts +++ b/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts @@ -1,5 +1,4 @@ import ErrorRegistry from '#error/ErrorRegistry' -import Regex from '#util/Regex' interface NicknameChangeRequestParams { nickname: string @@ -9,7 +8,7 @@ export default class NicknameChangeRequest { public nickname: string constructor(params: NicknameChangeRequestParams) { - if (!Regex.NICKNAME.test(params.nickname)) { + if (params.nickname.length < 2 || params.nickname.length > 12) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.nickname = params.nickname From 4e5cab023730b9564e606b1445c2532bd4e264bf Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Fri, 14 Mar 2025 14:49:00 +0900 Subject: [PATCH 26/29] =?UTF-8?q?[SUS-84]=20=EB=B0=9C=EC=83=9D=ED=95=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EC=88=98=EC=A0=95=20=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/error/ErrorRegistry.ts | 5 +++++ src/core/util/Regex/index.ts | 8 +++++++- src/core/util/multipartParser/index.ts | 2 +- .../frontend/request/NicknameChangeRequest.ts | 3 ++- .../frontend/request/body/MockEditRequest.ts | 11 +++-------- .../dao/frontend/request/body/SolveRequest.ts | 19 +++++++++---------- .../dao/frontend/request/body/WriteRequest.ts | 18 +++++------------- src/mock/service/ListService.ts | 4 ++++ src/mock/service/WriteService.ts | 2 ++ .../frontend/request/NoticeEditBodyRequest.ts | 12 ++++++------ .../dao/frontend/request/WriteRequest.ts | 11 +++-------- 11 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/core/error/ErrorRegistry.ts b/src/core/error/ErrorRegistry.ts index 9438a35..46cdc06 100644 --- a/src/core/error/ErrorRegistry.ts +++ b/src/core/error/ErrorRegistry.ts @@ -98,6 +98,11 @@ export default class ErrorRegistry { 'MU001', '지원하지 않는 파일 형식입니다', ) + static readonly OUT_OF_UPLOAD_LIMIT = new CustomError( + 400, + 'MU002', + '파일 업로드 개수를 초과했습니다', + ) // Like(LI) static readonly DUPLICATE_LIKE = new CustomError( diff --git a/src/core/util/Regex/index.ts b/src/core/util/Regex/index.ts index 81c3206..273e26e 100644 --- a/src/core/util/Regex/index.ts +++ b/src/core/util/Regex/index.ts @@ -2,9 +2,15 @@ export default class Regex { public static readonly ID = /^(?=.*[a-zA-Z])[a-zA-Z0-9]{5,16}$/ public static readonly PASSWORD = /^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z0-9!@#$%^&*()_+={}\[\]:;"'<>,.?~`-]{8,16}$/ + public static readonly EMAIL = /^[a-zA-Z0-9._%+-]{1,20}@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,100}$/ - public static readonly QUIZ_COUNT = /^(10|[1-9])$/ + + public static readonly NICKNAME = /^.{2,12}$/ + public static readonly SUBJECT = /^.{1,50}$/ + public static readonly TITLE = /^.{1,50}$/ + public static readonly DESCRIPTION = /^.{0,1000}$/ + public static readonly CONTENT = /^.{0,10000}$/ public static readonly TIER = /^(DIAMOND|PLATINUM|GOLD|SILVER|BRONZE)$/ public static readonly UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ diff --git a/src/core/util/multipartParser/index.ts b/src/core/util/multipartParser/index.ts index 3efa1d2..619b94a 100644 --- a/src/core/util/multipartParser/index.ts +++ b/src/core/util/multipartParser/index.ts @@ -49,7 +49,7 @@ const multipartParser = (contentType: string, limit: number) => { } }) if (existingUrls.length + req.files.length > limit) { - return next(ErrorRegistry.INVALID_INPUT_FORMAT) + return next(ErrorRegistry.OUT_OF_UPLOAD_LIMIT) } uploadUrls.push(...existingUrls) } diff --git a/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts b/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts index 22855ec..53e827f 100644 --- a/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts +++ b/src/member/entity/dao/frontend/request/NicknameChangeRequest.ts @@ -1,4 +1,5 @@ import ErrorRegistry from '#error/ErrorRegistry' +import Regex from '#util/Regex' interface NicknameChangeRequestParams { nickname: string @@ -8,7 +9,7 @@ export default class NicknameChangeRequest { public nickname: string constructor(params: NicknameChangeRequestParams) { - if (params.nickname.length < 2 || params.nickname.length > 12) { + if (!Regex.NICKNAME.test(params.nickname)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.nickname = params.nickname diff --git a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts index 6a2c0ed..d2e9957 100644 --- a/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/MockEditRequest.ts @@ -1,4 +1,5 @@ import ErrorRegistry from '#error/ErrorRegistry' +import Regex from '#util/Regex' interface MockEditRequestParams { title: string @@ -12,18 +13,12 @@ export default class MockEditRequest { uploadUrls: string[] constructor(params: MockEditRequestParams) { - if (!params.title) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (params.title.length > 50 || params.title.length < 2) { + if (!Regex.TITLE.test(params.title)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.title = params.title - if (!params.description) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (params.description.length > 1000) { + if (params.description && !Regex.DESCRIPTION.test(params.description)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.description = params.description diff --git a/src/mock/entity/dao/frontend/request/body/SolveRequest.ts b/src/mock/entity/dao/frontend/request/body/SolveRequest.ts index 6799a17..16d9a05 100644 --- a/src/mock/entity/dao/frontend/request/body/SolveRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/SolveRequest.ts @@ -10,19 +10,18 @@ export default class SolveRequest { textAnswer?: string constructor(params: SolveRequestParams) { - if (typeof params.singleChoiceAnswer === 'number') { - if (params.singleChoiceAnswer > 3 || params.singleChoiceAnswer < 0) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - this.singleChoiceAnswer = Number(params.singleChoiceAnswer) + if ( + params.singleChoiceAnswer && + (params.singleChoiceAnswer > 3 || params.singleChoiceAnswer < 0) + ) { + throw ErrorRegistry.INVALID_INPUT_FORMAT } + this.singleChoiceAnswer = Number(params.singleChoiceAnswer) - if (typeof params.textAnswer === 'string') { - if (params.textAnswer.length > 100) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - this.textAnswer = params.textAnswer + if (params.textAnswer && params.textAnswer.length > 100) { + throw ErrorRegistry.INVALID_INPUT_FORMAT } + this.textAnswer = params.textAnswer if (params.singleChoiceAnswer === null && params.textAnswer === null) { throw ErrorRegistry.INVALID_INPUT_FORMAT diff --git a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts index 3fbd28d..4d5f9c4 100644 --- a/src/mock/entity/dao/frontend/request/body/WriteRequest.ts +++ b/src/mock/entity/dao/frontend/request/body/WriteRequest.ts @@ -1,4 +1,5 @@ import ErrorRegistry from '#error/ErrorRegistry' +import Regex from '#util/Regex' interface WriteRequestParams { subject: string @@ -16,31 +17,22 @@ export default class WriteRequest { public uploadUrls: string[] constructor(params: WriteRequestParams) { - if (!params.subject) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (params.subject.length > 50 || params.subject.length < 2) { + if (!Regex.SUBJECT.test(params.subject)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.subject = params.subject - if (!params.title) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (params.title.length > 50 || params.title.length < 2) { + if (!Regex.TITLE.test(params.title)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.title = params.title - if (!params.description) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (params.description.length > 1000) { + if (params.description && !Regex.DESCRIPTION.test(params.description)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.description = params.description - if (params.quizCount > 10 || params.quizCount < 0) { + if (params.quizCount > 10 || params.quizCount < 1) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.quizCount = params.quizCount diff --git a/src/mock/service/ListService.ts b/src/mock/service/ListService.ts index ab749aa..821fd23 100644 --- a/src/mock/service/ListService.ts +++ b/src/mock/service/ListService.ts @@ -42,6 +42,10 @@ export default class ListService { } } + if (dbResult.totalCount === 0) { + return new ListResponse(current, display, 0, []) + } + return new ListResponse( current, display, diff --git a/src/mock/service/WriteService.ts b/src/mock/service/WriteService.ts index 3aa30f6..b7dc9d7 100644 --- a/src/mock/service/WriteService.ts +++ b/src/mock/service/WriteService.ts @@ -10,6 +10,8 @@ export default class WriteService { const singleChoiceQuizCount = Math.floor(quizCount * 0.8) const textQuizCount = Math.ceil(quizCount * 0.2) + console.log(body) + const generatedQuizzes = await Promise.all([ AIAdapter.getSingleChoiceQuizzes( body.title, diff --git a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts index de74d4c..30f2ebb 100644 --- a/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts +++ b/src/notice/entity/dao/frontend/request/NoticeEditBodyRequest.ts @@ -1,4 +1,5 @@ import ErrorRegistry from '#error/ErrorRegistry' +import Regex from '#util/Regex' interface NoticeEditBodyRequestParams { title: string @@ -12,17 +13,16 @@ export default class NoticeEditBodyRequest { public content: string public uploadUrls: string[] constructor(params: NoticeEditBodyRequestParams) { - if (!params.title) { + if (!Regex.TITLE.test(params.title)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - if (params.title.length > 50 && params.title.length < 2) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (params.content && params.content.length > 1000) { + this.title = params.title + + if (params.content && !Regex.CONTENT.test(params.content)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } - this.title = params.title this.content = params.content + this.uploadUrls = params.uploadUrls } } diff --git a/src/notice/entity/dao/frontend/request/WriteRequest.ts b/src/notice/entity/dao/frontend/request/WriteRequest.ts index 73463d8..c2421f1 100644 --- a/src/notice/entity/dao/frontend/request/WriteRequest.ts +++ b/src/notice/entity/dao/frontend/request/WriteRequest.ts @@ -1,4 +1,5 @@ import ErrorRegistry from '#error/ErrorRegistry' +import Regex from '#util/Regex' interface WriteRequestParams { title: string @@ -11,18 +12,12 @@ export default class WriteRequest { public content: string public uploadUrls: string[] constructor(params: WriteRequestParams) { - if (!params.title) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (params.title.length > 50 && params.title.length < 2) { + if (!Regex.TITLE.test(params.title)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.title = params.title - if (!params.content) { - throw ErrorRegistry.INVALID_INPUT_FORMAT - } - if (params.content.length > 10000) { + if (params.content && !Regex.CONTENT.test(params.content)) { throw ErrorRegistry.INVALID_INPUT_FORMAT } this.content = params.content From 4c8a1a64eb22d747b2017f6b08d06df90f76f1cc Mon Sep 17 00:00:00 2001 From: taegyun Date: Fri, 14 Mar 2025 16:40:28 +0900 Subject: [PATCH 27/29] [SUS-86]Feat/modify_mock_date_format --- src/mock/repository/MockRepository.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mock/repository/MockRepository.ts b/src/mock/repository/MockRepository.ts index 8a5a4e4..cb53b87 100644 --- a/src/mock/repository/MockRepository.ts +++ b/src/mock/repository/MockRepository.ts @@ -37,7 +37,7 @@ export default class MockRepository { mock.idx, mock.title, mock.description, - mock.created_at as "createdAt", + TO_CHAR(mock.created_at,'YYYY-MM-DD' )as "createdAt", mock.quiz_count as "quizCount", like_count.count as "likeCount", member.nickname as "writerNickname", @@ -96,7 +96,7 @@ export default class MockRepository { SELECT new_paginated.idx, new_paginated.title, - new_paginated.created_at as "createdAt", + TO_CHAR(new_paginated.created_at,'YYYY-MM-DD') as "createdAt", member.nickname as "writerNickname", (SELECT COUNT(*) FROM like_history lh WHERE lh.article_idx = new_paginated.idx) AS "likeCount" FROM new_paginated @@ -142,7 +142,7 @@ export default class MockRepository { SELECT like_count_paginated.idx, like_count_paginated.title, - like_count_paginated.created_at as "createdAt", + TO_CHAR(like_count_paginated.created_at,'YYYY-MM-DD') as "createdAt", member.nickname as "writerNickname", (SELECT COUNT(*) FROM like_history lc WHERE lc.article_idx = like_count_paginated.idx) AS "likeCount" FROM like_count_paginated @@ -188,7 +188,7 @@ export default class MockRepository { SELECT new_paginated.idx, new_paginated.title, - new_paginated.created_at as "createdAt", + TO_CHAR(new_paginated.created_at,'YYYY-MM-DD') as "createdAt", member.nickname as "writerNickname", (SELECT COUNT(*) FROM like_history lh WHERE lh.article_idx = new_paginated.idx) AS "likeCount" FROM new_paginated From 11e3f4f486ecab60f535a6ec6be9d1d4bb69bce6 Mon Sep 17 00:00:00 2001 From: Oh YoungJe Date: Fri, 14 Mar 2025 16:47:20 +0900 Subject: [PATCH 28/29] =?UTF-8?q?[SUS-85]=20=EC=9D=91=EB=8B=B5=20dto=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/dao/frontend/response/ResultResponse.ts | 13 ++++++++++--- src/mock/service/MockItemService.ts | 9 ++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/mock/entity/dao/frontend/response/ResultResponse.ts b/src/mock/entity/dao/frontend/response/ResultResponse.ts index 8fbfc26..a87781b 100644 --- a/src/mock/entity/dao/frontend/response/ResultResponse.ts +++ b/src/mock/entity/dao/frontend/response/ResultResponse.ts @@ -1,11 +1,18 @@ export default class ResultResponse { score: number maxScore: number - topPercentile: number + greaterEqualCandidateCount: number + totalCandidateCount: number - constructor(score: number, maxScore: number, topPercentile: number) { + constructor( + score: number, + maxScore: number, + greaterEqualCandidateCount: number, + totalCandidateCount: number, + ) { this.score = score this.maxScore = maxScore - this.topPercentile = topPercentile + this.greaterEqualCandidateCount = greaterEqualCandidateCount + this.totalCandidateCount = totalCandidateCount } } diff --git a/src/mock/service/MockItemService.ts b/src/mock/service/MockItemService.ts index 748af5a..e6c4141 100644 --- a/src/mock/service/MockItemService.ts +++ b/src/mock/service/MockItemService.ts @@ -33,9 +33,12 @@ export default class MockItemService { ): Promise { const result = await MockScoreRepository.getScore(userIdx, path.idx) - const topPercentile = - (result.greaterEqualCandidateCount / result.totalCandidateCount) * 100 - return new ResultResponse(result.score, result.maxScore, topPercentile) + return new ResultResponse( + result.score, + result.maxScore, + result.greaterEqualCandidateCount, + result.totalCandidateCount, + ) } static async saveMockResult( From 0f1ed1ff2485d5fc0227d01bef08517f6f62aef2 Mon Sep 17 00:00:00 2001 From: taegyun Date: Fri, 14 Mar 2025 17:07:39 +0900 Subject: [PATCH 29/29] HotfiX:google_login_url_edit --- src/member/service/LoginService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/member/service/LoginService.ts b/src/member/service/LoginService.ts index 2b7ec89..e092def 100644 --- a/src/member/service/LoginService.ts +++ b/src/member/service/LoginService.ts @@ -120,6 +120,6 @@ export default class LoginService { ) Token.generateCookie('loginToken', token, res) - return signupRedirectUrl + return loginRedirectUrl } }