From 27a5db8c852c49456ce4040b557921f35a63663b Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Fri, 10 Jul 2026 15:15:40 -0400 Subject: [PATCH] Fix views/controllers/router: command palette, create form, admin views - Consolidate the duplicated command palette to a single overlay + init in the footer; fix New Ticket to route to /ticket/create (was a 404 /create); keep the CSP nonce and all commands - TicketController create(): trim title, require a non-empty description, and honor the posted status (validated against the canonical list) instead of silently discarding it - UserActivityView: 'Active Users' counts only users active in the selected range, not every registered user - layout_footer/DashboardView: local esc() now escapes quotes so values used in HTML attributes can't break out - TicketView: comments tab badge shows the true total, not just page one - layout_header: gate the 'View activity log' link behind the admin flag - index.php: validate /admin/user-activity date params; anchor the legacy /ticket.php route; align the audit action-type whitelist with the dropdown - ApiKeysView: correct the external API sample to /create_ticket_api.php Co-Authored-By: Claude Opus 4.8 --- controllers/TicketController.php | 23 +++++++++-- index.php | 16 +++++--- views/DashboardView.php | 2 +- views/TicketView.php | 4 +- views/admin/ApiKeysView.php | 2 +- views/admin/AuditLogView.php | 9 ++++- views/admin/UserActivityView.php | 14 ++++++- views/layout_footer.php | 20 +++++++++- views/layout_header.php | 65 ++------------------------------ 9 files changed, 76 insertions(+), 79 deletions(-) diff --git a/controllers/TicketController.php b/controllers/TicketController.php index 2e2c0d4..5b3adb0 100644 --- a/controllers/TicketController.php +++ b/controllers/TicketController.php @@ -93,19 +93,27 @@ class TicketController $visibilityGroups = implode(',', array_map('trim', $_POST['visibility_groups'])); } + // Honor the posted status, validated against the app's canonical list + $validStatuses = $GLOBALS['config']['TICKET_STATUSES'] ?? ['Open', 'Pending', 'In Progress', 'Closed']; + $status = $_POST['status'] ?? 'Open'; + if (!in_array($status, $validStatuses, true)) { + $status = 'Open'; + } + $ticketData = [ - 'title' => $_POST['title'] ?? '', + 'title' => trim($_POST['title'] ?? ''), 'description' => $_POST['description'] ?? '', 'priority' => $_POST['priority'] ?? '4', 'category' => $_POST['category'] ?? 'General', 'type' => $_POST['type'] ?? 'Issue', + 'status' => $status, 'visibility' => $_POST['visibility'] ?? 'public', 'visibility_groups' => $visibilityGroups, 'assigned_to' => !empty($_POST['assigned_to']) ? $_POST['assigned_to'] : null ]; - // Validate input - if (empty($ticketData['title'])) { + // Validate input (server-side; form is novalidate) + if ($ticketData['title'] === '') { $error = "Title is required"; $templates = $this->templateModel->getAllTemplates(); $allUsers = $this->userModel->getAllUsers(); @@ -114,6 +122,15 @@ class TicketController return; } + if (trim($ticketData['description']) === '') { + $error = "Description is required"; + $templates = $this->templateModel->getAllTemplates(); + $allUsers = $this->userModel->getAllUsers(); + $conn = $this->conn; // Make $conn available to view + include dirname(__DIR__) . '/views/CreateTicketView.php'; + return; + } + // Create ticket with user tracking $result = $this->ticketModel->createTicket($ticketData, $userId); diff --git a/index.php b/index.php index 602f671..f9732ed 100644 --- a/index.php +++ b/index.php @@ -249,8 +249,11 @@ switch (true) { $params = []; $types = ''; - $allowedActionTypes = ['create','update','delete','comment','assign','status_change','login','security', - 'ticket_create','ticket_update','ticket_delete','attachment_delete','attachment_upload']; + // Mirrors AuditLogModel::VALID_ACTION_TYPES so every option offered by the + // audit-log filter dropdown is actually accepted here. + $allowedActionTypes = ['create','update','delete','view','security_event', + 'login','logout','assign','unassign','comment','mention', + 'revoke','attachment_upload','attachment_delete','bulk_update']; if (!empty($_GET['action_type']) && in_array($_GET['action_type'], $allowedActionTypes, true)) { $whereConditions[] = "al.action_type = ?"; $params[] = $_GET['action_type']; @@ -335,9 +338,12 @@ switch (true) { case $requestPath == '/admin/user-activity': requireAdmin($currentUser); + // Validate date params (YYYY-MM-DD) like the audit-log route; fall back to defaults on garbage + $uaFrom = $_GET['date_from'] ?? ''; + $uaTo = $_GET['date_to'] ?? ''; $dateRange = [ - 'from' => $_GET['date_from'] ?? date('Y-m-d', strtotime('-30 days')), - 'to' => $_GET['date_to'] ?? date('Y-m-d') + 'from' => preg_match('/^\d{4}-\d{2}-\d{2}$/', $uaFrom) ? $uaFrom : date('Y-m-d', strtotime('-30 days')), + 'to' => preg_match('/^\d{4}-\d{2}-\d{2}$/', $uaTo) ? $uaTo : date('Y-m-d') ]; // Optimized query using LEFT JOINs with aggregated subqueries instead of correlated subqueries @@ -410,7 +416,7 @@ switch (true) { header("Location: /"); exit; - case preg_match('/^\/ticket\.php/', $requestPath) && isset($_GET['id']): + case preg_match('/^\/ticket\.php$/', $requestPath) && isset($_GET['id']): $legacyId = (string)$_GET['id']; if (ctype_digit($legacyId) && (int)$legacyId > 0) { header("Location: /ticket/" . $legacyId); diff --git a/views/DashboardView.php b/views/DashboardView.php index 4384d98..af6895d 100644 --- a/views/DashboardView.php +++ b/views/DashboardView.php @@ -1317,7 +1317,7 @@ if (advForm) advForm.addEventListener('submit', function(e) { var pLabels = { '1':'P1 — Critical', '2':'P2 — High', '3':'P3 — Medium', '4':'P4 — Low', '5':'P5 — Minimal' }; var dotClass = { 'Open':'lt-dot-up', 'In Progress':'lt-dot-warn', 'Pending':'lt-dot--orange', 'Closed':'lt-dot-idle' }; - function esc(s) { return String(s||'').replace(/&/g,'&').replace(//g,'>'); } + function esc(s) { return String(s||'').replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,'''); } function fmtAge(dateStr) { var d = new Date(dateStr); diff --git a/views/TicketView.php b/views/TicketView.php index 635c5f9..767ffc0 100644 --- a/views/TicketView.php +++ b/views/TicketView.php @@ -461,8 +461,8 @@ include __DIR__ . '/layout_header.php';