From cd894b4e3bd8a0f30b55da554c4583b83ca58608 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Thu, 12 Feb 2026 15:37:03 +0100 Subject: [PATCH] Refactor `orderBookingRoute` to integrate subuser-specific permission checks - Add dynamic authentication and subuser permission handling using `subusers_permission_node_key`. - Refactor route-level permission logic for creating, viewing, editing, and deleting bookings to respect subuser context. - Ensure proper error handling for unauthorized access and enforce departmental scope for admin-level actions. --- .../nginx/app/routes/orderBookingRoute.php | 92 +++++++++++++++++-- 1 file changed, 83 insertions(+), 9 deletions(-) diff --git a/services/nginx/app/routes/orderBookingRoute.php b/services/nginx/app/routes/orderBookingRoute.php index 49f3d2e9..09dd627d 100644 --- a/services/nginx/app/routes/orderBookingRoute.php +++ b/services/nginx/app/routes/orderBookingRoute.php @@ -36,6 +36,46 @@ class orderBookingRoute $po = self::getTargetPo(); // String | Null $pickup = self::getTargetPickup(); // Bool | Null $items = self::getTargetItems(); // Array of order_items_o objects + /** + * Authentication & Permissions + */ + $auth = new authentication(); + $user = $auth->get_user(); // Classic user (may be false if a subuser token is used) + $permission_own = self::definePermission('add_own_bookings', subusers_permission_node_key::BOOKINGS_ADD); // Subuser-aware: can add for own customer only + $permission_other = self::definePermission('add_bookings'); // Admin/department scope: can add for any customer within permitted departments + $has_permission_own = self::hasPermission($permission_own); + $has_permission_other = self::hasPermission($permission_other); + $has_permission = false; // Updated below + + // Own booking creation (either classic user for own customer or subuser with proper node on target customer) + if ($has_permission_own) { + $targetCustomer = (int)$customer_number->customer_number->value(); + $subuser = $auth->get_subuser(); + if ($subuser !== false) { + // For subusers ensure provided customer_number matches X-Customer-Number target context + $sub_target = $auth->get_subuser_customer_number_target(); + if ((int)$sub_target !== $targetCustomer) { + $response->error('You do not have permission to create bookings for this customer.', 403); + } + $has_permission = true; // Node permission already validated via hasPermission above + } else { + // Classic user: ensure creating for own customer only in the "own" permission path + if ($user !== false && (int)$user->customer_number->value() === $targetCustomer) { + $has_permission = true; + } + } + } + + // Department/admin booking creation for other customers + if (!$has_permission && $has_permission_other) { + // Must be within permitted department + self::requireDepartmentAccess((int)$department->id); + $has_permission = true; + } + + if (!$has_permission) { + $response->error('You do not have permission to create this order booking.', 403); + } /** * Input data */ @@ -60,7 +100,8 @@ class orderBookingRoute $response->success($order_bookings_o->asArray()); }, [ - // No Permissions required. + 'add_own_bookings' => 'Permission to create own order bookings. Subusers require node: BOOKINGS_ADD and X-Customer-Number header.', + 'add_bookings' => 'Permission to create department order bookings.' ] ); @@ -74,7 +115,8 @@ class orderBookingRoute /** * Authentication */ - $user = (new authentication())->get_user(); + $auth = new authentication(); + $user = $auth->get_user(); /** * Permissions */ @@ -84,8 +126,20 @@ class orderBookingRoute $has_permission_other = self::hasPermission($permission_other); $has_permission = false; // Updated below // Check if the user has permission to view their own bookings - if ($has_permission_own && (!$object || (int)$object->customer_number->value() === (int)$user->customer_number->value())) { - $has_permission = true; + if ($has_permission_own) { + if (!$object) { + $has_permission = true; + } else { + $subuser = $auth->get_subuser(); + if ($subuser !== false) { + $sub_target = $auth->get_subuser_customer_number_target(); + if ((int)$object->customer_number->value() === (int)$sub_target) { + $has_permission = true; + } + } elseif ($user !== false && (int)$object->customer_number->value() === (int)$user->customer_number->value()) { + $has_permission = true; + } + } } // Check if the user has permission to view other users' bookings if (!$has_permission && $has_permission_other) { @@ -145,7 +199,8 @@ class orderBookingRoute /** * Authentication */ - $user = (new authentication())->get_user(); + $auth = new authentication(); + $user = $auth->get_user(); /** * Permissions */ @@ -158,13 +213,23 @@ class orderBookingRoute $has_permission_other = self::hasPermission($permission_other); $has_permission = false; // Updated below // Check if the user has permission to edit their own bookings - if ($has_permission_own && (int)$object->customer_number->value() === (int)$user->customer_number->value()) { + if ($has_permission_own) { + $isOwn = false; + $subuser = $auth->get_subuser(); + if ($subuser !== false) { + $sub_target = $auth->get_subuser_customer_number_target(); + $isOwn = ((int)$object->customer_number->value() === (int)$sub_target); + } elseif ($user !== false) { + $isOwn = ((int)$object->customer_number->value() === (int)$user->customer_number->value()); + } + if ($isOwn) { // Check if the booking has a transaction associated with it // If this is the case, prevent user from editing the booking if (!$has_permission_other && $object->hasTransaction()) { $response->error('You cannot edit this order booking because it has a transaction associated with it.', 403); } $has_permission = true; + } } // Check if the user has permission to edit other users' bookings if (!$has_permission && $has_permission_other) { @@ -217,7 +282,8 @@ class orderBookingRoute /** * Authentication */ - $user = (new authentication())->get_user(); + $auth = new authentication(); + $user = $auth->get_user(); /** * Permissions */ @@ -230,8 +296,16 @@ class orderBookingRoute $has_permission_other = self::hasPermission($permission_other); $has_permission = false; // Updated below // Check if the user has permission to delete their own bookings - if ($has_permission_own && (int)$object->customer_number->value() === (int)$user->customer_number->value()) { - $has_permission = true; + if ($has_permission_own) { + $subuser = $auth->get_subuser(); + if ($subuser !== false) { + $sub_target = $auth->get_subuser_customer_number_target(); + if ((int)$object->customer_number->value() === (int)$sub_target) { + $has_permission = true; + } + } elseif ($user !== false && (int)$object->customer_number->value() === (int)$user->customer_number->value()) { + $has_permission = true; + } } // Check if the user has permission to delete other users' bookings if (!$has_permission && $has_permission_other) {