Skip to content

Commit

Permalink
[FEAT] 카테고리별 커뮤니티 게시글 조회 API (#348)
Browse files Browse the repository at this point in the history
* [FEAT] user profile dummy image url 추가

* [FEAT] 커뮤니티 게시글 상세조회 API

* [FIX] createdAt 형식 포맷팅

* [FIX] db query 결과 반환 형식 수정

* [FIX] createdAt format 수정

* [WIP] 커뮤니티 카테고리별 게시글 조회 구현 중

* [FEAT] 커뮤니티 카테고리별 게시글 조회 API 구현

* [FIX] communityCategoryId 검증

* [FIX] 불필요한 주석과 isLastPage 변수 삭제

* [FIX] getComunityCategoryPostsValidator, getCommunityCategoryPostsById로 변경

---------

Co-authored-by: jokj624 <[email protected]>
  • Loading branch information
yubinquitous and jokj624 authored Apr 22, 2024
1 parent f2a14eb commit fefb4f3
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 10 deletions.
74 changes: 72 additions & 2 deletions functions/api/routes/community/communityCategoryPostsGET.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,79 @@
const dayjs = require('dayjs');
const customParseFormat = require('dayjs/plugin/customParseFormat');
const util = require('../../../lib/util');
const statusCode = require('../../../constants/statusCode');
const responseMessage = require('../../../constants/responseMessage');
const asyncWrapper = require('../../../lib/asyncWrapper');
const db = require('../../../db/db');
const { communityDB } = require('../../../db');
const dummyImages = require('../../../constants/dummyImages');
/**
* @route GET /community/categories/:communityCategoryId
* @desc 커뮤니티 카테고리별 게시글 조회
* @access Private
*/

module.exports = async (req, res) => {
module.exports = asyncWrapper(async (req, res) => {
const { userId } = req.user;
const { page, limit } = req.query;
};
const { communityCategoryId } = req.params;

const dbConnection = await db.connect(req);
req.dbConnection = dbConnection;

dayjs().format();
dayjs.extend(customParseFormat);

// category id가 존재하지 않는 경우
const isExistingCategory = await communityDB.isExistingCategory(
dbConnection,
communityCategoryId,
);
if (!isExistingCategory) {
return res
.status(statusCode.NOT_FOUND)
.send(util.fail(statusCode.NOT_FOUND, responseMessage.NO_CATEGORY));
}

const totalItemCount = await communityDB.getCommunityCategoryPostsCount(
dbConnection,
userId,
communityCategoryId,
);
const totalPageCount = Math.ceil(totalItemCount / limit);
const currentPage = +page;

// 요청한 페이지가 존재하지 않는 경우
if (page > totalPageCount) {
return res
.status(statusCode.NOT_FOUND)
.send(util.fail(statusCode.NOT_FOUND, responseMessage.NO_PAGE));
}

const offset = (page - 1) * limit;
const communityCategoryPosts = await communityDB.getCommunityCategoryPostsById(
dbConnection,
userId,
communityCategoryId,
limit,
offset,
);
// 각 게시글의 createdAt 형식 변경 및 프로필 이미지 추가
const result = await Promise.all(
communityCategoryPosts.map((communityPost) => {
communityPost.createdAt = dayjs(`${communityPost.createdAt}`).format('YYYY. MM. DD');
communityPost.profileImage = dummyImages.user_profile_dummy;
return communityPost;
}),
);

res.status(statusCode.OK).send(
util.success(statusCode.OK, responseMessage.READ_COMMUNITY_CATEGORY_POSTS_SUCCESS, {
posts: result,
currentPage,
totalPageCount,
totalItemCount,
isLastPage: currentPage === totalPageCount,
}),
);
});
11 changes: 6 additions & 5 deletions functions/api/routes/community/communityPostsGET.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ module.exports = asyncWrapper(async (req, res) => {
dayjs.extend(customParseFormat);

const totalItemCount = await communityDB.getCommunityPostsCount(dbConnection, userId); // 총 게시글 수
const totalPageCount = Math.ceil(totalItemCount / limit); // 총 페이지 수
const currentPage = +page; // 현재 페이지
const isLastPage = totalPageCount === currentPage; // 마지막 페이지인지 여부
const totalPageCount = Math.ceil(totalItemCount / limit);
const currentPage = +page;

// 요청한 페이지가 존재하지 않는 경우
if (page > totalPageCount) {
return res
.status(statusCode.NOT_FOUND)
.send(util.fail(statusCode.NOT_FOUND, responseMessage.NO_PAGE));
}

const communityPosts = await communityDB.getCommunityPosts(dbConnection, userId, limit, page);
const offset = (page - 1) * limit;
const communityPosts = await communityDB.getCommunityPosts(dbConnection, userId, limit, offset);
// 각 게시글의 createdAt 형식 변경 및 프로필 이미지 추가
const result = await Promise.all(
communityPosts.map((communityPost) => {
Expand All @@ -51,7 +52,7 @@ module.exports = asyncWrapper(async (req, res) => {
currentPage,
totalPageCount,
totalItemCount,
isLastPage,
isLastPage: currentPage === totalPageCount,
}),
);
});
1 change: 1 addition & 0 deletions functions/api/routes/community/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ router.get(
router.get(
'/categories/:communityCategoryId',
checkUser,
[...communityValidator.getCommunityCategoryPostsValidator, validate],
require('./communityCategoryPostsGET'),
/**
* #swagger.summary = "커뮤니티 카테고리별 게시글 조회"
Expand Down
1 change: 1 addition & 0 deletions functions/constants/responseMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ module.exports = {
NO_COMMUNITY_CATEGORY: '존재하지 않는 커뮤니티 카테고리',
NO_PAGE: '존재하지 않는 페이지',
READ_COMMUNITY_CATEGORIES_SUCCESS: '커뮤니티 카테고리 조회 성공',
READ_COMMUNITY_CATEGORY_POSTS_SUCCESS: '커뮤니티 카테고리별 게시글 조회 성공',

// 서버 상태 체크
HEALTH_CHECK_SUCCESS: '서버 상태 정상',
Expand Down
59 changes: 57 additions & 2 deletions functions/db/community.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const getCommunityPostDetail = async (client, communityPostId) => {
return convertSnakeToCamel.keysToCamel(rows[0]);
};

const getCommunityPosts = async (client, userId, limit, page) => {
const getCommunityPosts = async (client, userId, limit, offset) => {
const { rows } = await client.query(
`
SELECT cp.id, u.nickname, cp.title, cp.body, cp.content_url, cp.content_title, cp.content_description, cp.thumbnail_url, cp.created_at
Expand All @@ -25,7 +25,7 @@ const getCommunityPosts = async (client, userId, limit, page) => {
ORDER BY cp.created_at DESC, cp.id DESC
LIMIT $2 OFFSET $3
`,
[userId, limit, (page - 1) * limit],
[userId, limit, offset],
);
return convertSnakeToCamel.keysToCamel(rows);
};
Expand Down Expand Up @@ -79,6 +79,19 @@ const verifyExistCategories = async (client, communityCategoryIds) => {
return convertSnakeToCamel.keysToCamel(rows[0]);
};

const isExistingCategory = async (client, communityCategoryId) => {
const { rows } = await client.query(
`
SELECT 1
FROM community_category
WHERE id = $1 AND is_deleted = FALSE
`,
[communityCategoryId],
);

return convertSnakeToCamel.keysToCamel(rows[0]);
};

const getCommunityCategories = async (client) => {
const { rows } = await client.query(
`
Expand All @@ -105,12 +118,54 @@ const getCommunityPostsCount = async (client, userId) => {
return rows[0].count;
};

const getCommunityCategoryPostsCount = async (client, userId, communityCategoryId) => {
const { rows } = await client.query(
`
SELECT COUNT(*)::int
FROM community_post cp
JOIN community_category_post ccp ON cp.id = ccp.community_post_id
LEFT JOIN community_post_report_user cpru ON cp.id = cpru.community_post_id AND cpru.report_user_id = $1
WHERE cp.is_deleted = FALSE AND ccp.community_category_id = $2 AND cpru.id IS NULL
`,
[userId, communityCategoryId],
);

return rows[0].count;
};

const getCommunityCategoryPostsById = async (
client,
userId,
communityCategoryId,
limit,
offset,
) => {
const { rows } = await client.query(
`
SELECT cp.id, u.nickname, cp.title, cp.body, cp.content_url, cp.content_title, cp.content_description, cp.thumbnail_url, cp.created_at
FROM community_post cp
JOIN "user" u ON cp.user_id = u.id
JOIN community_category_post ccp ON cp.id = ccp.community_post_id
LEFT JOIN community_post_report_user cpru ON cp.id = cpru.community_post_id AND cpru.report_user_id = $1
WHERE cp.is_deleted = FALSE AND ccp.community_category_id = $2 AND cpru.id IS NULL
ORDER BY cp.created_at DESC, cp.id DESC
LIMIT $3 OFFSET $4
`,
[userId, communityCategoryId, limit, offset],
);

return convertSnakeToCamel.keysToCamel(rows);
};

module.exports = {
getCommunityPostDetail,
getCommunityPosts,
addCommunityPost,
addCommunityCategoryPost,
verifyExistCategories,
isExistingCategory,
getCommunityCategories,
getCommunityPostsCount,
getCommunityCategoryPostsCount,
getCommunityCategoryPostsById,
};
12 changes: 11 additions & 1 deletion functions/middlewares/validator/communityValidator.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { body, query } = require('express-validator');
const { body, query, param } = require('express-validator');

const createCommunityPostValidator = [
body('communityCategoryIds')
Expand All @@ -16,7 +16,17 @@ const getCommunityPostsValidator = [
query('limit').notEmpty().isInt({ min: 1 }).withMessage('Invalid limit field'),
];

const getCommunityCategoryPostsValidator = [
query('page').notEmpty().isInt({ min: 1 }).withMessage('Invalid page field'),
query('limit').notEmpty().isInt({ min: 1 }).withMessage('Invalid limit field'),
param('communityCategoryId')
.notEmpty()
.isInt({ min: 1 })
.withMessage('Invalid communityCategoryId field'),
];

module.exports = {
createCommunityPostValidator,
getCommunityPostsValidator,
getCommunityCategoryPostsValidator,
};

0 comments on commit fefb4f3

Please sign in to comment.