Add attachment payload handling and tests for self-serve tasks
- Introduced `selfserve_task_attachment_payloads` class for managing task attachments, including formatting and download URL generation. - Added unit and API tests to validate attachment handling in self-serve tasks and customer-scoped workflows. - Enhanced wash start simulation and studio graph projections to integrate task attachment data.
This commit is contained in:
@@ -63,11 +63,11 @@ class moduleSelfServeRoute
|
||||
/** Modules > Self Serve > Lane > Wash > In-progress details */
|
||||
$this->get('/modules/self-serve/lane/wash/in-progress', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_selfserve_lane_wash_in_progress_view');
|
||||
self::requireParameters(['lane_id']);
|
||||
$lane_id = (int)$this->getParameter('lane_id');
|
||||
self::requireType($lane_id, self::type_int());
|
||||
self::requireMinValue($lane_id, 1);
|
||||
$customer_scope = $this->requireInProgressWashDetailsAccess();
|
||||
|
||||
$build_customer = static function (?int $customer_number): ?array {
|
||||
if ($customer_number === null || $customer_number <= 0) {
|
||||
@@ -170,13 +170,13 @@ class moduleSelfServeRoute
|
||||
|| $lane_state->equals(\modules\selfserve\helpers\selfserve_lane_state::IN_WASH);
|
||||
|
||||
if (!$in_progress) {
|
||||
$response->success([
|
||||
$response->success($this->scopeInProgressWashResponseForCustomer([
|
||||
'lane_id' => $lane_id,
|
||||
'in_progress' => false,
|
||||
'session' => null,
|
||||
'customer' => null,
|
||||
'vehicle' => null,
|
||||
]);
|
||||
], $customer_scope));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ class moduleSelfServeRoute
|
||||
|
||||
$customer = $build_customer($runtime_customer_number);
|
||||
$vehicle = $build_vehicle(null, $runtime_reg);
|
||||
$response->success([
|
||||
$response->success($this->scopeInProgressWashResponseForCustomer([
|
||||
'lane_id' => $lane_id,
|
||||
'in_progress' => true,
|
||||
'session' => [
|
||||
@@ -213,7 +213,7 @@ class moduleSelfServeRoute
|
||||
],
|
||||
'customer' => $customer,
|
||||
'vehicle' => $vehicle,
|
||||
]);
|
||||
], $customer_scope));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ class moduleSelfServeRoute
|
||||
];
|
||||
$in_progress = in_array($status, $in_progress_statusses);
|
||||
|
||||
$response->success([
|
||||
$response->success($this->scopeInProgressWashResponseForCustomer([
|
||||
'lane_id' => $lane_id,
|
||||
'status' => (string)$session->status->value(),
|
||||
'in_progress' => $in_progress,
|
||||
@@ -269,10 +269,11 @@ class moduleSelfServeRoute
|
||||
],
|
||||
'customer' => $customer,
|
||||
'vehicle' => $vehicle,
|
||||
]);
|
||||
], $customer_scope));
|
||||
},
|
||||
[
|
||||
'modules_selfserve_lane_wash_in_progress_view' => 'View customer and vehicle details for an in-progress self-serve wash on a lane',
|
||||
'list_own_department_selfserve_vehicle_conditions' => 'View in-progress self-serve wash details for the authenticated customer',
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1142,6 +1143,83 @@ class moduleSelfServeRoute
|
||||
]);
|
||||
}
|
||||
|
||||
private function requireInProgressWashDetailsAccess(): ?int
|
||||
{
|
||||
global $response;
|
||||
|
||||
$user = (new authentication())->get_user();
|
||||
if (!$user) {
|
||||
$response->error('Authentication failed. Invalid or missing token.', 401);
|
||||
}
|
||||
|
||||
if (self::hasPermission('modules_selfserve_lane_wash_in_progress_view')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (self::hasPermission('list_own_department_selfserve_vehicle_conditions')) {
|
||||
$customer_number = $this->resolveEffectiveCustomerNumber();
|
||||
if ($customer_number !== null && $customer_number > 0) {
|
||||
return (int)$customer_number;
|
||||
}
|
||||
}
|
||||
|
||||
$this->emitForbidden([
|
||||
'modules_selfserve_lane_wash_in_progress_view',
|
||||
'list_own_department_selfserve_vehicle_conditions',
|
||||
]);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customers poll all visible lanes to restore their own active wash. Keep that
|
||||
* poll successful without exposing another customer's session details.
|
||||
*
|
||||
* @param array<string,mixed> $payload
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
protected function scopeInProgressWashResponseForCustomer(array $payload, ?int $customer_number): array
|
||||
{
|
||||
if ($customer_number === null || $customer_number <= 0 || ($payload['in_progress'] ?? false) !== true) {
|
||||
return $payload;
|
||||
}
|
||||
|
||||
$session_customer_number = $this->extractInProgressWashCustomerNumber($payload);
|
||||
if ($session_customer_number === $customer_number) {
|
||||
return $payload;
|
||||
}
|
||||
|
||||
return [
|
||||
'lane_id' => (int)($payload['lane_id'] ?? 0),
|
||||
'in_progress' => true,
|
||||
'session' => null,
|
||||
'customer' => null,
|
||||
'vehicle' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $payload
|
||||
*/
|
||||
private function extractInProgressWashCustomerNumber(array $payload): ?int
|
||||
{
|
||||
$candidates = [
|
||||
$payload['session']['customer_number'] ?? null,
|
||||
$payload['customer']['customer_number'] ?? null,
|
||||
];
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
if ($candidate === null || $candidate === '') {
|
||||
continue;
|
||||
}
|
||||
$customer_number = (int)$candidate;
|
||||
if ($customer_number > 0) {
|
||||
return $customer_number;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $status
|
||||
* @param array<string,mixed> $extra
|
||||
|
||||
Reference in New Issue
Block a user