From 9f0f8767fca57911b7e9b53d1b053a5f44a9ff18 Mon Sep 17 00:00:00 2001 From: Carifio24 Date: Tue, 19 Nov 2024 16:06:01 -0500 Subject: [PATCH 1/3] Add SQL definition and model for Hubble waiting room overrides. --- .../models/hubble_waiting_room_override.ts | 28 +++++++++++++++++++ .../create_hubble_waiting_room_overrides.sql | 11 ++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/stories/hubbles_law/models/hubble_waiting_room_override.ts create mode 100644 src/stories/hubbles_law/sql/create_hubble_waiting_room_overrides.sql diff --git a/src/stories/hubbles_law/models/hubble_waiting_room_override.ts b/src/stories/hubbles_law/models/hubble_waiting_room_override.ts new file mode 100644 index 0000000..c3399b2 --- /dev/null +++ b/src/stories/hubbles_law/models/hubble_waiting_room_override.ts @@ -0,0 +1,28 @@ +import { Class } from "../../../models"; +import { Sequelize, DataTypes, Model, InferAttributes, InferCreationAttributes, CreationOptional } from "sequelize"; + +export class HubbleWaitingRoomOverride extends Model, InferCreationAttributes> { + declare class_id: number; + declare timestamp: CreationOptional; +} + +export function initializeHubbleWaitingRoomOverrideModel(sequelize: Sequelize) { + HubbleWaitingRoomOverride.init({ + class_id: { + type: DataTypes.INTEGER.UNSIGNED, + allowNull: false, + primaryKey: true, + references: { + model: Class, + key: "id", + } + }, + timestamp: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"), + } + }, { + sequelize, + }); +} diff --git a/src/stories/hubbles_law/sql/create_hubble_waiting_room_overrides.sql b/src/stories/hubbles_law/sql/create_hubble_waiting_room_overrides.sql new file mode 100644 index 0000000..d7321ae --- /dev/null +++ b/src/stories/hubbles_law/sql/create_hubble_waiting_room_overrides.sql @@ -0,0 +1,11 @@ +CREATE TABLE HubbleWaitingRoomOverrides ( + class_id int(11) UNSIGNED NOT NULL, + timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + ON UPDATE CURRENT_TIMESTAMP, + + PRIMARY KEY(class_id), + FOREIGN KEY(class_id) + REFERENCES Classes(id) + ON UPDATE CASCADE + ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci PACK_KEYS=0; From 7fef701b3e28a6d624ab2b8588df4d50192000ee Mon Sep 17 00:00:00 2001 From: Carifio24 Date: Tue, 19 Nov 2024 16:10:08 -0500 Subject: [PATCH 2/3] Add waiting room override to Hubble's Law model setup. --- src/stories/hubbles_law/models/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/stories/hubbles_law/models/index.ts b/src/stories/hubbles_law/models/index.ts index 976c691..bd1fc12 100644 --- a/src/stories/hubbles_law/models/index.ts +++ b/src/stories/hubbles_law/models/index.ts @@ -7,13 +7,15 @@ import { Sequelize } from "sequelize"; import { initializeHubbleStudentDataModel } from "./hubble_student_data"; import { initializeHubbleClassDataModel } from "./hubble_class_data"; import { initializeHubbleClassMergeGroupModel } from "./hubble_class_merge_group"; +import { initializeHubbleWaitingRoomOverrideModel, HubbleWaitingRoomOverride } from "./hubble_waiting_room_override"; export { Galaxy, HubbleMeasurement, SampleHubbleMeasurement, AsyncMergedHubbleStudentClasses, - SyncMergedHubbleClasses + SyncMergedHubbleClasses, + HubbleWaitingRoomOverride }; export function initializeModels(db: Sequelize) { @@ -25,4 +27,5 @@ export function initializeModels(db: Sequelize) { initializeHubbleStudentDataModel(db); initializeHubbleClassDataModel(db); initializeHubbleClassMergeGroupModel(db); + initializeHubbleWaitingRoomOverrideModel(db); } From 523d45c5ad88de2a42f4e3b6c0d42e563348d446 Mon Sep 17 00:00:00 2001 From: Carifio24 Date: Tue, 19 Nov 2024 17:29:33 -0500 Subject: [PATCH 3/3] Add endpoints for adding or removing Hubble waiting room overrides. --- src/stories/hubbles_law/database.ts | 22 ++++++- src/stories/hubbles_law/router.ts | 94 ++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/src/stories/hubbles_law/database.ts b/src/stories/hubbles_law/database.ts index 8e8c1a7..65fad45 100644 --- a/src/stories/hubbles_law/database.ts +++ b/src/stories/hubbles_law/database.ts @@ -1,5 +1,5 @@ import { Attributes, FindOptions, Op, QueryTypes, Sequelize, WhereAttributeHash, WhereOptions, col, fn, literal } from "sequelize"; -import { AsyncMergedHubbleStudentClasses, Galaxy, HubbleMeasurement, SampleHubbleMeasurement, SyncMergedHubbleClasses } from "./models"; +import { AsyncMergedHubbleStudentClasses, Galaxy, HubbleMeasurement, HubbleWaitingRoomOverride, SampleHubbleMeasurement, SyncMergedHubbleClasses } from "./models"; import { classSize, findClassById, findStudentById } from "../../database"; import { RemoveHubbleMeasurementResult, SubmitHubbleMeasurementResult } from "./request_results"; import { Class, StoryState, Student, StudentsClasses } from "../../models"; @@ -848,3 +848,23 @@ export async function addClassToMergeGroup(classID: number): Promise { + return HubbleWaitingRoomOverride.findOrCreate({ + where: { + class_id: classID, + } + }) + .then(result => result[1]) + .catch((error: Error) => error); +} + +export async function removeWaitingRoomOverride(classID: number): Promise { + return HubbleWaitingRoomOverride.destroy({ + where: { + class_id: classID, + } + }) + .then(_result => true) + .catch(_error => false); +} diff --git a/src/stories/hubbles_law/router.ts b/src/stories/hubbles_law/router.ts index 0f4acc9..01db3ba 100644 --- a/src/stories/hubbles_law/router.ts +++ b/src/stories/hubbles_law/router.ts @@ -38,7 +38,9 @@ import { getClassMeasurementCount, getStudentsWithCompleteMeasurementsCount, getMergedIDsForClass, - addClassToMergeGroup + addClassToMergeGroup, + setWaitingRoomOverride, + removeWaitingRoomOverride } from "./database"; import { @@ -47,7 +49,7 @@ import { } from "./request_results"; import { Express, Router } from "express"; -import { Sequelize } from "sequelize"; +import { Sequelize, ForeignKeyConstraintError, UniqueConstraintError } from "sequelize"; import { classForStudentStory, findClassById, findStudentById } from "../../database"; import { initializeModels } from "./models"; import { setUpHubbleAssociations } from "./associations"; @@ -553,6 +555,94 @@ router.get("/spectra/:type/:name", async (req, res) => { }); +const WaitingRoomOverrideSchema = S.struct({ + class_id: S.number.pipe(S.int()), +}); + +router.put("/waiting-room-override", async (req, res) => { + const body = req.body; + const maybe = S.decodeUnknownEither(WaitingRoomOverrideSchema)(body); + if (Either.isLeft(maybe)) { + res.status(400).json({ + error: "Invalid format. Request body should have the form { class_id: }", + }); + return; + } + + const right = maybe.right; + const result = await setWaitingRoomOverride(right.class_id); + const success = !(result instanceof Error); + const responseData = { + success, + class_id: right.class_id, + }; + if (!success) { + if (result instanceof ForeignKeyConstraintError) { + res.status(404).json({ + ...responseData, + error: `No class found with ID ${right.class_id}`, + }); + + // It's fine if the override already exists + } else if (result instanceof UniqueConstraintError) { + res.status(200).json({ + class_id: right.class_id, + success: true, + message: `The waiting room override for class ${right.class_id} was already set`, + }); + } else { + res.status(500).json({ + ...responseData, + error: `An error occurred while setting the waiting room override for class ${right.class_id}`, + }); + } + return; + } + + if (result) { + res.status(201).json({ + ...responseData, + message: `Successfully set waiting room override for class ${right.class_id}`, + }); + } else { + res.status(200).json({ + message: `The waiting room override for class ${right.class_id} was already set`, + }); + } +}); + + +router.delete("/waiting-room-override", async (req, res) => { + const body = req.body; + const maybe = S.decodeUnknownEither(WaitingRoomOverrideSchema)(body); + if (Either.isLeft(maybe)) { + res.status(400).json({ + error: "Invalid format. Request body should have the form { class_id: }", + }); + return; + } + + const right = maybe.right; + const success = await removeWaitingRoomOverride(right.class_id); + const responseData = { + success, + class_id: right.class_id, + }; + if (!success) { + res.status(500).json({ + ...responseData, + error: `An error occurred while removing the waiting room override for class ${right.class_id}`, + }); + return; + } + + res.json({ + ...responseData, + message: `The waiting room override for class ${right.class_id} was removed, if one existed.`, + }); +}); + + /** These endpoints are specifically for the spectrum-checking branch */ router.get("/unchecked-galaxies", async (_req, res) => {