fix: Enable proper sorting for Created By and Assigned To columns
Fixed server-side sorting for user-related columns on dashboard: Problem: - Clicking "Created By" or "Assigned To" headers didn't sort - Columns were missing from $allowedColumns validation - Fell back to ticket_id sort, appearing random to users Solution: 1. Added 'created_by' and 'assigned_to' to $allowedColumns array 2. Smart sort expression mapping: - created_by → sorts by display_name/username (not user ID) - assigned_to → uses CASE to put unassigned at end, then sorts by name - Other columns → use table prefix (t.column_name) 3. Database-level NULL handling for assigned_to: - Uses CASE WHEN to sort unassigned tickets last - Regardless of ASC/DESC direction - Then alphabetically sorts assigned users Result: - A→Z: Alice, Bob, Charlie... Unassigned - Z→A: Zack, Yolanda, Xavier... Unassigned - Consistent grouping and predictable order Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -151,26 +151,38 @@ class TicketModel {
|
||||
}
|
||||
|
||||
// Validate sort column to prevent SQL injection
|
||||
$allowedColumns = ['ticket_id', 'title', 'status', 'priority', 'category', 'type', 'created_at', 'updated_at'];
|
||||
$allowedColumns = ['ticket_id', 'title', 'status', 'priority', 'category', 'type', 'created_at', 'updated_at', 'created_by', 'assigned_to'];
|
||||
if (!in_array($sortColumn, $allowedColumns)) {
|
||||
$sortColumn = 'ticket_id';
|
||||
}
|
||||
|
||||
|
||||
// Map column names to actual sort expressions
|
||||
// For user columns, sort by display name with NULL handling for unassigned
|
||||
$sortExpression = $sortColumn;
|
||||
if ($sortColumn === 'created_by') {
|
||||
$sortExpression = "COALESCE(u_created.display_name, u_created.username, 'System')";
|
||||
} elseif ($sortColumn === 'assigned_to') {
|
||||
// Put unassigned (NULL) at the end regardless of sort direction
|
||||
$sortExpression = "CASE WHEN t.assigned_to IS NULL THEN 1 ELSE 0 END, COALESCE(u_assigned.display_name, u_assigned.username)";
|
||||
} else {
|
||||
$sortExpression = "t.$sortColumn";
|
||||
}
|
||||
|
||||
// Validate sort direction
|
||||
$sortDirection = strtolower($sortDirection) === 'asc' ? 'ASC' : 'DESC';
|
||||
|
||||
|
||||
// Get total count for pagination
|
||||
$countSql = "SELECT COUNT(*) as total FROM tickets $whereClause";
|
||||
$countStmt = $this->conn->prepare($countSql);
|
||||
|
||||
|
||||
if (!empty($params)) {
|
||||
$countStmt->bind_param($paramTypes, ...$params);
|
||||
}
|
||||
|
||||
|
||||
$countStmt->execute();
|
||||
$totalResult = $countStmt->get_result();
|
||||
$totalTickets = $totalResult->fetch_assoc()['total'];
|
||||
|
||||
|
||||
// Get tickets with pagination and creator info
|
||||
$sql = "SELECT t.*,
|
||||
u_created.username as creator_username,
|
||||
@@ -181,7 +193,7 @@ class TicketModel {
|
||||
LEFT JOIN users u_created ON t.created_by = u_created.user_id
|
||||
LEFT JOIN users u_assigned ON t.assigned_to = u_assigned.user_id
|
||||
$whereClause
|
||||
ORDER BY $sortColumn $sortDirection
|
||||
ORDER BY $sortExpression $sortDirection
|
||||
LIMIT ? OFFSET ?";
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user