From 8bbdf9daf5b6e917aa6f553dee40503aaf071544 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Mon, 6 Jul 2026 16:48:07 +0200 Subject: [PATCH] Require booking add node for subuser booking creation --- .../nginx/app/routes/orderBookingRoute.php | 19 +++++++++++++-- .../tests/Api/OrderBookingsCreateApiTest.php | 23 ++++++++++++++++++- ...OrderBookingCreatePermissionWiringTest.php | 12 ++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 services/nginx/app/tests/Unit/Bookings/OrderBookingCreatePermissionWiringTest.php diff --git a/services/nginx/app/routes/orderBookingRoute.php b/services/nginx/app/routes/orderBookingRoute.php index 264749d6..67573e68 100644 --- a/services/nginx/app/routes/orderBookingRoute.php +++ b/services/nginx/app/routes/orderBookingRoute.php @@ -87,7 +87,8 @@ class orderBookingRoute $response->success($order_bookings_o->asArray()); }, [ - 'add_bookings' => 'Permission to create order bookings for another customer or department scope.' + 'add_bookings' => 'Permission to create order bookings for another customer or department scope.', + 'add_own_bookings' => 'Permission to create own order bookings. Subusers require node: BOOKINGS_ADD.' ] ); @@ -651,7 +652,21 @@ class orderBookingRoute private function requireOrderBookingCreateAccess(int $targetCustomerNumber, int $departmentId): void { - if ($this->isOrderBookingCustomerSession() && $this->isOwnCustomerContext($targetCustomerNumber)) { + $auth = new authentication(); + + if ($auth->get_subuser() !== false && $this->isOwnCustomerContext($targetCustomerNumber)) { + $permissionOwn = self::definePermission('add_own_bookings', subusers_permission_node_key::BOOKINGS_ADD); + if (!self::hasPermission($permissionOwn)) { + $this->emitForbidden([$permissionOwn]); + } + return; + } + + if ( + $auth->get_user() !== false + && self::hasPermission('user') + && $this->isOwnCustomerContext($targetCustomerNumber) + ) { return; } diff --git a/services/nginx/app/tests/Api/OrderBookingsCreateApiTest.php b/services/nginx/app/tests/Api/OrderBookingsCreateApiTest.php index 1960ed65..bb236dbf 100644 --- a/services/nginx/app/tests/Api/OrderBookingsCreateApiTest.php +++ b/services/nginx/app/tests/Api/OrderBookingsCreateApiTest.php @@ -65,7 +65,7 @@ it('lets customers create their own order bookings without booking permissions', api_fixtures()->cleanupDeleteById('order_bookings', $bookingId); }); -it('lets subusers create own customer order bookings without the bookings add node', function (): void { +it('blocks subusers creating own customer order bookings without the bookings add node', function (): void { api_test_covers('POST /order-bookings', 'auth'); $customer = api_fixtures()->createUser(['display_name' => 'Subuser Booking Customer']); @@ -79,6 +79,27 @@ it('lets subusers create own customer order bookings without the bookings add no $session['headers'] ); + $response + ->assertStatus(403) + ->assertEnvelope() + ->assertSuccess(false) + ->assertMissingPermissions(['add_own_bookings']); +}); + +it('lets subusers create own customer order bookings with the bookings add node', function (): void { + api_test_covers('POST /order-bookings', 'auth'); + + $customer = api_fixtures()->createUser(['display_name' => 'Subuser Booking Customer With Add']); + $session = api_fixtures()->createSubuserSession((int)$customer['customer_number'], ['BOOKINGS_ADD']); + $department = order_booking_create_department('Subuser Booking Add Department'); + $product = api_fixtures()->createProduct(['name' => 'Subuser Booking Add Product']); + + $response = api_client()->post( + '/order-bookings', + order_booking_create_payload($customer, $department, $product, 'SUBBOOK2'), + $session['headers'] + ); + $response ->assertStatus(200) ->assertEnvelope() diff --git a/services/nginx/app/tests/Unit/Bookings/OrderBookingCreatePermissionWiringTest.php b/services/nginx/app/tests/Unit/Bookings/OrderBookingCreatePermissionWiringTest.php new file mode 100644 index 00000000..defd8e99 --- /dev/null +++ b/services/nginx/app/tests/Unit/Bookings/OrderBookingCreatePermissionWiringTest.php @@ -0,0 +1,12 @@ +toBeTrue(); + + $code = (string)file_get_contents($routeFile); + $normalized = preg_replace('/\s+/', ' ', $code); + + expect($normalized)->toContain("definePermission('add_own_bookings', subusers_permission_node_key::BOOKINGS_ADD)"); + expect($normalized)->toContain("'add_own_bookings' => 'Permission to create own order bookings. Subusers require node: BOOKINGS_ADD.'"); +});