Paginate attachment listing (#100)
Lint / PHP (phpcs PSR-12) (push) Successful in 36s
Lint / JS (eslint) (push) Successful in 12s
Lint / PHP requirements (version + extensions) (push) Successful in 44s
Lint / Notify on failure (push) Skipped
Security / PHP Security (semgrep) (push) Failing after 1m54s
Lint / Deploy (push) Successful in 2s
Lint / PHP (phpcs PSR-12) (push) Successful in 36s
Lint / JS (eslint) (push) Successful in 12s
Lint / PHP requirements (version + extensions) (push) Successful in 44s
Lint / Notify on failure (push) Skipped
Security / PHP Security (semgrep) (push) Failing after 1m54s
Lint / Deploy (push) Successful in 2s
AttachmentModel::getAttachments() had no LIMIT/OFFSET, so a ticket with hundreds of attachments loaded and rendered every one of them in a single API response and DOM grid, unbounded. Added optional limit/offset to getAttachments(), matching the pattern already used by CommentModel::getCommentsByTicketId(). The GET handler in upload_attachment.php now accepts limit/offset (default 40, capped at 100) and returns total/has_more alongside the page of attachments. ticket.js's loadAttachments()/renderAttachments() now fetch and append pages, showing a "Load more attachments (N remaining)" control when more are available. Verified against real MariaDB with 12 attachments across 3 pages of 5: no duplicates or gaps across pages, and the legacy unlimited call (getAttachments($ticketId) with no limit/offset) still returns everything unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015nCxwFFsy8ouMWzn56rPVP
This commit is contained in:
@@ -114,6 +114,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|||||||
ResponseHelper::error('Invalid ticket ID format');
|
ResponseHelper::error('Invalid ticket ID format');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$offset = isset($_GET['offset']) ? max(0, (int)$_GET['offset']) : 0;
|
||||||
|
$limit = isset($_GET['limit']) ? min(100, max(1, (int)$_GET['limit'])) : 40;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$conn = Database::getConnection();
|
$conn = Database::getConnection();
|
||||||
$ticketModel = new TicketModel($conn);
|
$ticketModel = new TicketModel($conn);
|
||||||
@@ -123,7 +126,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$attachmentModel = new AttachmentModel($conn);
|
$attachmentModel = new AttachmentModel($conn);
|
||||||
$attachments = $attachmentModel->getAttachments($ticketId);
|
$total = $attachmentModel->getAttachmentCount($ticketId);
|
||||||
|
$attachments = $attachmentModel->getAttachments($ticketId, $limit, $offset);
|
||||||
|
|
||||||
// Add formatted file size and icon to each attachment
|
// Add formatted file size and icon to each attachment
|
||||||
foreach ($attachments as &$att) {
|
foreach ($attachments as &$att) {
|
||||||
@@ -131,7 +135,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|||||||
$att['icon'] = AttachmentModel::getFileIcon($att['mime_type']);
|
$att['icon'] = AttachmentModel::getFileIcon($att['mime_type']);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponseHelper::success(['attachments' => $attachments]);
|
ResponseHelper::success([
|
||||||
|
'attachments' => $attachments,
|
||||||
|
'total' => $total,
|
||||||
|
'offset' => $offset,
|
||||||
|
'limit' => $limit,
|
||||||
|
'has_more' => ($offset + $limit) < $total,
|
||||||
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ResponseHelper::serverError('Failed to load attachments');
|
ResponseHelper::serverError('Failed to load attachments');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class AttachmentModel
|
|||||||
/**
|
/**
|
||||||
* Get all attachments for a ticket
|
* Get all attachments for a ticket
|
||||||
*/
|
*/
|
||||||
public function getAttachments($ticketId)
|
public function getAttachments($ticketId, int $limit = 0, int $offset = 0)
|
||||||
{
|
{
|
||||||
$sql = "SELECT a.*, u.username, u.display_name
|
$sql = "SELECT a.*, u.username, u.display_name
|
||||||
FROM ticket_attachments a
|
FROM ticket_attachments a
|
||||||
@@ -24,8 +24,16 @@ class AttachmentModel
|
|||||||
WHERE a.ticket_id = ?
|
WHERE a.ticket_id = ?
|
||||||
ORDER BY a.uploaded_at DESC";
|
ORDER BY a.uploaded_at DESC";
|
||||||
|
|
||||||
|
if ($limit > 0) {
|
||||||
|
$sql .= " LIMIT ? OFFSET ?";
|
||||||
|
}
|
||||||
|
|
||||||
$stmt = $this->conn->prepare($sql);
|
$stmt = $this->conn->prepare($sql);
|
||||||
$stmt->bind_param("s", $ticketId);
|
if ($limit > 0) {
|
||||||
|
$stmt->bind_param("sii", $ticketId, $limit, $offset);
|
||||||
|
} else {
|
||||||
|
$stmt->bind_param("s", $ticketId);
|
||||||
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$result = $stmt->get_result();
|
$result = $stmt->get_result();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user