@defra/forms-engine-plugin 4.0.25 → 4.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.server/server/plugins/engine/components/HiddenField.d.ts +21 -0
- package/.server/server/plugins/engine/components/HiddenField.js +50 -0
- package/.server/server/plugins/engine/components/HiddenField.js.map +1 -0
- package/.server/server/plugins/engine/components/helpers/components.d.ts +1 -1
- package/.server/server/plugins/engine/components/helpers/components.js +3 -0
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/components/index.d.ts +1 -0
- package/.server/server/plugins/engine/components/index.js +1 -0
- package/.server/server/plugins/engine/components/index.js.map +1 -1
- package/.server/server/plugins/engine/helpers.js +2 -1
- package/.server/server/plugins/engine/helpers.js.map +1 -1
- package/.server/server/plugins/engine/models/FormModel.d.ts +2 -0
- package/.server/server/plugins/engine/models/FormModel.js +2 -0
- package/.server/server/plugins/engine/models/FormModel.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/PageController.d.ts +1 -1
- package/.server/server/plugins/engine/pageControllers/PageController.js +2 -8
- package/.server/server/plugins/engine/pageControllers/PageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +7 -0
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/StatusPageController.js +8 -2
- package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +2 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/state.d.ts +11 -0
- package/.server/server/plugins/engine/pageControllers/helpers/state.js +66 -0
- package/.server/server/plugins/engine/pageControllers/helpers/state.js.map +1 -0
- package/.server/server/plugins/engine/routes/index.js +2 -1
- package/.server/server/plugins/engine/routes/index.js.map +1 -1
- package/.server/server/plugins/engine/services/formsService.d.ts +6 -0
- package/.server/server/plugins/engine/services/formsService.js +10 -0
- package/.server/server/plugins/engine/services/formsService.js.map +1 -1
- package/.server/server/plugins/engine/services/formsService.test.js +14 -0
- package/.server/server/plugins/engine/services/formsService.test.js.map +1 -0
- package/.server/server/plugins/engine/types.d.ts +4 -0
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/engine/views/components/hiddenfield.html +3 -0
- package/.server/server/plugins/engine/views/confirmation.html +5 -0
- package/.server/server/plugins/engine/views/partials/form.html +9 -1
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/.server/server/services/cacheService.d.ts +3 -7
- package/.server/server/services/cacheService.js.map +1 -1
- package/.server/server/types.d.ts +1 -0
- package/.server/server/types.js.map +1 -1
- package/.server/server/utils/file-form-service.d.ts +6 -0
- package/.server/server/utils/file-form-service.js +22 -1
- package/.server/server/utils/file-form-service.js.map +1 -1
- package/.server/server/utils/file-form-service.test.js +86 -0
- package/.server/server/utils/file-form-service.test.js.map +1 -0
- package/package.json +2 -2
- package/src/server/plugins/engine/components/HiddenField.test.ts +188 -0
- package/src/server/plugins/engine/components/HiddenField.ts +68 -0
- package/src/server/plugins/engine/components/helpers/components.ts +5 -0
- package/src/server/plugins/engine/components/helpers/helpers.test.ts +17 -0
- package/src/server/plugins/engine/components/index.ts +1 -0
- package/src/server/plugins/engine/helpers.ts +2 -1
- package/src/server/plugins/engine/models/FormModel.ts +3 -0
- package/src/server/plugins/engine/pageControllers/PageController.test.ts +4 -11
- package/src/server/plugins/engine/pageControllers/PageController.ts +1 -9
- package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +7 -0
- package/src/server/plugins/engine/pageControllers/StatusPageController.ts +9 -2
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +5 -1
- package/src/server/plugins/engine/pageControllers/helpers/state.test.ts +221 -0
- package/src/server/plugins/engine/pageControllers/helpers/state.ts +93 -0
- package/src/server/plugins/engine/routes/index.test.ts +24 -11
- package/src/server/plugins/engine/routes/index.ts +1 -1
- package/src/server/plugins/engine/services/formsService.js +10 -0
- package/src/server/plugins/engine/services/formsService.test.js +21 -0
- package/src/server/plugins/engine/types.ts +5 -0
- package/src/server/plugins/engine/views/components/hiddenfield.html +3 -0
- package/src/server/plugins/engine/views/confirmation.html +5 -0
- package/src/server/plugins/engine/views/partials/form.html +9 -1
- package/src/server/services/cacheService.ts +3 -2
- package/src/server/types.ts +1 -0
- package/src/server/utils/file-form-service.js +27 -1
- package/src/server/utils/file-form-service.test.js +114 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Boom","isEqual","EXTERNAL_STATE_APPENDAGE","EXTERNAL_STATE_PAYLOAD","PREVIEW_PATH_PREFIX","FormComponent","isFormState","checkEmailAddressForLiveFormSubmission","checkFormStatus","findPage","getCacheService","getPage","getStartPath","proceed","FormModel","generateUniqueReference","defaultServices","redirectOrMakeHandler","request","h","onRequest","makeHandler","app","params","model","notFound","path","cacheService","server","page","state","getState","$$__referenceNumber","prefix","def","metadata","referenceNumberPrefix","badImplementation","referenceNumber","mergeState","importExternalComponentState","flash","getFlash","context","getFormContext","errors","relevantPath","getRelevantPath","summaryPath","getSummaryPath","result","continue","startsWith","isForceAccess","redirectTo","next","length","query","returnUrl","getHref","externalComponentData","yar","Array","isArray","typedStateAppendage","componentName","component","stateAppendage","data","componentMap","get","Error","TypeError","isStateValid","isState","componentState","Object","fromEntries","entries","map","key","value","pageState","getStateFromValidForm","savedState","payload","stashedPayload","localState","makeLoadFormPreHandler","options","realm","modifiers","route","services","controllers","ordnanceSurveyApiKey","formsService","handler","slug","isPreview","formState","getFormMetadata","id","item","models","updatedAt","logger","info","definition","getFormDefinition","emailAddress","notificationEmail","outputEmail","basePath","substring","versionNumber","versions","set","dispatchHandler","servicePath"],"sources":["../../../../../src/server/plugins/engine/routes/index.ts"],"sourcesContent":["import Boom from '@hapi/boom'\nimport {\n type ResponseObject,\n type ResponseToolkit,\n type Server\n} from '@hapi/hapi'\nimport { isEqual } from 'date-fns'\n\nimport {\n EXTERNAL_STATE_APPENDAGE,\n EXTERNAL_STATE_PAYLOAD,\n PREVIEW_PATH_PREFIX\n} from '~/src/server/constants.js'\nimport {\n FormComponent,\n isFormState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus,\n findPage,\n getCacheService,\n getPage,\n getStartPath,\n proceed\n} from '~/src/server/plugins/engine/helpers.js'\nimport { FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { generateUniqueReference } from '~/src/server/plugins/engine/referenceNumbers.js'\nimport * as defaultServices from '~/src/server/plugins/engine/services/index.js'\nimport {\n type AnyFormRequest,\n type ExternalStateAppendage,\n type FormContext,\n type FormPayload,\n type FormSubmissionState,\n type OnRequestCallback,\n type PluginOptions\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport async function redirectOrMakeHandler(\n request: AnyFormRequest,\n h: FormResponseToolkit,\n onRequest: OnRequestCallback | undefined,\n makeHandler: (\n page: PageControllerClass,\n context: FormContext\n ) => ResponseObject | Promise<ResponseObject>\n) {\n const { app, params } = request\n const { model } = app\n\n if (!model) {\n throw Boom.notFound(`No model found for /${params.path}`)\n }\n\n const cacheService = getCacheService(request.server)\n const page = getPage(model, request)\n let state = await page.getState(request)\n\n if (!state.$$__referenceNumber) {\n const prefix = model.def.metadata?.referenceNumberPrefix ?? ''\n\n if (typeof prefix !== 'string') {\n throw Boom.badImplementation(\n 'Reference number prefix must be a string or undefined'\n )\n }\n\n const referenceNumber = generateUniqueReference(prefix)\n state = await page.mergeState(request, state, {\n $$__referenceNumber: referenceNumber\n })\n }\n\n state = await importExternalComponentState(request, page, state)\n\n const flash = cacheService.getFlash(request)\n const context = model.getFormContext(request, state, flash?.errors)\n const relevantPath = page.getRelevantPath(request, context)\n const summaryPath = page.getSummaryPath()\n\n // Call the onRequest callback if it has been supplied\n if (onRequest) {\n const result = await onRequest(request, h, context)\n if (result !== h.continue) {\n return result\n }\n }\n\n // Return handler for relevant pages or preview URL direct access\n if (relevantPath.startsWith(page.path) || context.isForceAccess) {\n return makeHandler(page, context)\n }\n\n // Redirect back to last relevant page\n const redirectTo = findPage(model, relevantPath)\n\n // Set the return URL unless an exit page\n if (redirectTo?.next.length) {\n request.query.returnUrl = page.getHref(summaryPath)\n }\n\n return proceed(request, h, page.getHref(relevantPath))\n}\n\nasync function importExternalComponentState(\n request: AnyFormRequest,\n page: PageControllerClass,\n state: FormSubmissionState\n): Promise<FormSubmissionState> {\n const externalComponentData = request.yar.flash(EXTERNAL_STATE_APPENDAGE)\n\n if (Array.isArray(externalComponentData)) {\n return state\n }\n\n const typedStateAppendage = externalComponentData as ExternalStateAppendage\n const componentName = typedStateAppendage.component\n const stateAppendage = typedStateAppendage.data\n const component = request.app.model?.componentMap.get(componentName)\n\n if (!component) {\n throw new Error(`Component ${componentName} not found in form`)\n }\n\n if (!(component instanceof FormComponent)) {\n throw new TypeError(\n `Component ${componentName} is not a FormComponent and does not support isState`\n )\n }\n\n const isStateValid = component.isState(stateAppendage)\n\n if (!isStateValid) {\n throw new Error(`State for component ${componentName} is invalid`)\n }\n\n const componentState = isFormState(stateAppendage)\n ? Object.fromEntries(\n Object.entries(stateAppendage).map(([key, value]) => [\n `${componentName}__${key}`,\n value\n ])\n )\n : { [componentName]: stateAppendage }\n\n // Save the external component state immediately\n const pageState = page.getStateFromValidForm(\n request,\n state,\n componentState as FormPayload\n )\n const savedState = await page.mergeState(request, state, pageState)\n\n // Merge any stashed payload into the local state\n const payload = request.yar.flash(EXTERNAL_STATE_PAYLOAD)\n const stashedPayload = Array.isArray(payload) ? {} : (payload as FormPayload)\n\n const localState = page.getStateFromValidForm(request, savedState, {\n ...stashedPayload,\n ...componentState\n } as FormPayload)\n\n return { ...savedState, ...localState }\n}\n\nexport function makeLoadFormPreHandler(server: Server, options: PluginOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- hapi types are wrong\n const prefix = server.realm.modifiers.route.prefix ?? ''\n\n const {\n services = defaultServices,\n controllers,\n ordnanceSurveyApiKey\n } = options\n\n const { formsService } = services\n\n async function handler(request: AnyFormRequest, h: ResponseToolkit) {\n if (server.app.model) {\n request.app.model = server.app.model\n\n return h.continue\n }\n\n const { params } = request\n const { slug } = params\n const { isPreview, state: formState } = checkFormStatus(params)\n\n // Get the form metadata using the `slug` param\n const metadata = await formsService.getFormMetadata(slug)\n\n const { id, [formState]: state } = metadata\n\n // Check the metadata supports the requested state\n if (!state) {\n throw Boom.notFound(`No '${formState}' state for form metadata ${id}`)\n }\n\n // Cache the models based on id, state and whether\n // it's a preview or not. There could be up to 3 models\n // cached for a single form:\n // \"{id}_live_false\" (live/live)\n // \"{id}_live_true\" (live/preview)\n // \"{id}_draft_true\" (draft/preview)\n const key = `${id}_${formState}_${isPreview}`\n let item = server.app.models.get(key)\n\n if (!item || !isEqual(item.updatedAt, state.updatedAt)) {\n server.logger.info(`Getting form definition ${id} (${slug}) ${formState}`)\n\n // Get the form definition using the `id` from the metadata\n const definition = await formsService.getFormDefinition(id, formState)\n\n if (!definition) {\n throw Boom.notFound(\n `No definition found for form metadata ${id} (${slug}) ${formState}`\n )\n }\n\n const emailAddress = metadata.notificationEmail ?? definition.outputEmail\n\n checkEmailAddressForLiveFormSubmission(emailAddress, isPreview)\n\n // Build the form model\n server.logger.info(\n `Building model for form definition ${id} (${slug}) ${formState}`\n )\n\n // Set up the basePath for the model\n const basePath = (\n isPreview\n ? `${prefix}${PREVIEW_PATH_PREFIX}/${formState}/${slug}`\n : `${prefix}/${slug}`\n ).substring(1)\n\n const versionNumber = metadata.versions?.[0]?.versionNumber\n\n // Construct the form model\n const model = new FormModel(\n definition,\n { basePath, versionNumber, ordnanceSurveyApiKey },\n services,\n controllers\n )\n\n // Create new item and add it to the item cache\n item = { model, updatedAt: state.updatedAt }\n server.app.models.set(key, item)\n }\n\n // Assign the model to the request data\n // for use in the downstream handler\n request.app.model = item.model\n\n return h.continue\n }\n\n return handler\n}\n\nexport function dispatchHandler(request: FormRequest, h: FormResponseToolkit) {\n const { model } = request.app\n\n const servicePath = model ? `/${model.basePath}` : ''\n return proceed(request, h, `${servicePath}${getStartPath(model)}`)\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"index.js","names":["Boom","isEqual","EXTERNAL_STATE_APPENDAGE","EXTERNAL_STATE_PAYLOAD","PREVIEW_PATH_PREFIX","FormComponent","isFormState","checkEmailAddressForLiveFormSubmission","checkFormStatus","findPage","getCacheService","getPage","getStartPath","proceed","FormModel","generateUniqueReference","defaultServices","redirectOrMakeHandler","request","h","onRequest","makeHandler","app","params","model","notFound","path","cacheService","server","page","state","getState","$$__referenceNumber","prefix","def","metadata","referenceNumberPrefix","badImplementation","referenceNumber","mergeState","importExternalComponentState","flash","getFlash","context","getFormContext","errors","relevantPath","getRelevantPath","summaryPath","getSummaryPath","result","continue","startsWith","isForceAccess","redirectTo","next","length","query","returnUrl","getHref","externalComponentData","yar","Array","isArray","typedStateAppendage","componentName","component","stateAppendage","data","componentMap","get","Error","TypeError","isStateValid","isState","componentState","Object","fromEntries","entries","map","key","value","pageState","getStateFromValidForm","savedState","payload","stashedPayload","localState","makeLoadFormPreHandler","options","realm","modifiers","route","services","controllers","ordnanceSurveyApiKey","formsService","handler","slug","isPreview","formState","getFormMetadata","id","item","models","updatedAt","logger","info","definition","getFormDefinition","emailAddress","notificationEmail","outputEmail","basePath","substring","versionNumber","versions","formId","set","dispatchHandler","servicePath"],"sources":["../../../../../src/server/plugins/engine/routes/index.ts"],"sourcesContent":["import Boom from '@hapi/boom'\nimport {\n type ResponseObject,\n type ResponseToolkit,\n type Server\n} from '@hapi/hapi'\nimport { isEqual } from 'date-fns'\n\nimport {\n EXTERNAL_STATE_APPENDAGE,\n EXTERNAL_STATE_PAYLOAD,\n PREVIEW_PATH_PREFIX\n} from '~/src/server/constants.js'\nimport {\n FormComponent,\n isFormState\n} from '~/src/server/plugins/engine/components/FormComponent.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus,\n findPage,\n getCacheService,\n getPage,\n getStartPath,\n proceed\n} from '~/src/server/plugins/engine/helpers.js'\nimport { FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { generateUniqueReference } from '~/src/server/plugins/engine/referenceNumbers.js'\nimport * as defaultServices from '~/src/server/plugins/engine/services/index.js'\nimport {\n type AnyFormRequest,\n type ExternalStateAppendage,\n type FormContext,\n type FormPayload,\n type FormSubmissionState,\n type OnRequestCallback,\n type PluginOptions\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormResponseToolkit\n} from '~/src/server/routes/types.js'\n\nexport async function redirectOrMakeHandler(\n request: AnyFormRequest,\n h: FormResponseToolkit,\n onRequest: OnRequestCallback | undefined,\n makeHandler: (\n page: PageControllerClass,\n context: FormContext\n ) => ResponseObject | Promise<ResponseObject>\n) {\n const { app, params } = request\n const { model } = app\n\n if (!model) {\n throw Boom.notFound(`No model found for /${params.path}`)\n }\n\n const cacheService = getCacheService(request.server)\n const page = getPage(model, request)\n let state = await page.getState(request)\n\n if (!state.$$__referenceNumber) {\n const prefix = model.def.metadata?.referenceNumberPrefix ?? ''\n\n if (typeof prefix !== 'string') {\n throw Boom.badImplementation(\n 'Reference number prefix must be a string or undefined'\n )\n }\n\n const referenceNumber = generateUniqueReference(prefix)\n state = await page.mergeState(request, state, {\n $$__referenceNumber: referenceNumber\n })\n }\n\n state = await importExternalComponentState(request, page, state)\n\n const flash = cacheService.getFlash(request)\n const context = model.getFormContext(request, state, flash?.errors)\n const relevantPath = page.getRelevantPath(request, context)\n const summaryPath = page.getSummaryPath()\n\n // Call the onRequest callback if it has been supplied\n if (onRequest) {\n const result = await onRequest(request, h, context)\n if (result !== h.continue) {\n return result\n }\n }\n\n // Return handler for relevant pages or preview URL direct access\n if (relevantPath.startsWith(page.path) || context.isForceAccess) {\n return makeHandler(page, context)\n }\n\n // Redirect back to last relevant page\n const redirectTo = findPage(model, relevantPath)\n\n // Set the return URL unless an exit page\n if (redirectTo?.next.length) {\n request.query.returnUrl = page.getHref(summaryPath)\n }\n\n return proceed(request, h, page.getHref(relevantPath))\n}\n\nasync function importExternalComponentState(\n request: AnyFormRequest,\n page: PageControllerClass,\n state: FormSubmissionState\n): Promise<FormSubmissionState> {\n const externalComponentData = request.yar.flash(EXTERNAL_STATE_APPENDAGE)\n\n if (Array.isArray(externalComponentData)) {\n return state\n }\n\n const typedStateAppendage = externalComponentData as ExternalStateAppendage\n const componentName = typedStateAppendage.component\n const stateAppendage = typedStateAppendage.data\n const component = request.app.model?.componentMap.get(componentName)\n\n if (!component) {\n throw new Error(`Component ${componentName} not found in form`)\n }\n\n if (!(component instanceof FormComponent)) {\n throw new TypeError(\n `Component ${componentName} is not a FormComponent and does not support isState`\n )\n }\n\n const isStateValid = component.isState(stateAppendage)\n\n if (!isStateValid) {\n throw new Error(`State for component ${componentName} is invalid`)\n }\n\n const componentState = isFormState(stateAppendage)\n ? Object.fromEntries(\n Object.entries(stateAppendage).map(([key, value]) => [\n `${componentName}__${key}`,\n value\n ])\n )\n : { [componentName]: stateAppendage }\n\n // Save the external component state immediately\n const pageState = page.getStateFromValidForm(\n request,\n state,\n componentState as FormPayload\n )\n const savedState = await page.mergeState(request, state, pageState)\n\n // Merge any stashed payload into the local state\n const payload = request.yar.flash(EXTERNAL_STATE_PAYLOAD)\n const stashedPayload = Array.isArray(payload) ? {} : (payload as FormPayload)\n\n const localState = page.getStateFromValidForm(request, savedState, {\n ...stashedPayload,\n ...componentState\n } as FormPayload)\n\n return { ...savedState, ...localState }\n}\n\nexport function makeLoadFormPreHandler(server: Server, options: PluginOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- hapi types are wrong\n const prefix = server.realm.modifiers.route.prefix ?? ''\n\n const {\n services = defaultServices,\n controllers,\n ordnanceSurveyApiKey\n } = options\n\n const { formsService } = services\n\n async function handler(request: AnyFormRequest, h: ResponseToolkit) {\n if (server.app.model) {\n request.app.model = server.app.model\n\n return h.continue\n }\n\n const { params } = request\n const { slug } = params\n const { isPreview, state: formState } = checkFormStatus(params)\n\n // Get the form metadata using the `slug` param\n const metadata = await formsService.getFormMetadata(slug)\n\n const { id, [formState]: state } = metadata\n\n // Check the metadata supports the requested state\n if (!state) {\n throw Boom.notFound(`No '${formState}' state for form metadata ${id}`)\n }\n\n // Cache the models based on id, state and whether\n // it's a preview or not. There could be up to 3 models\n // cached for a single form:\n // \"{id}_live_false\" (live/live)\n // \"{id}_live_true\" (live/preview)\n // \"{id}_draft_true\" (draft/preview)\n const key = `${id}_${formState}_${isPreview}`\n let item = server.app.models.get(key)\n\n if (!item || !isEqual(item.updatedAt, state.updatedAt)) {\n server.logger.info(`Getting form definition ${id} (${slug}) ${formState}`)\n\n // Get the form definition using the `id` from the metadata\n const definition = await formsService.getFormDefinition(id, formState)\n\n if (!definition) {\n throw Boom.notFound(\n `No definition found for form metadata ${id} (${slug}) ${formState}`\n )\n }\n\n const emailAddress = metadata.notificationEmail ?? definition.outputEmail\n\n checkEmailAddressForLiveFormSubmission(emailAddress, isPreview)\n\n // Build the form model\n server.logger.info(\n `Building model for form definition ${id} (${slug}) ${formState}`\n )\n\n // Set up the basePath for the model\n const basePath = (\n isPreview\n ? `${prefix}${PREVIEW_PATH_PREFIX}/${formState}/${slug}`\n : `${prefix}/${slug}`\n ).substring(1)\n\n const versionNumber = metadata.versions?.[0]?.versionNumber\n\n // Construct the form model\n const model = new FormModel(\n definition,\n { basePath, versionNumber, ordnanceSurveyApiKey, formId: id },\n services,\n controllers\n )\n\n // Create new item and add it to the item cache\n item = { model, updatedAt: state.updatedAt }\n server.app.models.set(key, item)\n }\n\n // Assign the model to the request data\n // for use in the downstream handler\n request.app.model = item.model\n\n return h.continue\n }\n\n return handler\n}\n\nexport function dispatchHandler(request: FormRequest, h: FormResponseToolkit) {\n const { model } = request.app\n\n const servicePath = model ? `/${model.basePath}` : ''\n return proceed(request, h, `${servicePath}${getStartPath(model)}`)\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
* @returns {Promise<FormMetadata>}
|
|
5
5
|
*/
|
|
6
6
|
export function getFormMetadata(_slug: string): Promise<FormMetadata>;
|
|
7
|
+
/**
|
|
8
|
+
* Dummy function to get form metadata.
|
|
9
|
+
* @param {string} _id - the id of the form
|
|
10
|
+
* @returns {Promise<FormMetadata>}
|
|
11
|
+
*/
|
|
12
|
+
export function getFormMetadataById(_id: string): Promise<FormMetadata>;
|
|
7
13
|
/**
|
|
8
14
|
* Dummy function to get form metadata.
|
|
9
15
|
* @param {string} _id - the id of the form
|
|
@@ -10,6 +10,16 @@ export function getFormMetadata(_slug) {
|
|
|
10
10
|
throw error;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
// eslint-disable-next-line jsdoc/require-returns-check
|
|
14
|
+
/**
|
|
15
|
+
* Dummy function to get form metadata.
|
|
16
|
+
* @param {string} _id - the id of the form
|
|
17
|
+
* @returns {Promise<FormMetadata>}
|
|
18
|
+
*/
|
|
19
|
+
export function getFormMetadataById(_id) {
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
// eslint-disable-next-line jsdoc/require-returns-check
|
|
14
24
|
/**
|
|
15
25
|
* Dummy function to get form metadata.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formsService.js","names":["error","Error","getFormMetadata","_slug","
|
|
1
|
+
{"version":3,"file":"formsService.js","names":["error","Error","getFormMetadata","_slug","getFormMetadataById","_id","getFormDefinition","_state"],"sources":["../../../../../src/server/plugins/engine/services/formsService.js"],"sourcesContent":["const error = Error(\n 'Not implemented. Consider setting up a form loader or providing a service implementation.'\n)\n\n// eslint-disable-next-line jsdoc/require-returns-check\n/**\n * Dummy function to get form metadata.\n * @param {string} _slug - the slug of the form\n * @returns {Promise<FormMetadata>}\n */\nexport function getFormMetadata(_slug) {\n throw error\n}\n\n// eslint-disable-next-line jsdoc/require-returns-check\n/**\n * Dummy function to get form metadata.\n * @param {string} _id - the id of the form\n * @returns {Promise<FormMetadata>}\n */\nexport function getFormMetadataById(_id) {\n throw error\n}\n\n// eslint-disable-next-line jsdoc/require-returns-check\n/**\n * Dummy function to get form metadata.\n * @param {string} _id - the id of the form\n * @param {FormStatus} _state - the state of the form\n * @returns {Promise<FormDefinition | undefined>}\n */\nexport function getFormDefinition(_id, _state) {\n throw error\n}\n\n/**\n * @import { FormStatus, FormDefinition, FormMetadata } from '@defra/forms-model'\n */\n"],"mappings":"AAAA,MAAMA,KAAK,GAAGC,KAAK,CACjB,2FACF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAACC,KAAK,EAAE;EACrC,MAAMH,KAAK;AACb;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASI,mBAAmBA,CAACC,GAAG,EAAE;EACvC,MAAML,KAAK;AACb;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASM,iBAAiBA,CAACD,GAAG,EAAEE,MAAM,EAAE;EAC7C,MAAMP,KAAK;AACb;;AAEA;AACA;AACA","ignoreList":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FormStatus } from '@defra/forms-model';
|
|
2
|
+
import { getFormDefinition, getFormMetadata, getFormMetadataById } from "./formsService.js";
|
|
3
|
+
describe('formsService', () => {
|
|
4
|
+
it('getFormMetadata should throw error', () => {
|
|
5
|
+
expect(() => getFormMetadata('slug')).toThrow();
|
|
6
|
+
});
|
|
7
|
+
it('getFormMetadataById should throw error', () => {
|
|
8
|
+
expect(() => getFormMetadataById('id')).toThrow();
|
|
9
|
+
});
|
|
10
|
+
it('getFormDefinition should throw error', () => {
|
|
11
|
+
expect(() => getFormDefinition('id', FormStatus.Draft)).toThrow();
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=formsService.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formsService.test.js","names":["FormStatus","getFormDefinition","getFormMetadata","getFormMetadataById","describe","it","expect","toThrow","Draft"],"sources":["../../../../../src/server/plugins/engine/services/formsService.test.js"],"sourcesContent":["import { FormStatus } from '@defra/forms-model'\n\nimport {\n getFormDefinition,\n getFormMetadata,\n getFormMetadataById\n} from '~/src/server/plugins/engine/services/formsService.js'\n\ndescribe('formsService', () => {\n it('getFormMetadata should throw error', () => {\n expect(() => getFormMetadata('slug')).toThrow()\n })\n\n it('getFormMetadataById should throw error', () => {\n expect(() => getFormMetadataById('id')).toThrow()\n })\n\n it('getFormDefinition should throw error', () => {\n expect(() => getFormDefinition('id', FormStatus.Draft)).toThrow()\n })\n})\n"],"mappings":"AAAA,SAASA,UAAU,QAAQ,oBAAoB;AAE/C,SACEC,iBAAiB,EACjBC,eAAe,EACfC,mBAAmB;AAGrBC,QAAQ,CAAC,cAAc,EAAE,MAAM;EAC7BC,EAAE,CAAC,oCAAoC,EAAE,MAAM;IAC7CC,MAAM,CAAC,MAAMJ,eAAe,CAAC,MAAM,CAAC,CAAC,CAACK,OAAO,CAAC,CAAC;EACjD,CAAC,CAAC;EAEFF,EAAE,CAAC,wCAAwC,EAAE,MAAM;IACjDC,MAAM,CAAC,MAAMH,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAACI,OAAO,CAAC,CAAC;EACnD,CAAC,CAAC;EAEFF,EAAE,CAAC,sCAAsC,EAAE,MAAM;IAC/CC,MAAM,CAAC,MAAML,iBAAiB,CAAC,IAAI,EAAED,UAAU,CAACQ,KAAK,CAAC,CAAC,CAACD,OAAO,CAAC,CAAC;EACnE,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
|
|
@@ -59,6 +59,10 @@ export interface FormSubmissionError extends Pick<ValidationErrorItem, 'context'
|
|
|
59
59
|
name: string;
|
|
60
60
|
text: string;
|
|
61
61
|
}
|
|
62
|
+
export interface FormConfirmationState {
|
|
63
|
+
confirmed?: true;
|
|
64
|
+
formId?: string;
|
|
65
|
+
}
|
|
62
66
|
export interface FormPayloadParams {
|
|
63
67
|
action?: FormAction;
|
|
64
68
|
confirm?: true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":["FileStatus","UploadStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Event,\n type FormVersionMetadata,\n type Item,\n type List,\n type Page,\n type UkAddressFieldComponent\n} from '@defra/forms-model'\nimport {\n type PluginProperties,\n type Request,\n type ResponseObject\n} from '@hapi/hapi'\nimport { type JoiExpression, type ValidationErrorItem } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { type FileUploadField } from '~/src/server/plugins/engine/components/index.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel,\n type DatePartsState,\n type EastingNorthingState,\n type LatLongState,\n type MonthYearState\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItemField } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { type QuestionPageController } from '~/src/server/plugins/engine/pageControllers/index.js'\nimport {\n type FileStatus,\n type FormAdapterSubmissionSchemaVersion,\n type UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport {\n type FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\nimport { type RequestOptions } from '~/src/server/services/httpService.js'\nimport { type Services } from '~/src/server/types.js'\n\nexport type AnyFormRequest = FormRequest | FormRequestPayload\nexport type AnyRequest = Request | AnyFormRequest\n\n/**\n * Form submission state stores the following in Redis:\n * Props containing user's submitted values as `{ [inputId]: value }` or as `{ [sectionName]: { [inputName]: value } }`\n * a) . e.g:\n * ```ts\n * {\n * _C9PRHmsgt: 'Ben',\n * WfLk9McjzX: 'Music',\n * IK7jkUFCBL: 'Royal Academy of Music'\n * }\n * ```\n *\n * b)\n * ```ts\n * {\n * checkBeforeYouStart: { ukPassport: true },\n * applicantDetails: {\n * numberOfApplicants: 1,\n * phoneNumber: '77777777',\n * emailAddress: 'aaa@aaa.com'\n * },\n * applicantOneDetails: {\n * firstName: 'a',\n * middleName: 'a',\n * lastName: 'a',\n * address: { addressLine1: 'a', addressLine2: 'a', town: 'a', postcode: 'a' }\n * }\n * }\n * ```\n */\n\n/**\n * Form submission state\n */\nexport type FormSubmissionState = {\n upload?: Record<string, TempFileState>\n} & FormState\n\nexport interface FormSubmissionError\n extends Pick<ValidationErrorItem, 'context' | 'path'> {\n href: string // e.g: '#dateField__day'\n name: string // e.g: 'dateField__day'\n text: string // e.g: 'Date field must be a real date'\n}\n\nexport interface FormPayloadParams {\n action?: FormAction\n confirm?: true\n crumb?: string\n itemId?: string\n}\n\n/**\n * Form POST for question pages\n * (after Joi has converted value types)\n */\nexport type FormPayload = FormPayloadParams & Partial<Record<string, FormValue>>\n\nexport type FormValue =\n | Item['value']\n | Item['value'][]\n | UploadState\n | RepeatListState\n | undefined\n\nexport type FormState = Partial<Record<string, FormStateValue>>\nexport type FormStateValue = Exclude<FormValue, undefined> | null\n\nexport interface FormValidationResult<\n ValueType extends FormPayload | FormSubmissionState\n> {\n value: ValueType\n errors: FormSubmissionError[] | undefined\n}\n\nexport interface FormContext {\n /**\n * Evaluation form state only (filtered by visited paths),\n * with values formatted for condition evaluation using\n * {@link FormComponent.getContextValueFromState}\n */\n evaluationState: FormState\n\n /**\n * Relevant form state only (filtered by visited paths)\n */\n relevantState: FormState\n\n /**\n * Relevant pages only (filtered by visited paths)\n */\n relevantPages: PageControllerClass[]\n\n /**\n * Form submission payload (single page)\n */\n payload: FormPayload\n\n /**\n * Form submission state (entire form)\n */\n state: FormSubmissionState\n\n /**\n * Validation errors (entire form)\n */\n errors?: FormSubmissionError[]\n\n /**\n * Visited paths evaluated from form state\n */\n paths: string[]\n\n /**\n * Preview URL direct access is allowed\n */\n isForceAccess: boolean\n\n /**\n * Miscellaneous extra data from event responses\n */\n data: object\n\n pageDefMap: Map<string, Page>\n listDefMap: Map<string, List>\n componentDefMap: Map<string, ComponentDef>\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n referenceNumber: string\n submittedVersionNumber?: number\n}\n\nexport type FormContextRequest = (\n | {\n method: 'get'\n payload?: undefined\n }\n | {\n method: 'post'\n payload: FormPayload\n }\n | {\n method: FormRequest['method']\n payload?: object | undefined\n }\n) &\n Pick<\n FormRequest,\n 'app' | 'method' | 'params' | 'path' | 'query' | 'url' | 'server'\n >\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport {\n FileStatus,\n UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\n\nexport type UploadState = FileState[]\n\nexport type FileUpload = {\n fileId: string\n filename: string\n contentLength: number\n} & (\n | {\n fileStatus: FileStatus.complete | FileStatus.rejected | FileStatus.pending\n errorMessage?: string\n }\n | {\n fileStatus: FileStatus.complete\n errorMessage?: undefined\n }\n)\n\nexport interface FileUploadMetadata {\n retrievalKey: string\n}\n\nexport type UploadStatusResponse =\n | {\n uploadStatus: UploadStatus.initiated\n metadata: FileUploadMetadata\n form: { file?: undefined }\n }\n | {\n uploadStatus: UploadStatus.pending | UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles?: number\n }\n | {\n uploadStatus: UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles: 0\n }\n\nexport type UploadStatusFileResponse = Exclude<\n UploadStatusResponse,\n { uploadStatus: UploadStatus.initiated }\n>\n\nexport interface FileState {\n uploadId: string\n status: UploadStatusFileResponse\n}\n\nexport interface TempFileState {\n upload?: UploadInitiateResponse\n files: UploadState\n}\n\nexport interface RepeatItemState extends FormPayload {\n itemId: string\n}\n\nexport type RepeatListState = RepeatItemState[]\n\nexport interface CheckAnswers {\n title?: ComponentText\n summaryList: SummaryList\n}\n\nexport interface SummaryList {\n classes?: string\n rows: SummaryListRow[]\n}\n\nexport interface SummaryListRow {\n key: ComponentText\n value: ComponentText\n actions?: { items: SummaryListAction[] }\n}\n\nexport type SummaryListAction = ComponentText & {\n href: string\n visuallyHiddenText: string\n}\n\nexport interface PageViewModelBase extends Partial<ViewContext> {\n page: PageController\n name?: string\n pageTitle: string\n sectionTitle?: string\n showTitle: boolean\n isStartPage: boolean\n backLink?: BackLink\n feedbackLink?: string\n serviceUrl: string\n phaseTag?: string\n}\n\nexport interface ItemDeletePageViewModel extends PageViewModelBase {\n context: FormContext\n itemTitle: string\n confirmation?: ComponentText\n buttonConfirm: ComponentText\n buttonCancel: ComponentText\n}\n\nexport interface FormPageViewModel extends PageViewModelBase {\n components: ComponentViewModel[]\n context: FormContext\n errors?: FormSubmissionError[]\n hasMissingNotificationEmail?: boolean\n allowSaveAndExit: boolean\n}\n\nexport interface RepeaterSummaryPageViewModel extends PageViewModelBase {\n context: FormContext\n errors?: FormSubmissionError[]\n checkAnswers: CheckAnswers[]\n repeatTitle: string\n allowSaveAndExit: boolean\n}\n\nexport interface FeaturedFormPageViewModel extends FormPageViewModel {\n formAction?: string\n formComponent: ComponentViewModel\n componentsBefore: ComponentViewModel[]\n uploadId: string | undefined\n proxyUrl: string | null\n}\n\nexport type PageViewModel =\n | PageViewModelBase\n | ItemDeletePageViewModel\n | FormPageViewModel\n | RepeaterSummaryPageViewModel\n | FeaturedFormPageViewModel\n\nexport type GlobalFunction = (value: unknown) => unknown\nexport type FilterFunction = (value: unknown) => unknown\nexport interface ErrorMessageTemplate {\n type: string\n template: JoiExpression\n}\n\nexport interface ErrorMessageTemplateList {\n baseErrors: ErrorMessageTemplate[]\n advancedSettingsErrors: ErrorMessageTemplate[]\n}\n\nexport type PreparePageEventRequestOptions = (\n options: RequestOptions,\n event: Event,\n page: PageControllerClass,\n context: FormContext\n) => void\n\nexport type OnRequestCallback = (\n request: AnyFormRequest,\n h: FormResponseToolkit,\n context: FormContext\n) =>\n | ResponseObject\n | FormResponseToolkit['continue']\n | Promise<ResponseObject | FormResponseToolkit['continue']>\n\nexport type SaveAndExitHandler = (\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n) => ResponseObject\n\nexport interface ExternalArgs {\n component: ComponentDef\n controller: QuestionPageController\n sourceUrl: string\n actionArgs: Record<string, string>\n}\n\nexport interface PostcodeLookupExternalArgs extends ExternalArgs {\n component: UkAddressFieldComponent\n actionArgs: { step: string }\n}\n\nexport interface ExternalStateAppendage {\n component: string\n data: FormStateValue | FormState\n}\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n cache?: CacheService | string\n globals?: Record<string, GlobalFunction>\n filters?: Record<string, FilterFunction>\n saveAndExit?: SaveAndExitHandler\n pluginPath?: string\n nunjucks: {\n baseLayoutPath: string\n paths: string[]\n }\n viewContext: PluginProperties['forms-engine-plugin']['viewContext']\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n baseUrl: string // base URL of the application, protocol and hostname e.g. \"https://myapp.com\"\n ordnanceSurveyApiKey?: string\n}\n\nexport interface FormAdapterSubmissionMessageMeta {\n schemaVersion: FormAdapterSubmissionSchemaVersion\n timestamp: Date\n referenceNumber: string\n formName: string\n formId: string\n formSlug: string\n status: FormStatus\n isPreview: boolean\n notificationEmail: string\n versionMetadata?: FormVersionMetadata\n custom?: Record<string, unknown>\n}\n\nexport type FormAdapterSubmissionMessageMetaSerialised = Omit<\n FormAdapterSubmissionMessageMeta,\n 'schemaVersion' | 'timestamp' | 'status'\n> & {\n schemaVersion: number\n status: string\n timestamp: string\n}\nexport interface FormAdapterFile {\n fileName: string\n fileId: string\n userDownloadLink: string\n}\n\nexport interface FormAdapterSubmissionMessageResult {\n files: {\n main: string\n repeaters: Record<string, string>\n }\n}\n\n/**\n * A detail item specifically for files\n */\nexport type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {\n field: FileUploadField\n}\nexport type RichFormValue =\n | FormValue\n | FormPayload\n | DatePartsState\n | MonthYearState\n | UkAddressState\n | EastingNorthingState\n | LatLongState\n\nexport interface FormAdapterSubmissionMessageData {\n main: Record<string, RichFormValue | null>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<string, FormAdapterFile[]>\n}\n\nexport interface FormAdapterSubmissionMessagePayload {\n meta: FormAdapterSubmissionMessageMeta\n data: FormAdapterSubmissionMessageData\n result: FormAdapterSubmissionMessageResult\n}\n\nexport interface FormAdapterSubmissionMessage\n extends FormAdapterSubmissionMessagePayload {\n messageId: string\n recordCreatedAt: Date\n}\n\nexport interface FormAdapterSubmissionService {\n handleFormSubmission: (\n submissionMessage: FormAdapterSubmissionMessage\n ) => unknown\n}\n"],"mappings":"AAsDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAmBA;AACA;AACA;AACA;;AAsGA,SACEA,UAAU,EACVC,YAAY;;AAmPd;AACA;AACA","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"types.js","names":["FileStatus","UploadStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Event,\n type FormVersionMetadata,\n type Item,\n type List,\n type Page,\n type UkAddressFieldComponent\n} from '@defra/forms-model'\nimport {\n type PluginProperties,\n type Request,\n type ResponseObject\n} from '@hapi/hapi'\nimport { type JoiExpression, type ValidationErrorItem } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { type FileUploadField } from '~/src/server/plugins/engine/components/index.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel,\n type DatePartsState,\n type EastingNorthingState,\n type LatLongState,\n type MonthYearState\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItemField } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport { type QuestionPageController } from '~/src/server/plugins/engine/pageControllers/index.js'\nimport {\n type FileStatus,\n type FormAdapterSubmissionSchemaVersion,\n type UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport {\n type FormAction,\n type FormRequest,\n type FormRequestPayload,\n type FormResponseToolkit,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\nimport { type RequestOptions } from '~/src/server/services/httpService.js'\nimport { type Services } from '~/src/server/types.js'\n\nexport type AnyFormRequest = FormRequest | FormRequestPayload\nexport type AnyRequest = Request | AnyFormRequest\n\n/**\n * Form submission state stores the following in Redis:\n * Props containing user's submitted values as `{ [inputId]: value }` or as `{ [sectionName]: { [inputName]: value } }`\n * a) . e.g:\n * ```ts\n * {\n * _C9PRHmsgt: 'Ben',\n * WfLk9McjzX: 'Music',\n * IK7jkUFCBL: 'Royal Academy of Music'\n * }\n * ```\n *\n * b)\n * ```ts\n * {\n * checkBeforeYouStart: { ukPassport: true },\n * applicantDetails: {\n * numberOfApplicants: 1,\n * phoneNumber: '77777777',\n * emailAddress: 'aaa@aaa.com'\n * },\n * applicantOneDetails: {\n * firstName: 'a',\n * middleName: 'a',\n * lastName: 'a',\n * address: { addressLine1: 'a', addressLine2: 'a', town: 'a', postcode: 'a' }\n * }\n * }\n * ```\n */\n\n/**\n * Form submission state\n */\nexport type FormSubmissionState = {\n upload?: Record<string, TempFileState>\n} & FormState\n\nexport interface FormSubmissionError\n extends Pick<ValidationErrorItem, 'context' | 'path'> {\n href: string // e.g: '#dateField__day'\n name: string // e.g: 'dateField__day'\n text: string // e.g: 'Date field must be a real date'\n}\n\nexport interface FormConfirmationState {\n confirmed?: true\n formId?: string\n}\n\nexport interface FormPayloadParams {\n action?: FormAction\n confirm?: true\n crumb?: string\n itemId?: string\n}\n\n/**\n * Form POST for question pages\n * (after Joi has converted value types)\n */\nexport type FormPayload = FormPayloadParams & Partial<Record<string, FormValue>>\n\nexport type FormValue =\n | Item['value']\n | Item['value'][]\n | UploadState\n | RepeatListState\n | undefined\n\nexport type FormState = Partial<Record<string, FormStateValue>>\nexport type FormStateValue = Exclude<FormValue, undefined> | null\n\nexport interface FormValidationResult<\n ValueType extends FormPayload | FormSubmissionState\n> {\n value: ValueType\n errors: FormSubmissionError[] | undefined\n}\n\nexport interface FormContext {\n /**\n * Evaluation form state only (filtered by visited paths),\n * with values formatted for condition evaluation using\n * {@link FormComponent.getContextValueFromState}\n */\n evaluationState: FormState\n\n /**\n * Relevant form state only (filtered by visited paths)\n */\n relevantState: FormState\n\n /**\n * Relevant pages only (filtered by visited paths)\n */\n relevantPages: PageControllerClass[]\n\n /**\n * Form submission payload (single page)\n */\n payload: FormPayload\n\n /**\n * Form submission state (entire form)\n */\n state: FormSubmissionState\n\n /**\n * Validation errors (entire form)\n */\n errors?: FormSubmissionError[]\n\n /**\n * Visited paths evaluated from form state\n */\n paths: string[]\n\n /**\n * Preview URL direct access is allowed\n */\n isForceAccess: boolean\n\n /**\n * Miscellaneous extra data from event responses\n */\n data: object\n\n pageDefMap: Map<string, Page>\n listDefMap: Map<string, List>\n componentDefMap: Map<string, ComponentDef>\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n referenceNumber: string\n submittedVersionNumber?: number\n}\n\nexport type FormContextRequest = (\n | {\n method: 'get'\n payload?: undefined\n }\n | {\n method: 'post'\n payload: FormPayload\n }\n | {\n method: FormRequest['method']\n payload?: object | undefined\n }\n) &\n Pick<\n FormRequest,\n 'app' | 'method' | 'params' | 'path' | 'query' | 'url' | 'server'\n >\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport {\n FileStatus,\n UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\n\nexport type UploadState = FileState[]\n\nexport type FileUpload = {\n fileId: string\n filename: string\n contentLength: number\n} & (\n | {\n fileStatus: FileStatus.complete | FileStatus.rejected | FileStatus.pending\n errorMessage?: string\n }\n | {\n fileStatus: FileStatus.complete\n errorMessage?: undefined\n }\n)\n\nexport interface FileUploadMetadata {\n retrievalKey: string\n}\n\nexport type UploadStatusResponse =\n | {\n uploadStatus: UploadStatus.initiated\n metadata: FileUploadMetadata\n form: { file?: undefined }\n }\n | {\n uploadStatus: UploadStatus.pending | UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles?: number\n }\n | {\n uploadStatus: UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles: 0\n }\n\nexport type UploadStatusFileResponse = Exclude<\n UploadStatusResponse,\n { uploadStatus: UploadStatus.initiated }\n>\n\nexport interface FileState {\n uploadId: string\n status: UploadStatusFileResponse\n}\n\nexport interface TempFileState {\n upload?: UploadInitiateResponse\n files: UploadState\n}\n\nexport interface RepeatItemState extends FormPayload {\n itemId: string\n}\n\nexport type RepeatListState = RepeatItemState[]\n\nexport interface CheckAnswers {\n title?: ComponentText\n summaryList: SummaryList\n}\n\nexport interface SummaryList {\n classes?: string\n rows: SummaryListRow[]\n}\n\nexport interface SummaryListRow {\n key: ComponentText\n value: ComponentText\n actions?: { items: SummaryListAction[] }\n}\n\nexport type SummaryListAction = ComponentText & {\n href: string\n visuallyHiddenText: string\n}\n\nexport interface PageViewModelBase extends Partial<ViewContext> {\n page: PageController\n name?: string\n pageTitle: string\n sectionTitle?: string\n showTitle: boolean\n isStartPage: boolean\n backLink?: BackLink\n feedbackLink?: string\n serviceUrl: string\n phaseTag?: string\n}\n\nexport interface ItemDeletePageViewModel extends PageViewModelBase {\n context: FormContext\n itemTitle: string\n confirmation?: ComponentText\n buttonConfirm: ComponentText\n buttonCancel: ComponentText\n}\n\nexport interface FormPageViewModel extends PageViewModelBase {\n components: ComponentViewModel[]\n context: FormContext\n errors?: FormSubmissionError[]\n hasMissingNotificationEmail?: boolean\n allowSaveAndExit: boolean\n}\n\nexport interface RepeaterSummaryPageViewModel extends PageViewModelBase {\n context: FormContext\n errors?: FormSubmissionError[]\n checkAnswers: CheckAnswers[]\n repeatTitle: string\n allowSaveAndExit: boolean\n}\n\nexport interface FeaturedFormPageViewModel extends FormPageViewModel {\n formAction?: string\n formComponent: ComponentViewModel\n componentsBefore: ComponentViewModel[]\n uploadId: string | undefined\n proxyUrl: string | null\n}\n\nexport type PageViewModel =\n | PageViewModelBase\n | ItemDeletePageViewModel\n | FormPageViewModel\n | RepeaterSummaryPageViewModel\n | FeaturedFormPageViewModel\n\nexport type GlobalFunction = (value: unknown) => unknown\nexport type FilterFunction = (value: unknown) => unknown\nexport interface ErrorMessageTemplate {\n type: string\n template: JoiExpression\n}\n\nexport interface ErrorMessageTemplateList {\n baseErrors: ErrorMessageTemplate[]\n advancedSettingsErrors: ErrorMessageTemplate[]\n}\n\nexport type PreparePageEventRequestOptions = (\n options: RequestOptions,\n event: Event,\n page: PageControllerClass,\n context: FormContext\n) => void\n\nexport type OnRequestCallback = (\n request: AnyFormRequest,\n h: FormResponseToolkit,\n context: FormContext\n) =>\n | ResponseObject\n | FormResponseToolkit['continue']\n | Promise<ResponseObject | FormResponseToolkit['continue']>\n\nexport type SaveAndExitHandler = (\n request: FormRequestPayload,\n h: FormResponseToolkit,\n context: FormContext\n) => ResponseObject\n\nexport interface ExternalArgs {\n component: ComponentDef\n controller: QuestionPageController\n sourceUrl: string\n actionArgs: Record<string, string>\n}\n\nexport interface PostcodeLookupExternalArgs extends ExternalArgs {\n component: UkAddressFieldComponent\n actionArgs: { step: string }\n}\n\nexport interface ExternalStateAppendage {\n component: string\n data: FormStateValue | FormState\n}\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n cache?: CacheService | string\n globals?: Record<string, GlobalFunction>\n filters?: Record<string, FilterFunction>\n saveAndExit?: SaveAndExitHandler\n pluginPath?: string\n nunjucks: {\n baseLayoutPath: string\n paths: string[]\n }\n viewContext: PluginProperties['forms-engine-plugin']['viewContext']\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n baseUrl: string // base URL of the application, protocol and hostname e.g. \"https://myapp.com\"\n ordnanceSurveyApiKey?: string\n}\n\nexport interface FormAdapterSubmissionMessageMeta {\n schemaVersion: FormAdapterSubmissionSchemaVersion\n timestamp: Date\n referenceNumber: string\n formName: string\n formId: string\n formSlug: string\n status: FormStatus\n isPreview: boolean\n notificationEmail: string\n versionMetadata?: FormVersionMetadata\n custom?: Record<string, unknown>\n}\n\nexport type FormAdapterSubmissionMessageMetaSerialised = Omit<\n FormAdapterSubmissionMessageMeta,\n 'schemaVersion' | 'timestamp' | 'status'\n> & {\n schemaVersion: number\n status: string\n timestamp: string\n}\nexport interface FormAdapterFile {\n fileName: string\n fileId: string\n userDownloadLink: string\n}\n\nexport interface FormAdapterSubmissionMessageResult {\n files: {\n main: string\n repeaters: Record<string, string>\n }\n}\n\n/**\n * A detail item specifically for files\n */\nexport type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {\n field: FileUploadField\n}\nexport type RichFormValue =\n | FormValue\n | FormPayload\n | DatePartsState\n | MonthYearState\n | UkAddressState\n | EastingNorthingState\n | LatLongState\n\nexport interface FormAdapterSubmissionMessageData {\n main: Record<string, RichFormValue | null>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<string, FormAdapterFile[]>\n}\n\nexport interface FormAdapterSubmissionMessagePayload {\n meta: FormAdapterSubmissionMessageMeta\n data: FormAdapterSubmissionMessageData\n result: FormAdapterSubmissionMessageResult\n}\n\nexport interface FormAdapterSubmissionMessage\n extends FormAdapterSubmissionMessagePayload {\n messageId: string\n recordCreatedAt: Date\n}\n\nexport interface FormAdapterSubmissionService {\n handleFormSubmission: (\n submissionMessage: FormAdapterSubmissionMessage\n ) => unknown\n}\n"],"mappings":"AAsDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAwBA;AACA;AACA;AACA;;AAsGA,SACEA,UAAU,EACVC,YAAY;;AAmPd;AACA;AACA","ignoreList":[]}
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
<div class="app-prose-scope">
|
|
15
15
|
{{ submissionGuidance | markdown(3) | safe }}
|
|
16
16
|
</div>
|
|
17
|
+
{% if feedbackLink %}
|
|
18
|
+
<p class="govuk-body">
|
|
19
|
+
<a href="{{ feedbackLink }}" class="govuk-link govuk-link--no-visited-state">What do you think of this service?</a> (takes 30 seconds)
|
|
20
|
+
</p>
|
|
21
|
+
{% endif %}
|
|
17
22
|
</div>
|
|
18
23
|
</div>
|
|
19
24
|
{% endblock %}
|
|
@@ -6,9 +6,17 @@
|
|
|
6
6
|
|
|
7
7
|
{{ componentList(components) }}
|
|
8
8
|
|
|
9
|
+
{% if isStartPage %}
|
|
10
|
+
{% set buttonText = "Start now" %}
|
|
11
|
+
{% elif submitButtonText %}
|
|
12
|
+
{% set buttonText = submitButtonText %}
|
|
13
|
+
{% else %}
|
|
14
|
+
{% set buttonText = "Continue" %}
|
|
15
|
+
{% endif %}
|
|
16
|
+
|
|
9
17
|
<div class="govuk-button-group">
|
|
10
18
|
{{ govukButton({
|
|
11
|
-
text:
|
|
19
|
+
text: buttonText,
|
|
12
20
|
isStartButton: isStartPage,
|
|
13
21
|
preventDoubleClick: true
|
|
14
22
|
}) }}
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* @this {NunjucksContext}
|
|
4
4
|
* @param {string} name - The name of the component
|
|
5
5
|
*/
|
|
6
|
-
export function field(this: NunjucksContext, name: string): import("../../engine/components/TextField.js").TextField | import("../../engine/components/SelectField.js").SelectField | import("../../engine/components/RadiosField.js").RadiosField | import("../../engine/components/YesNoField.js").YesNoField | import("../../engine/components/CheckboxesField.js").CheckboxesField | import("../../engine/components/DatePartsField.js").DatePartsField | import("../../engine/components/DeclarationField.js").DeclarationField | import("../../engine/components/EastingNorthingField.js").EastingNorthingField | import("../../engine/components/EmailAddressField.js").EmailAddressField | import("../../engine/components/LatLongField.js").LatLongField | import("../../engine/components/MonthYearField.js").MonthYearField | import("../../engine/components/MultilineTextField.js").MultilineTextField | import("../../engine/components/NationalGridFieldNumberField.js").NationalGridFieldNumberField | import("../../engine/components/NumberField.js").NumberField | import("../../engine/components/OsGridRefField.js").OsGridRefField | import("../../engine/components/TelephoneNumberField.js").TelephoneNumberField | import("../../engine/components/UkAddressField.js").UkAddressField | import("../../engine/components/FileUploadField.js").FileUploadField | import("../../engine/components/Details.js").Details | import("../../engine/components/Html.js").Html | import("../../engine/components/InsetText.js").InsetText | import("../../engine/components/List.js").List | import("../../engine/components/Markdown.js").Markdown | undefined;
|
|
6
|
+
export function field(this: NunjucksContext, name: string): import("../../engine/components/TextField.js").TextField | import("../../engine/components/SelectField.js").SelectField | import("../../engine/components/RadiosField.js").RadiosField | import("../../engine/components/YesNoField.js").YesNoField | import("../../engine/components/CheckboxesField.js").CheckboxesField | import("../../engine/components/DatePartsField.js").DatePartsField | import("../../engine/components/DeclarationField.js").DeclarationField | import("../../engine/components/EastingNorthingField.js").EastingNorthingField | import("../../engine/components/EmailAddressField.js").EmailAddressField | import("../../engine/components/LatLongField.js").LatLongField | import("../../engine/components/MonthYearField.js").MonthYearField | import("../../engine/components/MultilineTextField.js").MultilineTextField | import("../../engine/components/NationalGridFieldNumberField.js").NationalGridFieldNumberField | import("../../engine/components/NumberField.js").NumberField | import("../../engine/components/OsGridRefField.js").OsGridRefField | import("../../engine/components/TelephoneNumberField.js").TelephoneNumberField | import("../../engine/components/UkAddressField.js").UkAddressField | import("../../engine/components/FileUploadField.js").FileUploadField | import("../../engine/components/HiddenField.js").HiddenField | import("../../engine/components/Details.js").Details | import("../../engine/components/Html.js").Html | import("../../engine/components/InsetText.js").InsetText | import("../../engine/components/List.js").List | import("../../engine/components/Markdown.js").Markdown | undefined;
|
|
7
7
|
import type { NunjucksContext } from '~/src/server/plugins/nunjucks/types.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Server } from '@hapi/hapi';
|
|
2
|
-
import { type AnyFormRequest, type AnyRequest, type FormPayload, type FormState, type FormSubmissionError, type FormSubmissionState } from '~/src/server/plugins/engine/types.js';
|
|
2
|
+
import { type AnyFormRequest, type AnyRequest, type FormConfirmationState, type FormPayload, type FormState, type FormSubmissionError, type FormSubmissionState } from '~/src/server/plugins/engine/types.js';
|
|
3
3
|
export declare enum ADDITIONAL_IDENTIFIER {
|
|
4
4
|
Confirmation = ":confirmation"
|
|
5
5
|
}
|
|
@@ -18,12 +18,8 @@ export declare class CacheService {
|
|
|
18
18
|
});
|
|
19
19
|
getState(request: AnyRequest): Promise<FormSubmissionState>;
|
|
20
20
|
setState(request: AnyFormRequest, state: FormSubmissionState): Promise<FormSubmissionState>;
|
|
21
|
-
getConfirmationState(request: AnyFormRequest): Promise<
|
|
22
|
-
|
|
23
|
-
}>;
|
|
24
|
-
setConfirmationState(request: AnyFormRequest, confirmationState: {
|
|
25
|
-
confirmed?: true;
|
|
26
|
-
}): Promise<void>;
|
|
21
|
+
getConfirmationState(request: AnyFormRequest): Promise<FormConfirmationState>;
|
|
22
|
+
setConfirmationState(request: AnyFormRequest, confirmationState: FormConfirmationState): Promise<void>;
|
|
27
23
|
clearState(request: AnyFormRequest): Promise<void>;
|
|
28
24
|
getFlash(request: AnyFormRequest): {
|
|
29
25
|
errors: FormSubmissionError[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cacheService.js","names":["Hoek","config","partition","ADDITIONAL_IDENTIFIER","CacheService","cache","logger","constructor","server","cacheName","log","segment","getState","request","key","Key","cached","get","setState","state","ttl","set","getConfirmationState","Confirmation","value","setConfirmationState","confirmationState","clearState","yar","id","drop","getFlash","messages","flash","Array","isArray","length","at","setFlash","message","additionalIdentifier","Error","params","slug","merge","update","mergeArrays"],"sources":["../../../src/server/services/cacheService.ts"],"sourcesContent":["import { type Server } from '@hapi/hapi'\nimport * as Hoek from '@hapi/hoek'\n\nimport { config } from '~/src/config/index.js'\nimport { type createServer } from '~/src/server/index.js'\nimport {\n type AnyFormRequest,\n type AnyRequest,\n type FormPayload,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\n\nconst partition = 'cache'\n\nexport enum ADDITIONAL_IDENTIFIER {\n Confirmation = ':confirmation'\n}\n\nexport class CacheService {\n /**\n * This service is responsible for getting, storing or deleting a user's session data in the cache. This service has been registered by {@link createServer}\n */\n cache\n logger: Server['logger']\n\n constructor({ server, cacheName }: { server: Server; cacheName?: string }) {\n if (!cacheName) {\n server.log(\n 'warn',\n 'You are using the default hapi cache. Please provide a cache name in plugin registration options.'\n )\n }\n\n this.cache = server.cache({ cache: cacheName, segment: 'formSubmission' })\n this.logger = server.logger\n }\n\n async getState(request: AnyRequest): Promise<FormSubmissionState> {\n const key = this.Key(request)\n const cached = await this.cache.get(key)\n\n return cached ?? {}\n }\n\n async setState(request: AnyFormRequest, state: FormSubmissionState) {\n const key = this.Key(request)\n const ttl = config.get('sessionTimeout')\n\n await this.cache.set(key, state, ttl)\n\n return this.getState(request)\n }\n\n async getConfirmationState(\n request: AnyFormRequest\n ): Promise<
|
|
1
|
+
{"version":3,"file":"cacheService.js","names":["Hoek","config","partition","ADDITIONAL_IDENTIFIER","CacheService","cache","logger","constructor","server","cacheName","log","segment","getState","request","key","Key","cached","get","setState","state","ttl","set","getConfirmationState","Confirmation","value","setConfirmationState","confirmationState","clearState","yar","id","drop","getFlash","messages","flash","Array","isArray","length","at","setFlash","message","additionalIdentifier","Error","params","slug","merge","update","mergeArrays"],"sources":["../../../src/server/services/cacheService.ts"],"sourcesContent":["import { type Server } from '@hapi/hapi'\nimport * as Hoek from '@hapi/hoek'\n\nimport { config } from '~/src/config/index.js'\nimport { type createServer } from '~/src/server/index.js'\nimport {\n type AnyFormRequest,\n type AnyRequest,\n type FormConfirmationState,\n type FormPayload,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\n\nconst partition = 'cache'\n\nexport enum ADDITIONAL_IDENTIFIER {\n Confirmation = ':confirmation'\n}\n\nexport class CacheService {\n /**\n * This service is responsible for getting, storing or deleting a user's session data in the cache. This service has been registered by {@link createServer}\n */\n cache\n logger: Server['logger']\n\n constructor({ server, cacheName }: { server: Server; cacheName?: string }) {\n if (!cacheName) {\n server.log(\n 'warn',\n 'You are using the default hapi cache. Please provide a cache name in plugin registration options.'\n )\n }\n\n this.cache = server.cache({ cache: cacheName, segment: 'formSubmission' })\n this.logger = server.logger\n }\n\n async getState(request: AnyRequest): Promise<FormSubmissionState> {\n const key = this.Key(request)\n const cached = await this.cache.get(key)\n\n return cached ?? {}\n }\n\n async setState(request: AnyFormRequest, state: FormSubmissionState) {\n const key = this.Key(request)\n const ttl = config.get('sessionTimeout')\n\n await this.cache.set(key, state, ttl)\n\n return this.getState(request)\n }\n\n async getConfirmationState(\n request: AnyFormRequest\n ): Promise<FormConfirmationState> {\n const key = this.Key(request, ADDITIONAL_IDENTIFIER.Confirmation)\n const value = await this.cache.get(key)\n\n return value ?? {}\n }\n\n async setConfirmationState(\n request: AnyFormRequest,\n confirmationState: FormConfirmationState\n ) {\n const key = this.Key(request, ADDITIONAL_IDENTIFIER.Confirmation)\n const ttl = config.get('confirmationSessionTimeout')\n\n return this.cache.set(key, confirmationState, ttl)\n }\n\n async clearState(request: AnyFormRequest) {\n if (request.yar.id) {\n await this.cache.drop(this.Key(request))\n }\n }\n\n getFlash(\n request: AnyFormRequest\n ): { errors: FormSubmissionError[] } | undefined {\n const key = this.Key(request)\n const messages = request.yar.flash(key.id)\n\n if (Array.isArray(messages) && messages.length) {\n return messages.at(0)\n }\n }\n\n setFlash(\n request: AnyFormRequest,\n message: { errors: FormSubmissionError[] }\n ) {\n const key = this.Key(request)\n\n request.yar.flash(key.id, message)\n }\n\n /**\n * The key used to store user session data against.\n * If there are multiple forms on the same runner instance, for example `form-a` and `form-a-feedback` this will prevent CacheService from clearing data from `form-a` if a user gave feedback before they finished `form-a`\n * @param request - hapi request object\n * @param additionalIdentifier - appended to the id\n */\n Key(request: AnyRequest, additionalIdentifier?: ADDITIONAL_IDENTIFIER) {\n if (!request.yar.id) {\n throw new Error('No session ID found')\n }\n\n const state = (request.params.state as string) || ''\n const slug = (request.params.slug as string) || ''\n const key = `${request.yar.id}:${state}:${slug}:`\n\n return {\n segment: partition,\n id: `${key}${additionalIdentifier ?? ''}`\n }\n }\n}\n\n/**\n * State merge helper\n * 1. Merges objects (form fields)\n * 2. Overwrites arrays\n */\nexport function merge<StateType extends FormState | FormPayload>(\n state: StateType,\n update: object\n): StateType {\n return Hoek.merge(state, update, {\n mergeArrays: false\n })\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -8,6 +8,7 @@ import { type FormRequestPayload, type FormStatus } from '~/src/server/routes/ty
|
|
|
8
8
|
import { type CacheService } from '~/src/server/services/cacheService.js';
|
|
9
9
|
export interface FormsService {
|
|
10
10
|
getFormMetadata: (slug: string) => Promise<FormMetadata>;
|
|
11
|
+
getFormMetadataById: (id: string) => Promise<FormMetadata>;
|
|
11
12
|
getFormDefinition: (id: string, state: FormStatus) => Promise<FormDefinition | undefined>;
|
|
12
13
|
}
|
|
13
14
|
export interface FormSubmissionService {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../src/server/types.ts"],"sourcesContent":["import {\n type FormDefinition,\n type FormMetadata,\n type SubmitPayload,\n type SubmitResponsePayload\n} from '@defra/forms-model'\nimport { type Server } from '@hapi/hapi'\n\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport {\n type FormContext,\n type OnRequestCallback,\n type PluginOptions,\n type PreparePageEventRequestOptions\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequestPayload,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\n\nexport interface FormsService {\n getFormMetadata: (slug: string) => Promise<FormMetadata>\n getFormDefinition: (\n id: string,\n state: FormStatus\n ) => Promise<FormDefinition | undefined>\n}\n\nexport interface FormSubmissionService {\n persistFiles: (\n files: { fileId: string; initiatedRetrievalKey: string }[],\n persistedRetrievalKey: string\n ) => Promise<object>\n submit: (data: SubmitPayload) => Promise<SubmitResponsePayload | undefined>\n}\n\nexport interface Services {\n formsService: FormsService\n formSubmissionService: FormSubmissionService\n outputService: OutputService\n}\n\nexport interface RouteConfig {\n formFileName?: string\n formFilePath?: string\n enforceCsrf?: boolean\n services?: Services\n controllers?: Record<string, typeof PageController>\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n saveAndExit?: PluginOptions['saveAndExit']\n cacheServiceCreator?: (server: Server) => CacheService\n ordnanceSurveyApiKey?: string\n}\n\nexport interface OutputService {\n submit: (\n context: FormContext,\n request: FormRequestPayload,\n model: FormModel,\n emailAddress: string,\n items: DetailItem[],\n submitResponse: SubmitResponsePayload,\n formMetadata?: FormMetadata\n ) => Promise<void>\n}\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/server/types.ts"],"sourcesContent":["import {\n type FormDefinition,\n type FormMetadata,\n type SubmitPayload,\n type SubmitResponsePayload\n} from '@defra/forms-model'\nimport { type Server } from '@hapi/hapi'\n\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport {\n type FormContext,\n type OnRequestCallback,\n type PluginOptions,\n type PreparePageEventRequestOptions\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequestPayload,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/cacheService.js'\n\nexport interface FormsService {\n getFormMetadata: (slug: string) => Promise<FormMetadata>\n getFormMetadataById: (id: string) => Promise<FormMetadata>\n getFormDefinition: (\n id: string,\n state: FormStatus\n ) => Promise<FormDefinition | undefined>\n}\n\nexport interface FormSubmissionService {\n persistFiles: (\n files: { fileId: string; initiatedRetrievalKey: string }[],\n persistedRetrievalKey: string\n ) => Promise<object>\n submit: (data: SubmitPayload) => Promise<SubmitResponsePayload | undefined>\n}\n\nexport interface Services {\n formsService: FormsService\n formSubmissionService: FormSubmissionService\n outputService: OutputService\n}\n\nexport interface RouteConfig {\n formFileName?: string\n formFilePath?: string\n enforceCsrf?: boolean\n services?: Services\n controllers?: Record<string, typeof PageController>\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n saveAndExit?: PluginOptions['saveAndExit']\n cacheServiceCreator?: (server: Server) => CacheService\n ordnanceSurveyApiKey?: string\n}\n\nexport interface OutputService {\n submit: (\n context: FormContext,\n request: FormRequestPayload,\n model: FormModel,\n emailAddress: string,\n items: DetailItem[],\n submitResponse: SubmitResponsePayload,\n formMetadata?: FormMetadata\n ) => Promise<void>\n}\n"],"mappings":"","ignoreList":[]}
|
|
@@ -33,6 +33,12 @@ export class FileFormService {
|
|
|
33
33
|
* @returns {FormMetadata}
|
|
34
34
|
*/
|
|
35
35
|
getFormMetadata(slug: string): FormMetadata;
|
|
36
|
+
/**
|
|
37
|
+
* Get the form metadata by form id
|
|
38
|
+
* @param {string} id - the form id
|
|
39
|
+
* @returns {FormMetadata}
|
|
40
|
+
*/
|
|
41
|
+
getFormMetadataById(id: string): FormMetadata;
|
|
36
42
|
/**
|
|
37
43
|
* Get the form defintion by id
|
|
38
44
|
* @param {string} id - the form id
|
|
@@ -89,6 +89,19 @@ export class FileFormService {
|
|
|
89
89
|
return metadata;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Get the form metadata by form id
|
|
94
|
+
* @param {string} id - the form id
|
|
95
|
+
* @returns {FormMetadata}
|
|
96
|
+
*/
|
|
97
|
+
getFormMetadataById(id) {
|
|
98
|
+
const metadata = Array.from(this.#metadata.values()).find(form => form.id === id);
|
|
99
|
+
if (!metadata) {
|
|
100
|
+
throw new Error(`Form metadata id '${id}' not found`);
|
|
101
|
+
}
|
|
102
|
+
return metadata;
|
|
103
|
+
}
|
|
104
|
+
|
|
92
105
|
/**
|
|
93
106
|
* Get the form defintion by id
|
|
94
107
|
* @param {string} id - the form id
|
|
@@ -116,6 +129,14 @@ export class FileFormService {
|
|
|
116
129
|
getFormMetadata: slug => {
|
|
117
130
|
return Promise.resolve(this.getFormMetadata(slug));
|
|
118
131
|
},
|
|
132
|
+
/**
|
|
133
|
+
* Get the form metadata by form id
|
|
134
|
+
* @param {string} id
|
|
135
|
+
* @returns {Promise<FormMetadata>}
|
|
136
|
+
*/
|
|
137
|
+
getFormMetadataById: id => {
|
|
138
|
+
return Promise.resolve(this.getFormMetadataById(id));
|
|
139
|
+
},
|
|
119
140
|
/**
|
|
120
141
|
* Get the form defintion by id
|
|
121
142
|
* @param {string} id
|
|
@@ -129,6 +150,6 @@ export class FileFormService {
|
|
|
129
150
|
}
|
|
130
151
|
|
|
131
152
|
/**
|
|
132
|
-
* @import { FormMetadata, FormDefinition } from '@defra/forms-model'
|
|
153
|
+
* @import { FormMetadata, FormDefinition, FormStatus } from '@defra/forms-model'
|
|
133
154
|
*/
|
|
134
155
|
//# sourceMappingURL=file-form-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-form-service.js","names":["fs","path","YAML","FileFormService","metadata","Map","definition","addForm","filepath","readForm","set","slug","id","ext","extname","toLowerCase","readJsonForm","readYamlForm","Error","JSON","parse","readFile","getFormMetadata","get","getFormDefinition","toFormsService","Promise","resolve"],"sources":["../../../src/server/utils/file-form-service.js"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'node:path'\n\nimport YAML from 'yaml'\n\n/**\n * FileFormService class\n */\nexport class FileFormService {\n /**\n * The map of form metadatas by slug\n * @type {Map<string, FormMetadata>}\n */\n #metadata = new Map()\n\n /**\n * The map of form definitions by id\n * @type {Map<string, FormDefinition>}\n */\n #definition = new Map()\n\n /**\n * Add form from a file\n * @param {string} filepath - the file path\n * @param {FormMetadata} metadata - the metadata to use for this form\n * @returns {Promise<FormDefinition>}\n */\n async addForm(filepath, metadata) {\n const definition = await this.readForm(filepath)\n\n this.#metadata.set(metadata.slug, metadata)\n this.#definition.set(metadata.id, definition)\n\n return definition\n }\n\n /**\n * Read the form definition from file\n * @param {string} filepath - the file path\n * @returns {Promise<FormDefinition>}\n */\n async readForm(filepath) {\n const ext = path.extname(filepath).toLowerCase()\n\n switch (ext) {\n case '.json':\n return this.readJsonForm(filepath)\n case '.yaml':\n return this.readYamlForm(filepath)\n default:\n throw new Error(`Invalid file extension '${ext}'`)\n }\n }\n\n /**\n * Read the form definition from a json file\n * @param {string} filepath - the file path\n * @returns {Promise<FormDefinition>}\n */\n async readJsonForm(filepath) {\n /**\n * @type {FormDefinition}\n */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const definition = JSON.parse(await fs.readFile(filepath, 'utf8'))\n\n return definition\n }\n\n /**\n * Read the form definition from a yaml file\n * @param {string} filepath - the file path\n * @returns {Promise<FormDefinition>}\n */\n async readYamlForm(filepath) {\n /**\n * @type {FormDefinition}\n */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const definition = YAML.parse(await fs.readFile(filepath, 'utf8'))\n\n return definition\n }\n\n /**\n * Get the form metadata by slug\n * @param {string} slug - the form slug\n * @returns {FormMetadata}\n */\n getFormMetadata(slug) {\n const metadata = this.#metadata.get(slug)\n\n if (!metadata) {\n throw new Error(`Form metadata '${slug}' not found`)\n }\n\n return metadata\n }\n\n /**\n * Get the form defintion by id\n * @param {string} id - the form id\n * @returns {FormDefinition}\n */\n getFormDefinition(id) {\n const definition = this.#definition.get(id)\n\n if (!definition) {\n throw new Error(`Form definition '${id}' not found`)\n }\n\n return definition\n }\n\n /**\n * Returns a FormsService compliant interface\n * @returns {import('~/src/server/types.js').FormsService}\n */\n toFormsService() {\n return {\n /**\n * Get the form metadata by slug\n * @param {string} slug\n * @returns {Promise<FormMetadata>}\n */\n getFormMetadata: (slug) => {\n return Promise.resolve(this.getFormMetadata(slug))\n },\n\n /**\n * Get the form defintion by id\n * @param {string} id\n * @returns {Promise<FormDefinition>}\n */\n getFormDefinition: (id) => {\n return Promise.resolve(this.getFormDefinition(id))\n }\n }\n }\n}\n\n/**\n * @import { FormMetadata, FormDefinition } from '@defra/forms-model'\n */\n"],"mappings":"AAAA,OAAOA,EAAE,MAAM,aAAa;AAC5B,OAAOC,IAAI,MAAM,WAAW;AAE5B,OAAOC,IAAI,MAAM,MAAM;;AAEvB;AACA;AACA;AACA,OAAO,MAAMC,eAAe,CAAC;EAC3B;AACF;AACA;AACA;EACE,CAACC,QAAQ,GAAG,IAAIC,GAAG,CAAC,CAAC;;EAErB;AACF;AACA;AACA;EACE,CAACC,UAAU,GAAG,IAAID,GAAG,CAAC,CAAC;;EAEvB;AACF;AACA;AACA;AACA;AACA;EACE,MAAME,OAAOA,CAACC,QAAQ,EAAEJ,QAAQ,EAAE;IAChC,MAAME,UAAU,GAAG,MAAM,IAAI,CAACG,QAAQ,CAACD,QAAQ,CAAC;IAEhD,IAAI,CAAC,CAACJ,QAAQ,CAACM,GAAG,CAACN,QAAQ,CAACO,IAAI,EAAEP,QAAQ,CAAC;IAC3C,IAAI,CAAC,CAACE,UAAU,CAACI,GAAG,CAACN,QAAQ,CAACQ,EAAE,EAAEN,UAAU,CAAC;IAE7C,OAAOA,UAAU;EACnB;;EAEA;AACF;AACA;AACA;AACA;EACE,MAAMG,QAAQA,CAACD,QAAQ,EAAE;IACvB,MAAMK,GAAG,GAAGZ,IAAI,CAACa,OAAO,CAACN,QAAQ,CAAC,CAACO,WAAW,CAAC,CAAC;IAEhD,QAAQF,GAAG;MACT,KAAK,OAAO;QACV,OAAO,IAAI,CAACG,YAAY,CAACR,QAAQ,CAAC;MACpC,KAAK,OAAO;QACV,OAAO,IAAI,CAACS,YAAY,CAACT,QAAQ,CAAC;MACpC;QACE,MAAM,IAAIU,KAAK,CAAC,2BAA2BL,GAAG,GAAG,CAAC;IACtD;EACF;;EAEA;AACF;AACA;AACA;AACA;EACE,MAAMG,YAAYA,CAACR,QAAQ,EAAE;IAC3B;AACJ;AACA;IACI;IACA,MAAMF,UAAU,GAAGa,IAAI,CAACC,KAAK,CAAC,MAAMpB,EAAE,CAACqB,QAAQ,CAACb,QAAQ,EAAE,MAAM,CAAC,CAAC;IAElE,OAAOF,UAAU;EACnB;;EAEA;AACF;AACA;AACA;AACA;EACE,MAAMW,YAAYA,CAACT,QAAQ,EAAE;IAC3B;AACJ;AACA;IACI;IACA,MAAMF,UAAU,GAAGJ,IAAI,CAACkB,KAAK,CAAC,MAAMpB,EAAE,CAACqB,QAAQ,CAACb,QAAQ,EAAE,MAAM,CAAC,CAAC;IAElE,OAAOF,UAAU;EACnB;;EAEA;AACF;AACA;AACA;AACA;EACEgB,eAAeA,CAACX,IAAI,EAAE;IACpB,MAAMP,QAAQ,GAAG,IAAI,CAAC,CAACA,QAAQ,CAACmB,GAAG,CAACZ,IAAI,CAAC;IAEzC,IAAI,CAACP,QAAQ,EAAE;MACb,MAAM,IAAIc,KAAK,CAAC,kBAAkBP,IAAI,aAAa,CAAC;IACtD;IAEA,OAAOP,QAAQ;EACjB;;EAEA;AACF;AACA;AACA;AACA;EACEoB,
|
|
1
|
+
{"version":3,"file":"file-form-service.js","names":["fs","path","YAML","FileFormService","metadata","Map","definition","addForm","filepath","readForm","set","slug","id","ext","extname","toLowerCase","readJsonForm","readYamlForm","Error","JSON","parse","readFile","getFormMetadata","get","getFormMetadataById","Array","from","values","find","form","getFormDefinition","toFormsService","Promise","resolve"],"sources":["../../../src/server/utils/file-form-service.js"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'node:path'\n\nimport YAML from 'yaml'\n\n/**\n * FileFormService class\n */\nexport class FileFormService {\n /**\n * The map of form metadatas by slug\n * @type {Map<string, FormMetadata>}\n */\n #metadata = new Map()\n\n /**\n * The map of form definitions by id\n * @type {Map<string, FormDefinition>}\n */\n #definition = new Map()\n\n /**\n * Add form from a file\n * @param {string} filepath - the file path\n * @param {FormMetadata} metadata - the metadata to use for this form\n * @returns {Promise<FormDefinition>}\n */\n async addForm(filepath, metadata) {\n const definition = await this.readForm(filepath)\n\n this.#metadata.set(metadata.slug, metadata)\n this.#definition.set(metadata.id, definition)\n\n return definition\n }\n\n /**\n * Read the form definition from file\n * @param {string} filepath - the file path\n * @returns {Promise<FormDefinition>}\n */\n async readForm(filepath) {\n const ext = path.extname(filepath).toLowerCase()\n\n switch (ext) {\n case '.json':\n return this.readJsonForm(filepath)\n case '.yaml':\n return this.readYamlForm(filepath)\n default:\n throw new Error(`Invalid file extension '${ext}'`)\n }\n }\n\n /**\n * Read the form definition from a json file\n * @param {string} filepath - the file path\n * @returns {Promise<FormDefinition>}\n */\n async readJsonForm(filepath) {\n /**\n * @type {FormDefinition}\n */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const definition = JSON.parse(await fs.readFile(filepath, 'utf8'))\n\n return definition\n }\n\n /**\n * Read the form definition from a yaml file\n * @param {string} filepath - the file path\n * @returns {Promise<FormDefinition>}\n */\n async readYamlForm(filepath) {\n /**\n * @type {FormDefinition}\n */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const definition = YAML.parse(await fs.readFile(filepath, 'utf8'))\n\n return definition\n }\n\n /**\n * Get the form metadata by slug\n * @param {string} slug - the form slug\n * @returns {FormMetadata}\n */\n getFormMetadata(slug) {\n const metadata = this.#metadata.get(slug)\n\n if (!metadata) {\n throw new Error(`Form metadata '${slug}' not found`)\n }\n\n return metadata\n }\n\n /**\n * Get the form metadata by form id\n * @param {string} id - the form id\n * @returns {FormMetadata}\n */\n getFormMetadataById(id) {\n const metadata = Array.from(this.#metadata.values()).find(\n (form) => form.id === id\n )\n\n if (!metadata) {\n throw new Error(`Form metadata id '${id}' not found`)\n }\n\n return metadata\n }\n\n /**\n * Get the form defintion by id\n * @param {string} id - the form id\n * @returns {FormDefinition}\n */\n getFormDefinition(id) {\n const definition = this.#definition.get(id)\n\n if (!definition) {\n throw new Error(`Form definition '${id}' not found`)\n }\n\n return definition\n }\n\n /**\n * Returns a FormsService compliant interface\n * @returns {import('~/src/server/types.js').FormsService}\n */\n toFormsService() {\n return {\n /**\n * Get the form metadata by slug\n * @param {string} slug\n * @returns {Promise<FormMetadata>}\n */\n getFormMetadata: (slug) => {\n return Promise.resolve(this.getFormMetadata(slug))\n },\n\n /**\n * Get the form metadata by form id\n * @param {string} id\n * @returns {Promise<FormMetadata>}\n */\n getFormMetadataById: (id) => {\n return Promise.resolve(this.getFormMetadataById(id))\n },\n\n /**\n * Get the form defintion by id\n * @param {string} id\n * @returns {Promise<FormDefinition>}\n */\n getFormDefinition: (id) => {\n return Promise.resolve(this.getFormDefinition(id))\n }\n }\n }\n}\n\n/**\n * @import { FormMetadata, FormDefinition, FormStatus } from '@defra/forms-model'\n */\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { FormStatus } from "../routes/types.js";
|
|
3
|
+
import { FileFormService } from "./file-form-service.js";
|
|
4
|
+
describe('File-form-service', () => {
|
|
5
|
+
/** @type {FileFormService} */
|
|
6
|
+
let service;
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
const now = new Date();
|
|
9
|
+
const user = {
|
|
10
|
+
id: 'user',
|
|
11
|
+
displayName: 'Username'
|
|
12
|
+
};
|
|
13
|
+
const author = {
|
|
14
|
+
createdAt: now,
|
|
15
|
+
createdBy: user,
|
|
16
|
+
updatedAt: now,
|
|
17
|
+
updatedBy: user
|
|
18
|
+
};
|
|
19
|
+
service = new FileFormService();
|
|
20
|
+
const metadata = {
|
|
21
|
+
organisation: 'Defra',
|
|
22
|
+
teamName: 'Team name',
|
|
23
|
+
teamEmail: 'team@defra.gov.uk',
|
|
24
|
+
submissionGuidance: "Thanks for your submission, we'll be in touch",
|
|
25
|
+
notificationEmail: 'email@domain.com',
|
|
26
|
+
...author,
|
|
27
|
+
live: author
|
|
28
|
+
};
|
|
29
|
+
await service.addForm(`${join(import.meta.dirname, '../../../test/form/definitions')}/components.json`, {
|
|
30
|
+
...metadata,
|
|
31
|
+
id: '95e92559-968d-44ae-8666-2b1ad3dffd31',
|
|
32
|
+
title: 'Form test',
|
|
33
|
+
slug: 'form-test'
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe('metadata by slug', () => {
|
|
37
|
+
it('should get form metadata by slug', () => {
|
|
38
|
+
const meta = service.getFormMetadata('form-test');
|
|
39
|
+
expect(meta.id).toBe('95e92559-968d-44ae-8666-2b1ad3dffd31');
|
|
40
|
+
expect(meta.title).toBe('Form test');
|
|
41
|
+
});
|
|
42
|
+
it('should throw if not found', () => {
|
|
43
|
+
expect(() => service.getFormMetadata('form-test-missing')).toThrow("Form metadata 'form-test-missing' not found");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('metadata by id', () => {
|
|
47
|
+
it('should get form metadata by id', () => {
|
|
48
|
+
const meta = service.getFormMetadataById('95e92559-968d-44ae-8666-2b1ad3dffd31');
|
|
49
|
+
expect(meta.id).toBe('95e92559-968d-44ae-8666-2b1ad3dffd31');
|
|
50
|
+
expect(meta.title).toBe('Form test');
|
|
51
|
+
});
|
|
52
|
+
it('should throw if not found', () => {
|
|
53
|
+
expect(() => service.getFormMetadataById('id-missing')).toThrow("Form metadata id 'id-missing' not found");
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe('definition by id', () => {
|
|
57
|
+
it('should get form definition by id', () => {
|
|
58
|
+
const form = service.getFormDefinition('95e92559-968d-44ae-8666-2b1ad3dffd31');
|
|
59
|
+
expect(form.name).toBe('All components');
|
|
60
|
+
expect(form.startPage).toBe('/all-components');
|
|
61
|
+
});
|
|
62
|
+
it('should throw if not found', () => {
|
|
63
|
+
expect(() => service.getFormDefinition('id-missing')).toThrow("Form definition 'id-missing' not found");
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('toFormsService', () => {
|
|
67
|
+
it('should create interface', async () => {
|
|
68
|
+
const interfaceImpl = service.toFormsService();
|
|
69
|
+
const res1 = await interfaceImpl.getFormMetadata('form-test');
|
|
70
|
+
expect(res1.id).toBe('95e92559-968d-44ae-8666-2b1ad3dffd31');
|
|
71
|
+
expect(res1.title).toBe('Form test');
|
|
72
|
+
const res2 = await interfaceImpl.getFormMetadataById('95e92559-968d-44ae-8666-2b1ad3dffd31');
|
|
73
|
+
expect(res2.id).toBe('95e92559-968d-44ae-8666-2b1ad3dffd31');
|
|
74
|
+
expect(res2.title).toBe('Form test');
|
|
75
|
+
const res3 = await interfaceImpl.getFormDefinition('95e92559-968d-44ae-8666-2b1ad3dffd31', FormStatus.Draft);
|
|
76
|
+
expect(res3?.name).toBe('All components');
|
|
77
|
+
expect(res3?.startPage).toBe('/all-components');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('readForm', () => {
|
|
81
|
+
it('should throw if invalid extension', async () => {
|
|
82
|
+
await expect(service.readForm('/some-folder/some-file.bad')).rejects.toThrow("Invalid file extension '.bad'");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=file-form-service.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-form-service.test.js","names":["join","FormStatus","FileFormService","describe","service","beforeEach","now","Date","user","id","displayName","author","createdAt","createdBy","updatedAt","updatedBy","metadata","organisation","teamName","teamEmail","submissionGuidance","notificationEmail","live","addForm","import","meta","dirname","title","slug","it","getFormMetadata","expect","toBe","toThrow","getFormMetadataById","form","getFormDefinition","name","startPage","interfaceImpl","toFormsService","res1","res2","res3","Draft","readForm","rejects"],"sources":["../../../src/server/utils/file-form-service.test.js"],"sourcesContent":["import { join } from 'node:path'\n\nimport { FormStatus } from '~/src/server/routes/types.js'\nimport { FileFormService } from '~/src/server/utils/file-form-service.js'\n\ndescribe('File-form-service', () => {\n /** @type {FileFormService} */\n let service\n beforeEach(async () => {\n const now = new Date()\n const user = { id: 'user', displayName: 'Username' }\n const author = {\n createdAt: now,\n createdBy: user,\n updatedAt: now,\n updatedBy: user\n }\n service = new FileFormService()\n const metadata = {\n organisation: 'Defra',\n teamName: 'Team name',\n teamEmail: 'team@defra.gov.uk',\n submissionGuidance: \"Thanks for your submission, we'll be in touch\",\n notificationEmail: 'email@domain.com',\n ...author,\n live: author\n }\n await service.addForm(\n `${join(import.meta.dirname, '../../../test/form/definitions')}/components.json`,\n {\n ...metadata,\n id: '95e92559-968d-44ae-8666-2b1ad3dffd31',\n title: 'Form test',\n slug: 'form-test'\n }\n )\n })\n\n describe('metadata by slug', () => {\n it('should get form metadata by slug', () => {\n const meta = service.getFormMetadata('form-test')\n expect(meta.id).toBe('95e92559-968d-44ae-8666-2b1ad3dffd31')\n expect(meta.title).toBe('Form test')\n })\n\n it('should throw if not found', () => {\n expect(() => service.getFormMetadata('form-test-missing')).toThrow(\n \"Form metadata 'form-test-missing' not found\"\n )\n })\n })\n\n describe('metadata by id', () => {\n it('should get form metadata by id', () => {\n const meta = service.getFormMetadataById(\n '95e92559-968d-44ae-8666-2b1ad3dffd31'\n )\n expect(meta.id).toBe('95e92559-968d-44ae-8666-2b1ad3dffd31')\n expect(meta.title).toBe('Form test')\n })\n\n it('should throw if not found', () => {\n expect(() => service.getFormMetadataById('id-missing')).toThrow(\n \"Form metadata id 'id-missing' not found\"\n )\n })\n })\n\n describe('definition by id', () => {\n it('should get form definition by id', () => {\n const form = service.getFormDefinition(\n '95e92559-968d-44ae-8666-2b1ad3dffd31'\n )\n expect(form.name).toBe('All components')\n expect(form.startPage).toBe('/all-components')\n })\n\n it('should throw if not found', () => {\n expect(() => service.getFormDefinition('id-missing')).toThrow(\n \"Form definition 'id-missing' not found\"\n )\n })\n })\n\n describe('toFormsService', () => {\n it('should create interface', async () => {\n const interfaceImpl = service.toFormsService()\n const res1 = await interfaceImpl.getFormMetadata('form-test')\n expect(res1.id).toBe('95e92559-968d-44ae-8666-2b1ad3dffd31')\n expect(res1.title).toBe('Form test')\n\n const res2 = await interfaceImpl.getFormMetadataById(\n '95e92559-968d-44ae-8666-2b1ad3dffd31'\n )\n expect(res2.id).toBe('95e92559-968d-44ae-8666-2b1ad3dffd31')\n expect(res2.title).toBe('Form test')\n\n const res3 = await interfaceImpl.getFormDefinition(\n '95e92559-968d-44ae-8666-2b1ad3dffd31',\n FormStatus.Draft\n )\n expect(res3?.name).toBe('All components')\n expect(res3?.startPage).toBe('/all-components')\n })\n })\n\n describe('readForm', () => {\n it('should throw if invalid extension', async () => {\n await expect(\n service.readForm('/some-folder/some-file.bad')\n ).rejects.toThrow(\"Invalid file extension '.bad'\")\n })\n })\n})\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra/forms-engine-plugin",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.26",
|
|
4
4
|
"description": "Defra forms engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"license": "SEE LICENSE IN LICENSE",
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@defra/forms-model": "^3.0.
|
|
73
|
+
"@defra/forms-model": "^3.0.585",
|
|
74
74
|
"@defra/hapi-tracing": "^1.29.0",
|
|
75
75
|
"@elastic/ecs-pino-format": "^1.5.0",
|
|
76
76
|
"@hapi/boom": "^10.0.1",
|