diff --git a/app.js b/app.js index 0fd3e42d11a9875ac5397049f08d329b161eedc4..2897b98d5444dfa081660e44c5a819b7ffdb59c2 100644 --- a/app.js +++ b/app.js @@ -10,6 +10,7 @@ dotenv.config(); const meetingRouter = require('./routes/meeting'); const participantRouter = require('./routes/participant'); +const myScheduleRouter = require('./routes/mySchedule'); const { sequelize } = require('./models'); const app = express(); @@ -50,6 +51,7 @@ app.use( app.use('/meetings', meetingRouter); app.use('/meetings/:meetingId/participants', participantRouter); +app.use('/meetings/:meetingId/my/schedules', myScheduleRouter); app.use((req, res, next) => { const error = new Error(`There is no router. ${req.method} ${req.url}`); diff --git a/controllers/schedule.js b/controllers/schedule.js new file mode 100644 index 0000000000000000000000000000000000000000..56067f5d0b13da499397876b33fe0b0da2c6a18d --- /dev/null +++ b/controllers/schedule.js @@ -0,0 +1,41 @@ +const { Schedule, sequelize } = require('../models'); +const { getLoggedInParticipantId } = require('../middlewares/auth'); +const SchedulesResponse = require('../dto/response/schedulesResponse'); +const { createScheduleAlreadyExistError } = require('../errors/scheduleErrors'); + +async function validateScheduleNotExist(participantId) { + const numOfSchedules = await Schedule.count({ + where: { + ParticipantId: participantId, + }, + }); + if (numOfSchedules > 0) { + throw createScheduleAlreadyExistError(); + } +} + +exports.createMySchedules = async (req, res, next) => { + const participantId = getLoggedInParticipantId(req, res, next); + const { availableSchedules } = req.body; + try { + await validateScheduleNotExist(participantId); + + const schedules = await sequelize.transaction(async (transaction) => + Promise.all( + availableSchedules.map((availableSchedule) => + Schedule.create( + { + availableDate: availableSchedule.availableDate, + availableTimes: availableSchedule.availableTimes, + ParticipantId: participantId, + }, + { transaction }, + ), + ), + ), + ); + return res.json(SchedulesResponse.from(schedules)); + } catch (error) { + return next(error); + } +}; diff --git a/dto/response/schedulesResponse.js b/dto/response/schedulesResponse.js new file mode 100644 index 0000000000000000000000000000000000000000..db96a75f85e9c0048b1ccf1de9bc9c7f943f3a1c --- /dev/null +++ b/dto/response/schedulesResponse.js @@ -0,0 +1,15 @@ +const ScheduleResponse = require('./scheduleResponse'); + +class SchedulesResponse { + constructor(schedules) { + this.schedules = schedules; + } + + static from(schedules) { + return new SchedulesResponse( + schedules.map((schedule) => ScheduleResponse.from(schedule)), + ); + } +} + +module.exports = SchedulesResponse; diff --git a/errors/scheduleErrors.js b/errors/scheduleErrors.js new file mode 100644 index 0000000000000000000000000000000000000000..29ab8f8d043fdc5734a12169d8096a23bd6dd177 --- /dev/null +++ b/errors/scheduleErrors.js @@ -0,0 +1,7 @@ +exports.createScheduleAlreadyExistError = () => { + const error = new Error( + '기존에 저장한 스케줄이 존재합니다. 기존 스케줄 데이터를 삭제한 후 다시 시도하거나, 수정하기 API를 사용해주세요.', + ); + error.status = 409; + return error; +}; diff --git a/middlewares/auth.js b/middlewares/auth.js new file mode 100644 index 0000000000000000000000000000000000000000..81884a2752c8824b12b69bfbf554fb61498c089a --- /dev/null +++ b/middlewares/auth.js @@ -0,0 +1,28 @@ +function parseParticipantData(req, res, next) { + let participantData = null; + if (req.signedCookies.participantData) { + participantData = JSON.parse(req.signedCookies.participantData); + } + if (!participantData) { + const error = new Error('인증 권한이 없습니다.'); + error.status = 401; + return next(error); + } + return participantData; +} + +exports.isAuthenticated = (req, res, next) => { + const participantData = parseParticipantData(req); + if (participantData.meetingId !== req.params.meetingId) { + const error = new Error('접근 권한이 없습니다.'); + error.status = 401; + next(error); + return; + } + next(); +}; + +exports.getLoggedInParticipantId = (req, res, next) => { + const participantData = parseParticipantData(req, res, next); + return participantData?.participantId; +}; diff --git a/middlewares/index.js b/middlewares/index.js deleted file mode 100644 index 27afea007237bd0628d988f5599ec83906b6998c..0000000000000000000000000000000000000000 --- a/middlewares/index.js +++ /dev/null @@ -1,13 +0,0 @@ -exports.isAuthenticated = (req, res, next) => { - let participantData = null; - if (req.signedCookies.participantData) { - participantData = JSON.parse(req.signedCookies.participantData); - } - if (!participantData || participantData.meetingId !== req.params.meetingId) { - const error = new Error('접근 권한이 없습니다.'); - error.status = 401; - next(error); - return; - } - next(); -}; diff --git a/routes/meeting.js b/routes/meeting.js index 7763ca50e73f19460992430c8fb9b9337005eaeb..956df300ce4eb0d0b4a4444bee35f3c0a6419f9b 100644 --- a/routes/meeting.js +++ b/routes/meeting.js @@ -1,5 +1,5 @@ const express = require('express'); -const { isAuthenticated } = require('../middlewares/index'); +const { isAuthenticated } = require('../middlewares/auth'); const { createMeeting, entry, diff --git a/routes/mySchedule.js b/routes/mySchedule.js new file mode 100644 index 0000000000000000000000000000000000000000..20991dbdd65cf1833be185e2795e291d5de0d83b --- /dev/null +++ b/routes/mySchedule.js @@ -0,0 +1,9 @@ +const express = require('express'); +const { isAuthenticated } = require('../middlewares/auth'); +const { createMySchedules } = require('../controllers/schedule'); + +const router = express.Router({ mergeParams: true }); + +router.post('/bulk', isAuthenticated, createMySchedules); + +module.exports = router;