Skip to content

Commit

Permalink
[FEAT] 커뮤니티 게시글 전체조회 API (#345)
Browse files Browse the repository at this point in the history
* [FIX] 게시물 전체조회/카테고리별 조회 API response에 currentPage, totalPageCount,isLastPage 추가

* [FEAT] user profile dummy image url 추가

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

* [FIX] createdAt 형식 포맷팅

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

* [FIX] createdAt format 수정

* [FEAT] 커뮤니티 글 전체 조회 API

* [FIX] swagger options의 url 변경

* [FIX] page > totalPageCount일 경우 NOT_FOUND 에러 반환

* [FIX] query string 예외 처리 및 주석 추가

* [FIX] isLastPage 비교 조건 수정

* [FIX] 연산자를 이용해 number로 변환

Co-authored-by: Chae Jeong Ah <[email protected]>

* [FIX] COUNT 함수 ::int 이용해서 number로 형변환

Co-authored-by: Chae Jeong Ah <[email protected]>

* [FIX] ORDER BY created_at 중복 방지를 위해 ORDER BY id 추가

Co-authored-by: Chae Jeong Ah <[email protected]>

* [FIX] COUNT(*)::int로 number 변환됨에 따라 parseInt 삭제

* [FIX] 유저가 신고한 게시글 필터링

* [FIX] 커뮤니티 게시글 카운트할 때 유저가 신고한 게시글 제외

* [FIX] middleware를 이용해 query string validate

---------

Co-authored-by: jokj624 <[email protected]>
  • Loading branch information
yubinquitous and jokj624 authored Apr 9, 2024
1 parent 7d23202 commit f2a14eb
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 33 deletions.
52 changes: 50 additions & 2 deletions functions/api/routes/community/communityPostsGET.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,57 @@
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/posts
* @desc 커뮤니티 게시글 전체 조회
* @access Private
*/

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

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

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

const totalItemCount = await communityDB.getCommunityPostsCount(dbConnection, userId); // 총 게시글 수
const totalPageCount = Math.ceil(totalItemCount / limit); // 총 페이지 수
const currentPage = +page; // 현재 페이지
const isLastPage = totalPageCount === currentPage; // 마지막 페이지인지 여부
// 요청한 페이지가 존재하지 않는 경우
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);
// 각 게시글의 createdAt 형식 변경 및 프로필 이미지 추가
const result = await Promise.all(
communityPosts.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_POSTS_SUCCESS, {
posts: result,
currentPage,
totalPageCount,
totalItemCount,
isLastPage,
}),
);
});
1 change: 1 addition & 0 deletions functions/api/routes/community/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ router.get(
router.get(
'/posts',
checkUser,
[...communityValidator.getCommunityPostsValidator, validate],
require('./communityPostsGET'),
/**
* #swagger.summary = "커뮤니티 게시글 전체 조회"
Expand Down
60 changes: 30 additions & 30 deletions functions/config/swagger.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,40 @@ const dotenv = require('dotenv');
dotenv.config({ path: '.env.dev' });

const options = {
info: {
title: 'HAVIT API Docs',
description: 'HAVIT APP server API 문서입니다',
info: {
title: 'HAVIT API Docs',
description: 'HAVIT APP server API 문서입니다',
},
host: 'http://localhost:5001',
servers: [
{
url: 'http://localhost:5001/havit-wesopt29/asia-northeast3/api',
description: '로컬 개발환경 host',
},
host: "http://localhost:5001",
servers: [
{
url: 'http://localhost:5001/havit-production/asia-northeast3/api',
description: '로컬 개발환경 host',
},
{
url: process.env.DEV_HOST,
description: '개발환경 host',
},
],
schemes: ['http'],
securityDefinitions: {
bearerAuth: {
type: 'http',
name: 'x-auth-token',
in: 'header',
bearerFormat: 'JWT',
},
{
url: process.env.DEV_HOST,
description: '개발환경 host',
},
components: {
schemas: {
...commonErrorSchema,
...noticeSchema,
...communitySchema,
}
}
],
schemes: ['http'],
securityDefinitions: {
bearerAuth: {
type: 'http',
name: 'x-auth-token',
in: 'header',
bearerFormat: 'JWT',
},
},
components: {
schemas: {
...commonErrorSchema,
...noticeSchema,
...communitySchema,
},
},
};

const outputFile = '../constants/swagger/swagger-output.json';
const endpointsFiles = ['../api/index.js'];

swaggerAutogen(outputFile, endpointsFiles, options);
swaggerAutogen(outputFile, endpointsFiles, options);
2 changes: 2 additions & 0 deletions functions/constants/responseMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ module.exports = {

// 커뮤니티
READ_COMMUNITY_POST_SUCCESS: '커뮤니티 게시글 상세 조회 성공',
READ_COMMUNITY_POSTS_SUCCESS: '커뮤니티 게시글 전체 조회 성공',
NO_COMMUNITY_POST: '존재하지 않는 커뮤니티 게시글',
ADD_COMMUNITY_POST_SUCCESS: '커뮤니티 게시글 작성 성공',
NO_COMMUNITY_CATEGORY: '존재하지 않는 커뮤니티 카테고리',
NO_PAGE: '존재하지 않는 페이지',
READ_COMMUNITY_CATEGORIES_SUCCESS: '커뮤니티 카테고리 조회 성공',

// 서버 상태 체크
Expand Down
3 changes: 3 additions & 0 deletions functions/constants/swagger/schemas/communitySchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ const responseCommunityPostsSchema = {
$createdAt: '2024. 02. 03',
},
],
$currentPage: 1,
$totalPageCount: 1,
$totalItemCount: 3,
$isLastPage: true,
},
};

Expand Down
32 changes: 32 additions & 0 deletions functions/db/community.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@ const getCommunityPostDetail = async (client, communityPostId) => {
return convertSnakeToCamel.keysToCamel(rows[0]);
};

const getCommunityPosts = async (client, userId, limit, page) => {
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
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 cpru.id IS NULL
ORDER BY cp.created_at DESC, cp.id DESC
LIMIT $2 OFFSET $3
`,
[userId, limit, (page - 1) * limit],
);
return convertSnakeToCamel.keysToCamel(rows);
};

const addCommunityPost = async (
client,
userId,
Expand Down Expand Up @@ -75,10 +91,26 @@ const getCommunityCategories = async (client) => {
return convertSnakeToCamel.keysToCamel(rows);
};

const getCommunityPostsCount = async (client, userId) => {
const { rows } = await client.query(
`
SELECT COUNT(*)::int
FROM community_post cp
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 cpru.id IS NULL
`,
[userId],
);

return rows[0].count;
};

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

const createCommunityPostValidator = [
body('communityCategoryIds')
Expand All @@ -11,6 +11,12 @@ const createCommunityPostValidator = [
body('contentTitle').isString().notEmpty().withMessage('Invalid contentTitle field'),
];

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

module.exports = {
createCommunityPostValidator,
getCommunityPostsValidator,
};

0 comments on commit f2a14eb

Please sign in to comment.