From cf97d0dd902ef49b8d298d4efdc8f18f58f156e2 Mon Sep 17 00:00:00 2001 From: Ranindya Paramitha <23520019@std.stei.itb.ac.id> Date: Mon, 22 Mar 2021 10:47:35 +0000 Subject: [PATCH] #71 Feature/hook generator class meetings and attendances --- backend/docs/CourseClass.md | 20 ++++++++- backend/src/controllers/courseclass.js | 10 +++-- backend/src/hooks/course-class.js | 18 ++++++++ backend/src/hooks/study-plan.js | 26 ++++++++++- backend/src/index.js | 2 +- .../src/test/courseclass.controller.test.js | 17 ++++++- backend/src/util/db/course-class.js | 15 ++++++- backend/src/util/hook.js | 45 ++++++++++++++++++- 8 files changed, 139 insertions(+), 14 deletions(-) create mode 100644 backend/src/hooks/course-class.js diff --git a/backend/docs/CourseClass.md b/backend/docs/CourseClass.md index cebb08dc..0e5d59c6 100644 --- a/backend/docs/CourseClass.md +++ b/backend/docs/CourseClass.md @@ -139,7 +139,14 @@ "participantCount": 20, "semester": 2, "status": "OPEN", - "startYear": 2030 + "startYear": 2030, + "courseClassDefaultSchedules" : [ + { + "day": "MONDAY", + "start": "13:00:00", + "end": "15:00:00" + } + ] } ``` @@ -154,6 +161,17 @@ "participantCount": 20, "semester": "2", "status": "OPEN", + "courseClassDefaultSchedules": [ + { + "id": "6d5889e5-219b-4ab2-ad51-5a054b125280", + "day": "MONDAY", + "start": "13:00:00", + "end": "15:00:00", + "courseClassId": "a24a7b51-b705-49ea-85fe-e5f9df3f8e97", + "updatedAt": "2021-03-19T19:12:31.997Z", + "createdAt": "2021-03-19T19:12:31.997Z" + } + ], "updatedAt": "2021-03-02T07:12:41.065Z", "createdAt": "2021-03-02T07:12:41.065Z" } diff --git a/backend/src/controllers/courseclass.js b/backend/src/controllers/courseclass.js index 5fe68f8a..1f015696 100644 --- a/backend/src/controllers/courseclass.js +++ b/backend/src/controllers/courseclass.js @@ -1,8 +1,8 @@ 'use strict'; const { handleRequestWithInvalidRequestBody } = require('../util/common'); -const { - getCourseClass, - createCourseClass +const { + getCourseClass, + createCourseClass } = require('../util/db/course-class'); exports.getCourseClassData = async(req, res) => { @@ -48,6 +48,7 @@ exports.createCourseClassData = async(req, res) => { participantCount, semester, status, + courseClassDefaultSchedules } = req.body; const newCourseClass = { @@ -57,7 +58,8 @@ exports.createCourseClassData = async(req, res) => { capacity, participantCount, semester, - status + status, + courseClassDefaultSchedules }; try { diff --git a/backend/src/hooks/course-class.js b/backend/src/hooks/course-class.js new file mode 100644 index 00000000..632744ab --- /dev/null +++ b/backend/src/hooks/course-class.js @@ -0,0 +1,18 @@ +const { + CourseClass, +} = require('../models/index'); + +const { + deleteCurrentMeetings +} = require('../util/hook'); + +const { generateCourseClassMeetings } = require('../util/common'); + +CourseClass.afterCreate(async courseClass => { + await generateCourseClassMeetings(courseClass); +}); + +CourseClass.afterUpdate(async courseClass => { + await deleteCurrentMeetings(courseClass); + await generateCourseClassMeetings(courseClass); +}); diff --git a/backend/src/hooks/study-plan.js b/backend/src/hooks/study-plan.js index 78b0f858..417ce315 100644 --- a/backend/src/hooks/study-plan.js +++ b/backend/src/hooks/study-plan.js @@ -1,7 +1,16 @@ const { StudyPlan, } = require('../models/index'); -const { calculateTotalCredits } = require('../util/hook'); + +const { + StudyPlanStatusEnum, +} = require('../enums/index'); + +const { + calculateTotalCredits, + deleteCurrentMeetingAttendances +} = require('../util/hook'); +const { generateCourseClassMeetingAttendances } = require('../util/common'); StudyPlan.beforeCreate(async studyPlan => { studyPlan.creditsTotal = await calculateTotalCredits(studyPlan.studyPlanCourses); @@ -9,4 +18,17 @@ StudyPlan.beforeCreate(async studyPlan => { StudyPlan.beforeUpdate(async studyPlan => { studyPlan.creditsTotal = await calculateTotalCredits(studyPlan.studyPlanCourses); -}); \ No newline at end of file +}); + +StudyPlan.afterCreate(async studyPlan => { + if (studyPlan.status === StudyPlanStatusEnum.FINAL){ + await generateCourseClassMeetingAttendances(studyPlan); + } +}); + +StudyPlan.afterUpdate(async studyPlan => { + if (studyPlan.status === StudyPlanStatusEnum.FINAL) { + await deleteCurrentMeetingAttendances(studyPlan); + await generateCourseClassMeetingAttendances(studyPlan); + } +}); diff --git a/backend/src/index.js b/backend/src/index.js index ab450826..1a5ccbfe 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -18,7 +18,7 @@ const courseRouter = require('./routes/course'); const studyPlanRouter = require('./routes/study-plan'); require('./hooks/study-plan'); - +require('./hooks/course-class'); app.use(cors()); app.use(express.json()); diff --git a/backend/src/test/courseclass.controller.test.js b/backend/src/test/courseclass.controller.test.js index 6b39abaa..b4e82b71 100644 --- a/backend/src/test/courseclass.controller.test.js +++ b/backend/src/test/courseclass.controller.test.js @@ -6,7 +6,10 @@ const { Lecturer } = require('../models/index'); -const { EndpointEnum } = require('../enums/index'); +const { + EndpointEnum, + DayEnum +} = require('../enums/index'); let chai = require('chai'); let chaiHttp = require('chai-http'); @@ -25,6 +28,8 @@ let COURSE_CODE = "IF2036"; let COURSE_NAME = "Rekayasa Perangkat Lunak"; let DUMMY_ID = '57e19842-d712-45fd-9068-04cde6bf41f3'; let INVALID_ID = '57e19842-d712-45fd-9068-04cde6bf41f'; +let START_TIME = '13:00:00'; +let END_TIME = '15:00:00'; const COURSE_CLASS_ENDPOINT = '/course-class'; @@ -185,7 +190,14 @@ describe('Course Class Test', () => { "participantCount": 20, "semester": "2", "status": STATUS, - "startYear": START_YEAR + "startYear": START_YEAR, + "courseClassDefaultSchedules" : [ + { + "day": DayEnum.MONDAY.name, + "start": START_TIME, + "end": END_TIME + } + ] }; chai.request(server) @@ -201,6 +213,7 @@ describe('Course Class Test', () => { res.body.should.have.property('semester').deep.equal(requestBody.semester); res.body.should.have.property('status').deep.equal(requestBody.status); res.body.should.have.property('startYear').deep.equal(requestBody.startYear); + res.body.should.have.property('courseClassDefaultSchedules').to.not.equal(null); res.body.should.have.property('updatedAt').to.not.equal(null); res.body.should.have.property('createdAt').to.not.equal(null); done(); diff --git a/backend/src/util/db/course-class.js b/backend/src/util/db/course-class.js index f4308955..8d5e0021 100644 --- a/backend/src/util/db/course-class.js +++ b/backend/src/util/db/course-class.js @@ -4,7 +4,8 @@ const { Course, Major, Faculty, - Lecturer + Lecturer, + CourseClassDefaultSchedule } = require('../../models/index'); const { @@ -56,7 +57,17 @@ const getCourseClass = async(req, getMany) =>{ const createCourseClass = async(data) => { try { - const courseClass = await CourseClass.create(data); + const courseClass = await CourseClass.create( + data, + { + include: [ + { + model: CourseClassDefaultSchedule, + as: 'courseClassDefaultSchedules', + } + ] + } + ); if (courseClass) return courseClass; else throw new NotExistError(); diff --git a/backend/src/util/hook.js b/backend/src/util/hook.js index 02545e03..c9cd479e 100644 --- a/backend/src/util/hook.js +++ b/backend/src/util/hook.js @@ -1,7 +1,11 @@ +const { Op } = require("sequelize"); 'use strict'; const { Course, - CourseClass + CourseClass, + CourseClassMeeting, + StudyPlanCourse, + CourseClassMeetingAttendance, } = require('../models/index'); const calculateTotalCredits = async (studyPlanCourses) => { @@ -20,6 +24,43 @@ const calculateTotalCredits = async (studyPlanCourses) => { return totalCredits; }; +const deleteCurrentMeetings = async (courseClass) => { + await CourseClassMeeting.destroy({ + where: { + courseClassId: courseClass.id + } + }); +}; + +const deleteCurrentMeetingAttendances = async (studyPlan) => { + const studyPlanCourses = await StudyPlanCourse.findAll({ + where: { + studyPlanId: studyPlan.id + } + }); + + for (let i = 0; i < studyPlanCourses.length; i++) { + const meetings = await CourseClassMeeting.findAll({ + where: { + courseClassId: studyPlanCourses[i].courseClassId + } + }); + + const meetingIds = meetings.map(meet => meet.id); + + await CourseClassMeetingAttendance.destroy({ + where : { + courseClassMeetingId: { + [Op.or]: meetingIds + }, + studentId: studyPlan.studentId, + } + }); + } +}; + module.exports = { - calculateTotalCredits + calculateTotalCredits, + deleteCurrentMeetings, + deleteCurrentMeetingAttendances }; -- GitLab