From 15ad3ac11648dbb72883a734c7b8d67c8cf1b953 Mon Sep 17 00:00:00 2001 From: Krish Suraparaju Date: Thu, 26 Sep 2024 00:17:07 -0400 Subject: [PATCH 1/4] centralized course name admin setting --- client/public/index.html | 4 +-- client/public/manifest.json | 4 +-- .../src/components/navbar/OHQueueHeader.tsx | 6 +++- .../settings/admin/ConfigSettings.tsx | 36 +++++++++++++++++++ client/src/contexts/AdminSettingsContext.tsx | 2 ++ client/src/contexts/QueueDataContext.tsx | 2 +- client/src/services/SettingsService.tsx | 3 ++ server/controllers/home.js | 6 ++-- server/controllers/settings.js | 28 +++++++++++++++ server/package.json | 2 +- server/routes/settings.js | 1 + types/AdminSettings.ts | 1 + 12 files changed, 85 insertions(+), 10 deletions(-) diff --git a/client/public/index.html b/client/public/index.html index 0831608f..3cf1f53d 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -8,7 +8,7 @@ - 15-122 Office Hours Queue + Office Hours Queue diff --git a/client/public/manifest.json b/client/public/manifest.json index fae801c0..95bcb266 100644 --- a/client/public/manifest.json +++ b/client/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "15122 OHQ", - "name": "15-122 Office Hours Queue", + "short_name": "OHQ", + "name": "Office Hours Queue", "icons": [ { "src": "favicon.ico", diff --git a/client/src/components/navbar/OHQueueHeader.tsx b/client/src/components/navbar/OHQueueHeader.tsx index b3ddb642..d227ce4e 100644 --- a/client/src/components/navbar/OHQueueHeader.tsx +++ b/client/src/components/navbar/OHQueueHeader.tsx @@ -2,11 +2,15 @@ import React from 'react'; import { Link, } from '@mui/material'; +import {useContext} from 'react'; +import {AdminSettingsContext} from '../../contexts/AdminSettingsContext'; export default function OHQueueHeader() { + const {adminSettings} = useContext(AdminSettingsContext); + const courseName = adminSettings.courseName; return ( - 15-122 Office Hours Queue + {courseName} Office Hours Queue ); } diff --git a/client/src/components/settings/admin/ConfigSettings.tsx b/client/src/components/settings/admin/ConfigSettings.tsx index 2ead9b49..cc710df1 100644 --- a/client/src/components/settings/admin/ConfigSettings.tsx +++ b/client/src/components/settings/admin/ConfigSettings.tsx @@ -19,17 +19,31 @@ export default function ConfigSettings(props) { const [questionsURL, setQuestionsURL] = useState(''); const [enforceCMUEmail, setEnforceCMUEmail] = useState(true); const [allowCDOverride, setAllowCDOverride] = useState(true); + const [courseName, setCourseName] = useState(''); useEffect(() => { setCurrSem(adminSettings.currSem); setSlackURL(adminSettings.slackURL); setEnforceCMUEmail(adminSettings.enforceCMUEmail); + setCourseName(adminSettings.courseName); }, [adminSettings]); useEffect(() => { setAllowCDOverride(queueData.allowCDOverride); setQuestionsURL(queueData.questionsURL); }, [queueData]); + + const handleUpdateCourseName = (event) => { + event.preventDefault(); + if (courseName === adminSettings.courseName) return; + + SettingsService.updateCourseName( + JSON.stringify({ + courseName: courseName, + }), + ); + }; + const handleUpdateSemester = (event) => { event.preventDefault(); if (currSem === adminSettings.currSem) return; @@ -86,12 +100,34 @@ export default function ConfigSettings(props) { ); }; + return ( Config Settings +
+ + + Course Name: + { + setCourseName(e.target.value); + }} + /> + + + + + +
diff --git a/client/src/contexts/AdminSettingsContext.tsx b/client/src/contexts/AdminSettingsContext.tsx index 7acc4c45..23b716bf 100644 --- a/client/src/contexts/AdminSettingsContext.tsx +++ b/client/src/contexts/AdminSettingsContext.tsx @@ -15,6 +15,7 @@ const AdminSettingsContext = createContext({ currSem: '', slackURL: undefined, enforceCMUEmail: true, + courseName: '', }, setAdminSettings: ((adminSettings: AdminSettings) => {}) as React.Dispatch>, }); @@ -29,6 +30,7 @@ const AdminSettingsContextProvider = ({children}: {children: React.ReactNode}) = currSem: '', slackURL: undefined, enforceCMUEmail: true, + courseName: '', }); // Load admin settings if user is an admin diff --git a/client/src/contexts/QueueDataContext.tsx b/client/src/contexts/QueueDataContext.tsx index 0f782875..54e97c17 100644 --- a/client/src/contexts/QueueDataContext.tsx +++ b/client/src/contexts/QueueDataContext.tsx @@ -21,7 +21,7 @@ const QueueDataContext = createContext({ */ const QueueDataContextProvider = ({children}: {children: React.ReactNode}) => { const [queueData, setQueueData] = useState({ - title: '15-122 Office Hours Queue', + title: 'Office Hours Queue', uninitializedSem: false, queueFrozen: true, allowCDOverride: true, diff --git a/client/src/services/SettingsService.tsx b/client/src/services/SettingsService.tsx index 65289103..c01b8c7b 100644 --- a/client/src/services/SettingsService.tsx +++ b/client/src/services/SettingsService.tsx @@ -48,6 +48,9 @@ class SettingsDataService { }, }); } + updateCourseName(data) { + return http.post('/settings/config/coursename/update', data); + } updateSemester(data) { return http.post('/settings/config/sem/update', data); } diff --git a/server/controllers/home.js b/server/controllers/home.js index 867136d0..85e82724 100644 --- a/server/controllers/home.js +++ b/server/controllers/home.js @@ -74,7 +74,7 @@ function buildQueueData() { let data = { // most important global data - title: "15-122 Office Hours Queue", + title: "Office Hours Queue", uninitializedSem: adminSettings.currSem == null, queueFrozen: queueFrozen, allowCDOverride: adminSettings.allowCDOverride, @@ -516,7 +516,7 @@ exports.post_add_question = function (req, res) { if (!student) { throw new Error('No existing student account with provided andrew ID.'); } - + let allowCDOverride = settings.get_admin_settings().allowCDOverride; // check for cooldown violation if (overrideCooldown && !allowCDOverride) { @@ -893,7 +893,7 @@ exports.post_approve_cooldown_override = function (req, res) { respond_error(req, res, "This request was not made by a TA", 400); return } - + let cooldownAllowed = settings.get_admin_settings().allowCDOverride if (!cooldownAllowed) { respond_error(req, res, "Cooldown Override has been disabled", 400) diff --git a/server/controllers/settings.js b/server/controllers/settings.js index 3a407acb..53325c73 100644 --- a/server/controllers/settings.js +++ b/server/controllers/settings.js @@ -13,6 +13,7 @@ const home = require('./home'); // In production, these should be cleared var fs = require('fs'); const defaultAdminSettings = { + courseName: "", currSem: "S23", slackURL: null, questionsURL: '', @@ -203,6 +204,33 @@ exports.post_update_notifs = function (req, res) { /** ADMIN FUNCTIONS **/ /** Config Settings **/ +exports.post_update_course_name = function (req, res) { + if (!req.user || !req.user.isAdmin) { + respond_error(req, res, "You don't have permissions to perform this operation", 403); + return; + } + + var courseName = req.body.courseName; + // @Review: Any validations needed here (such as empty string)? + if (!courseName) { + respond_error(req, res, "Invalid/missing parameters in request", 400); + return; + } + + if (adminSettings.courseName == courseName) { + respond_success(req, res); + return; + } + + // @Review: Should the courseName be stored in the database? Currently, only + // storing it in the adminSettings.json file. Perhaps could be part of a + // larger medium-sized effort to move all admin settings to a new table in the + // database. + adminSettings.courseName = courseName; + writeAdminSettings(adminSettings); + respond_success(req, res, `Course name updated successfully to ${courseName}`); +} + exports.post_update_semester = function (req, res) { if (!req.user || !req.user.isAdmin) { respond_error(req, res, "You don't have permissions to perform this operation", 403); diff --git a/server/package.json b/server/package.json index f240d445..e1a8ba13 100644 --- a/server/package.json +++ b/server/package.json @@ -1,7 +1,7 @@ { "name": "122q", "version": "1.0.0", - "description": "Office Hours Queue for Carnegie Mellon University's 15-122", + "description": "Office Hours Queue for Carnegie Mellon University courses", "main": "app.js", "scripts": { "start": "nodemon app.js", diff --git a/server/routes/settings.js b/server/routes/settings.js index 26d36bb2..deafd64d 100644 --- a/server/routes/settings.js +++ b/server/routes/settings.js @@ -21,6 +21,7 @@ router.post('/tas/delete', settings.post_delete_ta); router.post('/tas/downloadCSV', settings.post_download_ta_csv); router.post('/tas/uploadCSV', settings.post_upload_ta_csv); +router.post('/config/coursename/update', settings.post_update_course_name); router.post('/config/sem/update', settings.post_update_semester); router.post('/config/slack/update', settings.post_update_slack_url); router.post('/config/questions/update', settings.post_update_questions_url); diff --git a/types/AdminSettings.ts b/types/AdminSettings.ts index cb35a883..82333471 100644 --- a/types/AdminSettings.ts +++ b/types/AdminSettings.ts @@ -5,4 +5,5 @@ export type AdminSettings = { currSem: string, slackURL: string | undefined, enforceCMUEmail: boolean, + courseName: string, } From 4eed0114905469cac704396aeadacc66a798760b Mon Sep 17 00:00:00 2001 From: Jackson Romero Date: Thu, 3 Oct 2024 22:51:51 -0400 Subject: [PATCH 2/4] Update page title and revent default manifest back to 15-122 for SEO --- client/public/index.html | 9 +- client/public/manifest.json | 4 +- server/controllers/home.js | 1559 +++++++++++++++++++---------------- 3 files changed, 853 insertions(+), 719 deletions(-) diff --git a/client/public/index.html b/client/public/index.html index 3cf1f53d..ab11ff9b 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -1,15 +1,12 @@ - + - + - Office Hours Queue + 15-122 Office Hours Queue diff --git a/client/public/manifest.json b/client/public/manifest.json index 95bcb266..4127d8c7 100644 --- a/client/public/manifest.json +++ b/client/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "OHQ", - "name": "Office Hours Queue", + "short_name": "15-122 OHQ", + "name": "15-122 Office Hours Queue", "icons": [ { "src": "favicon.ico", diff --git a/server/controllers/home.js b/server/controllers/home.js index 85e82724..4c679716 100644 --- a/server/controllers/home.js +++ b/server/controllers/home.js @@ -6,7 +6,7 @@ const Sequelize = require('sequelize'); const queue = require('./queue'); const models = require('../models'); const sockets = require('./sockets'); -const waittime = require('./waittimes') +const waittime = require('./waittimes'); const settings = require('./settings'); const notify = require('./notify'); @@ -18,136 +18,140 @@ let queueFrozen = false; const ohq = new queue.OHQueue(); exports.getOHQ = function () { - return ohq; + return ohq; }; /** Helper Functions **/ function respond_error(req, res, message, status) { - res.status(status); - res.json({ message: message }); + res.status(status); + res.json({ message: message }); } function respond(req, res, message, data, status) { - res.status(status); - if (message) { - data['message'] = message; - } - res.json(data); + res.status(status); + if (message) { + data['message'] = message; + } + res.json(data); } /** * Build a studentData object for a given student on the queue */ function buildStudentEntryData(student) { - let studentPos = ohq.getPosition(student.andrewID); //TODO: Should find cheaper way to grab this - let studentEntryData = { - name: student.preferredName, - andrewID: student.andrewID, - location: student.location, - topic: student.topic, - question: student.question, - status: student.status, - isFrozen: student.isFrozen, - message: student.message, - messageBuffer: student.messageBuffer, - position: studentPos, - } - - if (studentEntryData.status == StudentStatus.BEING_HELPED) { - studentEntryData.helpingTAInfo = { - taId: student.taID, - taAndrewID: student.taAndrewID, - taPrefName: student.taPrefName, - taZoomEnabled: student.taZoomEnabled, - taZoomUrl: student.taZoomUrl - } - } + let studentPos = ohq.getPosition(student.andrewID); //TODO: Should find cheaper way to grab this + let studentEntryData = { + name: student.preferredName, + andrewID: student.andrewID, + location: student.location, + topic: student.topic, + question: student.question, + status: student.status, + isFrozen: student.isFrozen, + message: student.message, + messageBuffer: student.messageBuffer, + position: studentPos, + }; + + if (studentEntryData.status == StudentStatus.BEING_HELPED) { + studentEntryData.helpingTAInfo = { + taId: student.taID, + taAndrewID: student.taAndrewID, + taPrefName: student.taPrefName, + taZoomEnabled: student.taZoomEnabled, + taZoomUrl: student.taZoomUrl, + }; + } - return studentEntryData; + return studentEntryData; } /** * Build a queueData object */ function buildQueueData() { - let adminSettings = settings.get_admin_settings(); - - let data = { - // most important global data - title: "Office Hours Queue", - uninitializedSem: adminSettings.currSem == null, - queueFrozen: queueFrozen, - allowCDOverride: adminSettings.allowCDOverride, - - // global stats - numStudents: ohq.size(), - rejoinTime: adminSettings.rejoinTime, - - announcements: announcements, - - questionsURL: adminSettings.questionsURL, - - topics: [], - locations: settings.internal_get_locations(), - tas: [] - }; - - return models.assignment_semester.findAll({ - where: { - sem_id: adminSettings.currSem - }, - order: [['end_date', 'ASC']], - include: models.assignment - }).then((results) => { - let assignments = []; - - for (const assignmentSem of results) { - let assignment = assignmentSem.assignment; - assignments.push({ - assignment_id: assignmentSem.assignment_id, - name: assignment.name, - category: assignment.category, - start_date: assignmentSem.start_date, - end_date: assignmentSem.end_date - }); - } - - data.topics = assignments; - - return models.semester_user.findAll({ - where: { sem_id: adminSettings.currSem, is_ta: 1 }, - include: [ - { - model: models.account, - include: [{ model: models.ta, as: "ta" }], - } - ], - order: [['account', 'preferred_name', 'ASC']] - }) - }).then((results) => { - let tas = []; - - for (const semUser of results) { - let account = semUser.account; - let ta = account.ta; - tas.push({ - ta_id: ta.ta_id, - name: account.name, - preferred_name: account.preferred_name, - email: account.email, - isAdmin: ta.is_admin == 1 - }); - } + let adminSettings = settings.get_admin_settings(); + + let data = { + // most important global data + title: adminSettings.courseName + ' Office Hours Queue', + uninitializedSem: adminSettings.currSem == null, + queueFrozen: queueFrozen, + allowCDOverride: adminSettings.allowCDOverride, + + // global stats + numStudents: ohq.size(), + rejoinTime: adminSettings.rejoinTime, + + announcements: announcements, + + questionsURL: adminSettings.questionsURL, + + topics: [], + locations: settings.internal_get_locations(), + tas: [], + }; + + return models.assignment_semester + .findAll({ + where: { + sem_id: adminSettings.currSem, + }, + order: [['end_date', 'ASC']], + include: models.assignment, + }) + .then((results) => { + let assignments = []; + + for (const assignmentSem of results) { + let assignment = assignmentSem.assignment; + assignments.push({ + assignment_id: assignmentSem.assignment_id, + name: assignment.name, + category: assignment.category, + start_date: assignmentSem.start_date, + end_date: assignmentSem.end_date, + }); + } + + data.topics = assignments; + + return models.semester_user.findAll({ + where: { sem_id: adminSettings.currSem, is_ta: 1 }, + include: [ + { + model: models.account, + include: [{ model: models.ta, as: 'ta' }], + }, + ], + order: [['account', 'preferred_name', 'ASC']], + }); + }) + .then((results) => { + let tas = []; + + for (const semUser of results) { + let account = semUser.account; + let ta = account.ta; + tas.push({ + ta_id: ta.ta_id, + name: account.name, + preferred_name: account.preferred_name, + email: account.email, + isAdmin: ta.is_admin == 1, + }); + } - data.tas = tas; + data.tas = tas; - return waittime.wait_time_data(); - }).then((waitTimeData) => { - data.numUnhelped = waitTimeData.numUnhelped; - data.minsPerStudent = waitTimeData.minsPerStudent; - data.numTAs = waitTimeData.numTAs; + return waittime.wait_time_data(); + }) + .then((waitTimeData) => { + data.numUnhelped = waitTimeData.numUnhelped; + data.minsPerStudent = waitTimeData.minsPerStudent; + data.numTAs = waitTimeData.numTAs; - return data; + return data; }); } @@ -157,9 +161,9 @@ exports.build_queue_data = buildQueueData; * Emit new queue data to all clients */ function emitNewQueueData() { - buildQueueData().then((data) => { - sockets.queueData(data); - }); + buildQueueData().then((data) => { + sockets.queueData(data); + }); } exports.emit_new_queue_data = emitNewQueueData; @@ -167,158 +171,191 @@ exports.emit_new_queue_data = emitNewQueueData; * Respond to initial request for queue data */ exports.get = function (req, res) { - buildQueueData().then((data) => { - respond(req, res, 'Successfully retrieved queue data', data, 200); - }).catch((err) => { - console.log(err); - respond_error(req, res, `Error retrieving queue data ${err.toString()}`, 500); + buildQueueData() + .then((data) => { + respond(req, res, 'Successfully retrieved queue data', data, 200); + }) + .catch((err) => { + console.log(err); + respond_error( + req, + res, + `Error retrieving queue data ${err.toString()}`, + 500 + ); }); -} +}; /** * Respond to initial request for user data */ exports.get_user_data = function (req, res) { - let data = { - userData: { - isOwner: req.user.isOwner, - isAuthenticated: req.user.isAuthenticated, - isTA: req.user.isTA, - isAdmin: req.user.isAdmin, - andrewID: req.user.andrewID, - preferredName: req.user.account ? req.user.account.dataValues.preferred_name : '', - } - } - - if (!data.userData.isOwner && data.userData.isTA) { - data.userData = { - ...data.userData, - taSettings: { - videoChatEnabled: req.user.account.dataValues.settings.videoChatEnabled, - videoChatURL: req.user.ta.dataValues.zoom_url, - joinNotifsEnabled: req.user.account.dataValues.settings.joinNotifsEnabled, - remindNotifsEnabled: req.user.account.dataValues.settings.remindNotifsEnabled, - remindTime: req.user.account.dataValues.settings.remindTime, - } - } - } + let data = { + userData: { + isOwner: req.user.isOwner, + isAuthenticated: req.user.isAuthenticated, + isTA: req.user.isTA, + isAdmin: req.user.isAdmin, + andrewID: req.user.andrewID, + preferredName: req.user.account + ? req.user.account.dataValues.preferred_name + : '', + }, + }; + + if (!data.userData.isOwner && data.userData.isTA) { + data.userData = { + ...data.userData, + taSettings: { + videoChatEnabled: req.user.account.dataValues.settings.videoChatEnabled, + videoChatURL: req.user.ta.dataValues.zoom_url, + joinNotifsEnabled: + req.user.account.dataValues.settings.joinNotifsEnabled, + remindNotifsEnabled: + req.user.account.dataValues.settings.remindNotifsEnabled, + remindTime: req.user.account.dataValues.settings.remindTime, + }, + }; + } - respond(req, res, 'Successfully retrieved user data', data, 200); - return; -} + respond(req, res, 'Successfully retrieved user data', data, 200); + return; +}; /** * Respond to initial request for student data */ exports.get_student_data = function (req, res) { - let data = { - name: '', - andrewID: req.user.andrewID, - location: '', - topic: '', - question: '', - isFrozen: false, - message: '', - messageBuffer: [], - status: -1, - position: -1, - } - - // Handle when logged-in user is a student - let studentPos = ohq.getPosition(req.user.andrewID); - if (studentPos === -1) { - // Student is not on the queue - respond(req, res, 'Successfully retrieved student data', data, 200) - return; - } else { - respond(req, res, 'Successfully retrieved student data', buildStudentEntryData(ohq.queue.get(studentPos)), 200) - return; - } -} + let data = { + name: '', + andrewID: req.user.andrewID, + location: '', + topic: '', + question: '', + isFrozen: false, + message: '', + messageBuffer: [], + status: -1, + position: -1, + }; + + // Handle when logged-in user is a student + let studentPos = ohq.getPosition(req.user.andrewID); + if (studentPos === -1) { + // Student is not on the queue + respond(req, res, 'Successfully retrieved student data', data, 200); + return; + } else { + respond( + req, + res, + 'Successfully retrieved student data', + buildStudentEntryData(ohq.queue.get(studentPos)), + 200 + ); + return; + } +}; /** * Emit new student data to all clients (all clients receive data and check if it's for them) */ function emitNewStudentData(studentAndrewID) { - let data = ohq.getData(studentAndrewID) - - if (data !== StudentStatus.ERROR) { - sockets.studentData(buildStudentEntryData(ohq.getData(studentAndrewID))); - } else { - sockets.studentData({ - name: '', - andrewID: studentAndrewID, - location: '', - topic: '', - question: '', - isFrozen: false, - message: '', - messageBuffer: [], - status: -1, - position: -1, - }); - } + let data = ohq.getData(studentAndrewID); + + if (data !== StudentStatus.ERROR) { + sockets.studentData(buildStudentEntryData(ohq.getData(studentAndrewID))); + } else { + sockets.studentData({ + name: '', + andrewID: studentAndrewID, + location: '', + topic: '', + question: '', + isFrozen: false, + message: '', + messageBuffer: [], + status: -1, + position: -1, + }); + } } /** * Build student entry data for all students */ function buildAllStudents() { - // assuming that students at front of queue go first - let allStudents = ohq.getAllStudentData(); - allStudents = allStudents.map((student) => { - let studentEntryData = buildStudentEntryData(student); - return studentEntryData; - }) + // assuming that students at front of queue go first + let allStudents = ohq.getAllStudentData(); + allStudents = allStudents.map((student) => { + let studentEntryData = buildStudentEntryData(student); + return studentEntryData; + }); - return allStudents; + return allStudents; } /** * Respond to initial request for all student data */ exports.get_all_students = function (req, res) { - respond(req, res, 'Successfully retrieved all students', {allStudents: buildAllStudents()}, 200); -} + respond( + req, + res, + 'Successfully retrieved all students', + { allStudents: buildAllStudents() }, + 200 + ); +}; /** * Emit all student data to all TAs */ function emitNewAllStudents() { - sockets.allStudents(buildAllStudents()); + sockets.allStudents(buildAllStudents()); } /** * Freeze the queue */ exports.post_freeze_queue = function (req, res) { - if (!req.user || !req.user.isTA) { - respond_error(req, res, 'You do not have permissions to perform this operation', 403); - return; - } + if (!req.user || !req.user.isTA) { + respond_error( + req, + res, + 'You do not have permissions to perform this operation', + 403 + ); + return; + } - notify.stop(); + notify.stop(); - queueFrozen = true; - emitNewQueueData() - respond(req, res, 'Successfully froze queue', {}, 200) -} + queueFrozen = true; + emitNewQueueData(); + respond(req, res, 'Successfully froze queue', {}, 200); +}; /** * Unfreeze the queue */ exports.post_unfreeze_queue = function (req, res) { - if (!req.user || !req.user.isTA) { - respond_error(req, res, 'You do not have permissions to perform this operation', 403); - return; - } + if (!req.user || !req.user.isTA) { + respond_error( + req, + res, + 'You do not have permissions to perform this operation', + 403 + ); + return; + } - notify.init(); + notify.init(); - queueFrozen = false; - emitNewQueueData() - respond(req, res, 'Successfully unfroze queue', {}, 200) -} + queueFrozen = false; + emitNewQueueData(); + respond(req, res, 'Successfully unfroze queue', {}, 200); +}; /** Announcements */ /** @@ -334,587 +371,687 @@ let announcementId = 0; * Create a new announcement */ exports.post_create_announcement = function (req, res) { - if (!req.user || !req.user.isTA) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var content = req.body.content; - if (!content) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - let announcement = { - id: announcementId, - content: content - }; - - announcements.push(announcement); - announcementId++; + if (!req.user || !req.user.isTA) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } - emitNewQueueData() - respond(req, res, `Announcement created successfully`, { announcements: announcements }, 200); -} + var content = req.body.content; + if (!content) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + let announcement = { + id: announcementId, + content: content, + }; + + announcements.push(announcement); + announcementId++; + + emitNewQueueData(); + respond( + req, + res, + `Announcement created successfully`, + { announcements: announcements }, + 200 + ); +}; /** * Update an announcement */ exports.post_update_announcement = function (req, res) { - if (!req.user || !req.user.isTA) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var id = req.body.id; - var content = req.body.content; - if (!content) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - let index = announcements.findIndex(announcement => announcement.id == id); - if (index < 0) { - respond_error(req, res, "Announcement ID not found", 500); - return; - } - - announcements[index] = { - id: id, - content: content - } - emitNewQueueData() - respond(req, res, `Announcement updated successfully`, { announcements: announcements }, 200); -} + if (!req.user || !req.user.isTA) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var id = req.body.id; + var content = req.body.content; + if (!content) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + let index = announcements.findIndex((announcement) => announcement.id == id); + if (index < 0) { + respond_error(req, res, 'Announcement ID not found', 500); + return; + } + + announcements[index] = { + id: id, + content: content, + }; + emitNewQueueData(); + respond( + req, + res, + `Announcement updated successfully`, + { announcements: announcements }, + 200 + ); +}; /** * Delete an announcement */ exports.post_delete_announcement = function (req, res) { - if (!req.user || !req.user.isTA) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - let id = req.body.id; - let index = announcements.findIndex(announcement => announcement.id == id); - if (index < 0) { - respond_error(req, res, "Announcement ID not found", 500); - return; - } - - announcements.splice(index, 1); - emitNewQueueData() - respond(req, res, `Announcement deleted successfully`, { announcements: announcements }, 200); -} + if (!req.user || !req.user.isTA) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + let id = req.body.id; + let index = announcements.findIndex((announcement) => announcement.id == id); + if (index < 0) { + respond_error(req, res, 'Announcement ID not found', 500); + return; + } + + announcements.splice(index, 1); + emitNewQueueData(); + respond( + req, + res, + `Announcement deleted successfully`, + { announcements: announcements }, + 200 + ); +}; /** Questions */ /** * Add a question to the queue */ exports.post_add_question = function (req, res) { - if (!req.user || !req.user.isAuthenticated) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - let id = req.body.andrewID; - let overrideCooldown = req.body.overrideCooldown; - - if (ohq.getPosition(id) != -1) { - respond_error(req, res, "Student already on the queue", 400); - return; - } - - // handle TA created questions - if (req.user.isTA) { - models.account.findOrCreate({ + if (!req.user || !req.user.isAuthenticated) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + let id = req.body.andrewID; + let overrideCooldown = req.body.overrideCooldown; + + if (ohq.getPosition(id) != -1) { + respond_error(req, res, 'Student already on the queue', 400); + return; + } + + // handle TA created questions + if (req.user.isTA) { + models.account + .findOrCreate({ + where: { + email: { + [Sequelize.Op.like]: id + '@%', + }, + }, + defaults: { + name: req.body.name ? req.body.name : 'No Name', + preferred_name: req.body.name ? req.body.name : 'No Name', + email: id + '@andrew.cmu.edu', + }, + }) + .then(([account, created]) => { + return Promise.props({ + student: models.student.findOrCreate({ where: { - email: { - [Sequelize.Op.like]: id + '@%' - } + student_id: account.user_id, }, - defaults: { - name: req.body.name ? req.body.name : 'No Name', - preferred_name: req.body.name ? req.body.name : 'No Name', - email: id + '@andrew.cmu.edu' - } - }).then(([account, created]) => { - return Promise.props({ - student: models.student.findOrCreate({ - where: { - student_id: account.user_id - } - }), - account: account - }); - }).then((result) => { - let [student, created] = result.student; - let account = result.account; - - ohq.enqueue( - id, - account.preferred_name, - req.body.question, - req.body.location, - req.body.topic, - moment.tz(new Date(), "America/New_York").toDate() - ); + }), + account: account, + }); + }) + .then((result) => { + let [student, created] = result.student; + let account = result.account; + + ohq.enqueue( + id, + account.preferred_name, + req.body.question, + req.body.location, + req.body.topic, + moment.tz(new Date(), 'America/New_York').toDate() + ); + + let data = { + status: ohq.getStatus(id), + position: ohq.getPosition(id), + }; + + if (data.status == null || data.position == null) { + throw new Error('The server was unable to add you to the queue'); + } else if (data.status == -1 || data.position == -1) { + throw new Error( + 'The server was unable to find you on the queue after adding you' + ); + } - let data = { - status: ohq.getStatus(id), - position: ohq.getPosition(id) - }; - - if (data.status == null || data.position == null) { - throw new Error('The server was unable to add you to the queue'); - } else if (data.status == -1 || data.position == -1) { - throw new Error('The server was unable to find you on the queue after adding you'); - } - - respond(req, res, `Successfully added to queue`, data, 200); - - sockets.add({ - name: account.preferred_name, - andrewID: id, - topic: req.body.topic, - }); - - emitNewQueueData(); - emitNewStudentData(id); - emitNewAllStudents(); - }).catch((err) => { - console.log(err); - respond_error(req, res, err.message, 500); + respond(req, res, `Successfully added to queue`, data, 200); + + sockets.add({ + name: account.preferred_name, + andrewID: id, + topic: req.body.topic, }); - } - // handle Student created questions - else { - models.account.findOne({ + + emitNewQueueData(); + emitNewStudentData(id); + emitNewAllStudents(); + }) + .catch((err) => { + console.log(err); + respond_error(req, res, err.message, 500); + }); + } + // handle Student created questions + else { + models.account + .findOne({ + where: { + email: { + [Sequelize.Op.like]: id + '@%', + }, + }, + }) + .then((account) => { + if (!account) { + throw new Error('No existing account with provided andrew ID.'); + } + + return Promise.props({ + student: models.student.findOne({ where: { - email: { - [Sequelize.Op.like]: id + '@%' - } + student_id: account.user_id, }, - }).then((account) => { - if (!account) { - throw new Error('No existing account with provided andrew ID.'); - } - - return Promise.props({ - student: models.student.findOne({ - where: { - student_id: account.user_id - } - }), - account: account - }); - }).then((result) => { - let student = result.student; - let account = result.account; - - if (!student) { - throw new Error('No existing student account with provided andrew ID.'); - } - - let allowCDOverride = settings.get_admin_settings().allowCDOverride; - // check for cooldown violation - if (overrideCooldown && !allowCDOverride) { - throw new Error('Cooldown override is disabled'); - } - let rejoinTime = settings.get_admin_settings().rejoinTime - return Promise.props({ - questions: models.question.findAll({ - where: { - exit_time: { - [Sequelize.Op.gte]: moment.tz(new Date(), "America/New_York").subtract(rejoinTime, 'minutes').toDate(), - }, - help_time: { - [Sequelize.Op.ne]: null, - }, - student_id: student.student_id - } - }), - account: account - }) - }).then((result) => { - let questions = result.questions.sort((firstQ, secondQ) => { - return moment.tz(firstQ.exit_time, "America/New_York").diff(secondQ.exit_time) - }) - - let account = result.account - - // fail if cooldown violated - if (!overrideCooldown && questions.length > 0) { - res.status(200) - res.json({ - message: "cooldown_violation", - timePassed: `${moment.tz(new Date(), "America/New_York").diff(questions[questions.length - 1].exit_time, 'minutes')}` - }) - } else { - ohq.enqueue( - id, - account.preferred_name, - req.body.question, - req.body.location, - req.body.topic, - moment.tz(new Date(), "America/New_York").toDate() - ); - - let data = { - status: ohq.getStatus(id), - position: ohq.getPosition(id) - }; - - if (data.status == null || data.position == null) { - throw new Error('The server was unable to add you to the queue'); - } else if (data.status == -1 || data.position == -1) { - throw new Error('The server was unable to find you on the queue after adding you'); - } - - if (overrideCooldown) { - ohq.setCooldownViolation(id) - } - - respond(req, res, `Successfully added to queue`, data, 200); - - sockets.add({ - name: account.preferred_name, - andrewID: id, - topic: req.body.topic, - }); - - emitNewQueueData(); - emitNewStudentData(id); - emitNewAllStudents(); - } - }).catch((err) => { - console.log(err); - respond_error(req, res, err.message, 500); + }), + account: account, }); - } -} + }) + .then((result) => { + let student = result.student; + let account = result.account; + + if (!student) { + throw new Error( + 'No existing student account with provided andrew ID.' + ); + } + + let allowCDOverride = settings.get_admin_settings().allowCDOverride; + // check for cooldown violation + if (overrideCooldown && !allowCDOverride) { + throw new Error('Cooldown override is disabled'); + } + let rejoinTime = settings.get_admin_settings().rejoinTime; + return Promise.props({ + questions: models.question.findAll({ + where: { + exit_time: { + [Sequelize.Op.gte]: moment + .tz(new Date(), 'America/New_York') + .subtract(rejoinTime, 'minutes') + .toDate(), + }, + help_time: { + [Sequelize.Op.ne]: null, + }, + student_id: student.student_id, + }, + }), + account: account, + }); + }) + .then((result) => { + let questions = result.questions.sort((firstQ, secondQ) => { + return moment + .tz(firstQ.exit_time, 'America/New_York') + .diff(secondQ.exit_time); + }); + + let account = result.account; + + // fail if cooldown violated + if (!overrideCooldown && questions.length > 0) { + res.status(200); + res.json({ + message: 'cooldown_violation', + timePassed: `${moment + .tz(new Date(), 'America/New_York') + .diff(questions[questions.length - 1].exit_time, 'minutes')}`, + }); + } else { + ohq.enqueue( + id, + account.preferred_name, + req.body.question, + req.body.location, + req.body.topic, + moment.tz(new Date(), 'America/New_York').toDate() + ); + + let data = { + status: ohq.getStatus(id), + position: ohq.getPosition(id), + }; + + if (data.status == null || data.position == null) { + throw new Error('The server was unable to add you to the queue'); + } else if (data.status == -1 || data.position == -1) { + throw new Error( + 'The server was unable to find you on the queue after adding you' + ); + } + + if (overrideCooldown) { + ohq.setCooldownViolation(id); + } + + respond(req, res, `Successfully added to queue`, data, 200); + + sockets.add({ + name: account.preferred_name, + andrewID: id, + topic: req.body.topic, + }); + + emitNewQueueData(); + emitNewStudentData(id); + emitNewAllStudents(); + } + }) + .catch((err) => { + console.log(err); + respond_error(req, res, err.message, 500); + }); + } +}; /** * Remove a student from the queue */ exports.post_remove_student = function (req, res) { - if (!req.user || !req.user.isAuthenticated) { - respond_error(req, res, "User data not passed to server", 400); - return; - } + if (!req.user || !req.user.isAuthenticated) { + respond_error(req, res, 'User data not passed to server', 400); + return; + } - let id = req.body.andrewID; - let taID = req.user.isTA ? req.user.ta.ta_id : null; + let id = req.body.andrewID; + let taID = req.user.isTA ? req.user.ta.ta_id : null; - if (ohq.getPosition(id) === -1) { - respond_error(req, res, "Student not on the queue", 400) - return; - } + if (ohq.getPosition(id) === -1) { + respond_error(req, res, 'Student not on the queue', 400); + return; + } - let returnedData = ohq.remove(id); + let returnedData = ohq.remove(id); - if (ohq.getPosition(id) != -1) { - respond_error(req, res, "The server was unable to remove the student from the queue", 500); - return; - } + if (ohq.getPosition(id) != -1) { + respond_error( + req, + res, + 'The server was unable to remove the student from the queue', + 500 + ); + return; + } - sockets.remove(id); + sockets.remove(id); - emitNewQueueData(); - emitNewStudentData(id); - emitNewAllStudents(); + emitNewQueueData(); + emitNewStudentData(id); + emitNewAllStudents(); - // this necessary as places move up - ohq.getAllStudentData().forEach((student) => { - emitNewStudentData(student.andrewID); - }); + // this necessary as places move up + ohq.getAllStudentData().forEach((student) => { + emitNewStudentData(student.andrewID); + }); - // TODO, FIXME: Don't write TA added questions to the database or TA manually removed questions - if (req.body.doneHelping) { - let minutesDiff = moment.tz(new Date(), "America/New_York").diff(moment(returnedData.helpTime), "minutes") - sockets.doneHelping(req.user.andrewID, id, minutesDiff); + // TODO, FIXME: Don't write TA added questions to the database or TA manually removed questions + if (req.body.doneHelping) { + let minutesDiff = moment + .tz(new Date(), 'America/New_York') + .diff(moment(returnedData.helpTime), 'minutes'); + sockets.doneHelping(req.user.andrewID, id, minutesDiff); - models.account.findOrCreate({ + models.account + .findOrCreate({ + where: { + email: { + [Sequelize.Op.like]: returnedData.andrewID + '@%', + }, + }, + defaults: { + email: returnedData.andrewID + '@andrew.cmu.edu', + }, + }) + .then(([account]) => { + return Promise.props({ + account: account, + student: models.student.findOrCreate({ where: { - email: { - [Sequelize.Op.like]: returnedData.andrewID + '@%' - } + student_id: account.user_id, }, - defaults: { - email: returnedData.andrewID + '@andrew.cmu.edu' - } - }).then(([account,]) => { - return Promise.props({ - account: account, - student: models.student.findOrCreate({ - where: { - student_id: account.user_id - } - }) - }); - }).then((results) => { - return Promise.props({ - account: results.account, - student: results.student[0], - question: models.question.create({ - ta_id: taID, - student_id: results.student[0].student_id, - sem_id: settings.get_admin_settings().currSem, - question: returnedData.question, - location: returnedData.location, - assignment: returnedData.topic.assignment_id, - entry_time: returnedData.entryTime, - help_time: returnedData.helpTime, - exit_time: moment.tz(new Date(), "America/New_York").toDate(), - num_asked_to_fix: returnedData.numAskedToFix - }) - }); - }).then((results) => { - respond(req, res, 'The student was successfully removed form the queue and a question record was added to the database', {question_id: results.question.question_id}, 200); - }).catch((err) => { - console.log(err); - respond_error(req, res, 'The student was removed from the queue but an error occurred adding the question to the database', 500); - }) - } -} + }), + }); + }) + .then((results) => { + return Promise.props({ + account: results.account, + student: results.student[0], + question: models.question.create({ + ta_id: taID, + student_id: results.student[0].student_id, + sem_id: settings.get_admin_settings().currSem, + question: returnedData.question, + location: returnedData.location, + assignment: returnedData.topic.assignment_id, + entry_time: returnedData.entryTime, + help_time: returnedData.helpTime, + exit_time: moment.tz(new Date(), 'America/New_York').toDate(), + num_asked_to_fix: returnedData.numAskedToFix, + }), + }); + }) + .then((results) => { + respond( + req, + res, + 'The student was successfully removed form the queue and a question record was added to the database', + { question_id: results.question.question_id }, + 200 + ); + }) + .catch((err) => { + console.log(err); + respond_error( + req, + res, + 'The student was removed from the queue but an error occurred adding the question to the database', + 500 + ); + }); + } +}; /** * From a TA to help a student */ exports.post_help_student = function (req, res) { - if (!req.user || !req.user.isAuthenticated) { - respond_error(req, res, "User data not passed to server", 400); - return - } - else if (!req.user.isTA) { - respond_error(req, res, "This request was not made by a TA", 400); - return - } - - let id = req.body.andrewID - - if (ohq.getPosition(id) === -1) { - respond_error(req, res, "Student not on the queue", 400); - return - } - if (ohq.getStatus(id) === StudentStatus.BEING_HELPED) { - respond_error(req, res, "Student is already being helped", 400); - return - } - - let name = req.user.account.preferred_name ? req.user.account.preferred_name : req.user.account.name; - ohq.help(id, req.user.ta.ta_id, req.user.andrewID, name, req.user.account.settings.videoChatEnabled, req.user.ta.zoom_url, moment.tz(new Date(), "America/New_York").toDate()); - sockets.help(id, name); - - emitNewQueueData(); - emitNewStudentData(id); - emitNewAllStudents(); - - respond(req, res, 'The student was helped', {}, 200); -} + if (!req.user || !req.user.isAuthenticated) { + respond_error(req, res, 'User data not passed to server', 400); + return; + } else if (!req.user.isTA) { + respond_error(req, res, 'This request was not made by a TA', 400); + return; + } + + let id = req.body.andrewID; + + if (ohq.getPosition(id) === -1) { + respond_error(req, res, 'Student not on the queue', 400); + return; + } + if (ohq.getStatus(id) === StudentStatus.BEING_HELPED) { + respond_error(req, res, 'Student is already being helped', 400); + return; + } + + let name = req.user.account.preferred_name + ? req.user.account.preferred_name + : req.user.account.name; + ohq.help( + id, + req.user.ta.ta_id, + req.user.andrewID, + name, + req.user.account.settings.videoChatEnabled, + req.user.ta.zoom_url, + moment.tz(new Date(), 'America/New_York').toDate() + ); + sockets.help(id, name); + + emitNewQueueData(); + emitNewStudentData(id); + emitNewAllStudents(); + + respond(req, res, 'The student was helped', {}, 200); +}; /** * From a TA to unhelp a student */ exports.post_unhelp_student = function (req, res) { - if (!req.user || !req.user.isAuthenticated) { - respond_error(req, res, "User data not passed to server", 400); - return - } - else if (!req.user.isTA) { - respond_error(req, res, "This request was not made by a TA", 400); - return - } - - let id = req.body.andrewID - if (ohq.getPosition(id) === -1) { - respond_error(req, res, "Student not on the queue", 400); - return - } - if (ohq.getStatus(id) != StudentStatus.BEING_HELPED) { - respond_error(req, res, "Student was not being helped", 400); - return - } - - ohq.unhelp(id); - - emitNewQueueData(); - emitNewStudentData(id); - emitNewAllStudents(); - - respond(req, res, 'The student was unhelped', {}, 200); -} + if (!req.user || !req.user.isAuthenticated) { + respond_error(req, res, 'User data not passed to server', 400); + return; + } else if (!req.user.isTA) { + respond_error(req, res, 'This request was not made by a TA', 400); + return; + } + + let id = req.body.andrewID; + if (ohq.getPosition(id) === -1) { + respond_error(req, res, 'Student not on the queue', 400); + return; + } + if (ohq.getStatus(id) != StudentStatus.BEING_HELPED) { + respond_error(req, res, 'Student was not being helped', 400); + return; + } + + ohq.unhelp(id); + + emitNewQueueData(); + emitNewStudentData(id); + emitNewAllStudents(); + + respond(req, res, 'The student was unhelped', {}, 200); +}; /** * From a student to update their question */ exports.post_update_question = function (req, res) { - if (!req.user || !req.user.isAuthenticated) { - respond_error(req, res, "User data not passed to server", 400); - return; - } - - let id = req.user.andrewID; - let newQuestion = req.body.content; - if (!newQuestion) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - let pos = ohq.getPosition(id); - if (pos === -1) { - respond_error(req, res, "Student not yet on the queue", 400); - return; - } - - let studentData = ohq.getData(id); - - if (newQuestion == studentData.question) { - respond_error(req, res, "Question was not updated! Please be sure you've entered a new question", 400); - return; - } - - studentData.question = newQuestion; - ohq.unsetFixQuestion(id); - - emitNewStudentData(id); - emitNewAllStudents(); - - respond(req, res, 'Question updated successfully', studentData, 200); -} + if (!req.user || !req.user.isAuthenticated) { + respond_error(req, res, 'User data not passed to server', 400); + return; + } + + let id = req.user.andrewID; + let newQuestion = req.body.content; + if (!newQuestion) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + let pos = ohq.getPosition(id); + if (pos === -1) { + respond_error(req, res, 'Student not yet on the queue', 400); + return; + } + + let studentData = ohq.getData(id); + + if (newQuestion == studentData.question) { + respond_error( + req, + res, + "Question was not updated! Please be sure you've entered a new question", + 400 + ); + return; + } + + studentData.question = newQuestion; + ohq.unsetFixQuestion(id); + + emitNewStudentData(id); + emitNewAllStudents(); + + respond(req, res, 'Question updated successfully', studentData, 200); +}; /** * From a TA to request a student to fix their question */ exports.post_taRequestUpdateQ = function (req, res) { - if (!req.user || !req.user.isAuthenticated) { - respond_error(req, res, "User data not passed to server", 400); - } - else if (!req.user.isTA) { - respond_error(req, res, "This request was not made by a TA", 400); - return - } - - let id = req.body.andrewID - - if (ohq.getPosition(id) === -1) { - respond_error(req, res, "Student not on the queue", 400); - return - } - if (ohq.getStatus(id) === StudentStatus.FIXING_QUESTION) { - respond_error(req, res, "Student is already fixing question", 400); - return - } - - ohq.setFixQuestion(id); - - sockets.updateQRequest(id); - emitNewStudentData(id); - emitNewAllStudents(); - - respond(req, res, 'Update question request sent successfully', req.body, 200); -} + if (!req.user || !req.user.isAuthenticated) { + respond_error(req, res, 'User data not passed to server', 400); + } else if (!req.user.isTA) { + respond_error(req, res, 'This request was not made by a TA', 400); + return; + } + + let id = req.body.andrewID; + + if (ohq.getPosition(id) === -1) { + respond_error(req, res, 'Student not on the queue', 400); + return; + } + if (ohq.getStatus(id) === StudentStatus.FIXING_QUESTION) { + respond_error(req, res, 'Student is already fixing question', 400); + return; + } + + ohq.setFixQuestion(id); + + sockets.updateQRequest(id); + emitNewStudentData(id); + emitNewAllStudents(); + + respond(req, res, 'Update question request sent successfully', req.body, 200); +}; /** * From a TA to send a message to a student */ exports.post_message_student = function (req, res) { - if (!req.user || !req.user.isAuthenticated) { - respond_error(req, res, "User data not passed to server", 400); - return; - } else if (!req.user.isTA) { - respond_error(req, res, "This request was not made by a TA", 400); - return; - } - - let id = req.body.andrewID; - let message = req.body.message; + if (!req.user || !req.user.isAuthenticated) { + respond_error(req, res, 'User data not passed to server', 400); + return; + } else if (!req.user.isTA) { + respond_error(req, res, 'This request was not made by a TA', 400); + return; + } - if (ohq.getPosition(id) === -1) { - respond_error(req, res, "Student not on the queue", 400); - return; - } - if (ohq.getStatus(id) == StudentStatus.BEING_HELPED) { - respond_error(req, res, "Student is being helped and can not receive a message", 400); - return; - } + let id = req.body.andrewID; + let message = req.body.message; - let name = req.user.account.preferred_name ? req.user.account.preferred_name : req.user.account.name; + if (ohq.getPosition(id) === -1) { + respond_error(req, res, 'Student not on the queue', 400); + return; + } + if (ohq.getStatus(id) == StudentStatus.BEING_HELPED) { + respond_error( + req, + res, + 'Student is being helped and can not receive a message', + 400 + ); + return; + } - ohq.receiveMessage(id, req.user.ta.ta_id, req.user.andrewID, name, message); + let name = req.user.account.preferred_name + ? req.user.account.preferred_name + : req.user.account.name; - sockets.message(id, name); - emitNewStudentData(id); - emitNewAllStudents(); + ohq.receiveMessage(id, req.user.ta.ta_id, req.user.andrewID, name, message); - respond(req, res, 'The student was messaged', {}, 200); + sockets.message(id, name); + emitNewStudentData(id); + emitNewAllStudents(); -} + respond(req, res, 'The student was messaged', {}, 200); +}; /** * From a student to dismiss a message */ exports.post_dismiss_message = function (req, res) { - if (!req.user || !req.user.isAuthenticated) { - respond_error(req, res, "User data not passed to server", 400); - return; - } + if (!req.user || !req.user.isAuthenticated) { + respond_error(req, res, 'User data not passed to server', 400); + return; + } - let id = req.body.andrewID; + let id = req.body.andrewID; - if (ohq.getPosition(id) === -1) { - respond_error(req, res, "Student not on the queue", 400); - return; - } - if (ohq.getStatus(id) != StudentStatus.RECEIVED_MESSAGE) { - respond_error(req, res, "Student did not receive a message", 400); - return; - } + if (ohq.getPosition(id) === -1) { + respond_error(req, res, 'Student not on the queue', 400); + return; + } + if (ohq.getStatus(id) != StudentStatus.RECEIVED_MESSAGE) { + respond_error(req, res, 'Student did not receive a message', 400); + return; + } - ohq.dismissMessage(id); + ohq.dismissMessage(id); - sockets.dismiss_message(id); - emitNewStudentData(id); - emitNewAllStudents(); + sockets.dismiss_message(id); + emitNewStudentData(id); + emitNewAllStudents(); - respond(req, res, 'The message was dismissed', {}, 200); -} + respond(req, res, 'The message was dismissed', {}, 200); +}; /** * From a TA to approve a student's cooldown override */ exports.post_approve_cooldown_override = function (req, res) { - if (!req.user || !req.user.isAuthenticated) { - respond_error(req, res, "User data not passed to server", 400); - return - } - else if (!req.user.isTA) { - respond_error(req, res, "This request was not made by a TA", 400); - return - } - - let cooldownAllowed = settings.get_admin_settings().allowCDOverride - if (!cooldownAllowed) { - respond_error(req, res, "Cooldown Override has been disabled", 400) - return - } - - let id = req.body.andrewID - if (ohq.getPosition(id) === -1) { - respond_error(req, res, "Student not on the queue", 400); - return - } - if (ohq.getStatus(id) != StudentStatus.COOLDOWN_VIOLATION) { - respond_error(req, res, "Student was not on cooldown violation", 400); - return - } - - ohq.unsetCooldownViolation(id); - - sockets.approveCooldown(id); - emitNewStudentData(id); - emitNewAllStudents(); - - respond(req, res, 'The cooldown violation was approved', {}, 200); -} + if (!req.user || !req.user.isAuthenticated) { + respond_error(req, res, 'User data not passed to server', 400); + return; + } else if (!req.user.isTA) { + respond_error(req, res, 'This request was not made by a TA', 400); + return; + } + + let cooldownAllowed = settings.get_admin_settings().allowCDOverride; + if (!cooldownAllowed) { + respond_error(req, res, 'Cooldown Override has been disabled', 400); + return; + } + + let id = req.body.andrewID; + if (ohq.getPosition(id) === -1) { + respond_error(req, res, 'Student not on the queue', 400); + return; + } + if (ohq.getStatus(id) != StudentStatus.COOLDOWN_VIOLATION) { + respond_error(req, res, 'Student was not on cooldown violation', 400); + return; + } + + ohq.unsetCooldownViolation(id); + + sockets.approveCooldown(id); + emitNewStudentData(id); + emitNewAllStudents(); + + respond(req, res, 'The cooldown violation was approved', {}, 200); +}; From 0f849fc0a383c4aa30fa8aca0cc67f19926fdbc7 Mon Sep 17 00:00:00 2001 From: Jackson Romero Date: Thu, 3 Oct 2024 22:54:50 -0400 Subject: [PATCH 3/4] Emit new queue data on course name change so title updates live for anyone connected --- server/controllers/settings.js | 1942 ++++++++++++++++++-------------- 1 file changed, 1084 insertions(+), 858 deletions(-) diff --git a/server/controllers/settings.js b/server/controllers/settings.js index 53325c73..bfae5651 100644 --- a/server/controllers/settings.js +++ b/server/controllers/settings.js @@ -1,10 +1,10 @@ // For settings page -const moment = require("moment-timezone"); -const Promise = require("bluebird"); -const csvtojson = require("csvtojson"); +const moment = require('moment-timezone'); +const Promise = require('bluebird'); +const csvtojson = require('csvtojson'); const models = require('../models'); -const sockets = require('./sockets') +const sockets = require('./sockets'); const slack = require('./slack'); const home = require('./home'); @@ -13,17 +13,17 @@ const home = require('./home'); // In production, these should be cleared var fs = require('fs'); const defaultAdminSettings = { - courseName: "", - currSem: "S23", - slackURL: null, - questionsURL: '', - rejoinTime: 15, - enforceCMUEmail: true, - allowCDOverride: true, - dayDictionary: {} + courseName: '', + currSem: 'S23', + slackURL: null, + questionsURL: '', + rejoinTime: 15, + enforceCMUEmail: true, + allowCDOverride: true, + dayDictionary: {}, }; -let adminSettings = defaultAdminSettings +let adminSettings = defaultAdminSettings; function haveSameKeys(obj1, obj2) { const obj1Keys = Object.keys(obj1).sort(); @@ -33,807 +33,1018 @@ function haveSameKeys(obj1, obj2) { // If no admin setting have been generated, use the above default values if (!fs.existsSync('../adminSettings.json')) { - var json = JSON.stringify(adminSettings) - fs.writeFile('../adminSettings.json', json, 'utf8', function () { - console.log('Created admin settings JSON'); - }); + var json = JSON.stringify(adminSettings); + fs.writeFile('../adminSettings.json', json, 'utf8', function () { + console.log('Created admin settings JSON'); + }); } // If admin settings have been generated, but the keys don't match, update the missing keys -else if (fs.existsSync("../adminSettings.json") && !haveSameKeys(adminSettings, JSON.parse(fs.readFileSync('../adminSettings.json', 'utf8')))) { - let currAdminSettings = fs.readFileSync('../adminSettings.json', 'utf8', flag = 'r+'); - let newAdminSettings = JSON.parse(currAdminSettings); - for (let key in adminSettings) { - if (!newAdminSettings.hasOwnProperty(key)) { - newAdminSettings[key] = adminSettings[key]; - } +else if ( + fs.existsSync('../adminSettings.json') && + !haveSameKeys( + adminSettings, + JSON.parse(fs.readFileSync('../adminSettings.json', 'utf8')) + ) +) { + let currAdminSettings = fs.readFileSync( + '../adminSettings.json', + 'utf8', + (flag = 'r+') + ); + let newAdminSettings = JSON.parse(currAdminSettings); + for (let key in adminSettings) { + if (!newAdminSettings.hasOwnProperty(key)) { + newAdminSettings[key] = adminSettings[key]; } - var json = JSON.stringify(newAdminSettings) - fs.writeFileSync('../adminSettings.json', json, 'utf8', function () { - console.log('Updated admin settings JSON'); - }); + } + var json = JSON.stringify(newAdminSettings); + fs.writeFileSync('../adminSettings.json', json, 'utf8', function () { + console.log('Updated admin settings JSON'); + }); } exports.get_admin_settings = function () { - let data = fs.readFileSync('../adminSettings.json', 'utf8', flag = 'r+'); - if (data) { - adminSettings = JSON.parse(data); - } else { - console.log('No admin settings found'); - adminSettings = defaultAdminSettings - } - - return adminSettings; -} + let data = fs.readFileSync('../adminSettings.json', 'utf8', (flag = 'r+')); + if (data) { + adminSettings = JSON.parse(data); + } else { + console.log('No admin settings found'); + adminSettings = defaultAdminSettings; + } + + return adminSettings; +}; exports.get_queue_settings = function (req, res) { - res.status(200) - res.json(adminSettings) -} + res.status(200); + res.json(adminSettings); +}; /** Helper Functions **/ function respond_error(req, res, message, status) { - res.status(status); - res.json({ message: message }); + res.status(status); + res.json({ message: message }); } function respond(req, res, message, data, status) { - res.status(status); - if (message) { - data['message'] = message; - } - res.json(data); + res.status(status); + if (message) { + data['message'] = message; + } + res.json(data); } function respond_success(req, res, message = null) { - if (!req.user) { - respond_error(req, res, "You don't have permissions to view this page", 404); - return; - } - - respond(req, res, message, {}, 200); + if (!req.user) { + respond_error( + req, + res, + "You don't have permissions to view this page", + 404 + ); + return; + } + + respond(req, res, message, {}, 200); } -function writeAdminSettings (settings) { - var json = JSON.stringify(settings) - fs.writeFileSync('../adminSettings.json', json, 'utf8', function () { - return; - }); +function writeAdminSettings(settings) { + var json = JSON.stringify(settings); + fs.writeFileSync('../adminSettings.json', json, 'utf8', function () { + return; + }); } /** General Settings **/ exports.post_update_video_chat = function (req, res) { - if (!req.user || !req.user.isTA) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var enabled = req.body.enabled; - var url = req.body.url; - - let account = req.user.account; - let ta = req.user.ta; - let settings = {}; - if (account.settings) { - settings = account.settings; - } - - let urlChanged = ta.zoom_url != url; - - settings["videoChatEnabled"] = enabled; - account.settings = settings; - account.changed("settings", true); // JSON fields need to be explictly marked as changed - ta.zoom_url = url; - - Promise.props({ - ta: ta.save(), - account: account.save() - }).then(function (results) { - req.user.account = results.account; - req.user.ta = results.ta; - respond_success(req, res, urlChanged ? `Settings updated successfully` : ""); - }).catch(err => { - console.log(err); - message = err.message || "An error occurred while updating settings"; - respond_error(req, res, message, 500); + if (!req.user || !req.user.isTA) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var enabled = req.body.enabled; + var url = req.body.url; + + let account = req.user.account; + let ta = req.user.ta; + let settings = {}; + if (account.settings) { + settings = account.settings; + } + + let urlChanged = ta.zoom_url != url; + + settings['videoChatEnabled'] = enabled; + account.settings = settings; + account.changed('settings', true); // JSON fields need to be explictly marked as changed + ta.zoom_url = url; + + Promise.props({ + ta: ta.save(), + account: account.save(), + }) + .then(function (results) { + req.user.account = results.account; + req.user.ta = results.ta; + respond_success( + req, + res, + urlChanged ? `Settings updated successfully` : '' + ); + }) + .catch((err) => { + console.log(err); + message = err.message || 'An error occurred while updating settings'; + respond_error(req, res, message, 500); }); -} +}; exports.post_update_preferredname = function (req, res) { - if (!req.user) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - var pname = req.body.preferred_name; - - let account = req.user.account; - account.preferred_name = pname; - - Promise.props({ - account: account.save() - }).then(function (results) { - req.user.account = results.account; - respond_success(req, res, `Settings updated successfully`); - }).catch(err => { - console.log(err); - message = err.message || "An error occurred while updating settings"; - respond_error(req, res, message, 500); + if (!req.user) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + var pname = req.body.preferred_name; + + let account = req.user.account; + account.preferred_name = pname; + + Promise.props({ + account: account.save(), + }) + .then(function (results) { + req.user.account = results.account; + respond_success(req, res, `Settings updated successfully`); + }) + .catch((err) => { + console.log(err); + message = err.message || 'An error occurred while updating settings'; + respond_error(req, res, message, 500); }); -} +}; exports.post_update_notifs = function (req, res) { - if (!req.user || !req.user.isTA) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var joinEnabled = req.body.joinEnabled; - var remindEnabled = req.body.remindEnabled; - var remindTime = req.body.remindTime; - - if (remindTime < 0) { - // Do nothing if remind time is invalid - respond_success(req, res); - return; - } - - let account = req.user.account; - let settings = {}; - if (account.settings) { - settings = account.settings; - } - - settings["joinNotifsEnabled"] = joinEnabled; - settings["remindNotifsEnabled"] = remindEnabled; - settings["remindTime"] = remindTime; - account.settings = settings; - account.changed("settings", true); // JSON fields need to be explictly marked as changed - - Promise.props({ - account: account.save() - }).then(function (results) { - req.user.account = results.account; - respond_success(req, res); - }).catch(err => { - console.log(err); - message = err.message || "An error occurred while updating settings"; - respond_error(req, res, message, 500); + if (!req.user || !req.user.isTA) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var joinEnabled = req.body.joinEnabled; + var remindEnabled = req.body.remindEnabled; + var remindTime = req.body.remindTime; + + if (remindTime < 0) { + // Do nothing if remind time is invalid + respond_success(req, res); + return; + } + + let account = req.user.account; + let settings = {}; + if (account.settings) { + settings = account.settings; + } + + settings['joinNotifsEnabled'] = joinEnabled; + settings['remindNotifsEnabled'] = remindEnabled; + settings['remindTime'] = remindTime; + account.settings = settings; + account.changed('settings', true); // JSON fields need to be explictly marked as changed + + Promise.props({ + account: account.save(), + }) + .then(function (results) { + req.user.account = results.account; + respond_success(req, res); + }) + .catch((err) => { + console.log(err); + message = err.message || 'An error occurred while updating settings'; + respond_error(req, res, message, 500); }); -} - - +}; /** ADMIN FUNCTIONS **/ /** Config Settings **/ exports.post_update_course_name = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var courseName = req.body.courseName; - // @Review: Any validations needed here (such as empty string)? - if (!courseName) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - if (adminSettings.courseName == courseName) { - respond_success(req, res); - return; - } - - // @Review: Should the courseName be stored in the database? Currently, only - // storing it in the adminSettings.json file. Perhaps could be part of a - // larger medium-sized effort to move all admin settings to a new table in the - // database. - adminSettings.courseName = courseName; - writeAdminSettings(adminSettings); - respond_success(req, res, `Course name updated successfully to ${courseName}`); -} + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var courseName = req.body.courseName; + // @Review: Any validations needed here (such as empty string)? + if (!courseName) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + if (adminSettings.courseName == courseName) { + respond_success(req, res); + return; + } + + // @Review: Should the courseName be stored in the database? Currently, only + // storing it in the adminSettings.json file. Perhaps could be part of a + // larger medium-sized effort to move all admin settings to a new table in the + // database. + adminSettings.courseName = courseName; + writeAdminSettings(adminSettings); + home.emit_new_queue_data(); + respond_success( + req, + res, + `Course name updated successfully to ${courseName}` + ); +}; exports.post_update_semester = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var sem_id = req.body.sem_id; - if (!sem_id || sem_id.length != 3) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - // If already at current semester, no need to change - if (sem_id == adminSettings.currSem) { - respond_success(req, res); - return; - } - - models.semester.findOrCreate({ - where: { - sem_id: sem_id - } - }).then(function (results) { - adminSettings.currSem = results[0].sem_id; - writeAdminSettings(adminSettings); - respond_success(req, res, `Current semester set to ${sem_id} successfully`); - }).catch(err => { - message = err.message || "An error occurred while updating current semester"; - respond_error(req, res, message, 500); + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var sem_id = req.body.sem_id; + if (!sem_id || sem_id.length != 3) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + // If already at current semester, no need to change + if (sem_id == adminSettings.currSem) { + respond_success(req, res); + return; + } + + models.semester + .findOrCreate({ + where: { + sem_id: sem_id, + }, + }) + .then(function (results) { + adminSettings.currSem = results[0].sem_id; + writeAdminSettings(adminSettings); + respond_success( + req, + res, + `Current semester set to ${sem_id} successfully` + ); + }) + .catch((err) => { + message = + err.message || 'An error occurred while updating current semester'; + respond_error(req, res, message, 500); }); -} +}; exports.post_update_slack_url = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var slackURL = req.body.slackURL; - if (!slackURL) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - if (adminSettings.slackURL == slackURL) return; - - adminSettings.slackURL = slackURL; - writeAdminSettings(adminSettings); - slack.update_slack(); - respond_success(req, res, `Slack Webhook URL updated successfully`); -} + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var slackURL = req.body.slackURL; + if (!slackURL) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + if (adminSettings.slackURL == slackURL) return; + + adminSettings.slackURL = slackURL; + writeAdminSettings(adminSettings); + slack.update_slack(); + respond_success(req, res, `Slack Webhook URL updated successfully`); +}; exports.post_update_questions_url = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var questionsURL = req.body.questionsURL; - if (!questionsURL) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - if (adminSettings.questionsURL == questionsURL) return; - - adminSettings.questionsURL = questionsURL; - writeAdminSettings(adminSettings); - home.emit_new_queue_data(); - respond_success(req, res, `Questions Guide URL updated successfully`); -} + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var questionsURL = req.body.questionsURL; + if (!questionsURL) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + if (adminSettings.questionsURL == questionsURL) return; + + adminSettings.questionsURL = questionsURL; + writeAdminSettings(adminSettings); + home.emit_new_queue_data(); + respond_success(req, res, `Questions Guide URL updated successfully`); +}; exports.post_update_rejoin_time = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var rejoinTime = req.body.rejoinTime; - if (!rejoinTime || isNaN(rejoinTime)) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - if (adminSettings.rejoinTime == rejoinTime) return; - - adminSettings.rejoinTime = rejoinTime; - writeAdminSettings(adminSettings); - home.emit_new_queue_data(); - respond_success(req, res, `Rejoin time updated successfully to ${rejoinTime} minutes`); -} + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var rejoinTime = req.body.rejoinTime; + if (!rejoinTime || isNaN(rejoinTime)) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + if (adminSettings.rejoinTime == rejoinTime) return; + + adminSettings.rejoinTime = rejoinTime; + writeAdminSettings(adminSettings); + home.emit_new_queue_data(); + respond_success( + req, + res, + `Rejoin time updated successfully to ${rejoinTime} minutes` + ); +}; exports.post_update_enforce_cmu_email = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var enforceCMUEmail = req.body.enforceCMUEmail; - - if (enforceCMUEmail == null || enforceCMUEmail == undefined) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - if (adminSettings.enforceCMUEmail == enforceCMUEmail) return; - - adminSettings.enforceCMUEmail = enforceCMUEmail; - writeAdminSettings(adminSettings); - respond_success(req, res, `Enforcing CMU email updated successfully to: ${enforceCMUEmail}`); -} + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var enforceCMUEmail = req.body.enforceCMUEmail; + + if (enforceCMUEmail == null || enforceCMUEmail == undefined) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + if (adminSettings.enforceCMUEmail == enforceCMUEmail) return; + + adminSettings.enforceCMUEmail = enforceCMUEmail; + writeAdminSettings(adminSettings); + respond_success( + req, + res, + `Enforcing CMU email updated successfully to: ${enforceCMUEmail}` + ); +}; exports.post_update_allow_cooldown_override = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permission to perform this operation", 403); - return; - } - - var allowCDOverride = req.body.allowCDOverride; - - if (allowCDOverride == null || allowCDOverride == undefined) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - if (adminSettings.allowCDOverride == allowCDOverride) return; - - adminSettings.allowCDOverride = allowCDOverride; - writeAdminSettings(adminSettings); - home.emit_new_queue_data(); - respond_success(req, res, `Allow Cooldown Override updated successfuly to: ${allowCDOverride}`) -} + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permission to perform this operation", + 403 + ); + return; + } + + var allowCDOverride = req.body.allowCDOverride; + + if (allowCDOverride == null || allowCDOverride == undefined) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + if (adminSettings.allowCDOverride == allowCDOverride) return; + + adminSettings.allowCDOverride = allowCDOverride; + writeAdminSettings(adminSettings); + home.emit_new_queue_data(); + respond_success( + req, + res, + `Allow Cooldown Override updated successfuly to: ${allowCDOverride}` + ); +}; /** Topics Functions **/ exports.post_create_topic = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var name = req.body.name; - var category = req.body.category; - var start_date = moment.tz(new Date(req.body.start_date), "America/New_York").toDate(); // TODO: get timezone (get from client? global config?) - var end_date = moment.tz(new Date(req.body.end_date), "America/New_York").toDate(); - if (!start_date.getTime() || !end_date.getTime() || !name || !category) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - Promise.props({ - assignment: function () { - return models.assignment.findOrCreate({ - where: { - name: name, - category: category - } - }); - }() - }).then(function (results) { - return models.assignment_semester.create({ - assignment_id: results.assignment[0].assignment_id, - sem_id: adminSettings.currSem, - start_date: start_date, - end_date: end_date - }) - }).then(function () { - home.emit_new_queue_data(); - respond_success(req, res, `Assignment ${name} created successfully`); - }).catch(err => { - message = err.message || "An error occurred while creating topic"; - respond_error(req, res, message, 500); + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var name = req.body.name; + var category = req.body.category; + var start_date = moment + .tz(new Date(req.body.start_date), 'America/New_York') + .toDate(); // TODO: get timezone (get from client? global config?) + var end_date = moment + .tz(new Date(req.body.end_date), 'America/New_York') + .toDate(); + if (!start_date.getTime() || !end_date.getTime() || !name || !category) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + Promise.props({ + assignment: (function () { + return models.assignment.findOrCreate({ + where: { + name: name, + category: category, + }, + }); + })(), + }) + .then(function (results) { + return models.assignment_semester.create({ + assignment_id: results.assignment[0].assignment_id, + sem_id: adminSettings.currSem, + start_date: start_date, + end_date: end_date, + }); + }) + .then(function () { + home.emit_new_queue_data(); + respond_success(req, res, `Assignment ${name} created successfully`); + }) + .catch((err) => { + message = err.message || 'An error occurred while creating topic'; + respond_error(req, res, message, 500); }); -} +}; exports.post_update_topic = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var assignment_id = req.body.assignment_id; - var name = req.body.name; - var category = req.body.category; - var start_date = moment.tz(new Date(req.body.start_date), "America/New_York").toDate(); // TODO: get timezone (get from client? global config?) - var end_date = moment.tz(new Date(req.body.end_date), "America/New_York").toDate(); - if (!start_date.getTime() || !end_date.getTime() || !name || !category || !assignment_id) { - respond_error(req, res, "Invalid/missing parameters in request", 400); + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var assignment_id = req.body.assignment_id; + var name = req.body.name; + var category = req.body.category; + var start_date = moment + .tz(new Date(req.body.start_date), 'America/New_York') + .toDate(); // TODO: get timezone (get from client? global config?) + var end_date = moment + .tz(new Date(req.body.end_date), 'America/New_York') + .toDate(); + if ( + !start_date.getTime() || + !end_date.getTime() || + !name || + !category || + !assignment_id + ) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + Promise.props({ + assignment_semester: (function () { + return models.assignment_semester.findOne({ + where: { + assignment_id: assignment_id, + sem_id: adminSettings.currSem, + }, + }); + })(), + assignment: (function () { + return models.assignment.findOne({ + where: { + assignment_id: assignment_id, + }, + }); + })(), + }) + .then(function (results) { + if (results.assignment_semester == null || results.assignment == null) { + respond_error(req, res, 'Invalid assignment id: topic not found', 400); return; - } + } - Promise.props({ - assignment_semester: function () { - return models.assignment_semester.findOne({ - where: { - assignment_id: assignment_id, - sem_id: adminSettings.currSem - } - }) - }(), - assignment: function () { - return models.assignment.findOne({ - where: { - assignment_id: assignment_id - } - }); - }() - }).then(function (results) { - if (results.assignment_semester == null || results.assignment == null) { - respond_error(req, res, "Invalid assignment id: topic not found", 400); - return; - } - - return Promise.props({ - assignment_semester: function () { - return results.assignment_semester.update({ - start_date: start_date, - end_date: end_date - }) - }(), - assignment: function () { - return results.assignment.update({ - name: name, - category: category - }); - }() - }) - }).then(function () { - home.emit_new_queue_data(); - respond_success(req, res, `Assignment ${name} updated successfully`); - }).catch(err => { - message = err.message || "An error occurred while updating topic"; - respond_error(req, res, message, 500); + return Promise.props({ + assignment_semester: (function () { + return results.assignment_semester.update({ + start_date: start_date, + end_date: end_date, + }); + })(), + assignment: (function () { + return results.assignment.update({ + name: name, + category: category, + }); + })(), + }); + }) + .then(function () { + home.emit_new_queue_data(); + respond_success(req, res, `Assignment ${name} updated successfully`); + }) + .catch((err) => { + message = err.message || 'An error occurred while updating topic'; + respond_error(req, res, message, 500); }); -} +}; exports.post_delete_topic = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var assignment_id = req.body.assignment_id; - if (!assignment_id) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - models.assignment.destroy({ - where: { - assignment_id: assignment_id - } - }).then(function () { - home.emit_new_queue_data(); - respond_success(req, res, `Assignment deleted successfully`); - }).catch(err => { - message = err.message || "An error occurred while deleting topic"; - respond_error(req, res, message, 500); + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var assignment_id = req.body.assignment_id; + if (!assignment_id) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + models.assignment + .destroy({ + where: { + assignment_id: assignment_id, + }, + }) + .then(function () { + home.emit_new_queue_data(); + respond_success(req, res, `Assignment deleted successfully`); + }) + .catch((err) => { + message = err.message || 'An error occurred while deleting topic'; + respond_error(req, res, message, 500); }); -} +}; exports.post_download_topic_csv = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - try { - const file = `${__dirname}/../public/files/topics_example.csv`; - res.download(file); - } catch (err) { - console.log(err); - message = err.message || "An error occurred while downloading CSV"; - respond_error(req, res, message, 500); - } -} - -exports.post_upload_topic_csv = function(req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - const file = req.file; - if (!file) { - respond_error(req, res, "No CSV file was uploaded", 400); - return; - } - - let csvData = file.buffer.toString('utf8'); - csvtojson().fromString(csvData).then(async (data) => { - var assignments = []; - var topics = []; - for (var i = 0; i < data.length; ++i) { - topics.push(data[i]); - } - - await Promise.all(topics.map(topic => { - var name = topic.name; - var category = topic.category; - var start_date = new Date(topic.start_date); - var end_date = new Date(topic.end_date); - - if (!start_date.getTime() || !end_date.getTime() || !name || !category) { - throw new Error("Invalid fields in CSV file"); - } + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + try { + const file = `${__dirname}/../public/files/topics_example.csv`; + res.download(file); + } catch (err) { + console.log(err); + message = err.message || 'An error occurred while downloading CSV'; + respond_error(req, res, message, 500); + } +}; - assignments.push( - models.assignment.findOrCreate({ +exports.post_upload_topic_csv = function (req, res) { + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + const file = req.file; + if (!file) { + respond_error(req, res, 'No CSV file was uploaded', 400); + return; + } + + let csvData = file.buffer.toString('utf8'); + csvtojson() + .fromString(csvData) + .then(async (data) => { + var assignments = []; + var topics = []; + for (var i = 0; i < data.length; ++i) { + topics.push(data[i]); + } + + await Promise.all( + topics.map((topic) => { + var name = topic.name; + var category = topic.category; + var start_date = new Date(topic.start_date); + var end_date = new Date(topic.end_date); + + if ( + !start_date.getTime() || + !end_date.getTime() || + !name || + !category + ) { + throw new Error('Invalid fields in CSV file'); + } + + assignments.push( + models.assignment + .findOrCreate({ + where: { + name: name, + category: category, + }, + }) + .then(([assignment]) => { + return Promise.props({ + assignment_semester: models.assignment_semester.findOne({ where: { - name: name, - category: category - } - }).then(([assignment, ]) => { - return Promise.props({ - assignment_semester: models.assignment_semester.findOne({ - where: { - assignment_id: assignment.assignment_id, - sem_id: adminSettings.currSem - } - }), - assignment: assignment - }); - }).then((result) => { - let assignment_semester = result.assignment_semester; - let assignment = result.assignment; - - if (!assignment_semester) { - return models.assignment_semester.create({ - assignment_id: assignment.assignment_id, - sem_id: adminSettings.currSem, - start_date: start_date, - end_date: end_date - }); - } - - return assignment_semester.update({ - start_date: start_date, - end_date: end_date - }); - }) - ); - })); - - return Promise.props({ - assignments: Promise.all(assignments) - }); - }).then(() => { - home.emit_new_queue_data(); - respond_success(req, res, `Assignments created successfully`); - }).catch(err => { - console.log(err); - message = err.message || "An error occurred while creating uploaded topics"; - respond_error(req, res, message, 500); + assignment_id: assignment.assignment_id, + sem_id: adminSettings.currSem, + }, + }), + assignment: assignment, + }); + }) + .then((result) => { + let assignment_semester = result.assignment_semester; + let assignment = result.assignment; + + if (!assignment_semester) { + return models.assignment_semester.create({ + assignment_id: assignment.assignment_id, + sem_id: adminSettings.currSem, + start_date: start_date, + end_date: end_date, + }); + } + + return assignment_semester.update({ + start_date: start_date, + end_date: end_date, + }); + }) + ); + }) + ); + + return Promise.props({ + assignments: Promise.all(assignments), + }); + }) + .then(() => { + home.emit_new_queue_data(); + respond_success(req, res, `Assignments created successfully`); + }) + .catch((err) => { + console.log(err); + message = + err.message || 'An error occurred while creating uploaded topics'; + respond_error(req, res, message, 500); }); -} +}; /** TA Functions **/ exports.post_create_ta = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var name = req.body.name; - var email = req.body.email; - var isAdmin = req.body.isAdmin; - if (!name || !email) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - models.account.findOrCreate({ - where: { - email: email - } - }).then(function ([account, accountCreated]) { - return Promise.props({ - account: function () { - if (accountCreated) { - account.set({ name: name, preferred_name: name }); - } - return account.save(); - }(), - semester_user: models.semester_user.findOrCreate({ - where: { - user_id: account.user_id, - sem_id: adminSettings.currSem - } - }), - ta: models.ta.findOrCreate({ - where: { - ta_id: account.user_id - } - }) - }) - }).then(function (results) { - return Promise.props({ - semester_user: results.semester_user[0].update({ - is_ta: 1 - }), - ta: results.ta[0].update({ - is_admin: isAdmin ? 1 : 0 - }) - }); - }).then(function () { - home.emit_new_queue_data(); - respond_success(req, res, `TA ${name} created successfully`); - }).catch(err => { - console.log(err); - message = err.message || "An error occurred while creating topic"; - respond_error(req, res, message, 500); + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var name = req.body.name; + var email = req.body.email; + var isAdmin = req.body.isAdmin; + if (!name || !email) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + models.account + .findOrCreate({ + where: { + email: email, + }, + }) + .then(function ([account, accountCreated]) { + return Promise.props({ + account: (function () { + if (accountCreated) { + account.set({ name: name, preferred_name: name }); + } + return account.save(); + })(), + semester_user: models.semester_user.findOrCreate({ + where: { + user_id: account.user_id, + sem_id: adminSettings.currSem, + }, + }), + ta: models.ta.findOrCreate({ + where: { + ta_id: account.user_id, + }, + }), + }); + }) + .then(function (results) { + return Promise.props({ + semester_user: results.semester_user[0].update({ + is_ta: 1, + }), + ta: results.ta[0].update({ + is_admin: isAdmin ? 1 : 0, + }), + }); + }) + .then(function () { + home.emit_new_queue_data(); + respond_success(req, res, `TA ${name} created successfully`); + }) + .catch((err) => { + console.log(err); + message = err.message || 'An error occurred while creating topic'; + respond_error(req, res, message, 500); }); -} +}; exports.post_update_ta = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var user_id = req.body.user_id; - var isAdmin = req.body.isAdmin; - if (!user_id) { - respond_error(req, res, "Invalid/missing parameters in request", 400); + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var user_id = req.body.user_id; + var isAdmin = req.body.isAdmin; + if (!user_id) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + Promise.props({ + semester_user: (function () { + // We grab this to verify the user exists for this semester + return models.semester_user.findOne({ + where: { + user_id: user_id, + sem_id: adminSettings.currSem, + }, + }); + })(), + account: (function () { + // We grab this to verify the user has an account + return models.account.findOne({ + where: { + user_id: user_id, + }, + }); + })(), + ta: (function () { + return models.ta.findOne({ + where: { + ta_id: user_id, + }, + }); + })(), + }) + .then(function (results) { + if ( + results.semester_user == null || + results.account == null || + results.ta == null + ) { + respond_error(req, res, 'Invalid user id: TA not found', 400); return; - } - - Promise.props({ - semester_user: function () { - // We grab this to verify the user exists for this semester - return models.semester_user.findOne({ - where: { - user_id: user_id, - sem_id: adminSettings.currSem - } - }) - }(), - account: function () { - // We grab this to verify the user has an account - return models.account.findOne({ - where: { - user_id: user_id - } - }); - }(), - ta: function () { - return models.ta.findOne({ - where: { - ta_id: user_id - } - }); - }(), - }).then(function (results) { - if (results.semester_user == null || results.account == null || results.ta == null) { - respond_error(req, res, "Invalid user id: TA not found", 400); - return; - } - - return Promise.props({ - ta: function () { - return results.ta.update({ - is_admin: isAdmin ? 1 : 0 - }); - }(), - name: results.account.name - }) - }).then(function (results) { - home.emit_new_queue_data(); - respond_success(req, res, `TA ${results.name} updated successfully`); - }).catch(err => { - message = err.message || "An error occurred while updating TA"; - respond_error(req, res, message, 500); + } + + return Promise.props({ + ta: (function () { + return results.ta.update({ + is_admin: isAdmin ? 1 : 0, + }); + })(), + name: results.account.name, + }); + }) + .then(function (results) { + home.emit_new_queue_data(); + respond_success(req, res, `TA ${results.name} updated successfully`); + }) + .catch((err) => { + message = err.message || 'An error occurred while updating TA'; + respond_error(req, res, message, 500); }); -} +}; exports.post_delete_ta = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var user_id = req.body.user_id; - if (!user_id) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - models.semester_user.findOne({ - where: { - user_id: user_id, - sem_id: adminSettings.currSem, - } - }).then(function (sem_user) { - return sem_user.update({ - is_ta: 0 - }); - }).then(function () { - home.emit_new_queue_data(); - respond_success(req, res, `TA deleted successfully`); - }).catch(err => { - message = err.message || "An error occurred while deleting TA"; - respond_error(req, res, message, 500); + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var user_id = req.body.user_id; + if (!user_id) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + models.semester_user + .findOne({ + where: { + user_id: user_id, + sem_id: adminSettings.currSem, + }, + }) + .then(function (sem_user) { + return sem_user.update({ + is_ta: 0, + }); + }) + .then(function () { + home.emit_new_queue_data(); + respond_success(req, res, `TA deleted successfully`); + }) + .catch((err) => { + message = err.message || 'An error occurred while deleting TA'; + respond_error(req, res, message, 500); }); -} +}; exports.post_download_ta_csv = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - try { - const file = `${__dirname}/../public/files/tas_example.csv`; - res.download(file); - } catch (err) { - console.log(err); - message = err.message || "An error occurred while downloading CSV"; - respond_error(req, res, message, 500); - } -} + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + try { + const file = `${__dirname}/../public/files/tas_example.csv`; + res.download(file); + } catch (err) { + console.log(err); + message = err.message || 'An error occurred while downloading CSV'; + respond_error(req, res, message, 500); + } +}; exports.post_upload_ta_csv = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + const file = req.file; + if (!file) { + respond_error(req, res, 'No CSV file was uploaded', 400); + return; + } + + let csvData = file.buffer.toString('utf8'); + csvtojson() + .fromString(csvData) + .then((data) => { + var tas = []; + for (var i = 0; i < data.length; ++i) { + var name = data[i].name; + var email = data[i].email; + var is_admin = data[i].is_admin; + + if (!name || !email || !is_admin) { + throw new Error('Invalid fields in CSV file'); + } - const file = req.file; - if (!file) { - respond_error(req, res, "No CSV file was uploaded", 400); - return; - } + is_admin = is_admin.toLowerCase() == 'true'; - let csvData = file.buffer.toString('utf8'); - csvtojson().fromString(csvData).then((data) => { - var tas = []; - for (var i = 0; i < data.length; ++i) { - var name = data[i].name; - var email = data[i].email; - var is_admin = data[i].is_admin; - - if (!name || !email || !is_admin) { - throw new Error("Invalid fields in CSV file"); - } - - is_admin = is_admin.toLowerCase() == "true"; - - tas.push( - Promise.props({ - name: name, - isAdmin: is_admin, - account: models.account.findOrCreate({ - where: { - email: email - } - }) - }).then((results) => { - let [account, accountCreated] = results.account; - return Promise.props({ - account: function () { - if (accountCreated) { - account.set({ name: results.name, preferred_name: results.name }); - } - return account.save(); - }(), - semester_user: models.semester_user.findOrCreate({ - where: { - user_id: account.user_id, - sem_id: adminSettings.currSem - } - }), - ta: models.ta.findOrCreate({ - where: { - ta_id: account.user_id - } - }), - isAdmin: results.isAdmin - }); - }).then((results) => { - return Promise.props({ - semester_user: results.semester_user[0].update({ - is_ta: 1 - }), - ta: results.ta[0].update({ - is_admin: results.isAdmin ? 1 : 0 - }) + tas.push( + Promise.props({ + name: name, + isAdmin: is_admin, + account: models.account.findOrCreate({ + where: { + email: email, + }, + }), + }) + .then((results) => { + let [account, accountCreated] = results.account; + return Promise.props({ + account: (function () { + if (accountCreated) { + account.set({ + name: results.name, + preferred_name: results.name, }); - }) - ); - } - - return Promise.props({ - tas: Promise.all(tas) - }); - }).then(() => { - home.emit_new_queue_data(); - respond_success(req, res, `TAs created successfully`); - }).catch(err => { - console.log(err); - message = err.message || "An error occurred while creating uploaded tas"; - respond_error(req, res, message, 500); + } + return account.save(); + })(), + semester_user: models.semester_user.findOrCreate({ + where: { + user_id: account.user_id, + sem_id: adminSettings.currSem, + }, + }), + ta: models.ta.findOrCreate({ + where: { + ta_id: account.user_id, + }, + }), + isAdmin: results.isAdmin, + }); + }) + .then((results) => { + return Promise.props({ + semester_user: results.semester_user[0].update({ + is_ta: 1, + }), + ta: results.ta[0].update({ + is_admin: results.isAdmin ? 1 : 0, + }), + }); + }) + ); + } + + return Promise.props({ + tas: Promise.all(tas), + }); + }) + .then(() => { + home.emit_new_queue_data(); + respond_success(req, res, `TAs created successfully`); + }) + .catch((err) => { + console.log(err); + message = err.message || 'An error occurred while creating uploaded tas'; + respond_error(req, res, message, 500); }); -} +}; /* BEGIN LOCATIONS */ // invariant: rooms are held at -1 to make sure they appear in the options, but could be empty days @@ -841,142 +1052,157 @@ exports.post_upload_ta_csv = function (req, res) { // mapping is 1-to-1 where Sunday = 0... Saturday = 6 const dayToRoomDictionary = (obj) => { - if (obj) { - return Object.entries(obj).reduce((ret, entry) => { - const [key, rooms] = entry; - for (let roomIdx in rooms) { - let room = rooms[roomIdx] - if (ret[room]) { - // seen before - let keyInt = parseInt(key) - if (keyInt != null) { - ret[room].push(keyInt) - } - } else { - let keyInt = parseInt(key) - if (keyInt != null) { - ret[room] = [keyInt] - } - } - } + if (obj) { + return Object.entries(obj).reduce((ret, entry) => { + const [key, rooms] = entry; + for (let roomIdx in rooms) { + let room = rooms[roomIdx]; + if (ret[room]) { + // seen before + let keyInt = parseInt(key); + if (keyInt != null) { + ret[room].push(keyInt); + } + } else { + let keyInt = parseInt(key); + if (keyInt != null) { + ret[room] = [keyInt]; + } + } + } - return ret; - }, {}) - } else { - return {} - } -} + return ret; + }, {}); + } else { + return {}; + } +}; exports.add_location = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var room = req.body.room; - if (!room) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - if (adminSettings.dayDictionary["-1"]) { - adminSettings.dayDictionary["-1"].push(room) - } else { - adminSettings.dayDictionary["-1"] = [room] - } - - writeAdminSettings(adminSettings); - home.emit_new_queue_data(); - respond_success(req, res, `Location added successfully`); -} + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var room = req.body.room; + if (!room) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + if (adminSettings.dayDictionary['-1']) { + adminSettings.dayDictionary['-1'].push(room); + } else { + adminSettings.dayDictionary['-1'] = [room]; + } + + writeAdminSettings(adminSettings); + home.emit_new_queue_data(); + respond_success(req, res, `Location added successfully`); +}; exports.post_update_locations = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var room = req.body.room; - var days = req.body.days; - var daysOfWeek = req.body.daysOfWeek; - if (!room || !days || !daysOfWeek) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; - } - - var newDayDictionary = adminSettings.dayDictionary - for (var day in daysOfWeek) { - if (days.includes(daysOfWeek[day])) { - // day is selected for room - // check to see if room already appears for that day in dayDictionary - let currRoomForDay = newDayDictionary[day] - if (!currRoomForDay) { - // no rooms for this day yet - newDayDictionary[day] = [room] - } else if (currRoomForDay && !currRoomForDay.includes(room)) { - currRoomForDay.push(room) - newDayDictionary[day] = currRoomForDay - } - } else { - // day is NOT selected for room - // make sure that it room doesn't appear for that day - let currRoomForDay = newDayDictionary[day] - if (currRoomForDay && currRoomForDay.includes(room)) { - currRoomForDay.splice(currRoomForDay.indexOf(room), 1) - newDayDictionary[day] = currRoomForDay - } - } + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var room = req.body.room; + var days = req.body.days; + var daysOfWeek = req.body.daysOfWeek; + if (!room || !days || !daysOfWeek) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + var newDayDictionary = adminSettings.dayDictionary; + for (var day in daysOfWeek) { + if (days.includes(daysOfWeek[day])) { + // day is selected for room + // check to see if room already appears for that day in dayDictionary + let currRoomForDay = newDayDictionary[day]; + if (!currRoomForDay) { + // no rooms for this day yet + newDayDictionary[day] = [room]; + } else if (currRoomForDay && !currRoomForDay.includes(room)) { + currRoomForDay.push(room); + newDayDictionary[day] = currRoomForDay; + } + } else { + // day is NOT selected for room + // make sure that it room doesn't appear for that day + let currRoomForDay = newDayDictionary[day]; + if (currRoomForDay && currRoomForDay.includes(room)) { + currRoomForDay.splice(currRoomForDay.indexOf(room), 1); + newDayDictionary[day] = currRoomForDay; + } } - adminSettings.dayDictionary = newDayDictionary + } + adminSettings.dayDictionary = newDayDictionary; - writeAdminSettings(adminSettings); - home.emit_new_queue_data(); - respond_success(req, res, `Location changed successfully`); -} + writeAdminSettings(adminSettings); + home.emit_new_queue_data(); + respond_success(req, res, `Location changed successfully`); +}; exports.internal_get_locations = function () { - return { - dayDictionary: adminSettings.dayDictionary, - roomDictionary: dayToRoomDictionary(adminSettings.dayDictionary) - } -} + return { + dayDictionary: adminSettings.dayDictionary, + roomDictionary: dayToRoomDictionary(adminSettings.dayDictionary), + }; +}; exports.remove_location = function (req, res) { - if (!req.user || !req.user.isAdmin) { - respond_error(req, res, "You don't have permissions to perform this operation", 403); - return; - } - - var room = req.body.room; - var days = req.body.days; - if (!room || !days) { - respond_error(req, res, "Invalid/missing parameters in request", 400); - return; + if (!req.user || !req.user.isAdmin) { + respond_error( + req, + res, + "You don't have permissions to perform this operation", + 403 + ); + return; + } + + var room = req.body.room; + var days = req.body.days; + if (!room || !days) { + respond_error(req, res, 'Invalid/missing parameters in request', 400); + return; + } + + for (dayIdx in days) { + if (dayIdx && dayIdx != null) { + let dayInt = days[dayIdx]; + if (!adminSettings.dayDictionary[dayInt].includes(room)) { + console.log("hmm shouldn't really have a day selected for this room"); + } else { + let roomArrForDay = adminSettings.dayDictionary[dayInt]; + // safe because room is in roomArrForDay so idx >= 0 + roomArrForDay.splice(roomArrForDay.indexOf(room), 1); + adminSettings.dayDictionary[dayInt] = roomArrForDay; + } } - - for (dayIdx in days) { - if (dayIdx && dayIdx != null) { - let dayInt = days[dayIdx] - if (!adminSettings.dayDictionary[dayInt].includes(room)) { - console.log("hmm shouldn't really have a day selected for this room") - } else { - let roomArrForDay = adminSettings.dayDictionary[dayInt] - // safe because room is in roomArrForDay so idx >= 0 - roomArrForDay.splice(roomArrForDay.indexOf(room), 1) - adminSettings.dayDictionary[dayInt] = roomArrForDay - } - } - } - - // REMOVE ROOM FROM -1!! - let emptyRoomArr = adminSettings.dayDictionary["-1"] - let idx = emptyRoomArr.indexOf(room) - if (idx >= 0) { - emptyRoomArr.splice(idx, 1) - } - adminSettings.dayDictionary["-1"] = emptyRoomArr - - writeAdminSettings(adminSettings); - home.emit_new_queue_data(); - respond_success(req, res, `Location removed successfully`); -} + } + + // REMOVE ROOM FROM -1!! + let emptyRoomArr = adminSettings.dayDictionary['-1']; + let idx = emptyRoomArr.indexOf(room); + if (idx >= 0) { + emptyRoomArr.splice(idx, 1); + } + adminSettings.dayDictionary['-1'] = emptyRoomArr; + + writeAdminSettings(adminSettings); + home.emit_new_queue_data(); + respond_success(req, res, `Location removed successfully`); +}; From 074c142b2a77b30fbd6a7c90e2e8e0c8adc3a453 Mon Sep 17 00:00:00 2001 From: Jackson Romero Date: Thu, 3 Oct 2024 22:56:34 -0400 Subject: [PATCH 4/4] nvm that was a dumb idea --- server/controllers/settings.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/controllers/settings.js b/server/controllers/settings.js index bfae5651..c97af04c 100644 --- a/server/controllers/settings.js +++ b/server/controllers/settings.js @@ -271,7 +271,6 @@ exports.post_update_course_name = function (req, res) { // database. adminSettings.courseName = courseName; writeAdminSettings(adminSettings); - home.emit_new_queue_data(); respond_success( req, res,