diff --git a/package-lock.json b/package-lock.json index afa0144..5c2f4f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1307,6 +1307,7 @@ "integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@prisma/config": "6.19.0", "@prisma/engines": "6.19.0" diff --git a/src/controllers/post.controller.js b/src/controllers/post.controller.js index 6752a91..fe0ec29 100644 --- a/src/controllers/post.controller.js +++ b/src/controllers/post.controller.js @@ -30,7 +30,8 @@ export async function getPosts(req, res) { export async function getRecentPosts(req, res) { try { const limit = Number(req.query.limit ?? 5); - const result = await postService.getRecentPosts(limit); + const userDormId = req.user?.dorm_id ?? null; + const result = await postService.getRecentPosts(limit, userDormId); return res.status(200).json(result); } catch (err) { return res.status(err.status ?? 500).json({ message: err.message }); @@ -80,4 +81,3 @@ export async function getPostDetail(req, res) { return res.status(err.status ?? 500).json({ message: err.message }); } } - diff --git a/src/controllers/user.controller.js b/src/controllers/user.controller.js index 4191db6..e2b79ca 100644 --- a/src/controllers/user.controller.js +++ b/src/controllers/user.controller.js @@ -12,6 +12,39 @@ export async function getMe(req, res) { } } +export async function getMyPosts(req, res) { + try { + const userId = req.user.user_id; + const result = await userService.getMyPosts(userId, req.query); + return res.status(200).json(result); + } catch (err) { + console.error(err); + return res.status(err.status ?? 500).json({ message: err.message }); + } +} + +export async function getMyComments(req, res) { + try { + const userId = req.user.user_id; + const result = await userService.getMyComments(userId, req.query); + return res.status(200).json(result); + } catch (err) { + console.error(err); + return res.status(err.status ?? 500).json({ message: err.message }); + } +} + +export async function getMyParties(req, res) { + try { + const userId = req.user.user_id; + const result = await userService.getMyParties(userId, req.query); + return res.status(200).json(result); + } catch (err) { + console.error(err); + return res.status(err.status ?? 500).json({ message: err.message }); + } +} + export async function updateMe(req, res) { try { const userId = req.user.user_id; diff --git a/src/routes/user.route.js b/src/routes/user.route.js index 0894edc..6dff83f 100644 --- a/src/routes/user.route.js +++ b/src/routes/user.route.js @@ -5,6 +5,9 @@ import * as userController from "../controllers/user.controller.js"; const router = Router(); router.get("/me", authMiddleware, userController.getMe); +router.get("/me/posts", authMiddleware, userController.getMyPosts); +router.get("/me/comments", authMiddleware, userController.getMyComments); +router.get("/me/parties", authMiddleware, userController.getMyParties); router.patch("/me", authMiddleware, userController.updateMe); export default router; diff --git a/src/services/auth.service.js b/src/services/auth.service.js index 04b8b59..60a9c6b 100644 --- a/src/services/auth.service.js +++ b/src/services/auth.service.js @@ -34,12 +34,15 @@ async function register(data) { return { accessToken: token, user: { + user_id: user.user_id, name: user.name, email: user.email, + dorm_id: user.dorm_id, dorm_name: user.dorm?.dorm_name ?? null, room_no: user.room_no ?? null, phone: user.phone ?? null, account_number: user.account_number ?? null, + created_at: user.created_at }, }; } @@ -70,12 +73,15 @@ async function login(data) { return { accessToken: token, user: { + user_id: user.user_id, name: user.name, email: user.email, + dorm_id: user.dorm_id, dorm_name: user.dorm?.dorm_name ?? null, room_no: user.room_no ?? null, phone: user.phone ?? null, account_number: user.account_number ?? null, + created_at: user.created_at }, }; } @@ -93,12 +99,15 @@ async function getMe(user_id) { } return { + user_id: user.user_id, name: user.name, email: user.email, + dorm_id: user.dorm_id, dorm_name: user.dorm?.dorm_name ?? null, room_no: user.room_no, phone: user.phone, account_number: user.account_number ?? null, + created_at: user.created_at }; } @@ -110,13 +119,16 @@ async function updateMe(user_id, data) { }); return { + user_id: user.user_id, name: user.name, email: user.email, + dorm_id: user.dorm_id, dorm_name: user.dorm?.dorm_name ?? null, room_no: user.room_no, phone: user.phone, account_number: user.account_number ?? null, + created_at: user.created_at }; } -export default { register, login, getMe, updateMe }; \ No newline at end of file +export default { register, login, getMe, updateMe }; diff --git a/src/services/dorm.service.js b/src/services/dorm.service.js index 6961d85..8ecca02 100644 --- a/src/services/dorm.service.js +++ b/src/services/dorm.service.js @@ -1,6 +1,23 @@ import prisma from "../config/prisma.js"; +const DEFAULT_DORMS = [ + { dorm_id: 1, dorm_name: "남제관" }, + { dorm_id: 2, dorm_name: "용지관" }, + { dorm_id: 3, dorm_name: "광교관" }, + { dorm_id: 4, dorm_name: "화홍관" }, + { dorm_id: 5, dorm_name: "국제학사관" }, + { dorm_id: 6, dorm_name: "일신관" } +]; + async function getAllDorms() { + const count = await prisma.dormitory.count(); + if (count === 0) { + await prisma.dormitory.createMany({ + data: DEFAULT_DORMS, + skipDuplicates: true + }); + } + return await prisma.dormitory.findMany({ orderBy: { dorm_id: "asc" } }); diff --git a/src/services/post.service.js b/src/services/post.service.js index 56a6a7a..205dff9 100644 --- a/src/services/post.service.js +++ b/src/services/post.service.js @@ -189,11 +189,21 @@ async function getPosts(query) { }; } -async function getRecentPosts(limit = 5) { +async function getRecentPosts(limit = 5, userDormId = null) { + const where = { + status: "active", + }; + + // 택시는 dorm 제한 없음, 그 외에는 로그인 사용자의 dorm_id로 필터 + if (userDormId !== null) { + where.OR = [ + { category: "taxi" }, + { dorm_id: Number(userDormId) }, + ]; + } + const posts = await prisma.post.findMany({ - where: { - status: "active" - }, + where, include: { user: { select: { name: true, dorm_id: true } diff --git a/src/services/user.service.js b/src/services/user.service.js index dadd61a..3885132 100644 --- a/src/services/user.service.js +++ b/src/services/user.service.js @@ -26,7 +26,170 @@ async function getMe(user_id) { throw e; } - return user; + return { + user_id: user.user_id, + email: user.email, + name: user.name, + dorm_id: user.dorm_id, + dorm_name: user.dorm?.dorm_name ?? null, + room_no: user.room_no, + phone: user.phone, + account_number: user.account_number, + created_at: user.created_at + }; +} + +function buildPagination(query) { + const page = Number(query.page ?? 1); + const size = Number(query.size ?? 10); + const skip = (page - 1) * size; + return { page, size, skip }; +} + +async function getMyPosts(user_id, query = {}) { + const { page, size, skip } = buildPagination(query); + + const where = { + user_id, + ...(query.category ? { category: query.category } : {}), + }; + + const [posts, totalCount] = await Promise.all([ + prisma.post.findMany({ + where, + include: { + party: { + include: { members: true }, + }, + dorm: { + select: { dorm_name: true }, + }, + _count: { + select: { comments: true }, + }, + }, + orderBy: { created_at: "desc" }, + skip, + take: size, + }), + prisma.post.count({ where }), + ]); + + const items = posts.map((post) => { + const { dorm, _count, ...restPost } = post; + return { + ...restPost, + dorm_name: dorm?.dorm_name ?? null, + current_member_count: post.party ? post.party.members.length : null, + comment_count: _count.comments, + }; + }); + + return { items, totalCount, page, size }; +} + +async function getMyComments(user_id, query = {}) { + const { page, size, skip } = buildPagination(query); + + const [comments, totalCount] = await Promise.all([ + prisma.comment.findMany({ + where: { user_id }, + include: { + post: { + include: { + dorm: { select: { dorm_name: true } }, + party: { + include: { members: true }, + }, + _count: { select: { comments: true } }, + }, + }, + user: { select: { name: true } }, + }, + orderBy: { created_at: "desc" }, + skip, + take: size, + }), + prisma.comment.count({ where: { user_id } }), + ]); + + const items = comments.map((comment) => { + const { post, ...restComment } = comment; + if (!post) return { ...restComment, post: null }; + + const { dorm, _count, ...restPost } = post; + + return { + ...restComment, + post: { + ...restPost, + dorm_name: dorm?.dorm_name ?? null, + current_member_count: post.party ? post.party.members.length : null, + comment_count: _count.comments, + }, + }; + }); + + return { items, totalCount, page, size }; +} + +async function getMyParties(user_id, query = {}) { + const { page, size, skip } = buildPagination(query); + + const where = { + party: { + is: { + OR: [ + { host_id: user_id }, + { members: { some: { user_id } } }, + ], + }, + }, + }; + + const [posts, totalCount] = await Promise.all([ + prisma.post.findMany({ + where, + include: { + user: { select: { name: true, dorm_id: true } }, + party: { + include: { + members: true, + host: { select: { user_id: true, name: true } }, + }, + }, + dorm: { select: { dorm_name: true } }, + _count: { select: { comments: true } }, + }, + orderBy: { created_at: "desc" }, + skip, + take: size, + }), + prisma.post.count({ where }), + ]); + + const items = posts.map((post) => { + const { dorm, _count, ...restPost } = post; + const party = restPost.party; + const isHost = party?.host_id === user_id; + const isMember = party?.members.some((m) => m.user_id === user_id) ?? false; + + return { + ...restPost, + dorm_name: dorm?.dorm_name ?? null, + comment_count: _count.comments, + party: party + ? { + ...party, + current_member_count: party.members.length, + is_joined: isHost || isMember, + } + : null, + party_role: isHost ? "host" : isMember ? "member" : "guest", + }; + }); + + return { items, totalCount, page, size }; } async function updateMe(user_id, body) { @@ -56,14 +219,32 @@ async function updateMe(user_id, body) { room_no: true, phone: true, account_number: true, - created_at: true + created_at: true, + dorm: { + select: { + dorm_name: true + } + } } }); - return updated; + return { + user_id: updated.user_id, + email: updated.email, + name: updated.name, + dorm_id: updated.dorm_id, + dorm_name: updated.dorm?.dorm_name ?? null, + room_no: updated.room_no, + phone: updated.phone, + account_number: updated.account_number, + created_at: updated.created_at + }; } export default { getMe, + getMyPosts, + getMyComments, + getMyParties, updateMe, };