EventBuzz_Backend/src/routes/form.routes.js

202 lines
7.4 KiB
JavaScript

const Joi = require('joi');
const controller = require('../controllers/form.controller');
const grantController = require('../controllers/formGrant.controller');
const { requireFormPermissionPre, requirePermissionPre } = require('../services/acl.service');
const { FORM_TYPES, FIELD_TYPES, FORM_FIELD_MAPS_TO } = require('../config/constants');
/** stripUnknown: Mongo subdocs include _id; duplicates must not fail validation. */
const fieldSchema = Joi.object({
label: Joi.string(),
name: Joi.string().allow('', null),
type: Joi.string().valid(...FIELD_TYPES),
required: Joi.boolean(),
options: Joi.array().items(Joi.string()),
allowOther: Joi.boolean(),
otherLabel: Joi.string().allow('', null),
placeholder: Joi.string().allow('', null),
remarks: Joi.string().allow('', null),
uiType: Joi.string().allow('', null),
mapsTo: Joi.string().valid(...FORM_FIELD_MAPS_TO).allow('', null),
customMapsKey: Joi.string().allow('', null),
isFixed: Joi.boolean(),
convertToTag: Joi.boolean(),
}).options({ stripUnknown: true });
const eventHeaderSchema = Joi.object({
showLogo: Joi.boolean(),
showTitle: Joi.boolean(),
showDateRange: Joi.boolean(),
showEventType: Joi.boolean(),
showLocationType: Joi.boolean(),
showVenue: Joi.boolean(),
}).options({ stripUnknown: true });
const settingsSchema = Joi.object({
isActive: Joi.boolean(),
allowMultiple: Joi.boolean(),
submissionLimit: Joi.number(),
thankYouMessage: Joi.string().allow('', null),
responseDeadline: Joi.alternatives().try(Joi.date(), Joi.string().allow('', null), Joi.valid(null)),
showThankYou: Joi.boolean(),
collectEmail: Joi.boolean(),
allowAnonymous: Joi.boolean(),
paymentEnabled: Joi.boolean(),
paymentAmount: Joi.alternatives().try(Joi.string(), Joi.number()).allow('', null),
sendConfirmationEmail: Joi.boolean(),
confirmationEmailTemplateId: Joi.string().hex().length(24).allow(null).empty(''),
onSubmitAddTags: Joi.array().items(Joi.string()),
/** Empty string must become null — mongoose ObjectId rejects "". */
onSubmitParticipantListId: Joi.string().hex().length(24).allow(null).empty(''),
allowDuplicateEmail: Joi.boolean(),
allowDuplicatePhone: Joi.boolean(),
formClosedMessage: Joi.string().allow('', null),
submitErrorMessage: Joi.string().allow('', null),
captchaFailedMessage: Joi.string().allow('', null),
registrationClosedMessage: Joi.string().allow('', null),
registrationDeadlineMessage: Joi.string().allow('', null),
registrationFullMessage: Joi.string().allow('', null),
duplicateEmailMessage: Joi.string().allow('', null),
duplicatePhoneMessage: Joi.string().allow('', null),
eventHeader: eventHeaderSchema,
}).options({ stripUnknown: true });
const formPayload = Joi.object({
name: Joi.string().required(),
type: Joi.string().valid(...FORM_TYPES).required(),
description: Joi.string().allow('', null),
fields: Joi.array().items(fieldSchema),
settings: settingsSchema,
defaultVisibility: Joi.string().valid('private', 'org'),
}).options({ stripUnknown: true });
const formUpdatePayload = formPayload.keys({
event: Joi.string().hex().length(24).required(),
});
/** tenantOrganization: super_admin may set explicitly; others get it from JWT in the controller. */
const formOrgCreatePayload = Joi.object({
name: Joi.string().required(),
type: Joi.string().valid(...FORM_TYPES).required(),
description: Joi.string().allow('', null),
fields: Joi.array().items(fieldSchema),
settings: settingsSchema,
event: Joi.string().hex().length(24).required(),
defaultVisibility: Joi.string().valid('private', 'org'),
tenantOrganization: Joi.alternatives().try(
Joi.string().hex().length(24),
Joi.string().allow(null, ''),
Joi.valid(null)
),
}).options({ stripUnknown: true });
const submitPayload = Joi.object({
participantId: Joi.string(),
data: Joi.object().pattern(Joi.string(), Joi.any()),
captchaToken: Joi.string().allow('', null),
captchaAnswer: Joi.alternatives().try(Joi.string(), Joi.number()).allow('', null),
_gotcha: Joi.string().allow('', null),
});
const replyPayload = Joi.object({
submissionId: Joi.string().required(),
to: Joi.string().email().required(),
subject: Joi.string().allow('', null),
body: Joi.string().allow('', null),
});
const grantPayload = Joi.object({
subjectType: Joi.string().valid('user', 'role').required(),
subjectId: Joi.string().hex().length(24).required(),
actions: Joi.array().items(Joi.string().valid('read', 'write', 'delete')),
});
module.exports = [
{
method: 'GET',
path: '/api/forms',
options: { pre: [{ method: requirePermissionPre('forms', 'read') }], handler: controller.listByOrganization },
},
{
method: 'POST',
path: '/api/forms',
options: { validate: { payload: formOrgCreatePayload }, pre: [{ method: requirePermissionPre('forms', 'write') }], handler: controller.createByOrganization },
},
{
method: 'GET',
path: '/api/events/{eventId}/forms',
options: { pre: [{ method: requirePermissionPre('forms', 'read') }], handler: controller.list },
},
{
method: 'POST',
path: '/api/events/{eventId}/forms',
options: { validate: { payload: formPayload }, pre: [{ method: requirePermissionPre('forms', 'write') }], handler: controller.create },
},
{
method: 'GET',
path: '/api/forms/{id}',
options: { pre: [{ method: requireFormPermissionPre('read') }], handler: controller.get },
},
{
method: 'PUT',
path: '/api/forms/{id}',
options: { validate: { payload: formUpdatePayload }, pre: [{ method: requireFormPermissionPre('write') }], handler: controller.update },
},
{
method: 'DELETE',
path: '/api/forms/{id}',
options: { pre: [{ method: requireFormPermissionPre('delete') }], handler: controller.remove },
},
{
method: 'POST',
path: '/api/forms/{formId}/submit',
options: { auth: false, validate: { payload: submitPayload }, handler: controller.submit },
},
{
method: 'GET',
path: '/api/public/forms/{formId}',
options: { auth: false, handler: controller.getPublicForm },
},
{
method: 'GET',
path: '/api/forms/{formId}/submissions',
options: { pre: [{ method: requireFormPermissionPre('read', { idParam: 'formId' }) }], handler: controller.listSubmissions },
},
{
method: 'POST',
path: '/api/forms/{formId}/submissions/reply',
options: {
validate: { payload: replyPayload },
pre: [{ method: requireFormPermissionPre('read', { idParam: 'formId' }) }],
handler: controller.replyToSubmission,
},
},
{
method: 'GET',
path: '/api/forms/{formId}/grants',
options: { pre: [{ method: requireFormPermissionPre('read', { idParam: 'formId' }) }], handler: grantController.listGrants },
},
{
method: 'POST',
path: '/api/forms/{formId}/grants',
options: {
validate: { payload: grantPayload },
pre: [{ method: requireFormPermissionPre('write', { idParam: 'formId' }) }],
handler: grantController.createGrant,
},
},
{
method: 'DELETE',
path: '/api/forms/{formId}/grants/{grantId}',
options: { pre: [{ method: requireFormPermissionPre('write', { idParam: 'formId' }) }], handler: grantController.removeGrant },
},
{
method: 'PUT',
path: '/api/forms/{formId}/visibility',
options: {
validate: { payload: Joi.object({ defaultVisibility: Joi.string().valid('private', 'org').required() }) },
pre: [{ method: requireFormPermissionPre('write', { idParam: 'formId' }) }],
handler: grantController.updateFormVisibility,
},
},
];