Integrate cors_policy class to standardize CORS handling, refactor optionsRoute to use it, and add unit tests for CORS and Self-Serve Lane Access functionalities.
This commit is contained in:
@@ -30,6 +30,8 @@ class moduleSelfServeRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
private const CUSTOMER_SELFSERVE_PERMISSION = 'list_own_department_selfserve_vehicle_conditions';
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
global /** @var response $response */
|
||||
@@ -389,7 +391,6 @@ class moduleSelfServeRoute
|
||||
/** Modules > Self Serve > Lane > Command */
|
||||
$this->post('/modules/self-serve/lane/command', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_selfserve_lane_command_execute');
|
||||
$selfserve = new selfserve();
|
||||
// Get the request user
|
||||
$user = (new authentication())->get_user();
|
||||
@@ -412,35 +413,63 @@ class moduleSelfServeRoute
|
||||
if ($command === null) {
|
||||
$response->error("Invalid command: " . $commandParam);
|
||||
}
|
||||
$customer_number = $this->resolveEffectiveCustomerNumber();
|
||||
$customer_number = $customer_number === null ? 0 : (int)$customer_number;
|
||||
// Require permissions for specific commands
|
||||
switch ($command) {
|
||||
case selfserve_lane_command::START:
|
||||
self::requirePermission('modules_selfserve_lane_command_execute_start');
|
||||
$this->requireSelfServeLaneCommandPermission(
|
||||
$lane,
|
||||
$customer_number,
|
||||
'modules_selfserve_lane_command_execute_start',
|
||||
true
|
||||
);
|
||||
break;
|
||||
case selfserve_lane_command::STOP:
|
||||
self::requirePermission('modules_selfserve_lane_command_execute_stop');
|
||||
$this->requireSelfServeLaneCommandPermission(
|
||||
$lane,
|
||||
$customer_number,
|
||||
'modules_selfserve_lane_command_execute_stop',
|
||||
true,
|
||||
true
|
||||
);
|
||||
break;
|
||||
case selfserve_lane_command::RESERVE:
|
||||
self::requirePermission('modules_selfserve_lane_command_execute_reserve');
|
||||
$this->requireSelfServeLaneCommandPermission(
|
||||
$lane,
|
||||
$customer_number,
|
||||
'modules_selfserve_lane_command_execute_reserve',
|
||||
false
|
||||
);
|
||||
break;
|
||||
case selfserve_lane_command::RELEASE:
|
||||
self::requirePermission('modules_selfserve_lane_command_execute_release');
|
||||
$this->requireSelfServeLaneCommandPermission(
|
||||
$lane,
|
||||
$customer_number,
|
||||
'modules_selfserve_lane_command_execute_release',
|
||||
false
|
||||
);
|
||||
break;
|
||||
case selfserve_lane_command::RESET:
|
||||
self::requirePermission('modules_selfserve_lane_command_execute_reset');
|
||||
$this->requireSelfServeLaneCommandPermission(
|
||||
$lane,
|
||||
$customer_number,
|
||||
'modules_selfserve_lane_command_execute_reset',
|
||||
false
|
||||
);
|
||||
break;
|
||||
case selfserve_lane_command::OPEN_PROPERTY_ACCESS_GATE:
|
||||
$this->requirePropertyGateCommandPermission(
|
||||
'modules_selfserve_lane_command_execute_open_property_access_gate',
|
||||
$lane,
|
||||
(int)$user->customer_number->value()
|
||||
$customer_number
|
||||
);
|
||||
break;
|
||||
case selfserve_lane_command::OPEN_PROPERTY_EXIT_GATE:
|
||||
$this->requirePropertyGateCommandPermission(
|
||||
'modules_selfserve_lane_command_execute_open_property_exit_gate',
|
||||
$lane,
|
||||
(int)$user->customer_number->value()
|
||||
$customer_number
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -450,7 +479,7 @@ class moduleSelfServeRoute
|
||||
$args = new \modules\selfserve\classes\selfserve_lane_command_arguments();
|
||||
$args->setParameters([
|
||||
...$this->getParametersAsArray(), // Pass all parameters
|
||||
'customer_number' => (int)$user->customer_number->value(), // Get customer number from request user
|
||||
'customer_number' => $customer_number, // Get customer number from request user
|
||||
]);
|
||||
$lane->execute($command, $args);
|
||||
$response->success([
|
||||
@@ -493,7 +522,6 @@ class moduleSelfServeRoute
|
||||
/** Modules > Self Serve > Lane > Allowed services (derived from shown tasks) */
|
||||
$this->post('/modules/self-serve/lane/services/allowed', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_selfserve_lane_services_set_allowed');
|
||||
$selfserve = new selfserve();
|
||||
// Validate parameters
|
||||
self::requireParameters(['lane_id']);
|
||||
@@ -516,6 +544,12 @@ class moduleSelfServeRoute
|
||||
$task_ids = array_values(array_unique(array_map(fn($v) => (int)$v, $task_ids_param)));
|
||||
// Build allowed services from provided tasks
|
||||
$lane = $selfserve->lane($lane_id);
|
||||
$customer_number = $this->resolveEffectiveCustomerNumber();
|
||||
$this->requireSelfServeLaneAccess(
|
||||
$lane,
|
||||
$customer_number === null ? 0 : (int)$customer_number,
|
||||
['modules_selfserve_lane_services_set_allowed']
|
||||
);
|
||||
$allowed_services = [];
|
||||
foreach ($task_ids as $tid) {
|
||||
if ($tid <= 0) continue;
|
||||
@@ -835,7 +869,6 @@ class moduleSelfServeRoute
|
||||
/** Modules > Self Serve > Lane > Relay > Enable MACHINE (manual, gated by allowed services) */
|
||||
$this->post('/modules/self-serve/lane/relay/machine/enable', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_selfserve_lane_relay_enable_machine');
|
||||
$selfserve = new selfserve();
|
||||
// Validate parameters
|
||||
self::requireParameters(['lane_id']);
|
||||
@@ -848,6 +881,13 @@ class moduleSelfServeRoute
|
||||
self::requireMinValue($duration, 1);
|
||||
}
|
||||
$lane = $selfserve->lane($lane_id);
|
||||
$customer_number = $this->resolveEffectiveCustomerNumber();
|
||||
$this->requireSelfServeLaneAccess(
|
||||
$lane,
|
||||
$customer_number === null ? 0 : (int)$customer_number,
|
||||
['modules_selfserve_lane_relay_enable_machine'],
|
||||
true
|
||||
);
|
||||
try {
|
||||
$this->applyShellyTransportOverride($lane);
|
||||
$lane->turnOnRelay(selfserve_lane_relay::MACHINE, $duration);
|
||||
@@ -1271,9 +1311,87 @@ class moduleSelfServeRoute
|
||||
$lane->setShellyTransportOverride($transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int,string> $permissions
|
||||
*/
|
||||
private function hasAllPermissions(array $permissions): bool
|
||||
{
|
||||
foreach ($permissions as $permission) {
|
||||
if (!$this->hasPermission($permission)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int,string> $elevated_permissions
|
||||
*/
|
||||
private function requireSelfServeLaneAccess(
|
||||
selfserve_lane $lane,
|
||||
int $customer_number,
|
||||
array $elevated_permissions,
|
||||
bool $requires_active_wash = false,
|
||||
bool $requires_operational_lane = true
|
||||
): void {
|
||||
if ($this->hasAllPermissions($elevated_permissions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($requires_active_wash) {
|
||||
$customer_allowed = $this->canCustomerUseActiveSelfServeLane($lane, $customer_number)
|
||||
&& (!$requires_operational_lane || $this->isLaneSelfServeOperationallyEnabled($lane));
|
||||
} else {
|
||||
$customer_allowed = $this->canCustomerUseSelfServeLane($lane, $customer_number);
|
||||
}
|
||||
|
||||
if ($customer_allowed) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->emitForbidden([...$elevated_permissions, self::CUSTOMER_SELFSERVE_PERMISSION]);
|
||||
}
|
||||
|
||||
private function requireSelfServeLaneCommandPermission(
|
||||
selfserve_lane $lane,
|
||||
int $customer_number,
|
||||
string $command_permission,
|
||||
bool $allow_customer_self_serve,
|
||||
bool $requires_active_wash = false
|
||||
): void {
|
||||
$elevated_permissions = [
|
||||
'modules_selfserve_lane_command_execute',
|
||||
$command_permission,
|
||||
];
|
||||
if ($this->hasAllPermissions($elevated_permissions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($allow_customer_self_serve) {
|
||||
$customer_allowed = $requires_active_wash
|
||||
? $this->canCustomerUseActiveSelfServeLane($lane, $customer_number)
|
||||
: $this->canCustomerUseSelfServeLane($lane, $customer_number);
|
||||
|
||||
if ($customer_allowed) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->emitForbidden(
|
||||
$allow_customer_self_serve
|
||||
? [...$elevated_permissions, self::CUSTOMER_SELFSERVE_PERMISSION]
|
||||
: $elevated_permissions
|
||||
);
|
||||
}
|
||||
|
||||
private function requirePropertyGateCommandPermission(string $permission, selfserve_lane $lane, int $customer_number): void
|
||||
{
|
||||
if (self::hasPermission($permission)) {
|
||||
$elevated_permissions = [
|
||||
'modules_selfserve_lane_command_execute',
|
||||
$permission,
|
||||
];
|
||||
if ($this->hasAllPermissions($elevated_permissions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1281,21 +1399,70 @@ class moduleSelfServeRoute
|
||||
return;
|
||||
}
|
||||
|
||||
self::requirePermission($permission);
|
||||
$this->emitForbidden([...$elevated_permissions, self::CUSTOMER_SELFSERVE_PERMISSION]);
|
||||
}
|
||||
|
||||
protected function canCustomerUseSelfServeLane(selfserve_lane $lane, int $customer_number): bool
|
||||
{
|
||||
return $customer_number > 0
|
||||
&& $this->hasPermission(self::CUSTOMER_SELFSERVE_PERMISSION)
|
||||
&& $this->isLaneSelfServeOperationallyEnabled($lane);
|
||||
}
|
||||
|
||||
protected function canCustomerUseActiveSelfServeLane(selfserve_lane $lane, int $customer_number): bool
|
||||
{
|
||||
if ($customer_number <= 0 || !$this->hasPermission(self::CUSTOMER_SELFSERVE_PERMISSION)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if ((int)$lane->getCustomerNumber() === $customer_number) {
|
||||
return true;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// Fall back to the persisted session lookup below.
|
||||
}
|
||||
|
||||
$department_id = $this->departmentIdForLane($lane);
|
||||
return $department_id > 0
|
||||
&& $this->customerHasActiveSelfServeWashInDepartment($department_id, $customer_number);
|
||||
}
|
||||
|
||||
protected function canCustomerUsePropertyGateForLane(selfserve_lane $lane, int $customer_number): bool
|
||||
{
|
||||
if ($customer_number <= 0) {
|
||||
return $this->canCustomerUseActiveSelfServeLane($lane, $customer_number);
|
||||
}
|
||||
|
||||
protected function isLaneSelfServeOperationallyEnabled(selfserve_lane $lane): bool
|
||||
{
|
||||
try {
|
||||
if (empty($lane->department_lane) || !$lane->department_lane->isSelfServeEnabled()) {
|
||||
return false;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$department_id = (int)$lane->department_lane?->department?->value();
|
||||
$department_id = $this->departmentIdForLane($lane);
|
||||
if ($department_id <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->customerHasActiveSelfServeWashInDepartment($department_id, $customer_number);
|
||||
try {
|
||||
$department = (new departments_o())->select($department_id);
|
||||
return $department->exists() && $department->getSelfServeEnabled();
|
||||
} catch (\Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function departmentIdForLane(selfserve_lane $lane): int
|
||||
{
|
||||
try {
|
||||
return (int)$lane->department_lane?->department?->value();
|
||||
} catch (\Throwable) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected function customerHasActiveSelfServeWashInDepartment(int $department_id, int $customer_number): bool
|
||||
|
||||
Reference in New Issue
Block a user