Persist status-change comments transactionally with the update (#37)
A comment accompanying a status change (required or user-supplied) was posted via a separate, independent HTTP call/write (add_comment.php, or a second add_comment call in lt.ticketStatus.submit()'s requires_comment retry path) before the status update itself. A failure partway through — or the client never issuing the second call — could leave a "reason" comment persisted with no matching status change, or vice versa, with no rollback tying the two together. api/update_ticket.php and api/ticket_status_api.php now post the comment and apply the status update inside one transaction, rolling back both on any failure. assets/js/ticket.js and lt.ticketStatus.submit() in assets/js/base.js no longer make a separate add_comment.php call; they pass the comment directly to update_ticket.php, which persists it server-side alongside the status change. Verified against real MariaDB by extracting the live ApiTicketController and the ticket_status_api.php transaction logic and running them directly: a forced optimistic-lock conflict correctly rolled back both the comment and the status change, and a successful call persisted exactly one comment alongside the status change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117oBw2jN4kALYeS8HPq4zV
This commit is contained in:
+8
-5
@@ -2858,8 +2858,11 @@
|
||||
TICKET STATUS CHANGE (comment-aware)
|
||||
lt.ticketStatus.submit(ticketId, newStatus, { comment? }) → Promise<data>
|
||||
Posts /api/update_ticket.php. If the server rejects with
|
||||
requires_comment, opens a comment modal, persists the comment via
|
||||
/api/add_comment.php, then retries the update once WITH the comment.
|
||||
requires_comment, opens a comment modal, then retries the update once
|
||||
WITH the comment — update_ticket.php persists it in the same DB
|
||||
transaction as the status change itself, so there's no separate
|
||||
add_comment.php call that could leave an orphaned comment if the
|
||||
status update then failed.
|
||||
Rejects with err.cancelled === true if the user cancels the modal.
|
||||
================================================================ */
|
||||
function _statusCommentModal(newStatus) {
|
||||
@@ -2922,9 +2925,9 @@
|
||||
cancelErr.cancelled = true;
|
||||
throw cancelErr;
|
||||
}
|
||||
// Persist the comment, then retry the status change with it included.
|
||||
return api.post('/api/add_comment.php', { ticket_id: id, comment_text: comment })
|
||||
.then(() => api.post('/api/update_ticket.php', { ticket_id: id, status: newStatus, comment: comment }));
|
||||
// Retry with the comment included — update_ticket.php persists it
|
||||
// transactionally with the status update itself.
|
||||
return api.post('/api/update_ticket.php', { ticket_id: id, status: newStatus, comment: comment });
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
+7
-6
@@ -713,12 +713,13 @@ function updateTicketStatus() {
|
||||
return;
|
||||
}
|
||||
cleanup(true);
|
||||
// Post comment first (persists it), then change status with the same
|
||||
// comment included so the server's requires_comment check passes.
|
||||
const ticketId = getTicketIdFromUrl();
|
||||
lt.api.post('/api/add_comment.php', { ticket_id: ticketId, comment_text: comment })
|
||||
.then(() => performStatusChange(statusSelect, selectedOption, newStatus, comment))
|
||||
.catch(() => performStatusChange(statusSelect, selectedOption, newStatus, comment));
|
||||
// The comment is sent as part of the status-change request itself
|
||||
// (update_ticket.php persists it in the same DB transaction as the
|
||||
// status update) rather than as a separate prior add_comment.php
|
||||
// call — previously those were two independent, non-transactional
|
||||
// writes, so a failure partway through could leave the "reason"
|
||||
// comment persisted with no matching status change ever applied.
|
||||
performStatusChange(statusSelect, selectedOption, newStatus, comment);
|
||||
});
|
||||
// Focus textarea on open
|
||||
setTimeout(() => { const ta = document.getElementById(`${modalId}_comment`); if (ta) ta.focus(); }, 100);
|
||||
|
||||
Reference in New Issue
Block a user