From b6c74505c0d53d96260a69fd017187ac1b95753c Mon Sep 17 00:00:00 2001 From: pjw5521 Date: Tue, 1 Oct 2024 15:25:12 +0900 Subject: [PATCH 1/2] feat: add Pagination --- src/controller/user.controller.ts | 25 ++++- src/routes/user.ts | 146 ++++++++++++++++++------------ src/service/user.service.ts | 22 ++++- 3 files changed, 129 insertions(+), 64 deletions(-) diff --git a/src/controller/user.controller.ts b/src/controller/user.controller.ts index bc9d42b..b148ce0 100644 --- a/src/controller/user.controller.ts +++ b/src/controller/user.controller.ts @@ -79,9 +79,30 @@ const getSavedMemeList = async (req: CustomRequest, res: Response, next: NextFun const getRegisteredMemeList = async (req: CustomRequest, res: Response, next: NextFunction) => { const user = req.requestedUser; + const page = parseInt(req.query.page as string) || 1; + if (page < 1) { + return next(new CustomError(`Invalid 'page' parameter`, HttpCode.BAD_REQUEST)); + } + + const size = parseInt(req.query.size as string) || 10; + if (size < 1) { + return next(new CustomError(`Invalid 'size' parameter`, HttpCode.BAD_REQUEST)); + } + try { - const memeList = await UserService.getRegisteredMemeList(user); - return res.json(createSuccessResponse(HttpCode.OK, 'Get Registered Meme', memeList)); + const memeList = await UserService.getRegisteredMemeList(page, size, user); + + const data = { + pagination: { + total: memeList.total, + page: memeList.page, + perPage: size, + currentPage: memeList.page, + totalPages: memeList.totalPages, + }, + memeList: memeList.data, + }; + return res.json(createSuccessResponse(HttpCode.OK, 'Get Registered Meme', data)); } catch (err) { return next(new CustomError(err.message, err.status)); } diff --git a/src/routes/user.ts b/src/routes/user.ts index f76eea8..0f7596d 100644 --- a/src/routes/user.ts +++ b/src/routes/user.ts @@ -497,9 +497,21 @@ router.get('/recent-memes', getRequestedUserInfo, UserController.getLastSeenMeme * /api/user/registered-memes: * get: * tags: [User] - * summary: 사용자가 등록한 밈 정보 조회 - * description: 사용자가 등록한 밈 정보 조회 + * summary: 사용자가 등록한 밈 목록 조회 (페이지네이션) + * description: 사용자가 등록한 밈 목록 조회 * parameters: + * - in: query + * name: page + * schema: + * type: number + * example: 1 + * description: 현재 페이지 번호 (기본값 1) + * - in: query + * name: size + * schema: + * type: number + * example: 10 + * description: 한 번에 조회할 밈 개수 (기본값 10) * - name: x-device-id * in: header * description: 유저의 고유한 deviceId @@ -507,7 +519,7 @@ router.get('/recent-memes', getRequestedUserInfo, UserController.getLastSeenMeme * type: string * responses: * 200: - * description: 등록한 밈 목록 + * description: 사용자가 등록한 밈 목록 조회 * content: * application/json: * schema: @@ -515,64 +527,82 @@ router.get('/recent-memes', getRequestedUserInfo, UserController.getLastSeenMeme * properties: * status: * type: string - * example: "success" + * example: success * code: * type: integer * example: 200 * message: * type: string - * example: "Get Registered Meme" + * example: Get Registered Meme List * data: - * type: array - * items: - * type: object - * properties: - * _id: - * type: string - * example: "66f412741cdc0e3efad1c24e" - * deviceId: - * type: string - * example: "test1" - * title: - * type: string - * example: "폰보는 루피" - * image: - * type: string - * example: "https://ppac-meme.s3.ap-northeast-2.amazonaws.com/1727271540074" - * reaction: - * type: integer - * example: 0 - * source: - * type: string - * example: "google" - * isTodayMeme: - * type: boolean - * example: false - * createdAt: - * type: string - * format: date-time - * example: "2024-09-25T13:39:00.179Z" - * updatedAt: - * type: string - * format: date-time - * example: "2024-09-25T13:39:00.179Z" - * keywords: - * type: array - * items: - * type: object - * properties: - * _id: - * type: string - * example: "667ff3d1239eeaf78630a283" - * name: - * type: string - * example: "행복" - * isSaved: - * type: boolean - * example: true - * isReaction: - * type: boolean - * example: false + * type: object + * properties: + * pagination: + * type: object + * properties: + * total: + * type: integer + * example: 2 + * page: + * type: integer + * example: 1 + * perPage: + * type: integer + * example: 10 + * currentPage: + * type: integer + * example: 1 + * totalPages: + * type: integer + * example: 1 + * memeList: + * type: array + * items: + * type: object + * properties: + * _id: + * type: string + * example: "66f412741cdc0e3efad1c24e" + * image: + * type: string + * example: "https://ppac-meme.s3.ap-northeast-2.amazonaws.com/1727271540074" + * title: + * type: string + * example: "폰보는 루피" + * source: + * type: string + * example: "구글 이미지" + * reaction: + * type: integer + * example: 10 + * watch: + * type: integer + * example: 500 + * createdAt: + * type: string + * format: date-time + * example: "2024-09-25T13:39:00.179Z" + * updatedAt: + * type: string + * format: date-time + * example: "2024-09-25T13:39:00.179Z" + * keywords: + * type: array + * items: + * type: object + * properties: + * _id: + * type: string + * example: "667ff3d1239eeaf78630a283" + * name: + * type: string + * example: "행복" + * isSaved: + * type: boolean + * example: true + * isReaction: + * type: boolean + * example: false * 400: * description: 잘못된 요청 * content: @@ -582,7 +612,7 @@ router.get('/recent-memes', getRequestedUserInfo, UserController.getLastSeenMeme * properties: * status: * type: string - * example: "error" + * example: error * code: * type: integer * example: 400 @@ -600,13 +630,13 @@ router.get('/recent-memes', getRequestedUserInfo, UserController.getLastSeenMeme * properties: * status: * type: string - * example: "error" + * example: error * code: * type: integer * example: 500 * message: * type: string - * example: "Failed get registered meme list" + * example: "Failed to get registered meme list" * data: * type: null */ diff --git a/src/service/user.service.ts b/src/service/user.service.ts index a4be685..63505fe 100644 --- a/src/service/user.service.ts +++ b/src/service/user.service.ts @@ -251,25 +251,39 @@ async function createMemeRecommendWatch(user: IUserDocument, meme: IMemeDocument } } -async function getRegisteredMemeList(user: IUserDocument): Promise { +async function getRegisteredMemeList( + page: number, + size: number, + user: IUserDocument, +): Promise<{ total: number; page: number; totalPages: number; data: IMemeGetResponse[] }> { try { const deviceId = user.deviceId; + const totalRegisteredMemes = await MemeModel.countDocuments({ deviceId, isDeleted: false }); + const myMemeList = await MemeModel.find({ deviceId, isDeleted: false }, { isDeleted: 0 }) .sort({ createdAt: -1 }) + .skip((page - 1) * size) + .limit(size) .lean(); const myMemeListInfo = await MemeService.getMemeListWithKeywordsAndisSavedAndisReaction( user, myMemeList, ); + logger.info( - `Get registeredMemeList - deviceId(${user.deviceId}), memeList(${getRegisteredMemeList})`, + `Get registeredMemeList - deviceId(${user.deviceId}), memeList(${myMemeListInfo.length})`, ); - return myMemeListInfo; + return { + total: totalRegisteredMemes, + page, + totalPages: Math.ceil(totalRegisteredMemes / size), + data: myMemeListInfo, + }; } catch (err) { throw new CustomError( - `Failed get registered meme list(${err.message})`, + `Failed to get registered meme list(${err.message})`, HttpCode.INTERNAL_SERVER_ERROR, ); } From d44b8517cfe54a82c0de885f5b618bc51e348303 Mon Sep 17 00:00:00 2001 From: pjw5521 Date: Tue, 1 Oct 2024 17:15:29 +0900 Subject: [PATCH 2/2] fix: change log --- src/service/user.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/user.service.ts b/src/service/user.service.ts index 63505fe..942a05f 100644 --- a/src/service/user.service.ts +++ b/src/service/user.service.ts @@ -272,7 +272,7 @@ async function getRegisteredMemeList( ); logger.info( - `Get registeredMemeList - deviceId(${user.deviceId}), memeList(${myMemeListInfo.length})`, + `Get registeredMemeList - deviceId(${user.deviceId}), memeList count(${myMemeListInfo.length})`, ); return {