From 008e2af09a3113017bbbfd0d485b599b7da6edd4 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Wed, 18 Feb 2026 12:47:00 +0100 Subject: [PATCH] Add support for self-serve task services and validation logic - Introduce `services` property to `department_selfserve_tasks_o` for task-specific functionalities. - Add service validation and normalization via `selfserve_lane_services` enum. - Extend `departmentSelfserveTasksRoute` to handle `services` input for add/edit operations. - Create `selfserve_lane_services` enum to define and validate service types. --- .../helpers/selfserve_lane_services.php | 9 +++ .../objects/department_selfserve_tasks_o.php | 36 ++++++++- .../routes/departmentSelfserveTasksRoute.php | 75 ++++++++++++++++++- 3 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 services/nginx/app/modules/selfserve/helpers/selfserve_lane_services.php diff --git a/services/nginx/app/modules/selfserve/helpers/selfserve_lane_services.php b/services/nginx/app/modules/selfserve/helpers/selfserve_lane_services.php new file mode 100644 index 00000000..2dc4c6ac --- /dev/null +++ b/services/nginx/app/modules/selfserve/helpers/selfserve_lane_services.php @@ -0,0 +1,9 @@ +escape_string($task); $description = $db->escape_string($description); $order_priority = (int)$order_priority; + // If the services array is not null, validate and normalize to array of service names (strings) + $services_names = null; + if (!is_null($services)) { + $services_names = []; + foreach ($services as $service) { + if ($service instanceof selfserve_lane_services) { + $services_names[] = $service->name; // store by name + continue; + } + if (is_string($service)) { + $name = strtoupper(trim($service)); + $valid = false; + foreach (selfserve_lane_services::cases() as $case) { + if ($case->name === $name) { + $valid = true; + break; + } + } + if (!$valid) { + throw new Exception("Invalid service: " . $service); + } + $services_names[] = $name; + continue; + } + throw new Exception("Invalid service type"); + } + } // Add the object $tmp_id = self::add_object([ 'department' => $department, @@ -79,6 +110,7 @@ class department_selfserve_tasks_o extends db 'task' => $task, 'description' => $description, 'order_priority' => $order_priority, + 'services' => $services_names, ]); $this->id = $tmp_id; self::getObjectProperties(); @@ -96,6 +128,7 @@ class department_selfserve_tasks_o extends db $this->task = new object_property($this->table, $this->id, 'task', 'string', false); $this->description = new object_property($this->table, $this->id, 'description', 'string', false); $this->order_priority = new object_property($this->table, $this->id, 'order_priority', 'int', false); + $this->services = new object_property($this->table, $this->id, 'services', 'json', false); $this->created_at = new object_property($this->table, $this->id, 'created_at', 'timestamp', false); $this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'timestamp', false); $this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'timestamp', false); @@ -117,6 +150,7 @@ class department_selfserve_tasks_o extends db 'task' => (string)$this->task->value(), 'description' => (string)$this->description->value(), 'order_priority' => (int)$this->order_priority->value(), + 'services' => (array)$this->services->value(), // Timestamps 'created_at' => (string)$this->created_at->value(), 'updated_at' => (string)$this->updated_at->value(), diff --git a/services/nginx/app/routes/departmentSelfserveTasksRoute.php b/services/nginx/app/routes/departmentSelfserveTasksRoute.php index 0fc99896..5c5ce73f 100644 --- a/services/nginx/app/routes/departmentSelfserveTasksRoute.php +++ b/services/nginx/app/routes/departmentSelfserveTasksRoute.php @@ -12,6 +12,7 @@ use objects\logs_o; use attachments\helpers\attachment_content; use classes\attachment_store; use classes\attachments; +use modules\selfserve\helpers\selfserve_lane_services; use traits\route_t; class departmentSelfserveTasksRoute @@ -109,6 +110,40 @@ class departmentSelfserveTasksRoute $task = (string)$response->getRequestParameter('task'); $description = (string)$response->getRequestParameter('description'); $order_priority = (int)($response->getRequestParameter('order_priority') ?? 0); + // Optional services + $services_param = $response->isRequestParameterSet('services') ? $response->getRequestParameter('services') : null; + $services_enums = null; + if (!is_null($services_param)) { + // Accept array, JSON string, or comma-separated string + $raw = $services_param; + if (is_string($raw)) { + $decoded = json_decode($raw, true); + if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { + $raw = $decoded; + } else { + $raw = array_filter(array_map(function ($s) { return trim($s); }, explode(',', $services_param)), fn($s) => $s !== ''); + } + } + if (!is_array($raw)) { + $response->error('Invalid format for services. Expected array, JSON array, or comma-separated string of service names.', 400); + } + // Map to enum cases by name (case-insensitive) + $services_enums = []; + foreach ($raw as $srv) { + $name = strtoupper(is_string($srv) ? trim($srv) : (string)$srv); + $matched = null; + foreach (selfserve_lane_services::cases() as $case) { + if ($case->name === $name) { + $matched = $case; + break; + } + } + if (!$matched) { + $response->error('Invalid service: ' . (string)$srv, 400); + } + $services_enums[] = $matched; + } + } if (!$department || !$lane || !$product || !$task || !$description) { $response->error('Missing required fields', 400); @@ -127,7 +162,8 @@ class departmentSelfserveTasksRoute $condition_id, $task, $description, - $order_priority + $order_priority, + $services_enums, ); (new logs_o())->add('department_selfserve_tasks', 'global', 1, $user->id, 'ADD_TASK', 'User added a department self-serve task: ' . $task); $response->success($task_o->asArray()); @@ -188,6 +224,43 @@ class departmentSelfserveTasksRoute if (self::isParametersSet(['order_priority'])) { $task_o->order_priority->set((int)self::getParameter('order_priority')); } + if (self::isParametersSet(['services'])) { + $param = self::getParameter('services'); + if ($param === null) { + // Explicitly clear services + $task_o->services->set(null); + } else { + $raw = $param; + if (is_string($raw)) { + $decoded = json_decode($raw, true); + if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { + $raw = $decoded; + } else { + $raw = array_filter(array_map(function ($s) { return trim($s); }, explode(',', $param)), fn($s) => $s !== ''); + } + } + if (!is_array($raw)) { + $response->error('Invalid format for services. Expected array, JSON array, or comma-separated string of service names.', 400); + } + // Validate and store names + $names = []; + foreach ($raw as $srv) { + $name = strtoupper(is_string($srv) ? trim($srv) : (string)$srv); + $valid = false; + foreach (selfserve_lane_services::cases() as $case) { + if ($case->name === $name) { + $valid = true; + break; + } + } + if (!$valid) { + $response->error('Invalid service: ' . (string)$srv, 400); + } + $names[] = $name; + } + $task_o->services->set($names); + } + } (new logs_o())->add('department_selfserve_tasks', 'global', 1, $user->id, 'EDIT_TASK', 'User updated department self-serve task ID: ' . $id); $response->success($task_o->asArray());