Implement comprehensive improvement plan (Phases 1-6)

Security (Phase 1-2):
- Add SecurityHeadersMiddleware with CSP, X-Frame-Options, etc.
- Add RateLimitMiddleware for API rate limiting
- Add security event logging to AuditLogModel
- Add ResponseHelper for standardized API responses
- Update config.php with security constants

Database (Phase 3):
- Add migration 014 for additional indexes
- Add migration 015 for ticket dependencies
- Add migration 016 for ticket attachments
- Add migration 017 for recurring tickets
- Add migration 018 for custom fields

Features (Phase 4-5):
- Add ticket dependencies with DependencyModel and API
- Add duplicate detection with check_duplicates API
- Add file attachments with AttachmentModel and upload/download APIs
- Add @mentions with autocomplete and highlighting
- Add quick actions on dashboard rows

Collaboration (Phase 5):
- Add mention extraction in CommentModel
- Add mention autocomplete dropdown in ticket.js
- Add mention highlighting CSS styles

Admin & Export (Phase 6):
- Add StatsModel for dashboard widgets
- Add dashboard stats cards (open, critical, unassigned, etc.)
- Add CSV/JSON export via export_tickets API
- Add rich text editor toolbar in markdown.js
- Add RecurringTicketModel with cron job
- Add CustomFieldModel for per-category fields
- Add admin views: RecurringTickets, CustomFields, Workflow,
  Templates, AuditLog, UserActivity
- Add admin APIs: manage_workflows, manage_templates,
  manage_recurring, custom_fields, get_users
- Add admin routes in index.php

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-20 09:55:01 -05:00
parent 8c7211d311
commit be505b7312
53 changed files with 6640 additions and 169 deletions

View File

@@ -223,18 +223,6 @@ class TicketModel {
}
public function updateTicket($ticketData, $updatedBy = null) {
// Debug function
$debug = function($message, $data = null) {
$log_message = date('Y-m-d H:i:s') . " - [Model] " . $message;
if ($data !== null) {
$log_message .= ": " . (is_string($data) ? $data : json_encode($data));
}
$log_message .= "\n";
file_put_contents('/tmp/api_debug.log', $log_message, FILE_APPEND);
};
$debug("updateTicket called with data", $ticketData);
$sql = "UPDATE tickets SET
title = ?,
priority = ?,
@@ -246,43 +234,27 @@ class TicketModel {
updated_at = NOW()
WHERE ticket_id = ?";
$debug("SQL query", $sql);
try {
$stmt = $this->conn->prepare($sql);
if (!$stmt) {
$debug("Prepare statement failed", $this->conn->error);
return false;
}
$debug("Binding parameters");
$stmt->bind_param(
"sissssii",
$ticketData['title'],
$ticketData['priority'],
$ticketData['status'],
$ticketData['description'],
$ticketData['category'],
$ticketData['type'],
$updatedBy,
$ticketData['ticket_id']
);
$debug("Executing statement");
$result = $stmt->execute();
if (!$result) {
$debug("Execute failed", $stmt->error);
return false;
}
$debug("Update successful");
return true;
} catch (Exception $e) {
$debug("Exception", $e->getMessage());
$debug("Stack trace", $e->getTraceAsString());
throw $e;
$stmt = $this->conn->prepare($sql);
if (!$stmt) {
return false;
}
$stmt->bind_param(
"sissssii",
$ticketData['title'],
$ticketData['priority'],
$ticketData['status'],
$ticketData['description'],
$ticketData['category'],
$ticketData['type'],
$updatedBy,
$ticketData['ticket_id']
);
$result = $stmt->execute();
$stmt->close();
return $result;
}
public function createTicket($ticketData, $createdBy = null) {