diff --git a/services/nginx/app/modules/selfserve/classes/selfserve_studio_graph.php b/services/nginx/app/modules/selfserve/classes/selfserve_studio_graph.php index 935605fa..6d0d9f6c 100644 --- a/services/nginx/app/modules/selfserve/classes/selfserve_studio_graph.php +++ b/services/nginx/app/modules/selfserve/classes/selfserve_studio_graph.php @@ -340,7 +340,7 @@ class selfserve_studio_graph if ($versioning->isV2Config($config)) { foreach ($operations as $operation) { if (is_array($operation)) { - $this->applyConfigOperation($departmentId, $config, $operation); + $this->applyConfigOperation($departmentId, $config, $operation, $permissions); } } @@ -354,7 +354,7 @@ class selfserve_studio_graph } else { foreach ($operations as $operation) { if (is_array($operation)) { - $this->applyOperation($departmentId, $operation); + $this->applyOperation($departmentId, $operation, $permissions); } } } @@ -1511,7 +1511,7 @@ class selfserve_studio_graph * @param array $config * @param array $operation */ - private function applyConfigOperation(int $departmentId, array &$config, array $operation): void + private function applyConfigOperation(int $departmentId, array &$config, array $operation, array $permissions = []): void { $action = strtolower((string)($operation['action'] ?? '')); $entity = $this->normalizeEntity((string)($operation['entity'] ?? $operation['type'] ?? '')); @@ -1534,7 +1534,7 @@ class selfserve_studio_graph throw new \RuntimeException('Studio graph operation is missing entity.'); } if ($entity === 'lane') { - $this->applyLaneOperation($departmentId, $action, $id, $data); + $this->applyLaneOperation($departmentId, $action, $id, $data, $permissions); return; } if ($entity === 'rule') { @@ -2043,7 +2043,7 @@ class selfserve_studio_graph /** * @param array $operation */ - private function applyOperation(int $departmentId, array $operation): void + private function applyOperation(int $departmentId, array $operation, array $permissions = []): void { $action = strtolower((string)($operation['action'] ?? '')); $entity = $this->normalizeEntity((string)($operation['entity'] ?? $operation['type'] ?? '')); @@ -2066,7 +2066,7 @@ class selfserve_studio_graph throw new \RuntimeException('Studio graph operation is missing entity.'); } if ($entity === 'lane') { - $this->applyLaneOperation($departmentId, $action, $id, $data); + $this->applyLaneOperation($departmentId, $action, $id, $data, $permissions); return; } @@ -2092,12 +2092,14 @@ class selfserve_studio_graph /** * @param array $data */ - private function applyLaneOperation(int $departmentId, string $action, int $id, array $data): void + private function applyLaneOperation(int $departmentId, string $action, int $id, array $data, array $permissions = []): void { if (!$this->tableExists('department_lanes')) { throw new \RuntimeException('Department lanes are not available.'); } + $this->assertLaneOperationAuthorized($action, $data, $permissions); + if ($action === 'create') { $this->createLane($departmentId, $data); return; @@ -2124,6 +2126,37 @@ class selfserve_studio_graph throw new \RuntimeException('Unsupported studio lane operation: ' . $action); } + /** + * @param array $data + * @param array $permissions + */ + private function assertLaneOperationAuthorized(string $action, array $data, array $permissions): void + { + if ($action === 'create' && !($permissions['can_add_department_lane'] ?? false)) { + throw new \RuntimeException('Missing permission: add_department_lane.'); + } + if (in_array($action, ['update', 'delete'], true) && !($permissions['can_edit_department_lane'] ?? false)) { + throw new \RuntimeException('Missing permission: edit_department_lane.'); + } + + if (!in_array($action, ['create', 'update'], true)) { + return; + } + + $relayFields = [ + 'relay_in_id', + 'relay_out_id', + 'relay_machine_id', + 'relay_machine_program_picker_id', + 'relay_machine_cleaner_id', + ]; + foreach ($relayFields as $field) { + if (array_key_exists($field, $data) && !($permissions['modules_shelly_config'] ?? false)) { + throw new \RuntimeException('Missing permission: modules_shelly_config.'); + } + } + } + /** * @param array $data */ diff --git a/services/nginx/app/routes/departmentSelfserveStudioRoute.php b/services/nginx/app/routes/departmentSelfserveStudioRoute.php index 49a23599..82ec7d2f 100644 --- a/services/nginx/app/routes/departmentSelfserveStudioRoute.php +++ b/services/nginx/app/routes/departmentSelfserveStudioRoute.php @@ -306,6 +306,8 @@ class departmentSelfserveStudioRoute 'can_publish' => $this->hasPermission('publish_department_selfserve_config_versions'), 'can_rollback' => $this->hasPermission('rollback_department_selfserve_config_versions'), 'can_simulate' => $this->hasPermission('list_department_selfserve_vehicle_conditions'), + 'can_add_department_lane' => $this->hasPermission('add_department_lane'), + 'can_edit_department_lane' => $this->hasPermission('edit_department_lane'), 'modules_shelly_config' => $this->hasPermission('modules_shelly_config'), 'can_manage_gateways' => $this->hasPermission('modules_shelly_config'), 'can_run_gateway_destructive_actions' => $this->hasPermission('modules_shelly_config'),