From bf30c3db5b66569da191c54b12b2ee361c1b862f Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Thu, 18 Jun 2026 19:09:42 -0500 Subject: [PATCH] fix(api): type-safe update, filtered pagination, status sync, int cast assign - API update() now uses getInt/getString instead of raw input - API update() syncs status/status_id and priority/priority_id - API update() returns 404 if ticket not found - Pagination total count now uses filtered query (was unfiltered) - AutomationEngine assign action casts value to int --- .../admin/src/Service/AutomationEngine.php | 5 +- .../api/src/Controller/TicketsController.php | 52 +++++++++++++++---- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/source/packages/com_mokosuiteclient/admin/src/Service/AutomationEngine.php b/source/packages/com_mokosuiteclient/admin/src/Service/AutomationEngine.php index 69458a04..37d7773c 100644 --- a/source/packages/com_mokosuiteclient/admin/src/Service/AutomationEngine.php +++ b/source/packages/com_mokosuiteclient/admin/src/Service/AutomationEngine.php @@ -137,8 +137,9 @@ class AutomationEngine break; case 'assign': - if ($ticketId) { - $db->setQuery("UPDATE {$db->quoteName('#__mokosuiteclient_tickets')} SET assigned_to = {$db->quote($value)}, modified = {$db->quote(Factory::getDate()->toSql())} WHERE id = {$ticketId}")->execute(); + $assignId = (int) $value; + if ($ticketId && $assignId > 0) { + $db->setQuery("UPDATE {$db->quoteName('#__mokosuiteclient_tickets')} SET assigned_to = {$assignId}, modified = {$db->quote(Factory::getDate()->toSql())} WHERE id = {$ticketId}")->execute(); } break; diff --git a/source/packages/com_mokosuiteclient/api/src/Controller/TicketsController.php b/source/packages/com_mokosuiteclient/api/src/Controller/TicketsController.php index e66297c7..6250944d 100644 --- a/source/packages/com_mokosuiteclient/api/src/Controller/TicketsController.php +++ b/source/packages/com_mokosuiteclient/api/src/Controller/TicketsController.php @@ -68,8 +68,9 @@ class TicketsController extends BaseController $tickets = $db->loadObjectList() ?: []; - // Total count - $countQuery = $db->getQuery(true)->select('COUNT(*)')->from('#__mokosuiteclient_tickets'); + // Total count (with same filters applied) + $countQuery = clone $query; + $countQuery->clear('select')->clear('order')->select('COUNT(*)'); $db->setQuery($countQuery); $total = (int) $db->loadResult(); @@ -193,14 +194,18 @@ class TicketsController extends BaseController $id = $input->getInt('id', 0); $db = Factory::getDbo(); + // Type-safe input extraction $fields = []; - $updatable = ['status', 'status_id', 'priority', 'priority_id', 'category_id', 'assigned_to']; + $intFields = ['status_id', 'priority_id', 'category_id', 'assigned_to']; + $strFields = ['status', 'priority']; - foreach ($updatable as $field) { - $value = $input->get($field, null, 'raw'); - if ($value !== null) { - $fields[$field] = $value; - } + foreach ($intFields as $field) { + $value = $input->getInt($field, 0); + if ($value > 0) { $fields[$field] = $value; } + } + foreach ($strFields as $field) { + $value = $input->getString($field, ''); + if ($value !== '') { $fields[$field] = $value; } } if (empty($fields)) { @@ -208,14 +213,43 @@ class TicketsController extends BaseController return; } + // Sync status/status_id if only one is provided + if (isset($fields['status']) && !isset($fields['status_id'])) { + $q = $db->getQuery(true)->select('id')->from('#__mokosuiteclient_ticket_statuses') + ->where($db->quoteName('alias') . ' = ' . $db->quote($fields['status'])); + $resolved = (int) $db->setQuery($q, 0, 1)->loadResult(); + if ($resolved) { $fields['status_id'] = $resolved; } + } elseif (isset($fields['status_id']) && !isset($fields['status'])) { + $q = $db->getQuery(true)->select('alias')->from('#__mokosuiteclient_ticket_statuses') + ->where('id = ' . (int) $fields['status_id']); + $alias = $db->setQuery($q, 0, 1)->loadResult(); + if ($alias) { $fields['status'] = $alias; } + } + if (isset($fields['priority']) && !isset($fields['priority_id'])) { + $q = $db->getQuery(true)->select('id')->from('#__mokosuiteclient_ticket_priorities') + ->where($db->quoteName('alias') . ' = ' . $db->quote($fields['priority'])); + $resolved = (int) $db->setQuery($q, 0, 1)->loadResult(); + if ($resolved) { $fields['priority_id'] = $resolved; } + } elseif (isset($fields['priority_id']) && !isset($fields['priority'])) { + $q = $db->getQuery(true)->select('alias')->from('#__mokosuiteclient_ticket_priorities') + ->where('id = ' . (int) $fields['priority_id']); + $alias = $db->setQuery($q, 0, 1)->loadResult(); + if ($alias) { $fields['priority'] = $alias; } + } + $sets = []; foreach ($fields as $k => $v) { - $sets[] = $db->quoteName($k) . ' = ' . $db->quote($v); + $sets[] = $db->quoteName($k) . ' = ' . (is_int($v) ? $v : $db->quote($v)); } $sets[] = 'modified = ' . $db->quote(Factory::getDate()->toSql()); $db->setQuery('UPDATE ' . $db->quoteName('#__mokosuiteclient_tickets') . ' SET ' . implode(', ', $sets) . ' WHERE id = ' . $id)->execute(); + if ($db->getAffectedRows() === 0) { + $this->sendJson(404, ['error' => 'Ticket not found']); + return; + } + $this->sendJson(200, ['id' => $id, 'message' => 'Ticket updated', 'updated' => array_keys($fields)]); }