From 0acf5e84c37d4336c4c044bb3cf137969ff5a392 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sun, 29 Mar 2026 21:54:00 -0400 Subject: [PATCH] feat: duplicate link action, watcher migration, fulltext search migration - CreateTicketView: "Link as duplicate" button on each duplicate result; stores chosen ticket ID in hidden field, auto-creates duplicates dependency after ticket is saved (TicketController) - migrations/004: ticket_watchers table (ticket_id, user_id primary key) - migrations/005: FULLTEXT index on tickets(title, description) for fast relevance search replacing LIKE scan Co-Authored-By: Claude Sonnet 4.6 --- controllers/TicketController.php | 11 +++++++++++ migrations/004_add_ticket_watchers.sql | 10 ++++++++++ migrations/005_add_fulltext_search.sql | 6 ++++++ views/CreateTicketView.php | 20 +++++++++++++++++++- 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 migrations/004_add_ticket_watchers.sql create mode 100644 migrations/005_add_fulltext_search.sql diff --git a/controllers/TicketController.php b/controllers/TicketController.php index 3bfd2fb..9405f89 100644 --- a/controllers/TicketController.php +++ b/controllers/TicketController.php @@ -125,6 +125,17 @@ class TicketController { $GLOBALS['auditLog']->logTicketCreate($userId, $result['ticket_id'], $ticketData); } + // Auto-link as duplicate if requested from create form + $linkDupOf = isset($_POST['link_duplicate_of']) ? (int)$_POST['link_duplicate_of'] : 0; + if ($linkDupOf > 0) { + $depSql = "INSERT IGNORE INTO ticket_dependencies (ticket_id, depends_on_ticket_id, dependency_type, created_by) + VALUES (?, ?, 'duplicates', ?)"; + $depStmt = $this->conn->prepare($depSql); + $depStmt->bind_param("iii", $result['ticket_id'], $linkDupOf, $userId); + $depStmt->execute(); + $depStmt->close(); + } + // Send Matrix notification for new ticket NotificationHelper::sendTicketNotification($result['ticket_id'], $ticketData, 'manual'); diff --git a/migrations/004_add_ticket_watchers.sql b/migrations/004_add_ticket_watchers.sql new file mode 100644 index 0000000..4f13538 --- /dev/null +++ b/migrations/004_add_ticket_watchers.sql @@ -0,0 +1,10 @@ +-- Migration: Add ticket watchers table +-- Allows users to subscribe to ticket updates and receive Matrix notifications. + +CREATE TABLE IF NOT EXISTS ticket_watchers ( + ticket_id INT NOT NULL, + user_id INT NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (ticket_id, user_id), + INDEX idx_watcher_user (user_id) +); diff --git a/migrations/005_add_fulltext_search.sql b/migrations/005_add_fulltext_search.sql new file mode 100644 index 0000000..4f0622f --- /dev/null +++ b/migrations/005_add_fulltext_search.sql @@ -0,0 +1,6 @@ +-- Migration: Add FULLTEXT index on ticket title and description +-- Replaces LIKE '%term%' with MATCH ... AGAINST for dramatically better search +-- performance and relevance ranking at scale. +-- MyISAM not needed — InnoDB supports FULLTEXT since MySQL 5.6. + +ALTER TABLE tickets ADD FULLTEXT INDEX ft_title_description (title, description); diff --git a/views/CreateTicketView.php b/views/CreateTicketView.php index 06c8d3a..498d02d 100644 --- a/views/CreateTicketView.php +++ b/views/CreateTicketView.php @@ -37,6 +37,7 @@ include __DIR__ . '/layout_header.php'; +