From 2d6b2b8058487f77949be186a1233a50d6a1a58c Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sat, 11 Apr 2026 20:41:09 -0400 Subject: [PATCH] Fix watcher self-notification, unescaped output in views - NotificationHelper::notifyWatchers: excludeUserId parameter was accepted but never used; actors were notified of their own actions. Fix: add AND tw.user_id != ? clause to watcher query when exclusion is requested. - TicketView.php: formatAction() default case returned raw $event['action_type'] unescaped into HTML context. Fix: wrap with htmlspecialchars(). - Admin views: field_id, recurring_id, template_id, transition_id in data-id attributes were uncast; field_type was unescaped in CustomFieldsView; from/to_status slugs derived from DB values were used directly in class attributes in WorkflowDesignerView. Fix: (int) cast for IDs, htmlspecialchars for field_type, preg_replace to sanitize DB-derived CSS class slugs. Co-Authored-By: Claude Sonnet 4.6 --- helpers/NotificationHelper.php | 14 ++++++++++---- views/TicketView.php | 2 +- views/admin/CustomFieldsView.php | 6 +++--- views/admin/RecurringTicketsView.php | 6 +++--- views/admin/TemplatesView.php | 4 ++-- views/admin/WorkflowDesignerView.php | 6 +++--- 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/helpers/NotificationHelper.php b/helpers/NotificationHelper.php index a482697..48dcced 100644 --- a/helpers/NotificationHelper.php +++ b/helpers/NotificationHelper.php @@ -156,10 +156,16 @@ class NotificationHelper { return; } - // Fetch watcher usernames - $sql = "SELECT u.username FROM ticket_watchers tw JOIN users u ON tw.user_id = u.user_id WHERE tw.ticket_id = ?"; - $stmt = $conn->prepare($sql); - $stmt->bind_param("i", $ticketId); + // Fetch watcher usernames, excluding the actor so they don't notify themselves + if ($excludeUserId !== null) { + $sql = "SELECT u.username FROM ticket_watchers tw JOIN users u ON tw.user_id = u.user_id WHERE tw.ticket_id = ? AND tw.user_id != ?"; + $stmt = $conn->prepare($sql); + $stmt->bind_param("ii", $ticketId, $excludeUserId); + } else { + $sql = "SELECT u.username FROM ticket_watchers tw JOIN users u ON tw.user_id = u.user_id WHERE tw.ticket_id = ?"; + $stmt = $conn->prepare($sql); + $stmt->bind_param("i", $ticketId); + } $stmt->execute(); $result = $stmt->get_result(); $stmt->close(); diff --git a/views/TicketView.php b/views/TicketView.php index 2f51f45..ea5a1bc 100644 --- a/views/TicketView.php +++ b/views/TicketView.php @@ -62,7 +62,7 @@ function formatAction(array $event): string { } return 'updated this ticket'; default: - return $event['action_type']; + return htmlspecialchars($event['action_type']); } } diff --git a/views/admin/CustomFieldsView.php b/views/admin/CustomFieldsView.php index df25272..0b36f77 100644 --- a/views/admin/CustomFieldsView.php +++ b/views/admin/CustomFieldsView.php @@ -48,7 +48,7 @@ include __DIR__ . '/../../views/layout_header.php'; - + ✓' : '' ?> @@ -61,9 +61,9 @@ include __DIR__ . '/../../views/layout_header.php';
+ data-action="edit-field" data-id="">EDIT + data-action="delete-field" data-id="">DEL
diff --git a/views/admin/RecurringTicketsView.php b/views/admin/RecurringTicketsView.php index 32fe05b..0d89a05 100644 --- a/views/admin/RecurringTicketsView.php +++ b/views/admin/RecurringTicketsView.php @@ -71,13 +71,13 @@ include __DIR__ . '/../../views/layout_header.php';
+ data-action="edit-recurring" data-id="">EDIT + data-action="delete-recurring" data-id="">DEL
diff --git a/views/admin/TemplatesView.php b/views/admin/TemplatesView.php index b805fc3..7b3f869 100644 --- a/views/admin/TemplatesView.php +++ b/views/admin/TemplatesView.php @@ -56,9 +56,9 @@ include __DIR__ . '/../../views/layout_header.php';
+ data-action="edit-template" data-id="">EDIT + data-action="delete-template" data-id="">DEL
diff --git a/views/admin/WorkflowDesignerView.php b/views/admin/WorkflowDesignerView.php index 9923539..c472fc1 100644 --- a/views/admin/WorkflowDesignerView.php +++ b/views/admin/WorkflowDesignerView.php @@ -64,7 +64,7 @@ include __DIR__ . '/../../views/layout_header.php'; No transitions defined. Add transitions to enable status changes. - + @@ -87,9 +87,9 @@ include __DIR__ . '/../../views/layout_header.php';
+ data-action="edit-transition" data-id="">EDIT + data-action="delete-transition" data-id="">DEL