diff --git a/src/controllers/comment.controller.js b/src/controllers/comment.controller.js index 363f7c0..a458f3d 100644 --- a/src/controllers/comment.controller.js +++ b/src/controllers/comment.controller.js @@ -74,7 +74,7 @@ export const handleAddComment = async (req, res, next) => { */ try{ - console.log("댓글 추가를 요청했습니다!"); +// console.log("댓글 추가를 요청했습니다!"); const commentData = bodyToComment(req.body, req.user.id ,parseInt(req.params.momentId)); const newComment = await addUserComment(commentData); res.status(StatusCodes.OK).success(newComment); @@ -146,7 +146,7 @@ export const handleAddComment = async (req, res, next) => { */ try{ - console.log("댓글 수정 기능 요청했습니다!"); +// console.log("댓글 수정 기능 요청했습니다!"); const momentId = parseInt(req.params.momentId); const commentId = parseInt(req.params.commentId); const editData = bodyToEditComment(req.body, req.user.id, momentId, commentId); @@ -208,7 +208,7 @@ export const handleAddComment = async (req, res, next) => { */ try{ - console.log("댓글 삭제 기능 요청"); +// console.log("댓글 삭제 기능 요청"); const deleteData = bodyToDeleteComment(req.user.id, req.params.commentId); const deleteComment = await deleteUserComment(deleteData); res.status(StatusCodes.OK).success(deleteComment); diff --git a/src/controllers/like.controller.js b/src/controllers/like.controller.js index d7fc9ac..d5187e6 100644 --- a/src/controllers/like.controller.js +++ b/src/controllers/like.controller.js @@ -67,7 +67,7 @@ export const handleLikeMoment = async (req, res, next) => { */ try{ - console.log("Like를 요청했습니다!"); +// console.log("Like를 요청했습니다!"); const like = await likeMoment(bodyToLike(req.body,req.user.id)); res.status(StatusCodes.OK).success(like); } catch (error) { @@ -122,7 +122,7 @@ export const handleDeleteLikeMoment = async (req, res, next) =>{ */ try{ - console.log("Like 삭제를 요청했습니다!"); +// console.log("Like 삭제를 요청했습니다!"); const like = await deleteMomentLike(bodyToDeleteLike(req.body), req.user.id); res.status(StatusCodes.OK).success(like); } catch (error) { diff --git a/src/controllers/moment.controller.js b/src/controllers/moment.controller.js index 5c063d3..7d915c4 100644 --- a/src/controllers/moment.controller.js +++ b/src/controllers/moment.controller.js @@ -3,16 +3,16 @@ import { bodyToCreateMoment, bodyToUpdateMoment, responseFromMyMomentDetail, - responseFromFriendsMoments, - responseFromFriendMomentDetail } from "../dtos/moment.dto.js"; + responseFromOtherUserMoments, + responseFromOtherUserMomentDetail } from "../dtos/moment.dto.js"; import { momentCreate, momentUpdate, momentDelete, getMyMoments, getMyMomentDetail, - getFriendsMoments, - getFriendMomentDetail } from "../services/moment.service.js"; + getOtherUserMoments, + getOtherUserMomentDetail } from "../services/moment.service.js"; export const handleCreateMoment = async (req, res, next) => { @@ -228,66 +228,83 @@ export const handleGetMyMomentDetail = async (req, res, next) => { } }; +export const handleGetOtherUserMoments = async (req, res, next) => { + try { + // userId 확인: 잘못된 값이 전달되는지 확인 + const userId = Number(req.params.userId); + console.log("Received userId from params:", req.params.userId); // 확인용 로그 추가 + if (isNaN(userId)) { + throw new Error("유효하지 않은 사용자 ID입니다."); + } -export const handleGetFriendsMoments = async (req, res, next) => { - /* - #swagger.tags = ['Moments'] - #swagger.summary = '친구의 Moment 목록 조회 API' - #swagger.description = '친구의 페이지에서 해당 친구의 Moment 게시물 목록을 조회합니다.' - #swagger.security = [{ - "bearerAuth": [] - }] - - */ + // getOtherUserMoments 함수에서 userId 확인 + const responseData = await getOtherUserMoments(userId); - try { - console.log("친구의 Moment 목록 조회 요청"); - const friendId = parseInt(req.params.friendId, 10); - const moments = await getFriendsMoments(friendId); res.status(StatusCodes.OK).json({ resultType: "SUCCESS", error: null, - success: { - data: responseFromFriendsMoments(moments) - } + success: { data: responseData } }); + } catch (error) { + console.error("❌ 특정 사용자의 Moment 목록 조회 오류:", error); next(error); } }; -export const handleGetFriendMomentDetail = async (req, res, next) => { + + + + + + + +export const handleGetOtherUserMomentDetail = async (req, res, next) => { /* #swagger.tags = ['Moments'] - #swagger.summary = '친구의 특정 Moment 상세 조회 API' - #swagger.description = '친구의 페이지에서 특정 Moment 게시물의 상세 정보를 조회합니다.' - #swagger.security = [{ - "bearerAuth": [] - }] + #swagger.summary = '특정 사용자의 특정 Moment 상세 조회 API' + #swagger.description = '특정 사용자의 페이지에서 특정 Moment 게시물의 상세 정보를 조회합니다.' + #swagger.security = [{ "bearerAuth": [] }] + #swagger.parameters['userId'] = { + in: "path", + required: true, + description: "조회할 사용자의 ID", + schema: { type: "integer", example: 1234 } + } #swagger.parameters['momentId'] = { in: "path", required: true, description: "조회할 Moment의 ID", schema: { type: "integer", example: 456 } } - */ try { - console.log("친구의 특정 Moment 상세 조회 요청"); - const friendId = parseInt(req.params.friendId, 10); - const momentId = parseInt(req.params.momentId, 10); - const moment = await getFriendMomentDetail(friendId, momentId); + console.log("특정 사용자의 Moment 목록 조회 요청"); + + const userId = parseInt(req.params.userId, 10); + if (isNaN(userId)) { + throw new Error("유효하지 않은 사용자 ID입니다."); + } + + const moments = await getOtherUserMoments(userId); + + // 🔍 responseFromOtherUserMoments() 변환 결과 확인 + const responseData = responseFromOtherUserMoments(moments); + console.log("Swagger 응답 데이터:", JSON.stringify(responseData, null, 2)); + res.status(StatusCodes.OK).json({ resultType: "SUCCESS", error: null, success: { - data: responseFromFriendMomentDetail(moment) + data: responseData } }); } catch (error) { + console.error("특정 사용자의 Moment 목록 조회 오류:", error); next(error); } -}; \ No newline at end of file +}; + diff --git a/src/dtos/like.dto.js b/src/dtos/like.dto.js index d8f5329..df7987d 100644 --- a/src/dtos/like.dto.js +++ b/src/dtos/like.dto.js @@ -1,12 +1,12 @@ export const bodyToLike = ({ moment }, userId) => { - return { - fromUserId: userId, - userId: moment.userId, - entityId: moment.id, - entityType: moment.entityType || "moment", - }; - }; - - export const bodyToDeleteLike = ({ like }) => { - return { likeId: like?.likeId }; - }; \ No newline at end of file + return { + fromUserId: userId, + userId: moment.userId, + entityId: moment.id, + entityType: moment.entityType || "moment", + }; + }; + + export const bodyToDeleteLike = ({ like }) => { + return { likeId: like?.likeId }; + }; \ No newline at end of file diff --git a/src/dtos/moment.dto.js b/src/dtos/moment.dto.js index 77d001f..13ac790 100644 --- a/src/dtos/moment.dto.js +++ b/src/dtos/moment.dto.js @@ -194,33 +194,56 @@ export const responseFromMyMomentDetail = (moment) => { }; -// 친구의 Moment 목록 조회 DTO -export const responseFromFriendsMoments = (moments) => { - return moments.map(moment => ({ - userId: moment.userId, - momentId: moment.id, - title: moment.title, - status: moment.status, - createdAt: formatDateTime(moment.createdAt), - updatedAt: formatDateTime(moment.updatedAt), - thumbnailUrl: moment.momentContents[0]?.url || null - })); +export const responseFromOtherUserMoments = (moments) => { + if (!Array.isArray(moments)) { + console.error("❌ moments가 배열이 아님:", moments); + return []; + } + + return moments.map(moment => { + if (!moment || typeof moment.id === "undefined") { + console.error("❌ moment.id가 유실됨! 원인 추적 필요:", moment); + return null; + } + + const transformedMoment = { + userId: Number(moment.userId), // ✅ bigint 변환 + momentId: Number(moment.id), // ✅ bigint 변환 + title: moment.title, + date: moment.createdAt ? moment.createdAt.toISOString().split("T")[0] : "날짜 없음", + userName: moment.user?.name ?? "알 수 없음", + likingCount: Number(moment.likingCount ?? 0), + commentCount: Number(moment._count?.comments ?? 0), + thumbnailURL: moment.momentContents?.length > 0 ? moment.momentContents[0].url : null + }; + + return transformedMoment; + }).filter(moment => moment !== null); }; -// 친구의 moment 상세 조회 DTO -export const responseFromFriendMomentDetail = (moment) => { + + + + +// 친구의 Moment 상세 조회 DTO +export const responseFromOtherUserMomentDetail = (moment) => { + if (!moment || !moment.id) { + console.error("잘못된 moment 데이터:", moment); + return null; + } + return { userId: moment.userId, momentId: moment.id, title: moment.title, - status: moment.status, - plannerId: moment.plannerId || null, - createdAt: formatDateTime(moment.createdAt), - updatedAt: formatDateTime(moment.updatedAt), + date: formatDate(moment.createdAt), + plannerId: moment.plannerId ?? null, + createdAt: formatDateTime(moment.createdAt), + updatedAt: formatDateTime(moment.updatedAt), momentContents: moment.momentContents.map(content => ({ sortOrder: content.sortOrder, content: content.content, - url: content.url, + url: content.url ?? null })) }; -}; \ No newline at end of file +}; diff --git a/src/errors.js b/src/errors.js index fc1e10e..2989711 100644 --- a/src/errors.js +++ b/src/errors.js @@ -141,7 +141,7 @@ export class DuplicateLikeMomentError extends Error { statusCode = 409; //Conflict constructor(data) { - const reason = '이미 존재하는 좋아요입니다다.'; + const reason = '이미 존재하는 좋아요입니다.'; super(reason); this.reason = reason; this.data = data; @@ -177,20 +177,19 @@ export class LikeIdMissingError extends Error { statusCode = 400; // Bad Request constructor(data) { - const reason = 'likeId가 요청 데이터에 없습니다'; + const reason = 'likeId가 요청 데이터에 없습니다.'; super(reason); this.reason = reason; this.data = data; } } -//entityId, entityType 또는 userId가 누락 -export class ValidationError extends Error{ +export class EntityValidationError extends Error{ errorCode = "L005"; statusCode = 400; // Bad Request constructor(data) { - const reason = 'entityId, entityType 또는 userId가 누락되었습니다.'; + const reason = 'entityId 또는 entityType가 누락되었습니다.'; super(reason); this.reason = reason; this.data = data; @@ -207,7 +206,7 @@ export class DatabaseError extends Error{ statusCode = 500; // Internal Server Error constructor(data) { - const reason = '데이터베이스 연결에 실패했습니다'; + const reason = '데이터베이스 연결에 실패했습니다.'; super(reason); this.reason = reason; this.data = data; @@ -218,7 +217,7 @@ export class momentIdNotFoundError extends Error { statusCode = 404; // Not Found constructor(data) { - const reason = '존재하지 않는 게시글입니다'; + const reason = '존재하지 않는 게시글입니다.'; super(reason); this.reason = reason; this.data = data; diff --git a/src/index.js b/src/index.js index 109390e..94ae062 100644 --- a/src/index.js +++ b/src/index.js @@ -187,8 +187,8 @@ import { handleDeleteMoment, handleGetMyMoments, handleGetMyMomentDetail, - handleGetFriendsMoments, - handleGetFriendMomentDetail + handleGetOtherUserMoments, + handleGetOtherUserMomentDetail } from "./controllers/moment.controller.js"; app.post("/moments", authenticateJWT, handleCreateMoment); //모먼트 생성 @@ -196,8 +196,8 @@ app.patch("/moments/:momentId", authenticateJWT, handleUpdateMoment); //모먼 app.delete("/moments/:momentId", authenticateJWT, handleDeleteMoment); //모먼트 삭제 app.get("/mypage/moments", authenticateJWT, handleGetMyMoments); //마이페이지에서 나의 moment게시글 목록 조회 app.get("/mypage/moments/:momentId", authenticateJWT, handleGetMyMomentDetail); //마이페이지에서 나의 특정 moment게시물 조회 -app.get("/friends/:friendId/moments", authenticateJWT, handleGetFriendsMoments) //친구페이지 moment게시물 목록 조회 -app.get("/friends/:friendId/moments/momentId", authenticateJWT, handleGetFriendMomentDetail); //친구페이지 특정 moment게시물 조회 +app.get("/users/:userId/moments", authenticateJWT, handleGetOtherUserMoments) //친구페이지 moment게시물 목록 조회 +app.get("/users/:userId/moments/momentId", authenticateJWT, handleGetOtherUserMomentDetail); //친구페이지 특정 moment게시물 조회 diff --git a/src/repositories/moment.repository.js b/src/repositories/moment.repository.js index 8ca9f3e..28f1c56 100644 --- a/src/repositories/moment.repository.js +++ b/src/repositories/moment.repository.js @@ -203,57 +203,60 @@ export const findMyMomentDetail = async (userId, momentId) => { }; -// 친구들의 Moment 목록 조회 (status: public만 조회) -export const findFriendsMoments = async (userId) => { - // 친구 목록 조회 - const friendIds = await prisma.friend.findMany({ - where: { - fromUserId: BigInt(userId), - isAccepted: true, - }, - select: { - toUserId: true, - }, - }); - - const friendUserIds = friendIds.map(friend => friend.toUserId); - - return await prisma.moment.findMany({ - where: { - userId: { in: friendUserIds }, - status: 'public', - }, - include: { - momentContents: true, - }, - orderBy: { - createdAt: 'desc', - }, - }); +export const findOtherUserMoments = async (userId) => { + try { + + const moments = await prisma.moment.findMany({ + where: { userId: BigInt(userId) }, + include: { + user: { select: { name: true } }, + momentContents: { select: { url: true }, take: 1 }, + _count: { select: { comments: true } } + }, + orderBy: { createdAt: "desc" }, + }); + + for (const moment of moments) { + const likesCount = await prisma.like.count({ + where: { + entityId: Number(moment.id), + entityType: "moment", + }, + }); + moment.likingCount = likesCount; + } + + return moments; + } catch (error) { + console.error("[findOtherUserMoments] DB 조회 오류:", error); + throw new Error("Moment 목록 조회 실패"); + } }; -// 친구의 특정 Moment 상세 조회 (status: public만 조회) -export const findFriendMomentDetail = async (userId, momentId) => { - // 친구인지 확인 - const isFriend = await prisma.friend.findFirst({ - where: { - fromUserId: BigInt(userId), - isAccepted: true, - }, - }); - - if (!isFriend) { - throw new Error("친구가 아닌 사용자입니다."); - } - - return await prisma.moment.findFirst({ - where: { - id: BigInt(momentId), - userId: isFriend.toUserId, - status: 'public', - }, - include: { - momentContents: true, - }, - }); -}; \ No newline at end of file + + + + +// 특정 사용자의 특정 Moment 상세 조회 +export const findOtherUserMomentDetail = async (userId, momentId) => { + try { + console.log(`[findOtherUserMomentDetail] API 호출됨! userId: ${userId}, momentId: ${momentId}`); + + const moment = await prisma.moment.findUnique({ + where: { id: BigInt(momentId) }, + include: { + momentContents: true, + planner: true + } + }); + + if (!moment) { + throw new Error("Moment를 찾을 수 없습니다."); + } + + return moment; + } catch (error) { + console.error("[findOtherUserMomentDetail] DB 조회 오류:", error.message); + throw error; + } +}; diff --git a/src/services/comment.service.js b/src/services/comment.service.js index ef9f504..02734a6 100644 --- a/src/services/comment.service.js +++ b/src/services/comment.service.js @@ -17,10 +17,6 @@ try { const momentExists = await prisma.moment.findUnique({ where: { id: data.momentId }, }); - - if (!data.userId) { - throw new Error("userId가 요청되지 않았습니다."); - } if (!momentExists) { throw new momentIdNotFoundError(data); } diff --git a/src/services/like.service.js b/src/services/like.service.js index ac6b1e7..cd2a1fa 100644 --- a/src/services/like.service.js +++ b/src/services/like.service.js @@ -1,5 +1,5 @@ import { - ValidationError, + EntityValidationError, DuplicateLikeMomentError, momentIdNotFoundError, LikeIdNotExistError, @@ -25,7 +25,7 @@ export const likeMoment = async (data) => { try { // 입력값 검증 if (!data.entityId || !data.entityType || !data.userId) { - throw new ValidationError(data); + throw new EntityValidationError(data); } // 게시글 존재 여부 확인 @@ -56,7 +56,7 @@ export const likeMoment = async (data) => { } catch (error) { // 사용자의 잘못된 요청 - if (error instanceof ValidationError || + if (error instanceof EntityValidationError || error instanceof momentIdNotFoundError || error instanceof DuplicateLikeMomentError) { throw error; diff --git a/src/services/moment.service.js b/src/services/moment.service.js index 1df5ffa..fcf6755 100644 --- a/src/services/moment.service.js +++ b/src/services/moment.service.js @@ -4,8 +4,8 @@ import { deleteMomentFromDB, findMyMoments, findMyMomentDetail, - findFriendsMoments, - findFriendMomentDetail + findOtherUserMoments, + findOtherUserMomentDetail } from "../repositories/moment.repository.js"; import { @@ -13,8 +13,8 @@ import { responseFromUpdateMoment, responseFromMyMoments, responseFromMyMomentDetail, - responseFromFriendsMoments, - responseFromFriendMomentDetail + responseFromOtherUserMoments, + responseFromOtherUserMomentDetail } from "../dtos/moment.dto.js"; import { @@ -177,33 +177,54 @@ export const getMyMomentDetail = async (userId, momentId) => { }; - -export const getFriendsMoments = async (userId) => { +export const getOtherUserMoments = async (userId) => { try { - const friendsMoments = await findFriendsMoments(userId); - - if (!friendsMoments) { - throw new Error("친구의 Moment 목록 조회에 실패했습니다."); + // 인증되지 않은 사용자 처리 + if (!userId) { + throw new UnauthorizedAccessError(); } - return responseFromFriendsMoments(friendsMoments); + const otherUsersMoments = await findOtherUserMoments(userId); + + return responseFromOtherUserMoments(otherUsersMoments); } catch (error) { - console.error("친구의 Moment 목록 조회 중 오류 발생:", error.message); - throw new Error("친구의 Moment 목록 조회에 실패했습니다. 다시 시도해주세요."); + console.error("다른사람의 Moment 목록 조회 중 오류 발생:", error); + + if (error instanceof UnauthorizedAccessError) { + throw error; + } + + // 기타 예상치 못한 오류는 서버 오류로 처리 + throw new MomentServerError(); } }; -export const getFriendMomentDetail = async (userId, momentId) => { + +export const getOtherUserMomentDetail = async (userId, momentId) => { try { - const friendMomentDetail = await findFriendMomentDetail(userId, momentId); + // 유효하지 않은 momentId 체크 + if (isNaN(momentId) || !Number.isInteger(Number(momentId))) { + throw new InvalidMomentIdError(momentId); + } + + const otherUserMomentDetail = await findOtherUserMomentDetail(userId, BigInt(momentId)); - if (!friendMomentDetail) { - throw new Error("친구의 Moment 상세 조회에 실패했습니다."); + // 존재하지 않는 momentId 체크 + if (!otherUserMomentDetail) { + throw new MomentNotFoundError(momentId); } - return responseFromFriendMomentDetail(friendMomentDetail); + return responseFromOtherUserMomentDetail(otherUserMomentDetail); } catch (error) { console.error("친구의 Moment 상세 조회 중 오류 발생:", error.message); - throw new Error("친구의 Moment 상세 조회에 실패했습니다. 다시 시도해주세요."); + + // 존재하지 않는 moment 에러 + if (error instanceof MomentNotFoundError || error instanceof InvalidMomentIdError) { + throw error; + } + + // 기타 예상치 못한 오류는 서버 오류로 처리 + throw new MomentServerError("다른 사용자의의 Moment 상세 조회에 실패했습니다. 다시 시도해주세요.", { error }); } }; +