diff --git a/src/stories/minids/database.ts b/src/stories/minids/database.ts index e35d109..6cd1d55 100644 --- a/src/stories/minids/database.ts +++ b/src/stories/minids/database.ts @@ -31,7 +31,7 @@ export function isValidEclipseMiniData(data: any): data is EclipseMiniData { export async function submitEclipseMiniResponse(data: EclipseMiniData): Promise { - logger.verbose(`Attempting to submit measurement for user ${data.user_uuid}`); + logger.verbose(`Attempting to submit annular eclipse 2023 measurement for user ${data.user_uuid}`); const dataWithCounts = { ...data, diff --git a/src/stories/minids/router.ts b/src/stories/minids/router.ts index a7e300f..a1f3d1b 100644 --- a/src/stories/minids/router.ts +++ b/src/stories/minids/router.ts @@ -21,7 +21,7 @@ router.put("/annular-eclipse-2023/response", async (req, res) => { const response = await submitEclipseMiniResponse(data); if (!response) { res.status(400); - res.json({ error: "Error creating eclipse mini response" }); + res.json({ error: "Error creating annular eclipse 2023 mini response" }); return; } diff --git a/src/stories/solar-eclipse-2024/database.ts b/src/stories/solar-eclipse-2024/database.ts new file mode 100644 index 0000000..ade1487 --- /dev/null +++ b/src/stories/solar-eclipse-2024/database.ts @@ -0,0 +1,46 @@ +import { cosmicdsDB } from "../../database"; +import { logger } from "../../logger"; +import { + isArrayThatSatisfies, + isNumberArray, +} from "../../utils"; + +import { initializeModels, SolarEclipse2024Response } from "./models"; + +initializeModels(cosmicdsDB); + +export interface SolarEclipse2024Data { + user_uuid: string; + user_selected_locations: [number, number][], + timestamp: Date +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isValidSolarEclipseData(data: any): data is SolarEclipse2024Response { + return typeof data.user_uuid === "string" && + isArrayThatSatisfies(data.user_selected_locations, (arr) => { + return arr.every(x => isNumberArray(x) && x.length === 2); + }); +} + +export async function submitSolarEclipse2024Response(data: SolarEclipse2024Response): Promise { + + logger.verbose(`Attempting to submit solar eclipse 2024 measurement for user ${data.user_uuid}`); + + const dataWithCounts = { + ...data, + user_selected_locations_count: data.user_selected_locations.length + }; + + return SolarEclipse2024Response.upsert(dataWithCounts).then(([item, _]) => item); +} + +export async function getAllSolarEclipse2024Responses(): Promise { + return SolarEclipse2024Response.findAll(); +} + +export async function getSolarEclipse2024Response(userUUID: string): Promise { + return SolarEclipse2024Response.findOne({ + where: { user_uuid: userUUID } + }); +} diff --git a/src/stories/solar-eclipse-2024/main.ts b/src/stories/solar-eclipse-2024/main.ts new file mode 100644 index 0000000..95af5bb --- /dev/null +++ b/src/stories/solar-eclipse-2024/main.ts @@ -0,0 +1,6 @@ +import router from "./router"; + +module.exports = { + path: "/solar-eclipse-2024", + router +}; diff --git a/src/stories/solar-eclipse-2024/models/eclipse_response.ts b/src/stories/solar-eclipse-2024/models/eclipse_response.ts new file mode 100644 index 0000000..fef30df --- /dev/null +++ b/src/stories/solar-eclipse-2024/models/eclipse_response.ts @@ -0,0 +1,41 @@ +import { Sequelize, DataTypes, Model, InferAttributes, InferCreationAttributes, CreationOptional } from "sequelize"; + +export class SolarEclipse2024Response extends Model, InferCreationAttributes> { + declare id: CreationOptional; + declare user_uuid: string; + declare user_selected_locations: [number, number][]; + declare user_selected_locations_count: number; + declare timestamp: CreationOptional; +} + +export function initializeSolarEclipse2024ResponseModel(sequelize: Sequelize) { + SolarEclipse2024Response.init({ + id: { + type: DataTypes.INTEGER.UNSIGNED, + allowNull: false, + primaryKey: true, + autoIncrement: true + }, + user_uuid: { + type: DataTypes.STRING, + unique: true, + allowNull: false + }, + user_selected_locations: { + type: DataTypes.JSON, + allowNull: false + }, + user_selected_locations_count: { + type: DataTypes.INTEGER, + allowNull: false + }, + timestamp: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: Sequelize.literal("CURRENT_TIMESTAMP") + } + }, { + sequelize, + engine: "InnoDB" + }); +} diff --git a/src/stories/solar-eclipse-2024/models/index.ts b/src/stories/solar-eclipse-2024/models/index.ts new file mode 100644 index 0000000..ffc3095 --- /dev/null +++ b/src/stories/solar-eclipse-2024/models/index.ts @@ -0,0 +1,10 @@ +import { Sequelize } from "sequelize"; +import { SolarEclipse2024Response, initializeSolarEclipse2024ResponseModel } from "./eclipse_response"; + +export { + SolarEclipse2024Response +}; + +export function initializeModels(db: Sequelize) { + initializeSolarEclipse2024ResponseModel(db); +} diff --git a/src/stories/solar-eclipse-2024/router.ts b/src/stories/solar-eclipse-2024/router.ts new file mode 100644 index 0000000..9a44f45 --- /dev/null +++ b/src/stories/solar-eclipse-2024/router.ts @@ -0,0 +1,37 @@ +import { Router } from "express"; +import { getAllSolarEclipse2024Responses, getSolarEclipse2024Response, isValidSolarEclipseData, submitSolarEclipse2024Response } from "./database"; + +const router = Router(); + +router.put("/response", async (req, res) => { + const data = req.body; + const valid = isValidSolarEclipseData(data); + + if (!valid) { + res.status(400); + res.json({ error: "Malformed response submission" }); + return; + } + + const response = await submitSolarEclipse2024Response(data); + if (response === null) { + res.status(400); + res.json({ error: "Error creating solar eclipse 2024 response" }); + return; + } + + res.json({ response }); +}); + +router.get("/responses", async (_req, res) => { + const responses = await getAllSolarEclipse2024Responses(); + res.json({ responses }); +}); + +router.get("/response/:userUUID", async (req, res) => { + const uuid = req.params.userUUID as string; + const response = await getSolarEclipse2024Response(uuid); + res.json({ response }); +}); + +export default router; diff --git a/src/stories/solar-eclipse-2024/sql/create_eclipse_response_table.sql b/src/stories/solar-eclipse-2024/sql/create_eclipse_response_table.sql new file mode 100644 index 0000000..3ee8ffa --- /dev/null +++ b/src/stories/solar-eclipse-2024/sql/create_eclipse_response_table.sql @@ -0,0 +1,10 @@ +CREATE TABLE SolarEclipse2024Responses ( + id int(11) UNSIGNED NOT NULL UNIQUE AUTO_INCREMENT, + user_uuid varchar(36) NOT NULL UNIQUE, + user_selected_locations JSON NOT NULL, + user_selected_locations_count INT NOT NULL, + timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + + PRIMARY KEY(id), + INDEX(user_uuid) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci PACK_KEYS=0;