diff --git a/controllers/meeting.js b/controllers/meeting.js index 27532ee5a66d273bd913ab86566dce2ed7ea2d68..0ab9479914e7be561c4692ded83311f50ba0438b 100644 --- a/controllers/meeting.js +++ b/controllers/meeting.js @@ -1,10 +1,12 @@ const bcrypt = require('bcrypt'); const { Meeting, Participant, Schedule } = require('../models'); +const meetingRepositotry = require('../repository/meeting'); const { createMeetingNotFoundError, createMeetingIsAlreadyClosedError, createPasswordNotMatchedError, createPasswordIsNullError, + createMostConfirmedTimeNotFoundError, } = require('../errors/meetingErrors'); const MeetingResponse = require('../dto/response/meetingResponse'); const MeetingWithParticipantsResponse = require('../dto/response/meetingWithParticipantsResponse'); @@ -175,6 +177,19 @@ exports.getMeetingDetailById = async (req, res, next) => { } }; +exports.getMostConfirmedTime = async (req, res, next) => { + const { purpose } = req.query; + if (!purpose) { + return res.status(400).json({ message: 'Purpose is required' }); + } + try { + const result = await meetingRepositotry.getMostConfirmedTime(purpose); + return res.json(result); + } catch (error) { + return next(error); + } +}; + function validateMeetingIsNotClosed(meeting) { if (meeting.isClosed === true) { throw createMeetingIsAlreadyClosedError(); diff --git a/errors/meetingErrors.js b/errors/meetingErrors.js index 5b1e71f6e24747ef9222b084a60ab23f1fa19c0f..b52602fdbb9a26b64aca065a68418ef837c1c486 100644 --- a/errors/meetingErrors.js +++ b/errors/meetingErrors.js @@ -21,3 +21,11 @@ exports.createPasswordIsNullError = () => { error.status = 400; return error; }; + +exports.createMostConfirmedTimeNotFoundError = () => { + const error = new Error( + '데이터가 충분하지 않아 통계 정보를 찾을 수 없습니다.', + ); + error.status = 404; + return error; +}; diff --git a/repository/meeting.js b/repository/meeting.js new file mode 100644 index 0000000000000000000000000000000000000000..d634c3f7d23040d68ee16b950c3591aba33e1d14 --- /dev/null +++ b/repository/meeting.js @@ -0,0 +1,31 @@ +const Sequelize = require('sequelize'); +const { sequelize } = require('../models/index'); +const { + createMostConfirmedTimeNotFoundError, +} = require('../errors/meetingErrors'); + +exports.getMostConfirmedTime = async (purpose) => { + const query = ` + SELECT EXTRACT(HOUR FROM m.confirmed_time) AS confirmed_time_hour, + COUNT(1) AS confirmed_time_count + FROM meetings m + WHERE m.is_closed + AND m.purpose = :purpose + AND m.confirmed_time IS NOT NULL + GROUP BY confirmed_time_hour + ORDER BY confirmed_time_count DESC; + `; + const params = { + replacements: { purpose }, + type: Sequelize.QueryTypes.SELECT, + plain: true, + }; + const result = await sequelize.query(query, params); + if (!result) { + throw createMostConfirmedTimeNotFoundError(); + } + return { + hour: result.confirmed_time_hour, + count: result.confirmed_time_count, + }; +}; diff --git a/routes/meeting.js b/routes/meeting.js index d32bd4e17c79b693901b85a84a9129417b2df481..4ad462d02083a3e5f04147876ece5543d124d2b6 100644 --- a/routes/meeting.js +++ b/routes/meeting.js @@ -5,6 +5,7 @@ const { entry, getMeetingById, getMeetingDetailById, + getMostConfirmedTime, closeMeeting, confirmTime, } = require('../controllers/meeting'); @@ -13,6 +14,8 @@ const router = express.Router(); router.post('/', createMeeting); +router.get('/most-confirmed-time', getMostConfirmedTime); + router.post('/:meetingId/entry', entry); router.get('/:meetingId', isAuthenticated, getMeetingById);