From ef32fc32f03e6c632faff70a56f5b46743002635 Mon Sep 17 00:00:00 2001 From: ArmaanMehra Date: Sun, 16 Feb 2025 02:53:56 -0500 Subject: [PATCH 1/2] #141 task template stages visibility successfully toggles. --- packages/api/src/models/battery.ts | 1 + packages/api/src/routes/admin.route.ts | 12 +++++++++++ packages/api/src/services/admin.service.ts | 25 ++++++++++++++++++++++ packages/shared/types/models/battery.ts | 1 + 4 files changed, 39 insertions(+) diff --git a/packages/api/src/models/battery.ts b/packages/api/src/models/battery.ts index 2844e50..623f5e3 100644 --- a/packages/api/src/models/battery.ts +++ b/packages/api/src/models/battery.ts @@ -28,6 +28,7 @@ const batteryStageSchema = new Schema({ type: { type: String, required: true }, stageLabel: String, options: optionGroupSchema, + isVisibleToNonAdmins: { type: Boolean, default: true }, }); const optArray = optionGroupSchema.path("options"); diff --git a/packages/api/src/routes/admin.route.ts b/packages/api/src/routes/admin.route.ts index 7840f16..7d662fb 100644 --- a/packages/api/src/routes/admin.route.ts +++ b/packages/api/src/routes/admin.route.ts @@ -42,4 +42,16 @@ router.delete( route((req) => adminService.removeUserAsAdmin(req.params.id)) ); +router.put( + "/battery/:id/stage/:stageId/visibility/:status", + isAdmin, + route((req) => + adminService.updateStageVisibility( + req.params.id, + req.params.stageId, + req.params.status + ) + ) +); + export default router; diff --git a/packages/api/src/services/admin.service.ts b/packages/api/src/services/admin.service.ts index cf1d438..043c91a 100644 --- a/packages/api/src/services/admin.service.ts +++ b/packages/api/src/services/admin.service.ts @@ -87,6 +87,31 @@ export const removeUserAsAdmin = async (userId: string): APIResponse => { return [200]; }; +export const updateStageVisibility = async ( + batteryId: string, + stageId: string, + visibility: string +): APIResponse => { + if (visibility !== "on" && visibility !== "off") { + throw new HttpError(400, "Invalid visibility must be 'on' or 'off'"); + } + const visibilityBool = visibility === "on"; + const updatedBattery = await Battery.findOneAndUpdate( + { _id: batteryId, "stages._id": stageId }, + { $set: { "stages.$.isVisibleToNonAdmins": visibilityBool } }, + { new: true } + ); + + if (!updatedBattery) { + throw new HttpError( + 404, + `Battery ${batteryId} or Stage ${stageId} not found.` + ); + } + + return [200, updatedBattery]; +}; + function parseOptions(s: any): CreateOption[] { return Object.entries(s).reduce((acc: CreateOption[], item: any) => { const optionName = item[0]; diff --git a/packages/shared/types/models/battery.ts b/packages/shared/types/models/battery.ts index 388773f..95565d3 100644 --- a/packages/shared/types/models/battery.ts +++ b/packages/shared/types/models/battery.ts @@ -53,6 +53,7 @@ export interface CreateBatteryStage { type: string; stageLabel: string; options: CreateOptionGroup; + isVisibleToNonAdmins: boolean; } export interface IBatteryStage extends Required { From 104e868d9389691b8f56b73102188db189053cf8 Mon Sep 17 00:00:00 2001 From: Bradford Derby Date: Sat, 22 Feb 2025 10:43:40 -0500 Subject: [PATCH 2/2] addressing comment - visibility error handling --- packages/api/src/services/admin.service.ts | 9 ++++----- packages/api/src/types/errors.ts | 6 ++++++ packages/api/src/util/validation.utils.ts | 23 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 packages/api/src/util/validation.utils.ts diff --git a/packages/api/src/services/admin.service.ts b/packages/api/src/services/admin.service.ts index 043c91a..f7fc1cc 100644 --- a/packages/api/src/services/admin.service.ts +++ b/packages/api/src/services/admin.service.ts @@ -10,6 +10,7 @@ import type { IBattery, IUser, } from "@seitz/shared"; +import { parseVisibility } from "@/util/validation.utils"; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -92,13 +93,11 @@ export const updateStageVisibility = async ( stageId: string, visibility: string ): APIResponse => { - if (visibility !== "on" && visibility !== "off") { - throw new HttpError(400, "Invalid visibility must be 'on' or 'off'"); - } - const visibilityBool = visibility === "on"; + const isVisibleToNonAdmins = parseVisibility(visibility); + const updatedBattery = await Battery.findOneAndUpdate( { _id: batteryId, "stages._id": stageId }, - { $set: { "stages.$.isVisibleToNonAdmins": visibilityBool } }, + { $set: { "stages.$.isVisibleToNonAdmins": isVisibleToNonAdmins } }, { new: true } ); diff --git a/packages/api/src/types/errors.ts b/packages/api/src/types/errors.ts index 39a99c4..3fc68be 100644 --- a/packages/api/src/types/errors.ts +++ b/packages/api/src/types/errors.ts @@ -6,3 +6,9 @@ export default class HttpError extends Error { this.status = status; } } + +export class VisibilityError extends HttpError { + constructor(message: string) { + super(403, message); + } +} diff --git a/packages/api/src/util/validation.utils.ts b/packages/api/src/util/validation.utils.ts new file mode 100644 index 0000000..1d2f905 --- /dev/null +++ b/packages/api/src/util/validation.utils.ts @@ -0,0 +1,23 @@ +import { VisibilityError } from "@/types/errors"; + +export enum Visibility { + ON = "on", + OFF = "off", +} + +export const parseVisibility = (visibility: string): boolean => { + try { + if (!Object.values(Visibility).includes(visibility as Visibility)) { + throw new VisibilityError( + `Invalid visibility value: '${visibility}'. Must be either '${Visibility.ON}' or '${Visibility.OFF}'` + ); + } + return visibility === Visibility.ON; + } catch (e) { + // Log the error for monitoring but default to OFF for safety - debugging statement :/ + console.warn( + `Invalid visibility value received: ${visibility}. Defaulting to OFF` + ); + return false; + } +};