UserCampusScope relation and audit action; scopeEvent/scopeList/unscopedOnly/ campusIndependent/scopeBroadcast markers; tests/campusScopeRoutes.test.js (still failing: events, payments, registrations, scan locks, tickets left). Can't delete a campus that has scoped staff. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
65 lines
2.4 KiB
JavaScript
65 lines
2.4 KiB
JavaScript
const prisma = require('../config/db');
|
|
|
|
// @desc List submitted form responses with optional filters
|
|
// @route GET /api/forms/responses
|
|
// @access Private/Staff (admin, supervisor, staff)
|
|
const listFormResponses = async (req, res) => {
|
|
try {
|
|
const { eventId, userId, registrationId, limit, cursor } = req.query;
|
|
|
|
// Build where clause
|
|
const where = {};
|
|
if (registrationId) {
|
|
where.registrationId = String(registrationId);
|
|
}
|
|
// For eventId/userId we filter through the related registration
|
|
const registrationFilter = {};
|
|
if (eventId) registrationFilter.eventId = String(eventId);
|
|
if (userId) registrationFilter.userId = String(userId);
|
|
Object.assign(registrationFilter, await require('../utils/campusScope').listWhere(req, 'event'));
|
|
if (Object.keys(registrationFilter).length > 0) {
|
|
// Prisma relation filter requires `is` wrapper
|
|
where.registration = { is: registrationFilter };
|
|
}
|
|
|
|
// Basic pagination (optional)
|
|
const take = Math.min(Math.max(parseInt(limit || '50', 10) || 50, 1), 200);
|
|
const cursorClause = cursor ? { id: String(cursor) } : undefined;
|
|
|
|
const responses = await prisma.formResponse.findMany({
|
|
where,
|
|
include: {
|
|
registration: {
|
|
include: {
|
|
user: { select: { id: true, name: true, email: true } },
|
|
event: { select: { id: true, title: true } },
|
|
}
|
|
},
|
|
answers: { include: { field: true } },
|
|
},
|
|
orderBy: { createdAt: 'desc' },
|
|
take,
|
|
...(cursorClause ? { skip: 1, cursor: cursorClause } : {}),
|
|
});
|
|
|
|
const nextCursor = responses.length === take ? responses[responses.length - 1].id : null;
|
|
|
|
// The first page of a list (not one registration's own form, nor the next pages of the
|
|
// same list) is logged as a bulk view of form answers.
|
|
if (!registrationId && !cursor && responses.length) {
|
|
require('../utils/accessLog').logDataAccess(req, {
|
|
action: 'form_responses',
|
|
what: `Attendee form answers${responses[0].registration?.event && eventId ? ` — ${responses[0].registration.event.title}` : ''}`,
|
|
eventId: eventId ? String(eventId) : null,
|
|
records: responses.length,
|
|
});
|
|
}
|
|
|
|
res.json({ items: responses, nextCursor });
|
|
} catch (error) {
|
|
res.status(400).json({ message: error.message });
|
|
}
|
|
};
|
|
|
|
module.exports = { listFormResponses };
|