Refactor ordersRoute, vehiclesRoute, and related routes for subuser permission handling

- Integrate `subusers_permission_node_key` for dynamic subuser-specific permission checks.
- Refactor authentication and permission logic to streamline checks for own vs. department-level access.
- Simplify error handling and enforce scoped permissions for vehicles, orders, and their attachments.
- Localize permission labels and descriptions to Danish for relevant modules.
This commit is contained in:
Jeppe Bundgaard
2026-02-12 15:52:37 +01:00
parent f265a83034
commit 16094575a7
4 changed files with 387 additions and 514 deletions
+214 -357
View File
@@ -14,6 +14,7 @@ use objects\plate_scans_o;
use objects\products_o;
use objects\users_o;
use traits\route_t;
use modules\subusers\helpers\subusers_permission_node_key;
class vehiclesRoute
{
@@ -22,73 +23,52 @@ class vehiclesRoute
public function run(): void
{
$this->get('/vehicles', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('list_own_vehicles');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_OWN_VEHICLES', 'Successfully listed own vehicles');
// Check if the id parameter is set
if ($this->isParametersSet(['id'])) {
// Get the id parameter
$id = (int)$this->getParameter('id');
$this->requireType($id, self::type_int());
$this->requireMinValue($id, 1);
$this->requireMaxValue($id, 9999999999);
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_OWN_VEHICLES', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to list the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to list other users vehicles
if (!$user->hasPermission('list_vehicles_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'LIST_OWN_VEHICLES', 'User tried to list a vehicle from another user');
// Return an error
$response->error('You are not allowed to list vehicles from other users', 403);
}
}
// Return the vehicle as an array
$response->success(
[...$vehicle->asArray()]
);
$auth = new authentication();
$user = $auth->get_user();
// Define permissions with subuser node linkage
$permission_own = self::definePermission('list_own_vehicles', subusers_permission_node_key::VEHICLES_LIST);
$permission_other = self::definePermission('list_vehicles_other');
$has_permission_other = self::hasPermission($permission_other);
// If a specific ID is requested, validate access against that vehicle's customer context
if ($this->isParametersSet(['id'])) {
$id = (int)$this->getParameter('id');
$this->requireType($id, self::type_int());
$this->requireMinValue($id, 1);
$this->requireMaxValue($id, 9999999999);
$vehicle = (new customer_vehicles_o())->select($id);
if (!$vehicle->exists()) {
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'LIST_OWN_VEHICLES', 'Vehicle not found');
$response->error('Vehicle not found', 404);
}
// Return the list of the user's vehicles
$vehicles_o = new customer_vehicles_o();
// Check if the user is allowed to list other user's vehicles
if (!$user->hasPermission('list_vehicles_other')) {
$restrict = [
'customer_id' => (int)$user->customer_number->value(),
];
}
$response->success(
$vehicles_o->listObjectsWithPaginationIfSet(
function ($vehicle) use ($user) {
// Return the object as an array
return [
...(new customer_vehicles_o())->select($vehicle['id'])->asArray(),
];
},
$vehicles_o->forceRestrictFilters([
...$restrict ?? []
])
)
$targetCustomer = (int)$vehicle->customer_id->value();
self::allowOwnOrDepartmentAccess(
$permission_own,
$permission_other,
$targetCustomer,
null,
null,
'You do not have permission to view this vehicle.'
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'LIST_OWN_VEHICLES', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 400);
$response->success([...$vehicle->asArray()]);
}
// Listing: restrict to effective customer when lacking the broader permission
$vehicles_o = new customer_vehicles_o();
$effectiveCustomer = self::resolveEffectiveCustomerNumber();
$response->success(
$vehicles_o->listObjectsWithPaginationIfSet(
function ($vehicle) {
return [...(new customer_vehicles_o())->select($vehicle['id'])->asArray()];
},
$vehicles_o->forceRestrictFilters([
...(!$has_permission_other && $effectiveCustomer !== null ? [
'customer_id' => [(int)$effectiveCustomer]
] : [])
])
)
);
},
[
'list_own_vehicles' => 'List own vehicles',
@@ -128,95 +108,70 @@ class vehiclesRoute
);
$this->post('/vehicles', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('add_vehicle');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Require the parameters
self::requireParameters([
'type',
'reg',
'wash_subscription',
]);
// Set the customer_id to the one from the user
$target_user = $user;
// Check if customer_id is set
if (self::isParametersSet([
'customer_id',
])) {
// Check if the customer_id is the same as the current user
if ((int)$user->customer_number->value() !== (int)self::getParameter('customer_id')) {
// Check if the user has permission to add vehicles to other users
if (!$user->hasPermission('add_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'ADD_VEHICLE', 'User tried to add a vehicle to another user');
// Return an error
$response->error('You are not allowed to add vehicles to other users', 403);
} else {
// Set the customer_id to the one from the request
$target_user = (new users_o());
$target_user->getUserByCustomerNumber((int)self::getParameter('customer_id'));
}
}
}
$reference = null;
// Check if the reference is set
if (self::isParametersSet([
'reference',
])) {
// If the reference is not empty, check if it is valid
if (!empty(self::getParameter('reference'))) {
// Check if the reference is valid
$reference = (string)self::getParameter('reference');
self::requireType($reference, self::type_string());
self::requireMinLength('reference', 1);
self::requireMaxLength('reference', 255);
}
}
// Validate the parameters
self::requireType(
self::getParameter('reg'),
self::type_string()
);
self::requireType(
self::getParameter('type'),
self::type_int()
);
self::requireType(
self::getParameter('wash_subscription'),
self::type_bool()
);
// Get the parameters
$reg = (string)self::getParameter('reg');
$type = (int)self::getParameter('type');
$subscription = (bool)self::getParameter('wash_subscription');
// Strip the registration number of whitespace
$reg = trim($reg);
// Create a new vehicle
$vehicle = new customer_vehicles_o();
$vehicle->add(
$target_user->customer_number->value(),
$type,
$reg,
$subscription ? 1 : 0,
$reference
);
$auth = new authentication();
$user = $auth->get_user();
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'ADD_VEHICLE', 'Successfully added vehicle');
// Return the new vehicle
$response->success(
$vehicle->asArray()
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'ADD_VEHICLE', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
// Define permissions with subuser node linkage
$permission_own = self::definePermission('add_vehicle', subusers_permission_node_key::VEHICLES_ADD);
$permission_other = self::definePermission('add_vehicle_other');
// Require the parameters
self::requireParameters([
'type',
'reg',
'wash_subscription',
]);
// Determine target customer
$targetCustomer = self::isParametersSet(['customer_id'])
? (int)self::getParameter('customer_id')
: (int)(self::resolveEffectiveCustomerNumber() ?? 0);
self::requireType($targetCustomer, self::type_int());
self::requireMinValue($targetCustomer, 1);
self::requireMaxValue($targetCustomer, 9999999999);
// Enforce access (own vs broader)
self::allowOwnOrDepartmentAccess(
$permission_own,
$permission_other,
$targetCustomer,
null,
null,
'You are not allowed to add vehicles to this customer'
);
$reference = null;
if (self::isParametersSet(['reference'])) {
if (!empty(self::getParameter('reference'))) {
$reference = (string)self::getParameter('reference');
self::requireType($reference, self::type_string());
self::requireMinLength('reference', 1);
self::requireMaxLength('reference', 255);
}
}
// Validate the parameters
self::requireType(self::getParameter('reg'), self::type_string());
self::requireType(self::getParameter('type'), self::type_int());
self::requireType(self::getParameter('wash_subscription'), self::type_bool());
// Get the parameters
$reg = (string)self::getParameter('reg');
$type = (int)self::getParameter('type');
$subscription = (bool)self::getParameter('wash_subscription');
$reg = trim($reg);
// Create a new vehicle
$vehicle = new customer_vehicles_o();
$vehicle->add(
$targetCustomer,
$type,
$reg,
$subscription ? 1 : 0,
$reference
);
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'ADD_VEHICLE', 'Successfully added vehicle');
$response->success($vehicle->asArray());
},
[
'add_vehicle' => 'Add a vehicle to own vehicles',
@@ -225,39 +180,28 @@ class vehiclesRoute
);
$this->put('/vehicles', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('edit_vehicle');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'EDIT_VEHICLE', 'User edited a vehicle');
// Get the request data
self::requireParameters([
'id'
]);
$id = (int)self::getParameter('id');
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'EDIT_VEHICLE', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to edit the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to edit other users vehicles
if (!$user->hasPermission('edit_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'EDIT_VEHICLE', 'User tried to edit a vehicle from another user');
// Return an error
$response->error('You are not allowed to edit vehicles from other users', 403);
}
}
$auth = new authentication();
$user = $auth->get_user();
$permission_own = self::definePermission('edit_vehicle', subusers_permission_node_key::VEHICLES_EDIT);
$permission_other = self::definePermission('edit_vehicle_other');
// Get the request data
self::requireParameters(['id']);
$id = (int)self::getParameter('id');
$vehicle = (new customer_vehicles_o())->select($id);
if (!$vehicle->exists()) {
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'EDIT_VEHICLE', 'Vehicle not found');
$response->error('Vehicle not found', 404);
}
// Enforce access (own vs broader)
self::allowOwnOrDepartmentAccess(
$permission_own,
$permission_other,
(int)$vehicle->customer_id->value(),
null,
null,
'You are not allowed to edit vehicles from other users'
);
// Check all the fields, and if they are set, validate and set them
if (self::isParametersSet(['type'])) {
$type = (int)self::getParameter('type');
@@ -326,15 +270,7 @@ class vehiclesRoute
}
$vehicle->objectChanged();
// Return the vehicle
$response->success(
$vehicle->asArray()
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'EDIT_VEHICLE', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
}
$response->success($vehicle->asArray());
},
[
'edit_vehicle' => 'Edit a vehicle',
@@ -343,54 +279,34 @@ class vehiclesRoute
);
$this->delete('/vehicles', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('delete_vehicle');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'DELETE_VEHICLE', 'User deleted a vehicle');
// Get the request data
self::requireParameters([
'id'
]);
$id = (int)self::getParameter('id');
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'DELETE_VEHICLE', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to delete the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to delete other users vehicles
if (!$user->hasPermission('delete_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'DELETE_VEHICLE', 'User tried to delete a vehicle from another user');
// Return an error
$response->error('You are not allowed to delete vehicles from other users', 403);
}
}
// Delete the vehicle
$vehicle->delete();
// Return success
$response->success(
[
'success' => true,
'message' => 'Vehicle deleted successfully'
]
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'DELETE_VEHICLE', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
$auth = new authentication();
$user = $auth->get_user();
$permission_own = self::definePermission('delete_vehicle', subusers_permission_node_key::VEHICLES_DELETE);
$permission_other = self::definePermission('delete_vehicle_other');
// Get the request data
self::requireParameters(['id']);
$id = (int)self::getParameter('id');
$vehicle = (new customer_vehicles_o())->select($id);
if (!$vehicle->exists()) {
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'DELETE_VEHICLE', 'Vehicle not found');
$response->error('Vehicle not found', 404);
}
// Enforce access (own vs broader)
self::allowOwnOrDepartmentAccess(
$permission_own,
$permission_other,
(int)$vehicle->customer_id->value(),
null,
null,
'You are not allowed to delete vehicles from other users'
);
// Delete the vehicle
$vehicle->delete();
$response->success([
'success' => true,
'message' => 'Vehicle deleted successfully'
]);
},
[
'delete_vehicle' => 'Delete a vehicle',
@@ -461,60 +377,33 @@ class vehiclesRoute
);
$this->post('/vehicles/set-auto-start-on-lpr', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('set_auto_start_on_lpr');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_AUTO_START_ON_LPR', 'User set auto start on LPR');
// Get the request data
self::requireParameters([
'id',
'active',
]);
$id = (int)self::getParameter('id');
self::requireType($id, self::type_int());
self::requireMinValue($id, 1);
self::requireMaxValue($id, 9999999999);
// Validate the autoStartOnLpr (active) parameter
$autoStartOnLpr = (bool)self::getParameter('active');
self::requireType($autoStartOnLpr, self::type_bool());
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_AUTO_START_ON_LPR', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to edit the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to edit other users vehicles
if (!$user->hasPermission('edit_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_AUTO_START_ON_LPR', 'User tried to set auto start on LPR from another user');
// Return an error
$response->error('You are not allowed to edit vehicles from other users', 403);
}
}
// Set the auto start on LPR
$vehicle->setAutoStartOnLpr(
$autoStartOnLpr
);
// Return the vehicle as an array
$response->success(
[...$vehicle->asArray()]
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'SET_AUTO_START_ON_LPR', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
$auth = new authentication();
$user = $auth->get_user();
$permission_own = self::definePermission('set_auto_start_on_lpr', subusers_permission_node_key::VEHICLES_EDIT);
$permission_other = self::definePermission('set_auto_start_on_lpr_other');
self::requireParameters(['id', 'active']);
$id = (int)self::getParameter('id');
self::requireType($id, self::type_int());
self::requireMinValue($id, 1);
self::requireMaxValue($id, 9999999999);
$autoStartOnLpr = (bool)self::getParameter('active');
self::requireType($autoStartOnLpr, self::type_bool());
$vehicle = (new customer_vehicles_o())->select($id);
if (!$vehicle->exists()) {
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'SET_AUTO_START_ON_LPR', 'Vehicle not found');
$response->error('Vehicle not found', 404);
}
self::allowOwnOrDepartmentAccess(
$permission_own,
$permission_other,
(int)$vehicle->customer_id->value(),
null,
null,
'You are not allowed to edit vehicles from other users'
);
$vehicle->setAutoStartOnLpr($autoStartOnLpr);
$response->success([...$vehicle->asArray()]);
},
[
'set_auto_start_on_lpr' => 'Set auto start on LPR',
@@ -523,77 +412,45 @@ class vehiclesRoute
);
$this->post('/vehicles/set-vehicle-type-id', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('set_vehicle_type_id');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_VEHICLE_TYPE_ID', 'User set vehicle type ID');
// Get the request data
self::requireParameters([
'id',
'vehicleTypeId',
]);
$id = (int)self::getParameter('id');
self::requireType($id, self::type_int());
self::requireMinValue($id, 1);
self::requireMaxValue($id, 9999999999);
// Validate the vehicleTypeId
$vehicleTypeId = (string)self::getParameter('vehicleTypeId');
self::requireType($vehicleTypeId, self::type_string());
self::requireMinLength('vehicleTypeId', 1);
self::requireMaxLength('vehicleTypeId', 50);
// Get the vehicle object
$vehicle = (new customer_vehicles_o())->select($id);
// Check if the vehicle exists
if (!$vehicle->exists()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_VEHICLE_TYPE_ID', 'Vehicle not found');
// Return an error
$response->error('Vehicle not found', 404);
}
// Check if the user is allowed to edit the vehicle
if ((int)$vehicle->customer_id->value() !== (int)$user->customer_number->value()) {
// Check if the user has permission to edit other users vehicles
if (!$user->hasPermission('edit_vehicle_other')) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_VEHICLE_TYPE_ID', 'User tried to set vehicle type ID from another user');
// Return an error
$response->error('You are not allowed to edit vehicles from other users', 403);
}
}
// Get the customer object
$customer = (new users_o())->getUserByCustomerNumber((int)$vehicle->customer_id->value());
// Check if the vehicle is registered in the XL Vask system
if (!$vehicle->hasXLVask()) {
// Check if the customer has an XL Vask customer account
if (!$customer->hasXLVaskCustomerAccount()) {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, $user->id, 'SET_VEHICLE_TYPE_ID', 'User tried to set vehicle type ID on a vehicle that is not registered in the XL Vask system, without a customer account');
// Return an error
$response->error('Vehicle is not registered in the XL Vask system', 400);
} else {
$vehicle->createXLVaskVehicle($vehicleTypeId);
}
} else {
// Set the vehicle type ID
$vehicle->setVehicleTypeId(
$vehicleTypeId
);
}
// Return the vehicle as an array
$response->success(
[...$vehicle->asArray()]
);
} else {
// Log the incident
(new logs_o())->add('vehicles', 'global', 1, 0, 'SET_VEHICLE_TYPE_ID', 'No user found, or invalid session');
// Return an error
$response->error('Invalid session', 401);
$auth = new authentication();
$user = $auth->get_user();
$permission_own = self::definePermission('set_vehicle_type_id', subusers_permission_node_key::VEHICLES_EDIT);
$permission_other = self::definePermission('set_vehicle_type_id_other');
self::requireParameters(['id', 'vehicleTypeId']);
$id = (int)self::getParameter('id');
self::requireType($id, self::type_int());
self::requireMinValue($id, 1);
self::requireMaxValue($id, 9999999999);
$vehicleTypeId = (string)self::getParameter('vehicleTypeId');
self::requireType($vehicleTypeId, self::type_string());
self::requireMinLength('vehicleTypeId', 1);
self::requireMaxLength('vehicleTypeId', 50);
$vehicle = (new customer_vehicles_o())->select($id);
if (!$vehicle->exists()) {
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'SET_VEHICLE_TYPE_ID', 'Vehicle not found');
$response->error('Vehicle not found', 404);
}
self::allowOwnOrDepartmentAccess(
$permission_own,
$permission_other,
(int)$vehicle->customer_id->value(),
null,
null,
'You are not allowed to edit vehicles from other users'
);
$customer = (new users_o())->getUserByCustomerNumber((int)$vehicle->customer_id->value());
if (!$vehicle->hasXLVask()) {
if (!$customer->hasXLVaskCustomerAccount()) {
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'SET_VEHICLE_TYPE_ID', 'Attempt to set vehicle type ID without XL Vask registration and no customer account');
$response->error('Vehicle is not registered in the XL Vask system', 400);
} else {
$vehicle->createXLVaskVehicle($vehicleTypeId);
}
} else {
$vehicle->setVehicleTypeId($vehicleTypeId);
}
$response->success([...$vehicle->asArray()]);
},
[
'set_vehicle_type_id' => 'Set vehicle type ID',