diff --git a/src/controllers/alarm.controller.js b/src/controllers/alarm.controller.js index 8cefa35..ff6c564 100644 --- a/src/controllers/alarm.controller.js +++ b/src/controllers/alarm.controller.js @@ -1,7 +1,7 @@ -import { BadRequestError } from "../errors/custom.error.js"; +import { BadRequestError, NotFoundError } from "../errors/custom.error.js"; import * as AlarmService from "../services/alarm.service.js"; -// ✅ GET /v1/api/alarm - 알람 목록 조회 +// 알람 목록 조회 export const handleAlarmList = async (req, res) => { const userId = req.user.id; // req.user는 로그인 미들웨어에서 설정됨 @@ -17,9 +17,8 @@ export const handleAlarmList = async (req, res) => { return res.success(result, "알림 목록 조회 성공"); }; -// ✅ DELETE /v1/api/alarm/:alarmId - 개별 알림 삭제 +// 개별 알림 삭제 export const handleAlarmDelete = async (req, res) => { - // userId (임시 - 로그인 미들웨어 생성 후 req.user.id 사용) const userId = req.user.id; // alarmId 파라미터 파싱 및 검증 @@ -42,7 +41,7 @@ export const handleAlarmDelete = async (req, res) => { return res.success(null, "개별 알림 삭제 성공"); }; -// ✅ DELETE /v1/api/alarm - 전체 알림 삭제 +// 전체 알림 삭제 export const handleAlarmDeleteAll = async (req, res) => { const userId = req.user.id; @@ -53,14 +52,18 @@ export const handleAlarmDeleteAll = async (req, res) => { return res.success(null, "알림 전체 삭제 성공"); }; -// ✅ PATCH /v1/api/alarm/deadline - 최종 마감 알림 수정 +// 최종 마감 알림 수정 export const handleAlarmUpdateDeadline = async (req, res) => { const userId = req.user.id; const deadlineAlarm = req.body.deadlineAlarm; + if (!userId) { + throw new NotFoundError("USER_NOT_FOUND", "사용자를 찾을 수 없습니다."); + } + // 400 에러: 파라미터가 숫자가 아닌 경우 if (!deadlineAlarm || isNaN(parseInt(deadlineAlarm))) { - throw new BadRequestError("INVALID_BODY", "Body의 데이터 형식이 다를 경우"); + throw new BadRequestError("INVALID_BODY", "Body의 deadlineAlarm 데이터는 number 형식으로 보내야합니다."); } const parsedDeadlineAlarm = parseInt(deadlineAlarm); @@ -77,9 +80,13 @@ export const handleAlarmUpdateTask = async (req, res) => { const userId = req.user.id; const taskAlarm = req.body.taskAlarm; + + if (!userId) { + throw new NotFoundError("USER_NOT_FOUND", "사용자를 찾을 수 없습니다."); + } // 400 에러: 파라미터가 숫자가 아닌 경우 if (!taskAlarm || isNaN(parseInt(taskAlarm))) { - throw new BadRequestError("INVALID_BODY", "Body의 데이터 형식이 다를 경우"); + throw new BadRequestError("INVALID_BODY", "Body의 taskAlarm 데이터는 number 형식으로 보내야합니다."); } const parsedTaskAlarm = parseInt(taskAlarm); @@ -91,14 +98,29 @@ export const handleAlarmUpdateTask = async (req, res) => { return res.success(result, "과제 마감 시간의 알림 전송 시간을 변경했습니다."); }; -// ✅ 과제 알림 여부 설정 +// 과제 알림 여부 설정 export const handleAlarmUpdateTaskStatus = async (req, res) => { const userId = req.user.id; const taskId = req.params.taskId; const isAlarm = req.body.isAlarm; + if (!userId) { + throw new NotFoundError("USER_NOT_FOUND", "사용자를 찾을 수 없습니다."); + } + + if (!taskId) { + throw new BadRequestError("INVALID_PARAMETER", "요청하신 taskId가 존재하지 않습니다."); + } + if (isNaN(parseInt(taskId))) { + throw new BadRequestError("INVALID_PARAMETER", "params의 taskId는 숫자로 보내야합니다."); + } + if (typeof isAlarm !== "boolean") { + throw new BadRequestError("INVALID_BODY", "Body의 isAlarm 데이터는 Boolean 형식으로 보내야합니다."); + } + const parsedTaskId = parseInt(taskId); + // Service 호출 const result = await AlarmService.updateTaskAlarmStatus( userId, @@ -110,12 +132,26 @@ export const handleAlarmUpdateTaskStatus = async (req, res) => { return res.success(result, "과제에 대한 알림 여부를 변경하였습니다.."); }; -// ✅ PATCH /v1/api/alarm/subtask/:subTaskId - subtask 알림 여부 설정 +// subtask 알림 여부 설정 export const handleAlarmUpdateSubtaskStatus = async (req, res) => { const userId = req.user.id; const subTaskId = req.params.subtaskId; const isAlarm = req.body.isAlarm; + if (!userId) { + throw new NotFoundError("USER_NOT_FOUND", "사용자를 찾을 수 없습니다."); + } + + if (!subTaskId) { + throw new BadRequestError("INVALID_PARAMETER", "요청하신 subTaskId가 존재하지 않습니다."); + } + if (isNaN(parseInt(subTaskId))) { + throw new BadRequestError("INVALID_PARAMETER", "params의 subTaskId는 숫자로 보내야합니다."); + } + if (typeof isAlarm !== "boolean") { + throw new BadRequestError("INVALID_BODY", "Body의 isAlarm 데이터는 Boolean 형식으로 보내야합니다."); + } + const parsedSubTaskId = parseInt(subTaskId); // Service 호출 @@ -129,7 +165,7 @@ export const handleAlarmUpdateSubtaskStatus = async (req, res) => { return res.success(result, "세부과제에 대한 알림 여부를 변경하였습니다.."); }; -// ✅ PATCH /v1/api/alarm/read/:alarmId - 알림 읽음 처리 +// 알림 읽음 처리 export const handleAlarmUpdateAlarmReadStatus = async (req, res) => { const userId = req.user.id; const alarmId = req.params.alarmId; @@ -137,6 +173,10 @@ export const handleAlarmUpdateAlarmReadStatus = async (req, res) => { const parsedAlarmId = parseInt(alarmId); + if (!alarmId || isNaN(parseInt(alarmId))) { + throw new BadRequestError("INVALID_PARAMETER", "params는 숫자로 보내야합니다."); + } + // Service 호출 const result = await AlarmService.updateAlarmReadStatus( userId, diff --git a/src/repositories/user.repository.js b/src/repositories/user.repository.js index 27f8f73..dfbc77b 100644 --- a/src/repositories/user.repository.js +++ b/src/repositories/user.repository.js @@ -4,7 +4,7 @@ export const getUserData = async (userId) => { const user = await prisma.user.findUnique({ where: { id: userId }, - include: { folders: true }, + include: { folders: true }, }); return user; @@ -20,6 +20,14 @@ export const updateProfile = async (userId, data) => { profileImage: data.profileImage, }, }); - return updatedUser; -} \ No newline at end of file +} + +//탈퇴한 회원인지 확인 +export const checkDeletedUser = async (userId) => { + const user = await prisma.user.findUnique({ + where: { id: userId }, + select: { id: true, deletedAt: true }, + }); + return user; +} \ No newline at end of file diff --git a/src/services/alarm.service.js b/src/services/alarm.service.js index f7dbdb6..33cd1a1 100644 --- a/src/services/alarm.service.js +++ b/src/services/alarm.service.js @@ -23,6 +23,7 @@ import { BadRequestError, } from "../errors/custom.error.js"; import prisma from "../db.config.js"; +import { checkDeletedUser } from "../repositories/user.repository.js"; export const getAlarms = async (userId, cursor, limit, orderBy, order) => { // 알람 조회 @@ -40,6 +41,15 @@ export const getAlarms = async (userId, cursor, limit, orderBy, order) => { const nextCursor = hasNextPage && data.length > 0 ? data[data.length - 1].id : null; + const user = await checkDeletedUser(userId); + if (user.deletedAt) { + throw new ForbiddenError("USER_DELETED", "탈퇴한 유저는 알림을 조회할 수 없습니다."); + } + + if (!user) { + throw new NotFoundError("USER_NOT_FOUND", "사용자를 찾을 수 없습니다."); + } + // DTO 변환 const responseData = alarmListResponseDto(data); @@ -56,6 +66,21 @@ export const getAlarms = async (userId, cursor, limit, orderBy, order) => { export const deleteAlarm = async (userId, alarmId) => { // 알림 존재 여부 확인 const alarm = await findAlarmById(alarmId); + const user = await checkDeletedUser(userId); + + if (user.deletedAt) { + throw new ForbiddenError( + "USER_DELETED", + "탈퇴한 유저는 알림을 삭제할 수 없습니다." + ); + } + + if (!userId) { + throw new NotFoundError( + "USER_NOT_FOUND", + "사용자를 찾을 수 없습니다." + ); + } if (!alarm) { throw new NotFoundError( @@ -80,6 +105,12 @@ export const deleteAlarm = async (userId, alarmId) => { // 전체 알림 삭제 export const deleteAllAlarms = async (userId) => { + if (!userId) { + throw new NotFoundError( + "USER_NOT_FOUND", + "사용자를 찾을 수 없습니다." + ); + } // 유저의 모든 알림 삭제 await deleteAllAlarmsByUserId(userId); @@ -98,6 +129,11 @@ export const updateDeadline = async (userId, deadlineAlarm) => { // Task 마감 알림 수정 export const updateTask = async (userId, taskAlarm) => { // Task 마감 알림 수정 (Repository 호출) + + if (!userId) { + throw new NotFoundError("USER_NOT_FOUND", "사용자를 찾을 수 없습니다."); + } + const updatedUser = await updateTaskAlarm(userId, taskAlarm); // DTO 변환 @@ -230,6 +266,7 @@ export const updateSubtaskAlarmStatus = async (userId, subTaskId, isAlarm) => { export const updateAlarmReadStatus = async (userId, alarmId, isRead) => { // 알림 존재 여부 확인 const alarm = await findAlarmById(alarmId); + if (!alarm) { throw new NotFoundError("ALARM_NOT_FOUND", "알림을 찾을 수 없습니다."); } @@ -243,7 +280,7 @@ export const updateAlarmReadStatus = async (userId, alarmId, isRead) => { if (typeof isRead !== "boolean") { throw new BadRequestError( "INVALID_BODY", - "Body의 isRead 데이터는 boolean 형식으로 보내야합니다." + "Body의 isRead 데이터는 Boolean 형식으로 보내야합니다." ); }