Block self-service payment and cancellation on closed/past registrations

Extends the earlier user-dashboard fix: canEditActive is renamed
canModifyActive and now also gates the "Make payment" and "Cancel
registration" actions, not just editing. Backend enforcement added to
cancelRegistration and createYocoCheckout to block past-event
self-service payment/cancellation server-side (cashup-closed events
were already blocked via assertEventOpen; admins/supervisors are
exempt from the past-date check, consistent with existing overrides).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 16:51:10 +02:00
parent eb46ed8264
commit 349686e182
4 changed files with 21 additions and 8 deletions
+5 -1
View File
@@ -788,11 +788,15 @@ const createYocoCheckout = async (req, res) => {
// Branch 1: Registration payment — delegate to internal helper
if (registrationId) {
// Authorisation check (the internal helper skips this)
const reg = await prisma.registration.findUnique({ where: { id: registrationId }, select: { userId: true, eventId: true } });
const reg = await prisma.registration.findUnique({ where: { id: registrationId }, select: { userId: true, eventId: true, event: { select: { endDate: true } } } });
if (!reg) { res.status(404); throw new Error('Registration not found'); }
if (reg.userId !== userId && req.user.role !== 'admin' && req.user.role !== 'supervisor') {
res.status(403); throw new Error('Not authorized to create checkout for this registration');
}
// If event is in the past, block self-service payment (mirrors the registration-edit block)
if (req.user.role !== 'admin' && req.user.role !== 'supervisor' && reg.event?.endDate && new Date(reg.event.endDate).getTime() < Date.now()) {
res.status(400); throw new Error('This event has already ended; payment can no longer be made for this registration');
}
await assertEventOpen(reg.eventId, res);
// Refresh early-bird pricing — updates priceSnapshot if any tier has expired or sold out.
@@ -583,7 +583,8 @@ const updateRegistrationStatus = async (req, res) => {
const cancelRegistration = async (req, res) => {
try {
const registration = await prisma.registration.findUnique({
where: { id: req.params.id }
where: { id: req.params.id },
include: { event: { select: { endDate: true } } }
});
if (!registration) {
@@ -597,6 +598,12 @@ const cancelRegistration = async (req, res) => {
throw new Error('Not authorized to cancel this registration');
}
// If event is in the past, block self-cancellation (mirrors the edit-block above)
if (req.user.role !== 'admin' && registration.event?.endDate && new Date(registration.event.endDate).getTime() < Date.now()) {
res.status(400);
throw new Error('This event has already ended; registration can no longer be cancelled');
}
await assertEventOpen(registration.eventId, res);
// Check if registration can be cancelled