From 680c0ed1f56ec222b1a06b0da54eaf269c40329f Mon Sep 17 00:00:00 2001 From: Emre Ozden Date: Thu, 17 Jul 2025 23:40:57 +0300 Subject: [PATCH 1/3] Added PATCH route to API for pizza. Started working on handler --- server/src/routes/application/application-handlers.ts | 10 ++++++++++ server/src/routes/application/index.ts | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/server/src/routes/application/application-handlers.ts b/server/src/routes/application/application-handlers.ts index 2dbbc257..795f7214 100644 --- a/server/src/routes/application/application-handlers.ts +++ b/server/src/routes/application/application-handlers.ts @@ -633,6 +633,16 @@ class ApplicationHandlers { response.sendStatus(200) } } + + @onlyKnownUsers() + patchPizza(): Middleware { + return async (request, _response) => { + const { user } = request + assert(user) + + // Do some magic here + } + } } const applicationHandlers = new ApplicationHandlers() diff --git a/server/src/routes/application/index.ts b/server/src/routes/application/index.ts index abe6c739..4e0f4e44 100644 --- a/server/src/routes/application/index.ts +++ b/server/src/routes/application/index.ts @@ -63,6 +63,13 @@ applicationApp .patch(applicationHandlers.patchCv()) .all(forbiddenOrUnauthorised()) +applicationApp + .route("/pizza") + .all(methodNotAllowed(["PATCH"])) + .all(authenticate()) + .patch(applicationHandlers.patchPizza()) + .all(forbiddenOrUnauthorised()) + applicationApp .route("/submit") .all(methodNotAllowed(["POST"])) From 1de25a23ac6cddbd02a200281bf81f84d66a2c89 Mon Sep 17 00:00:00 2001 From: Emre Ozden Date: Fri, 18 Jul 2025 00:10:14 +0300 Subject: [PATCH 2/3] Defined pizza choice schema and types in zod --- common/src/input/pizza-flavor.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 common/src/input/pizza-flavor.ts diff --git a/common/src/input/pizza-flavor.ts b/common/src/input/pizza-flavor.ts new file mode 100644 index 00000000..2a565754 --- /dev/null +++ b/common/src/input/pizza-flavor.ts @@ -0,0 +1,21 @@ +import { z } from "zod/v4" +import { recordEntries } from "@/util/record-entries" + +export const pizzaFlavorSchema = z.enum(["nothing", "alternative", "margherita", "pepperoni"]) + +export type PizzaFlavor = z.output + +const PizzaFlavourMetadata: Record = { + nothing: { label: "Nothing" }, + alternative: { label: "Alternative" }, + margherita: { label: "Margherita" }, + pepperoni: { label: "Pepperoni" }, +} + +export const pizzaFlavourOptions = recordEntries(PizzaFlavourMetadata).map(([value, metadata]) => ({ + value, + label: metadata.label, +})) satisfies Array<{ + value: PizzaFlavor + label: string +}> From 9b8d3d6567c17b4abfafe3e41d28738ba96447ce Mon Sep 17 00:00:00 2001 From: Emre Ozden Date: Fri, 18 Jul 2025 00:52:13 +0300 Subject: [PATCH 3/3] Thought it may be a better idea to include pizza flavor under extra details, removed API route for pizza, started working on adding it to PATCH /applications/personal --- common/src/types/application.ts | 2 ++ .../src/routes/application/application-handlers.ts | 12 ++++++++++++ server/src/routes/application/index.ts | 7 ------- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/common/src/types/application.ts b/common/src/types/application.ts index a39d249c..8b1d32a3 100644 --- a/common/src/types/application.ts +++ b/common/src/types/application.ts @@ -1,5 +1,6 @@ import type { DisciplineOfStudy } from "@/input/discipline-of-study" import type { DietaryRequirement } from "@/input/dietary-requirement" +import { PizzaFlavor } from "@/input/pizza-flavor"; export type { DisciplineOfStudy, DietaryRequirement } @@ -23,6 +24,7 @@ export type Application = { university: string | null graduationYear: number | null disciplinesOfStudy: null | DisciplineOfStudy[] + pizzaFlavors: null | PizzaFlavor[] levelOfStudy: | null | "secondary" diff --git a/server/src/routes/application/application-handlers.ts b/server/src/routes/application/application-handlers.ts index 795f7214..e91ee277 100644 --- a/server/src/routes/application/application-handlers.ts +++ b/server/src/routes/application/application-handlers.ts @@ -2,6 +2,7 @@ import assert from "node:assert/strict" import { parse as parsePath } from "node:path/posix" import { type DietaryRequirement, dietaryRequirementSchema } from "@durhack/durhack-common/input/dietary-requirement" import { type DisciplineOfStudy, disciplineOfStudySchema } from "@durhack/durhack-common/input/discipline-of-study" +import { type PizzaFlavor, pizzaFlavorSchema } from "@durhack/durhack-common/input/pizza-flavor" import type { Application } from "@durhack/durhack-common/types/application" import { ClientError, HttpStatus } from "@otterhttp/errors" import type { ContentType, ParsedFormFieldFile } from "@otterhttp/parsec" @@ -49,6 +50,13 @@ const personalFormSchema = z.object({ message: "Please select an ethnicity", }) .transform(adaptEthnicityToDatabase), + pizza: z + .array(pizzaFlavorSchema) + .min(1, { message: "Please select at least one pizza flavor." }) + .refine((list) => { + const mutuallyExclusivePreferences = list.filter((item) => item === "alternative" || item === "nothing") + return mutuallyExclusivePreferences.length <= 1 + }, "If you don't want pizza, please choose one of 'nothing' or 'alternative'."), }) const contactFormSchema = z.object({ @@ -154,6 +162,9 @@ class ApplicationHandlers { const dietaryRequirements = userFlags .filter((flag) => flag.flagName.startsWith("dietary-requirement:")) .map((flag) => flag.flagName.slice(20) as DietaryRequirement) + const pizzaFlavors = userFlags + .filter((flag) => flag.flagName.startsWith("pizza-flavor:")) + .map((flag) => flag.flagName.slice(13) as PizzaFlavor) const { phone_number, @@ -190,6 +201,7 @@ class ApplicationHandlers { disciplinesOfStudy: disciplinesOfStudy, tShirtSize: (userInfo?.tShirtSize?.trimEnd() as Application["tShirtSize"] | null | undefined) ?? null, dietaryRequirements: dietaryRequirements, + pizzaFlavors: pizzaFlavors, accessRequirements: userInfo?.accessRequirements ?? null, countryOfResidence: userInfo?.countryOfResidence ?? null, consents: userConsents.map((consent) => ({ name: consent.consentName, choice: consent.choice })), diff --git a/server/src/routes/application/index.ts b/server/src/routes/application/index.ts index 4e0f4e44..abe6c739 100644 --- a/server/src/routes/application/index.ts +++ b/server/src/routes/application/index.ts @@ -63,13 +63,6 @@ applicationApp .patch(applicationHandlers.patchCv()) .all(forbiddenOrUnauthorised()) -applicationApp - .route("/pizza") - .all(methodNotAllowed(["PATCH"])) - .all(authenticate()) - .patch(applicationHandlers.patchPizza()) - .all(forbiddenOrUnauthorised()) - applicationApp .route("/submit") .all(methodNotAllowed(["POST"]))