Fix data-layer bugs: bind_param fatals, ticket_id bindings, cache poisoning
- CustomFieldModel: assign ?? fallbacks to variables before bind_param
(by-reference args cannot be ?? expressions; fatal on PHP 8.2, custom
fields were uncreatable/uneditable)
- RecurringTicketModel::create: fix swapped bind type for schedule_type
(enum bound as int coerced 'daily' to 0, breaking the cron)
- TicketModel/CommentModel: bind varchar ticket_id as string not int so
the unique index is usable and leading-zero IDs match; ticket_watchers
(int column) left as integer
- TicketModel::deleteTicket: delete from custom_field_values (real table)
not the nonexistent ticket_custom_fields
- TicketModel search: honor literal '0'; never emit AGAINST('*') on
all-special-char input (fall back to LIKE)
- TicketModel::updateTicket: disambiguate not-found vs no-op vs genuine
optimistic-lock conflict on zero affected rows
- WorkflowModel: do not cache transitions/statuses on DB failure (a
transient error no longer blocks all status changes for the TTL)
- DependencyModel: filter linked tickets by visibility (new optional user
context params) to stop confidential metadata leaking via dependencies
- BulkOperationsModel: validate status/priority/assignee before mutating
- AuditLogModel: gate getClientIP forwarded headers on trusted proxies;
add missing action/entity types so audit-log filters work
- WorkflowModel: add transitionRequiresComment() accessor for enforcement
- CommentModel: stop leaking raw DB errors to clients (log instead)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+11
-9
@@ -58,12 +58,12 @@ class CommentModel
|
||||
/**
|
||||
* Get total comment count for a ticket
|
||||
*/
|
||||
public function getCommentCount(int $ticketId): int
|
||||
public function getCommentCount(string $ticketId): int
|
||||
{
|
||||
$stmt = $this->conn->prepare(
|
||||
"SELECT COUNT(*) as total FROM ticket_comments WHERE ticket_id = ?"
|
||||
);
|
||||
$stmt->bind_param("i", $ticketId);
|
||||
$stmt->bind_param("s", $ticketId);
|
||||
$stmt->execute();
|
||||
$row = $stmt->get_result()->fetch_assoc();
|
||||
$stmt->close();
|
||||
@@ -108,9 +108,9 @@ class CommentModel
|
||||
|
||||
$stmt = $this->conn->prepare($sql);
|
||||
if ($limit > 0) {
|
||||
$stmt->bind_param("iii", $ticketId, $limit, $offset);
|
||||
$stmt->bind_param("sii", $ticketId, $limit, $offset);
|
||||
} else {
|
||||
$stmt->bind_param("i", $ticketId);
|
||||
$stmt->bind_param("s", $ticketId);
|
||||
}
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
@@ -146,7 +146,7 @@ class CommentModel
|
||||
/**
|
||||
* Paginated threaded comments: fetch one page of root comments + all their replies.
|
||||
*/
|
||||
private function getThreadedCommentsPaged(int $ticketId, int $limit, int $offset): array
|
||||
private function getThreadedCommentsPaged(string $ticketId, int $limit, int $offset): array
|
||||
{
|
||||
// Page of root comments
|
||||
$rootSql = "SELECT tc.*, u.display_name, u.username
|
||||
@@ -156,7 +156,7 @@ class CommentModel
|
||||
ORDER BY tc.created_at DESC
|
||||
LIMIT ? OFFSET ?";
|
||||
$stmt = $this->conn->prepare($rootSql);
|
||||
$stmt->bind_param("iii", $ticketId, $limit, $offset);
|
||||
$stmt->bind_param("sii", $ticketId, $limit, $offset);
|
||||
$stmt->execute();
|
||||
$rootResult = $stmt->get_result();
|
||||
$stmt->close();
|
||||
@@ -192,7 +192,7 @@ class CommentModel
|
||||
AND tc.parent_comment_id IN ($placeholders)
|
||||
ORDER BY tc.created_at ASC";
|
||||
$replyStmt = $this->conn->prepare($replySql);
|
||||
$types = 'i' . str_repeat('i', count($parentIds));
|
||||
$types = 's' . str_repeat('i', count($parentIds));
|
||||
$replyStmt->bind_param($types, $ticketId, ...$parentIds);
|
||||
$replyStmt->execute();
|
||||
$replyResult = $replyStmt->get_result();
|
||||
@@ -394,7 +394,8 @@ class CommentModel
|
||||
'updated_at' => $hasUpdatedAt ? date('M d, Y H:i') : null
|
||||
];
|
||||
} else {
|
||||
return ['success' => false, 'error' => $this->conn->error];
|
||||
error_log('CommentModel::updateComment failed: ' . $this->conn->error);
|
||||
return ['success' => false, 'error' => 'Failed to update comment'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,7 +429,8 @@ class CommentModel
|
||||
'ticket_id' => $ticketId
|
||||
];
|
||||
} else {
|
||||
return ['success' => false, 'error' => $this->conn->error];
|
||||
error_log('CommentModel::deleteComment failed: ' . $this->conn->error);
|
||||
return ['success' => false, 'error' => 'Failed to delete comment'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user