Files
hope-events/backend/src/controllers/registrationController.js
T
joshuaandClaude Opus 5.5 31ee2a9aee Managing registrations on API v2 (1.51.10)
- v2: staff list (paged), event registrations, registration in full (+ /me), status, manual
  registration, bulk, items, invoice, coupon, attendees and form links, form drafts and responses.
- src/services/registrationAdmin.ts holds the rest of registrationController.js (now v1 wrappers).
- Frontend: fetchAllRegistrations(); every registration screen on v2.
- Roadmap: money gets its own release (1.51.11); webhooks and links move to 1.51.16.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ls1vMdg2GYqbnKZmPaX1ot
2026-10-29 13:16:59 +02:00

65 lines
2.8 KiB
JavaScript

// Registrations (v1). The work is in src/services: registrations.ts (making and cancelling
// one) and registrationAdmin.ts (everything after) — shared with /api/v2.
const { getClientIp } = require('../utils/requestUtils');
const { v1StatusOf } = require('../services/errors');
const registrationService = require('../services/registrations');
const admin = require('../services/registrationAdmin');
// @desc Create a new registration
// @route POST /api/registrations
// @access Private
const createRegistration = async (req, res) => {
try {
const actor = req.user ? { id: req.user.id, role: req.user.role, email: req.user.email } : null;
const { registration, couponError } = await registrationService.createRegistration(req.body || {}, actor);
res.status(201).json({ ...registration, ...(couponError ? { couponError } : {}) });
} catch (error) {
res.status(400).json({ message: error.message });
}
};
// @desc Cancel a registration
// @route DELETE /api/registrations/:id
// @access Private (owner, or an admin)
const cancelRegistration = async (req, res) => {
try {
const updatedRegistration = await registrationService.cancelRegistration(req.params.id, req.user, getClientIp(req));
res.json({ message: 'Registration cancelled', registration: updatedRegistration });
} catch (error) {
res.status(400).json({ message: error.message });
}
};
/** A service function as a v1 handler: its answer as JSON, its error as `{ message }`. */
const handler = (fn, status = () => 200) => async (req, res) => {
try {
const out = await fn(admin.callOf(req));
res.status(status(out)).json(out);
} catch (error) {
if (!error.statusCode) console.error(error);
res.status(v1StatusOf(error, 400)).json({ message: error.message });
}
};
module.exports = {
createRegistration,
cancelRegistration,
getRegistrations: handler(admin.getRegistrations),
getUserRegistrations: handler(admin.getUserRegistrations),
getRegistrationById: handler(admin.getRegistrationById),
updateRegistrationStatus: handler(admin.updateRegistrationStatus),
getRegistrationsByEvent: handler(admin.getRegistrationsByEvent),
createManualRegistration: handler(admin.createManualRegistration, () => 201),
updateRegistrationOptions: handler(admin.updateRegistrationOptions),
// "No form for this event" was a 200; responses saved are a 201.
submitFormResponses: handler(admin.submitFormResponses, out => (out && out.count !== undefined ? 201 : 200)),
replaceFormResponses: handler(admin.replaceFormResponses),
getFormDraft: handler(admin.getFormDraft),
saveFormDraft: handler(admin.saveFormDraft),
sendInvoice: handler(admin.sendInvoice),
applyCoupon: handler(admin.applyCoupon),
removeCoupon: handler(admin.removeCoupon),
updateAttendees: handler(admin.updateAttendees),
sendAttendeeFormLink: handler(admin.sendAttendeeFormLink),
};