202 lines
7.4 KiB
JavaScript
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,
|
|
},
|
|
},
|
|
];
|