diff --git a/CHANGELOG.md b/CHANGELOG.md index 9be170b..a8cd13d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project follows [Semantic Versioning](https://semver.org/). ### Fixed - Creating an event was never recorded in the admin audit log — 1.10.0 added `event_created` as a logged action on the frontend's filter list, but the backend's `createEvent` never actually called `logAdminAction`, only `updateEvent`/`deleteEvent` did. Event creation is now logged the same way. +- Staff cancelling a registration via `PUT /api/registrations/:id` (the staff status-change endpoint, separate from the owner-facing `DELETE /:id` cancel route) wasn't logged at all — only the `DELETE` path logged `registration_cancelled`. Both paths now log it, verified against all six audit categories promised in 1.10.0 (refunds, donation assign/unassign, manual registrations, staff-initiated cancellations, event create/update/delete, settings changes) with no other gaps found. - Added a "Back to dashboard" link to Admin → Audit log, matching the back-link pattern already used on the Cashup page. ## [1.10.2] - 2026-08-28 diff --git a/backend/src/controllers/registrationController.js b/backend/src/controllers/registrationController.js index fafb112..3f22e84 100644 --- a/backend/src/controllers/registrationController.js +++ b/backend/src/controllers/registrationController.js @@ -626,6 +626,22 @@ const updateRegistrationStatus = async (req, res) => { } }); + // This is the staff-only status-change endpoint (separate from the owner-facing + // DELETE /:id cancel route), so any transition into 'cancelled' here is always a + // staff-initiated cancellation — log it the same way DELETE /:id does, so both + // paths land under the one 'registration_cancelled' filter in the audit log. + if (status === 'cancelled' && registration.status !== 'cancelled') { + logAdminAction({ + actorId: req.user.id, + actorRole: req.user.role, + action: 'registration_cancelled', + targetType: 'Registration', + targetId: req.params.id, + metadata: { registrationOwnerId: registration.userId, previousStatus: registration.status }, + ip: getClientIp(req), + }); + } + // Generate tickets and email them when status is manually set to 'paid' by staff if (status === 'paid') { (async () => {