Files
api/services/nginx/app/routes/departmentSelfserveTasksRoute.php
T
Jeppe Bundgaard 73ac77a2f5 Add support for dynamic image buttons and vehicle type selection in self-serve tasks
- Extend `department_selfserve_tasks_o` with `buttons` and `dynamic_images_vehicle_type` properties.
- Add normalization/validation methods for `buttons` and `dynamic_images_vehicle_type` parameters.
- Update `departmentSelfserveTasksRoute` to handle new fields in task creation and update.
- Add OpenAPI specifications for `buttons` and `dynamic_images_vehicle_type`.
- Include comprehensive tests for button normalization and vehicle type selection.
2026-02-18 16:34:58 +01:00

526 lines
25 KiB
PHP

<?php
/**
* Route for department self-serve tasks
*/
namespace routes;
use classes\authentication;
use classes\response;
use objects\department_selfserve_tasks_o;
use objects\logs_o;
use attachments\helpers\attachment_content;
use classes\attachment_store;
use classes\attachments;
use modules\selfserve\helpers\selfserve_lane_services;
use traits\route_t;
class departmentSelfserveTasksRoute
{
use route_t;
public function run(): void
{
/**
* List department self-serve tasks
*/
$this->get('/department/selfserve/tasks', function () {
global $response;
$this->requirePermission('list_department_selfserve_tasks');
$user = (new authentication())->get_user();
if ($user) {
(new logs_o())->add('department_selfserve_tasks', 'global', 1, $user->id, 'LIST_TASKS', 'User listed department self-serve tasks');
$tasks_o = new department_selfserve_tasks_o();
$authorized_department_ids = $user->getGroup()->getDepartments();
$has_view_all_permission = $this->hasPermission('view_all_department_selfserve_tasks');
// If an ID is provided, return that specific task
if (self::isParametersSet(['id'])) {
$tasks_o->select((int)self::getParameter('id'));
if ($tasks_o->exists()) {
if (!in_array((int)$tasks_o->department->value(), $authorized_department_ids)) {
if (!$has_view_all_permission) {
$response->error('You do not have access to this department', 403);
}
}
$response->success($tasks_o->asArray());
} else {
$response->error('Task not found', 404);
}
}
$filters = [];
if (self::isParametersSet(['department'])) {
$requested_department = (int)self::getParameter('department');
if (!in_array($requested_department, $authorized_department_ids) && !$has_view_all_permission) {
$response->error('You do not have access to this department', 403);
}
$filters['department'] = $requested_department;
} else {
if (!$has_view_all_permission) {
if (empty($authorized_department_ids)) {
$response->success([]);
return;
}
$filters['department'] = $authorized_department_ids;
}
}
if (self::isParametersSet(['lane'])) {
$filters['lane'] = (int)self::getParameter('lane');
}
if (self::isParametersSet(['product'])) {
$filters['product'] = (int)self::getParameter('product');
}
if (self::isParametersSet(['condition_id'])) {
$filters['condition_id'] = (int)self::getParameter('condition_id');
}
$response->success(
$tasks_o->setSearchableFields(['id', 'department', 'lane', 'product', 'condition_id', 'task', 'description', 'deleted_at'])
->listObjectsWithPaginationIfSet(function ($task) {
$t = new department_selfserve_tasks_o();
$t->select((int)$task['id']);
return $t->asArray();
}, $tasks_o->forceRestrictFilters($filters))
);
} else {
$response->error('Invalid session', 400);
}
}, [
'list_department_selfserve_tasks' => 'List all department self-serve tasks',
'view_all_department_selfserve_tasks' => 'View all department self-serve tasks'
]);
/**
* Add a department self-serve task
*/
$this->post('/department/selfserve/tasks', function () {
global $response;
$this->requirePermission('add_department_selfserve_tasks');
$user = (new authentication())->get_user();
if ($user) {
$department = (int)$response->getRequestParameter('department');
$lane = (int)$response->getRequestParameter('lane');
$product = (int)$response->getRequestParameter('product');
$condition_id = $response->isRequestParameterSet('condition_id') ? (int)$response->getRequestParameter('condition_id') : null;
$task = (string)$response->getRequestParameter('task');
$description = (string)$response->getRequestParameter('description');
$order_priority = (int)($response->getRequestParameter('order_priority') ?? 0);
// Optional services
$services_param = $response->isRequestParameterSet('services') ? $response->getRequestParameter('services') : null;
$services_enums = null;
if (!is_null($services_param)) {
// Accept array, JSON string, or comma-separated string
$raw = $services_param;
if (is_string($raw)) {
$decoded = json_decode($raw, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
$raw = $decoded;
} else {
$raw = array_filter(array_map(function ($s) { return trim($s); }, explode(',', $services_param)), fn($s) => $s !== '');
}
}
if (!is_array($raw)) {
$response->error('Invalid format for services. Expected array, JSON array, or comma-separated string of service names.', 400);
}
// Map to enum cases by name (case-insensitive)
$services_enums = [];
foreach ($raw as $srv) {
$name = strtoupper(is_string($srv) ? trim($srv) : (string)$srv);
$matched = null;
foreach (selfserve_lane_services::cases() as $case) {
if ($case->name === $name) {
$matched = $case;
break;
}
}
if (!$matched) {
$response->error('Invalid service: ' . (string)$srv, 400);
}
$services_enums[] = $matched;
}
}
// Optional buttons
$buttons_param = $response->isRequestParameterSet('buttons') ? $response->getRequestParameter('buttons') : null;
$buttons_ids = null;
if (!is_null($buttons_param)) {
try {
$buttons_ids = department_selfserve_tasks_o::normalizeButtonsInput($buttons_param);
} catch (\Exception $e) {
$response->error($e->getMessage(), 400);
}
}
// Optional dynamic_images_vehicle_type
$vehicle_type_param = $response->isRequestParameterSet('dynamic_images_vehicle_type') ? $response->getRequestParameter('dynamic_images_vehicle_type') : null;
$vehicle_type = null;
if ($vehicle_type_param !== null) {
try {
$vehicle_type = department_selfserve_tasks_o::normalizeVehicleTypeInput($vehicle_type_param);
} catch (\Exception $e) {
$response->error($e->getMessage(), 400);
}
}
if (!$department || !$lane || !$product || !$task || !$description) {
$response->error('Missing required fields', 400);
}
$authorized_department_ids = $user->getGroup()->getDepartments();
if (!in_array($department, $authorized_department_ids)) {
$response->error('You do not have access to this department', 403);
}
try {
$task_o = (new department_selfserve_tasks_o())->add(
$department,
$lane,
$product,
$condition_id,
$task,
$description,
$order_priority,
$services_enums,
$buttons_ids,
$vehicle_type,
);
(new logs_o())->add('department_selfserve_tasks', 'global', 1, $user->id, 'ADD_TASK', 'User added a department self-serve task: ' . $task);
$response->success($task_o->asArray());
} catch (\Exception $e) {
$response->error($e->getMessage(), 500);
}
} else {
$response->error('Invalid session', 400);
}
}, [
'add_department_selfserve_tasks' => 'Add a department self-serve task'
]);
/**
* Update a department self-serve task
*/
$this->put('/department/selfserve/tasks', function () {
global $response;
$this->requirePermission('edit_department_selfserve_tasks');
$user = (new authentication())->get_user();
if ($user) {
self::requireParameters(['id']);
$id = (int)self::getParameter('id');
$task_o = new department_selfserve_tasks_o();
$task_o->select($id);
if (!$task_o->exists()) {
$response->error('Task not found', 404);
}
$authorized_department_ids = $user->getGroup()->getDepartments();
if (!in_array((int)$task_o->department->value(), $authorized_department_ids)) {
$response->error('You do not have access to this department', 403);
}
if (self::isParametersSet(['department'])) {
$new_department = (int)self::getParameter('department');
if (!in_array($new_department, $authorized_department_ids)) {
$response->error('You do not have access to the new department', 403);
}
$task_o->department->set($new_department);
}
if (self::isParametersSet(['lane'])) {
$task_o->lane->set((int)self::getParameter('lane'));
}
if (self::isParametersSet(['product'])) {
$task_o->product->set((int)self::getParameter('product'));
}
if (self::isParametersSet(['condition_id'])) {
$task_o->condition_id->set(self::getParameter('condition_id') === null ? null : (int)self::getParameter('condition_id'));
}
if (self::isParametersSet(['task'])) {
$task_o->task->set((string)self::getParameter('task'));
}
if (self::isParametersSet(['description'])) {
$task_o->description->set((string)self::getParameter('description'));
}
if (self::isParametersSet(['order_priority'])) {
$task_o->order_priority->set((int)self::getParameter('order_priority'));
}
if (self::isParametersSet(['services'])) {
$param = self::getParameter('services');
if ($param === null) {
// Explicitly clear services
$task_o->services->set(null);
} else {
$raw = $param;
if (is_string($raw)) {
$decoded = json_decode($raw, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
$raw = $decoded;
} else {
$raw = array_filter(array_map(function ($s) { return trim($s); }, explode(',', $param)), fn($s) => $s !== '');
}
}
if (!is_array($raw)) {
$response->error('Invalid format for services. Expected array, JSON array, or comma-separated string of service names.', 400);
}
// Validate and store names
$names = [];
foreach ($raw as $srv) {
$name = strtoupper(is_string($srv) ? trim($srv) : (string)$srv);
$valid = false;
foreach (selfserve_lane_services::cases() as $case) {
if ($case->name === $name) {
$valid = true;
break;
}
}
if (!$valid) {
$response->error('Invalid service: ' . (string)$srv, 400);
}
$names[] = $name;
}
$task_o->services->set($names);
}
}
if (self::isParametersSet(['buttons'])) {
$param = self::getParameter('buttons');
if ($param === null) {
// Explicitly clear buttons
$task_o->buttons->set(null);
} else {
try {
$ids = department_selfserve_tasks_o::normalizeButtonsInput($param);
$task_o->buttons->set($ids);
} catch (\Exception $e) {
$response->error($e->getMessage(), 400);
}
}
}
// Optional dynamic_images_vehicle_type update
if (self::isParametersSet(['dynamic_images_vehicle_type'])) {
$param = self::getParameter('dynamic_images_vehicle_type');
if ($param === null) {
$task_o->dynamic_images_vehicle_type->set(null);
} else {
try {
$val = department_selfserve_tasks_o::normalizeVehicleTypeInput($param);
$task_o->dynamic_images_vehicle_type->set($val);
} catch (\Exception $e) {
$response->error($e->getMessage(), 400);
}
}
}
(new logs_o())->add('department_selfserve_tasks', 'global', 1, $user->id, 'EDIT_TASK', 'User updated department self-serve task ID: ' . $id);
$response->success($task_o->asArray());
} else {
$response->error('Invalid session', 400);
}
}, [
'edit_department_selfserve_tasks' => 'Edit a department self-serve task'
]);
/**
* Delete a department self-serve task
*/
$this->delete('/department/selfserve/tasks', function () {
global $response;
$this->requirePermission('delete_department_selfserve_tasks');
$user = (new authentication())->get_user();
if ($user) {
self::requireParameters(['id']);
$id = (int)self::getParameter('id');
$task_o = new department_selfserve_tasks_o();
$task_o->select($id);
if (!$task_o->exists()) {
$response->error('Task not found', 404);
}
$authorized_department_ids = $user->getGroup()->getDepartments();
if (!in_array((int)$task_o->department->value(), $authorized_department_ids)) {
$response->error('You do not have access to this department', 403);
}
$task_o->delete();
(new logs_o())->add('department_selfserve_tasks', 'global', 1, $user->id, 'DELETE_TASK', 'User deleted department self-serve task ID: ' . $id);
$response->success('Task deleted');
} else {
$response->error('Invalid session', 400);
}
}, [
'delete_department_selfserve_tasks' => 'Delete a department self-serve task'
]);
/**
* Download an attachment for a department self-serve task
*/
$this->get('/department/selfserve/tasks/attachments/download', function () {
global $response;
$this->requirePermission('download_department_selfserve_task_attachments');
$user = (new authentication())->get_user();
if ($user) {
self::requireParameters(['task_id', 'attachment_id']);
$task_id = (int)self::getParameter('task_id');
$attachment_id = (int)self::getParameter('attachment_id');
$task_o = new department_selfserve_tasks_o();
$task_o->select($task_id);
if (!$task_o->exists()) {
$response->error('Task not found', 404);
}
$authorized_department_ids = $user->getGroup()->getDepartments();
$has_view_all_permission = $this->hasPermission('view_all_department_selfserve_tasks');
if (!in_array((int)$task_o->department->value(), $authorized_department_ids)) {
if (!$has_view_all_permission) {
$response->error('You do not have access to this department', 403);
}
}
$attachment = $task_o->getAttachment($attachment_id);
if (!$attachment->exists()) {
$response->error('Attachment not found', 404);
}
$attachment_store = new attachment_store();
$attachments = new attachments();
$attachment_formatted = $attachments->format($attachment);
$download_link = $attachment_store->generateDirectDownloadUrl($attachment_formatted->content->document);
(new logs_o())->add('department_selfserve_tasks', (int)$task_o->department->value(), 1, $user->id, 'DOWNLOAD_TASK_ATTACHMENT', 'User downloaded attachment ID: ' . $attachment_id . ' for task ID: ' . $task_id);
$response->success(['download_link' => $download_link]);
} else {
$response->error('Invalid session', 400);
}
}, [
'download_department_selfserve_task_attachments' => 'Download attachments for a department self-serve task',
'view_all_department_selfserve_tasks' => 'View all department self-serve tasks'
]);
/**
* List attachments for a department self-serve task
*/
$this->get('/department/selfserve/tasks/attachments', function () {
global $response;
$this->requirePermission('list_department_selfserve_task_attachments');
$user = (new authentication())->get_user();
if ($user) {
self::requireParameters(['id']);
$task_id = (int)self::getParameter('id');
$task_o = new department_selfserve_tasks_o();
$task_o->select($task_id);
if (!$task_o->exists()) {
$response->error('Task not found', 404);
}
$authorized_department_ids = $user->getGroup()->getDepartments();
$has_view_all_permission = $this->hasPermission('view_all_department_selfserve_tasks');
if (!in_array((int)$task_o->department->value(), $authorized_department_ids)) {
if (!$has_view_all_permission) {
$response->error('You do not have access to this department', 403);
}
}
$attachments = $task_o->listAttachments();
(new logs_o())->add('department_selfserve_tasks', (int)$task_o->department->value(), 1, $user->id, 'LIST_TASK_ATTACHMENTS', 'User listed attachments for task ID: ' . $task_id);
$response->success($attachments);
} else {
$response->error('Invalid session', 400);
}
}, [
'list_department_selfserve_task_attachments' => 'List attachments for a department self-serve task',
'view_all_department_selfserve_tasks' => 'View all department self-serve tasks'
]);
/**
* Upload an attachment for a department self-serve task
*/
$this->post('/department/selfserve/tasks/attachments/upload', function () {
global $response;
$this->requirePermission('add_department_selfserve_task_attachments');
$user = (new authentication())->get_user();
if ($user) {
$this->requireParameters(['task_id', 'base64_file', 'file_name']);
$task_id = (int)$this->getParameter('task_id');
$base64_file = (string)$this->getParameter('base64_file');
$file_name = (string)$this->getParameter('file_name');
$task_o = new department_selfserve_tasks_o();
$task_o->select($task_id);
if (!$task_o->exists()) {
$response->error('Task not found', 404);
}
$authorized_department_ids = $user->getGroup()->getDepartments();
if (!in_array((int)$task_o->department->value(), $authorized_department_ids)) {
$response->error('You do not have access to this department', 403);
}
$attachment_store = new attachment_store();
$extension = pathinfo($file_name, PATHINFO_EXTENSION);
$object_name = $attachment_store->storeTempFileFromBase64($base64_file, $extension);
if ($object_name === false) {
$response->error('Failed to store the attachment file.', 500);
}
$object_attachment = $task_o->addAttachment((new attachment_content())->setDocument($object_name)->setOther($file_name));
(new logs_o())->add('department_selfserve_tasks', (int)$task_o->department->value(), 1, $user->id, 'ADD_TASK_ATTACHMENT', 'User added an attachment for task ID: ' . $task_id);
$attachments = new attachments();
$response->success($attachments->format($attachments->get($object_attachment->id)));
} else {
$response->error('Invalid session', 400);
}
}, [
'add_department_selfserve_task_attachments' => 'Add attachments for a department self-serve task'
]);
/**
* Delete an attachment for a department self-serve task
*/
$this->delete('/department/selfserve/tasks/attachments', function () {
global $response;
$this->requirePermission('delete_department_selfserve_task_attachments');
$user = (new authentication())->get_user();
if ($user) {
self::requireParameters(['task_id', 'attachment_id']);
$task_id = (int)self::getParameter('task_id');
$attachment_id = (int)self::getParameter('attachment_id');
$task_o = new department_selfserve_tasks_o();
$task_o->select($task_id);
if (!$task_o->exists()) {
$response->error('Task not found', 404);
}
$authorized_department_ids = $user->getGroup()->getDepartments();
if (!in_array((int)$task_o->department->value(), $authorized_department_ids)) {
$response->error('You do not have access to this department', 403);
}
$task_o->removeAttachment($attachment_id);
(new logs_o())->add('department_selfserve_tasks', (int)$task_o->department->value(), 1, $user->id, 'DELETE_TASK_ATTACHMENT', 'User deleted attachment ID: ' . $attachment_id . ' for task ID: ' . $task_id);
$response->success(['message' => 'Attachment deleted successfully']);
} else {
$response->error('Invalid session', 400);
}
}, [
'delete_department_selfserve_task_attachments' => 'Delete attachments for a department self-serve task'
]);
}
}