diff --git a/src/repositories/letter.repository.js b/src/repositories/letter.repository.js index c695160..249ae6a 100644 --- a/src/repositories/letter.repository.js +++ b/src/repositories/letter.repository.js @@ -467,4 +467,112 @@ export const selectQueuedLetter = async () => { }) return letter; -} \ No newline at end of file +} + +// 세션별 편지 개수 조회 +export const countLettersBySessionIdAndUserId = async ({ sessionId, userId, letterType }) => { + return await prisma.letter.count({ + where: { + letterType, + sessionId: sessionId, + OR: [ + { receiverUserId: userId }, + { senderUserId: userId } + ] + } + }); +}; + +// 세션별 읽지 않은 편지 개수 조회 +export const countUnreadLettersBySessionIdAndUserId = async ({ sessionId, userId, letterType }) => { + return await prisma.letter.count({ + where: { + letterType, + sessionId: sessionId, + receiverUserId: userId, + readAt: null, + } + }); +}; + +// 세션별 받은 편지 조회 +export const findReceivedLettersBySessionIdAndUserId = async ({ sessionId, userId, letterType }) => { + return await prisma.letter.findMany({ + where: { + receiverUserId: userId, + sessionId: sessionId, + letterType, + }, + orderBy: [{ deliveredAt: "desc" }, { createdAt: "desc" }], + select: { + id: true, + title: true, + deliveredAt: true, + readAt: true, + createdAt: true, + question: { + select: { + content: true + } + }, + design: { + select: { + paper: { + select: { + id: true, + color: true, + } + }, + stamp: { + select: { + id: true, + name: true, + assetUrl: true + } + }, + }, + }, + }, + }); +}; + +// 세션별 보낸 편지 조회 +export const findSentLettersBySessionIdAndUserId = async ({ sessionId, userId, letterType }) => { + return await prisma.letter.findMany({ + where: { + senderUserId: userId, + sessionId: sessionId, + letterType, + }, + orderBy: [{ deliveredAt: "desc" }, { createdAt: "desc" }], + select: { + id: true, + title: true, + deliveredAt: true, + readAt: true, + createdAt: true, + question: { + select: { + content: true + } + }, + design: { + select: { + paper: { + select: { + id: true, + color: true, + } + }, + stamp: { + select: { + id: true, + name: true, + assetUrl: true + } + }, + }, + }, + }, + }); +}; \ No newline at end of file diff --git a/src/repositories/session.repository.js b/src/repositories/session.repository.js index 86af207..01ef6f5 100644 --- a/src/repositories/session.repository.js +++ b/src/repositories/session.repository.js @@ -202,3 +202,24 @@ export const countMatchingSessionByUserId = async (userId) => { return count; }; + +// 세션 ID와 사용자 ID로 세션 조회 (참가자 포함) +export const findMatchingSessionBySessionIdAndUserId = async ({ sessionId, userId }) => { + return await prisma.matchingSession.findFirst({ + where: { + id: sessionId, + participants: { + some: { + userId: userId + } + } + }, + include: { + participants: { + select: { + userId: true + } + } + } + }); +}; \ No newline at end of file diff --git a/src/repositories/user.repository.js b/src/repositories/user.repository.js index 3b6f051..1583579 100644 --- a/src/repositories/user.repository.js +++ b/src/repositories/user.repository.js @@ -591,6 +591,11 @@ export const findSelfLetters = async ({ userId, letterType }) => { createdAt: true, deliveredAt: true, questionId: true, + question: { + select: { + content: true + } + }, design: { select: { paperId: true, diff --git a/src/services/mailbox.service.js b/src/services/mailbox.service.js index 1e96796..0f17cf4 100644 --- a/src/services/mailbox.service.js +++ b/src/services/mailbox.service.js @@ -6,8 +6,15 @@ import { import { LETTER_TYPE_ANON, LETTER_TYPE_SELF, makePreview } from "../utils/user.util.js"; import { findFriendById } from "../repositories/friend.repository.js"; import { NotFriendError } from "../errors/friend.error.js"; -import { getFriendLetters, getMyLettersWithFriend } from "../repositories/letter.repository.js"; -import { prisma } from "../configs/db.config.js"; +import { + getFriendLetters, + getMyLettersWithFriend, + countLettersBySessionIdAndUserId, + countUnreadLettersBySessionIdAndUserId, + findReceivedLettersBySessionIdAndUserId, + findSentLettersBySessionIdAndUserId, +} from "../repositories/letter.repository.js"; +import { findMatchingSessionBySessionIdAndUserId } from "../repositories/session.repository.js"; import { MailboxInvalidSessionIdError } from "../errors/mailbox.error.js"; // ------------------------------ @@ -62,15 +69,10 @@ export const getAnonymousThreads = async (userId) => { // 각 세션별 편지 개수 조회 (sessionId 기준, 개별 조회) const letterCounts = await Promise.all( sessionIds.map(async (sessionId) => { - const count = await prisma.letter.count({ - where: { - letterType: LETTER_TYPE_ANON, - sessionId: sessionId, - OR: [ - { receiverUserId: userId }, - { senderUserId: userId } - ] - } + const count = await countLettersBySessionIdAndUserId({ + sessionId, + userId, + letterType: LETTER_TYPE_ANON, }); return [sessionId, count]; }) @@ -80,13 +82,10 @@ export const getAnonymousThreads = async (userId) => { // 각 세션별 읽지 않은 편지 체크 (받은 편지만 체크) const unreadChecks = await Promise.all( sessionIds.map(async (sessionId) => { - const unreadCount = await prisma.letter.count({ - where: { - letterType: LETTER_TYPE_ANON, - sessionId: sessionId, - receiverUserId: userId, - readAt: null, // 읽지 않은 편지 - } + const unreadCount = await countUnreadLettersBySessionIdAndUserId({ + sessionId, + userId, + letterType: LETTER_TYPE_ANON, }); return [sessionId, unreadCount > 0]; // 하나라도 있으면 true }) @@ -129,22 +128,9 @@ export const getAnonymousThreadLetters = async (userId, sessionIdRaw) => { const sessionId = Number(sessionIdRaw); // 세션 참가자 조회하여 권한 확인 - const session = await prisma.matchingSession.findFirst({ - where: { - id: sessionId, - participants: { - some: { - userId: userId // 현재 사용자가 참가자인 세션만 - } - } - }, - include: { - participants: { - select: { - userId: true - } - } - } + const session = await findMatchingSessionBySessionIdAndUserId({ + sessionId, + userId, }); if (!session) { @@ -152,81 +138,17 @@ export const getAnonymousThreadLetters = async (userId, sessionIdRaw) => { } // 받은 편지 조회 (sessionId로 필터링) - const receivedLetters = await prisma.letter.findMany({ - where: { - receiverUserId: userId, - sessionId: sessionId, - letterType: LETTER_TYPE_ANON, - }, - orderBy: [{ deliveredAt: "desc" }, { createdAt: "desc" }], - select: { - id: true, - title: true, - deliveredAt: true, - readAt: true, - createdAt: true, - question: { - select: { - content: true - } - }, - design: { - select: { - paper: { - select: { - id: true, - color: true, - } - }, - stamp: { - select: { - id: true, - name: true, - assetUrl: true - } - }, - }, - }, - }, + const receivedLetters = await findReceivedLettersBySessionIdAndUserId({ + sessionId, + userId, + letterType: LETTER_TYPE_ANON, }); // 보낸 편지 조회 (sessionId로 필터링) - const sentLetters = await prisma.letter.findMany({ - where: { - senderUserId: userId, - sessionId: sessionId, - letterType: LETTER_TYPE_ANON, - }, - orderBy: [{ deliveredAt: "desc" }, { createdAt: "desc" }], - select: { - id: true, - title: true, - deliveredAt: true, - readAt: true, - createdAt: true, - question: { - select: { - content: true - } - }, - design: { - select: { - paper: { - select: { - id: true, - color: true, - } - }, - stamp: { - select: { - id: true, - name: true, - assetUrl: true - } - }, - }, - }, - }, + const sentLetters = await findSentLettersBySessionIdAndUserId({ + sessionId, + userId, + letterType: LETTER_TYPE_ANON, }); // firstQuestion: 받은 편지의 첫 번째 질문 우선, 없으면 보낸 편지의 첫 번째 질문 @@ -296,7 +218,7 @@ export const getSelfMailbox = async (userId) => { id: l.id, title: l.title, createdAt: l.createdAt ?? null, - questionId: l.questionId ?? null, + questionTitle: l.question?.content ?? null, paperId: l.design?.paperId ?? null, stampId: l.design?.stampId ?? null, stampUrl: l.design?.stamp?.assetUrl ?? null, diff --git a/src/swagger/mailbox.swagger.js b/src/swagger/mailbox.swagger.js index 44a1ee3..3b1ffa5 100644 --- a/src/swagger/mailbox.swagger.js +++ b/src/swagger/mailbox.swagger.js @@ -522,9 +522,10 @@ * type: string * format: date-time * nullable: true - * questionId: - * type: integer + * questionTitle: + * type: string * nullable: true + * description: 질문 내용 * paperId: * type: integer * nullable: true