@defra/forms-engine-plugin 0.0.5 → 0.1.0
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/index.js +0 -4
- package/.server/server/index.js.map +1 -1
- package/.server/server/plugins/engine/helpers.js +3 -0
- package/.server/server/plugins/engine/helpers.js.map +1 -1
- package/.server/server/plugins/engine/index.js +27 -1
- package/.server/server/plugins/engine/index.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js +2 -4
- package/.server/server/plugins/engine/pageControllers/FileUploadPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +4 -10
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/StatusPageController.js +2 -3
- package/.server/server/plugins/engine/pageControllers/StatusPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +2 -4
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/.server/server/plugins/engine/plugin.js +65 -6
- package/.server/server/plugins/engine/plugin.js.map +1 -1
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/{views → plugins/engine/views}/components/service-banner/template.test.js +1 -1
- package/.server/server/plugins/engine/views/components/service-banner/template.test.js.map +1 -0
- package/.server/server/{views → plugins/engine/views}/components/tag-env/template.test.js +1 -1
- package/.server/server/plugins/engine/views/components/tag-env/template.test.js.map +1 -0
- package/.server/server/services/cacheService.js +5 -2
- package/.server/server/services/cacheService.js.map +1 -1
- package/.server/typings/hapi/index.d.js.map +1 -1
- package/README.md +283 -5
- package/package.json +1 -2
- package/src/server/index.ts +0 -5
- package/src/server/plugins/engine/helpers.ts +6 -1
- package/src/server/plugins/engine/index.ts +41 -1
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +20 -12
- package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +2 -1
- package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +7 -3
- package/src/server/plugins/engine/pageControllers/StatusPageController.ts +2 -1
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +3 -2
- package/src/server/plugins/engine/plugin.ts +84 -4
- package/src/server/plugins/engine/types.ts +2 -0
- package/src/server/services/cacheService.test.ts +1 -0
- package/src/server/services/cacheService.ts +9 -2
- package/src/typings/hapi/index.d.ts +3 -11
- package/.server/server/views/components/service-banner/template.test.js.map +0 -1
- package/.server/server/views/components/tag-env/template.test.js.map +0 -1
- /package/.server/server/{views → plugins/engine/views}/components/debug/macro.njk +0 -0
- /package/.server/server/{views → plugins/engine/views}/components/debug/template.njk +0 -0
- /package/.server/server/{views → plugins/engine/views}/components/service-banner/macro.njk +0 -0
- /package/.server/server/{views → plugins/engine/views}/components/service-banner/template.njk +0 -0
- /package/.server/server/{views → plugins/engine/views}/components/tag-env/macro.njk +0 -0
- /package/.server/server/{views → plugins/engine/views}/components/tag-env/template.njk +0 -0
- /package/.server/server/{views → plugins/engine/views}/confirmation.html +0 -0
- /package/.server/server/{views → plugins/engine/views}/layout.html +0 -0
- /package/.server/server/{views → plugins/engine/views}/summary.html +0 -0
- /package/src/server/{views → plugins/engine/views}/components/debug/macro.njk +0 -0
- /package/src/server/{views → plugins/engine/views}/components/debug/template.njk +0 -0
- /package/src/server/{views → plugins/engine/views}/components/service-banner/macro.njk +0 -0
- /package/src/server/{views → plugins/engine/views}/components/service-banner/template.njk +0 -0
- /package/src/server/{views → plugins/engine/views}/components/service-banner/template.test.js +0 -0
- /package/src/server/{views → plugins/engine/views}/components/tag-env/macro.njk +0 -0
- /package/src/server/{views → plugins/engine/views}/components/tag-env/template.njk +0 -0
- /package/src/server/{views → plugins/engine/views}/components/tag-env/template.test.js +0 -0
- /package/src/server/{views → plugins/engine/views}/confirmation.html +0 -0
- /package/src/server/{views → plugins/engine/views}/layout.html +0 -0
- /package/src/server/{views → plugins/engine/views}/summary.html +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusPageController.js","names":["QuestionPageController","StatusPageController","constructor","model","pageDef","viewName","getRelevantPath","getStatusPath","makeGetRouteHandler","request","context","h","viewModel","cacheService","
|
|
1
|
+
{"version":3,"file":"StatusPageController.js","names":["getCacheService","QuestionPageController","StatusPageController","constructor","model","pageDef","viewName","getRelevantPath","getStatusPath","makeGetRouteHandler","request","context","h","viewModel","cacheService","server","confirmationState","getConfirmationState","confirmed","proceed","getStartPath","slug","params","formsService","services","getFormMetadata","submissionGuidance","view"],"sources":["../../../../../src/server/plugins/engine/pageControllers/StatusPageController.ts"],"sourcesContent":["import { type PageStatus } from '@defra/forms-model'\nimport { type ResponseToolkit } from '@hapi/hapi'\n\nimport { getCacheService } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport { type FormContext } from '~/src/server/plugins/engine/types.js'\nimport { type FormRequest } from '~/src/server/routes/types.js'\n\nexport class StatusPageController extends QuestionPageController {\n declare pageDef: PageStatus\n\n constructor(model: FormModel, pageDef: PageStatus) {\n super(model, pageDef)\n this.viewName = 'confirmation'\n }\n\n getRelevantPath() {\n return this.getStatusPath()\n }\n\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { viewModel, viewName } = this\n\n const cacheService = getCacheService(request.server)\n const confirmationState = await cacheService.getConfirmationState(request)\n\n // If there's no confirmation state, then\n // redirect the user back to the start of the form\n if (!confirmationState.confirmed) {\n return this.proceed(request, h, this.getStartPath())\n }\n\n const slug = request.params.slug\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n const { submissionGuidance } = await getFormMetadata(slug)\n\n return h.view(viewName, {\n ...viewModel,\n submissionGuidance\n })\n }\n }\n}\n"],"mappings":"AAGA,SAASA,eAAe;AAExB,SAASC,sBAAsB;AAI/B,OAAO,MAAMC,oBAAoB,SAASD,sBAAsB,CAAC;EAG/DE,WAAWA,CAACC,KAAgB,EAAEC,OAAmB,EAAE;IACjD,KAAK,CAACD,KAAK,EAAEC,OAAO,CAAC;IACrB,IAAI,CAACC,QAAQ,GAAG,cAAc;EAChC;EAEAC,eAAeA,CAAA,EAAG;IAChB,OAAO,IAAI,CAACC,aAAa,CAAC,CAAC;EAC7B;EAEAC,mBAAmBA,CAAA,EAAG;IACpB,OAAO,OACLC,OAAoB,EACpBC,OAAoB,EACpBC,CAA6C,KAC1C;MACH,MAAM;QAAEC,SAAS;QAAEP;MAAS,CAAC,GAAG,IAAI;MAEpC,MAAMQ,YAAY,GAAGd,eAAe,CAACU,OAAO,CAACK,MAAM,CAAC;MACpD,MAAMC,iBAAiB,GAAG,MAAMF,YAAY,CAACG,oBAAoB,CAACP,OAAO,CAAC;;MAE1E;MACA;MACA,IAAI,CAACM,iBAAiB,CAACE,SAAS,EAAE;QAChC,OAAO,IAAI,CAACC,OAAO,CAACT,OAAO,EAAEE,CAAC,EAAE,IAAI,CAACQ,YAAY,CAAC,CAAC,CAAC;MACtD;MAEA,MAAMC,IAAI,GAAGX,OAAO,CAACY,MAAM,CAACD,IAAI;MAChC,MAAM;QAAEE;MAAa,CAAC,GAAG,IAAI,CAACnB,KAAK,CAACoB,QAAQ;MAC5C,MAAM;QAAEC;MAAgB,CAAC,GAAGF,YAAY;MAExC,MAAM;QAAEG;MAAmB,CAAC,GAAG,MAAMD,eAAe,CAACJ,IAAI,CAAC;MAE1D,OAAOT,CAAC,CAACe,IAAI,CAACrB,QAAQ,EAAE;QACtB,GAAGO,SAAS;QACZa;MACF,CAAC,CAAC;IACJ,CAAC;EACH;AACF","ignoreList":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Boom from '@hapi/boom';
|
|
2
2
|
import { FileUploadField } from "../components/FileUploadField.js";
|
|
3
3
|
import { getAnswer } from "../components/helpers.js";
|
|
4
|
-
import { checkEmailAddressForLiveFormSubmission, checkFormStatus } from "../helpers.js";
|
|
4
|
+
import { checkEmailAddressForLiveFormSubmission, checkFormStatus, getCacheService } from "../helpers.js";
|
|
5
5
|
import { SummaryViewModel } from "../models/index.js";
|
|
6
6
|
import { QuestionPageController } from "./QuestionPageController.js";
|
|
7
7
|
export class SummaryPageController extends QuestionPageController {
|
|
@@ -53,9 +53,7 @@ export class SummaryPageController extends QuestionPageController {
|
|
|
53
53
|
const {
|
|
54
54
|
state
|
|
55
55
|
} = context;
|
|
56
|
-
const
|
|
57
|
-
cacheService
|
|
58
|
-
} = request.services([]);
|
|
56
|
+
const cacheService = getCacheService(request.server);
|
|
59
57
|
const {
|
|
60
58
|
formsService
|
|
61
59
|
} = this.model.services;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SummaryPageController.js","names":["Boom","FileUploadField","getAnswer","checkEmailAddressForLiveFormSubmission","checkFormStatus","SummaryViewModel","QuestionPageController","SummaryPageController","constructor","model","pageDef","viewName","getSummaryViewModel","request","context","viewModel","backLink","getBackLink","feedbackLink","phaseTag","makeGetRouteHandler","h","hasMissingNotificationEmail","view","makePostRouteHandler","params","state","cacheService","services","formsService","getFormMetadata","notificationEmail","slug","isPreview","path","emailAddress","def","outputEmail","submitForm","setConfirmationState","confirmed","clearState","proceed","getStatusPath","postRouteOptions","ext","onPreHandler","method","continue","summaryViewModel","extendFileRetention","formStatus","logTags","logger","info","items","getFormSubmissionData","details","submitResponse","submitData","yar","id","undefined","badRequest","outputService","submit","updatedRetrievalKey","formSubmissionService","persistFiles","files","pages","forEach","page","fileUploadComponents","collection","fields","filter","component","values","getFormValueFromState","length","push","map","status","fileId","form","file","initiatedRetrievalKey","metadata","retrievalKey","sessionId","payload","main","item","name","title","label","value","field","format","repeaters","subItems","detailItems","subItem","relevantPages","href","flatMap","flat"],"sources":["../../../../../src/server/plugins/engine/pageControllers/SummaryPageController.ts"],"sourcesContent":["import { type PageSummary, type SubmitPayload } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type ResponseToolkit, type RouteOptions } from '@hapi/hapi'\n\nimport { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'\nimport { getAnswer } from '~/src/server/plugins/engine/components/helpers.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus\n} from '~/src/server/plugins/engine/helpers.js'\nimport {\n SummaryViewModel,\n type FormModel\n} from '~/src/server/plugins/engine/models/index.js'\nimport {\n type Detail,\n type DetailItem\n} from '~/src/server/plugins/engine/models/types.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n type FormContext,\n type FormContextRequest,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs\n} from '~/src/server/routes/types.js'\n\nexport class SummaryPageController extends QuestionPageController {\n declare pageDef: PageSummary\n\n /**\n * The controller which is used when Page[\"controller\"] is defined as \"./pages/summary.js\"\n */\n\n constructor(model: FormModel, pageDef: PageSummary) {\n super(model, pageDef)\n this.viewName = 'summary'\n }\n\n getSummaryViewModel(\n request: FormContextRequest,\n context: FormContext\n ): SummaryViewModel {\n const viewModel = new SummaryViewModel(request, this, context)\n\n // We already figure these out in the base page controller. Take them and apply them to our page-specific model.\n // This is a stop-gap until we can add proper inheritance in place.\n viewModel.backLink = this.getBackLink(request, context)\n viewModel.feedbackLink = this.feedbackLink\n viewModel.phaseTag = this.phaseTag\n\n return viewModel\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a GET request at `/{id}/{path*}`,\n */\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { viewName } = this\n\n const viewModel = this.getSummaryViewModel(request, context)\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n return h.view(viewName, viewModel)\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a POST request at `/{id}/{path*}`.\n * If a form is incomplete, a user will be redirected to the start page.\n */\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { model } = this\n const { params } = request\n const { state } = context\n\n const { cacheService } = request.services([])\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n // Get the form metadata using the `slug` param\n const { notificationEmail } = await getFormMetadata(params.slug)\n const { isPreview } = checkFormStatus(request.path)\n const emailAddress = notificationEmail ?? this.model.def.outputEmail\n\n checkEmailAddressForLiveFormSubmission(emailAddress, isPreview)\n\n // Send submission email\n if (emailAddress) {\n const viewModel = this.getSummaryViewModel(request, context)\n await submitForm(request, viewModel, model, state, emailAddress)\n }\n\n await cacheService.setConfirmationState(request, { confirmed: true })\n\n // Clear all form data\n await cacheService.clearState(request)\n\n return this.proceed(request, h, this.getStatusPath())\n }\n }\n\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n ext: {\n onPreHandler: {\n method(request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n\nasync function submitForm(\n request: FormRequestPayload,\n summaryViewModel: SummaryViewModel,\n model: FormModel,\n state: FormSubmissionState,\n emailAddress: string\n) {\n await extendFileRetention(model, state, emailAddress)\n\n const { path } = request\n const formStatus = checkFormStatus(path)\n const logTags = ['submit', 'submissionApi']\n\n request.logger.info(logTags, 'Preparing email', formStatus)\n\n // Get detail items\n const items = getFormSubmissionData(\n summaryViewModel.context,\n summaryViewModel.details\n )\n\n // Submit data\n request.logger.info(logTags, 'Submitting data')\n const submitResponse = await submitData(\n model,\n items,\n emailAddress,\n request.yar.id\n )\n\n if (submitResponse === undefined) {\n throw Boom.badRequest('Unexpected empty response from submit api')\n }\n\n return model.services.outputService.submit(\n request,\n model,\n emailAddress,\n items,\n submitResponse\n )\n}\n\nasync function extendFileRetention(\n model: FormModel,\n state: FormSubmissionState,\n updatedRetrievalKey: string\n) {\n const { formSubmissionService } = model.services\n const { persistFiles } = formSubmissionService\n const files: { fileId: string; initiatedRetrievalKey: string }[] = []\n\n // For each file upload component with files in\n // state, add the files to the batch getting persisted\n model.pages.forEach((page) => {\n const fileUploadComponents = page.collection.fields.filter(\n (component) => component instanceof FileUploadField\n )\n\n fileUploadComponents.forEach((component) => {\n const values = component.getFormValueFromState(state)\n if (!values?.length) {\n return\n }\n\n files.push(\n ...values.map(({ status }) => ({\n fileId: status.form.file.fileId,\n initiatedRetrievalKey: status.metadata.retrievalKey\n }))\n )\n })\n })\n\n if (files.length) {\n return persistFiles(files, updatedRetrievalKey)\n }\n}\n\nfunction submitData(\n model: FormModel,\n items: DetailItem[],\n retrievalKey: string,\n sessionId: string\n) {\n const { formSubmissionService } = model.services\n const { submit } = formSubmissionService\n\n const payload: SubmitPayload = {\n sessionId,\n retrievalKey,\n\n // Main form answers\n main: items\n .filter((item) => 'field' in item)\n .map((item) => ({\n name: item.name,\n title: item.label,\n value: getAnswer(item.field, item.state, { format: 'data' })\n })),\n\n // Repeater form answers\n repeaters: items\n .filter((item) => 'subItems' in item)\n .map((item) => ({\n name: item.name,\n title: item.label,\n\n // Repeater item values\n value: item.subItems.map((detailItems) =>\n detailItems.map((subItem) => ({\n name: subItem.name,\n title: subItem.label,\n value: getAnswer(subItem.field, subItem.state, { format: 'data' })\n }))\n )\n }))\n }\n\n return submit(payload)\n}\n\nexport function getFormSubmissionData(context: FormContext, details: Detail[]) {\n return context.relevantPages\n .map(({ href }) =>\n details.flatMap(({ items }) =>\n items.filter(({ page }) => page.href === href)\n )\n )\n .flat()\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"SummaryPageController.js","names":["Boom","FileUploadField","getAnswer","checkEmailAddressForLiveFormSubmission","checkFormStatus","getCacheService","SummaryViewModel","QuestionPageController","SummaryPageController","constructor","model","pageDef","viewName","getSummaryViewModel","request","context","viewModel","backLink","getBackLink","feedbackLink","phaseTag","makeGetRouteHandler","h","hasMissingNotificationEmail","view","makePostRouteHandler","params","state","cacheService","server","formsService","services","getFormMetadata","notificationEmail","slug","isPreview","path","emailAddress","def","outputEmail","submitForm","setConfirmationState","confirmed","clearState","proceed","getStatusPath","postRouteOptions","ext","onPreHandler","method","continue","summaryViewModel","extendFileRetention","formStatus","logTags","logger","info","items","getFormSubmissionData","details","submitResponse","submitData","yar","id","undefined","badRequest","outputService","submit","updatedRetrievalKey","formSubmissionService","persistFiles","files","pages","forEach","page","fileUploadComponents","collection","fields","filter","component","values","getFormValueFromState","length","push","map","status","fileId","form","file","initiatedRetrievalKey","metadata","retrievalKey","sessionId","payload","main","item","name","title","label","value","field","format","repeaters","subItems","detailItems","subItem","relevantPages","href","flatMap","flat"],"sources":["../../../../../src/server/plugins/engine/pageControllers/SummaryPageController.ts"],"sourcesContent":["import { type PageSummary, type SubmitPayload } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport { type ResponseToolkit, type RouteOptions } from '@hapi/hapi'\n\nimport { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'\nimport { getAnswer } from '~/src/server/plugins/engine/components/helpers.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus,\n getCacheService\n} from '~/src/server/plugins/engine/helpers.js'\nimport {\n SummaryViewModel,\n type FormModel\n} from '~/src/server/plugins/engine/models/index.js'\nimport {\n type Detail,\n type DetailItem\n} from '~/src/server/plugins/engine/models/types.js'\nimport { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'\nimport {\n type FormContext,\n type FormContextRequest,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs\n} from '~/src/server/routes/types.js'\n\nexport class SummaryPageController extends QuestionPageController {\n declare pageDef: PageSummary\n\n /**\n * The controller which is used when Page[\"controller\"] is defined as \"./pages/summary.js\"\n */\n\n constructor(model: FormModel, pageDef: PageSummary) {\n super(model, pageDef)\n this.viewName = 'summary'\n }\n\n getSummaryViewModel(\n request: FormContextRequest,\n context: FormContext\n ): SummaryViewModel {\n const viewModel = new SummaryViewModel(request, this, context)\n\n // We already figure these out in the base page controller. Take them and apply them to our page-specific model.\n // This is a stop-gap until we can add proper inheritance in place.\n viewModel.backLink = this.getBackLink(request, context)\n viewModel.feedbackLink = this.feedbackLink\n viewModel.phaseTag = this.phaseTag\n\n return viewModel\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a GET request at `/{id}/{path*}`,\n */\n makeGetRouteHandler() {\n return async (\n request: FormRequest,\n context: FormContext,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { viewName } = this\n\n const viewModel = this.getSummaryViewModel(request, context)\n\n viewModel.hasMissingNotificationEmail =\n await this.hasMissingNotificationEmail(request, context)\n\n return h.view(viewName, viewModel)\n }\n }\n\n /**\n * Returns an async function. This is called in plugin.ts when there is a POST request at `/{id}/{path*}`.\n * If a form is incomplete, a user will be redirected to the start page.\n */\n makePostRouteHandler() {\n return async (\n request: FormRequestPayload,\n context: FormContext,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { model } = this\n const { params } = request\n const { state } = context\n const cacheService = getCacheService(request.server)\n\n const { formsService } = this.model.services\n const { getFormMetadata } = formsService\n\n // Get the form metadata using the `slug` param\n const { notificationEmail } = await getFormMetadata(params.slug)\n const { isPreview } = checkFormStatus(request.path)\n const emailAddress = notificationEmail ?? this.model.def.outputEmail\n\n checkEmailAddressForLiveFormSubmission(emailAddress, isPreview)\n\n // Send submission email\n if (emailAddress) {\n const viewModel = this.getSummaryViewModel(request, context)\n await submitForm(request, viewModel, model, state, emailAddress)\n }\n\n await cacheService.setConfirmationState(request, { confirmed: true })\n\n // Clear all form data\n await cacheService.clearState(request)\n\n return this.proceed(request, h, this.getStatusPath())\n }\n }\n\n get postRouteOptions(): RouteOptions<FormRequestPayloadRefs> {\n return {\n ext: {\n onPreHandler: {\n method(request, h) {\n return h.continue\n }\n }\n }\n }\n }\n}\n\nasync function submitForm(\n request: FormRequestPayload,\n summaryViewModel: SummaryViewModel,\n model: FormModel,\n state: FormSubmissionState,\n emailAddress: string\n) {\n await extendFileRetention(model, state, emailAddress)\n\n const { path } = request\n const formStatus = checkFormStatus(path)\n const logTags = ['submit', 'submissionApi']\n\n request.logger.info(logTags, 'Preparing email', formStatus)\n\n // Get detail items\n const items = getFormSubmissionData(\n summaryViewModel.context,\n summaryViewModel.details\n )\n\n // Submit data\n request.logger.info(logTags, 'Submitting data')\n const submitResponse = await submitData(\n model,\n items,\n emailAddress,\n request.yar.id\n )\n\n if (submitResponse === undefined) {\n throw Boom.badRequest('Unexpected empty response from submit api')\n }\n\n return model.services.outputService.submit(\n request,\n model,\n emailAddress,\n items,\n submitResponse\n )\n}\n\nasync function extendFileRetention(\n model: FormModel,\n state: FormSubmissionState,\n updatedRetrievalKey: string\n) {\n const { formSubmissionService } = model.services\n const { persistFiles } = formSubmissionService\n const files: { fileId: string; initiatedRetrievalKey: string }[] = []\n\n // For each file upload component with files in\n // state, add the files to the batch getting persisted\n model.pages.forEach((page) => {\n const fileUploadComponents = page.collection.fields.filter(\n (component) => component instanceof FileUploadField\n )\n\n fileUploadComponents.forEach((component) => {\n const values = component.getFormValueFromState(state)\n if (!values?.length) {\n return\n }\n\n files.push(\n ...values.map(({ status }) => ({\n fileId: status.form.file.fileId,\n initiatedRetrievalKey: status.metadata.retrievalKey\n }))\n )\n })\n })\n\n if (files.length) {\n return persistFiles(files, updatedRetrievalKey)\n }\n}\n\nfunction submitData(\n model: FormModel,\n items: DetailItem[],\n retrievalKey: string,\n sessionId: string\n) {\n const { formSubmissionService } = model.services\n const { submit } = formSubmissionService\n\n const payload: SubmitPayload = {\n sessionId,\n retrievalKey,\n\n // Main form answers\n main: items\n .filter((item) => 'field' in item)\n .map((item) => ({\n name: item.name,\n title: item.label,\n value: getAnswer(item.field, item.state, { format: 'data' })\n })),\n\n // Repeater form answers\n repeaters: items\n .filter((item) => 'subItems' in item)\n .map((item) => ({\n name: item.name,\n title: item.label,\n\n // Repeater item values\n value: item.subItems.map((detailItems) =>\n detailItems.map((subItem) => ({\n name: subItem.name,\n title: subItem.label,\n value: getAnswer(subItem.field, subItem.state, { format: 'data' })\n }))\n )\n }))\n }\n\n return submit(payload)\n}\n\nexport function getFormSubmissionData(context: FormContext, details: Detail[]) {\n return context.relevantPages\n .map(({ href }) =>\n details.flatMap(({ items }) =>\n items.filter(({ page }) => page.href === href)\n )\n )\n .flat()\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { hasFormComponents, slugSchema } from '@defra/forms-model';
|
|
2
2
|
import Boom from '@hapi/boom';
|
|
3
|
+
// import vision from '@hapi/vision'
|
|
3
4
|
import { isEqual } from 'date-fns';
|
|
4
5
|
import Joi from 'joi';
|
|
6
|
+
// import nunjucks, { type Environment } from 'nunjucks'
|
|
7
|
+
|
|
5
8
|
import { PREVIEW_PATH_PREFIX } from "../../constants.js";
|
|
6
|
-
import { checkEmailAddressForLiveFormSubmission, checkFormStatus, findPage, getPage, getStartPath, normalisePath, proceed, redirectPath } from "./helpers.js";
|
|
9
|
+
import { checkEmailAddressForLiveFormSubmission, checkFormStatus, findPage, getCacheService, getPage, getStartPath, normalisePath, proceed, redirectPath } from "./helpers.js";
|
|
10
|
+
// import {
|
|
11
|
+
// PLUGIN_PATH,
|
|
12
|
+
// VIEW_PATH,
|
|
13
|
+
// context,
|
|
14
|
+
// prepareNunjucksEnvironment
|
|
15
|
+
// } from '~/src/server/plugins/engine/index.js'
|
|
7
16
|
import { FormModel, SummaryViewModel } from "./models/index.js";
|
|
8
17
|
import { format } from "./outputFormatters/machine/v1.js";
|
|
9
18
|
import { FileUploadPageController } from "./pageControllers/FileUploadPageController.js";
|
|
@@ -13,19 +22,71 @@ import * as defaultServices from "./services/index.js";
|
|
|
13
22
|
import { getUploadStatus } from "./services/uploadService.js";
|
|
14
23
|
import { actionSchema, confirmSchema, crumbSchema, itemIdSchema, pathSchema, stateSchema } from "../../schemas/index.js";
|
|
15
24
|
import * as httpService from "../../services/httpService.js";
|
|
25
|
+
import { CacheService } from "../../services/index.js";
|
|
16
26
|
export const plugin = {
|
|
17
27
|
name: '@defra/forms-engine-plugin',
|
|
18
|
-
dependencies: ['@hapi/
|
|
28
|
+
dependencies: ['@hapi/crumb', '@hapi/yar', 'hapi-pino'],
|
|
19
29
|
multiple: true,
|
|
20
30
|
register(server, options) {
|
|
21
31
|
const {
|
|
22
32
|
model,
|
|
23
33
|
services = defaultServices,
|
|
24
|
-
controllers
|
|
34
|
+
controllers,
|
|
35
|
+
cacheName
|
|
36
|
+
// pluginPath = PLUGIN_PATH,
|
|
37
|
+
// filters
|
|
25
38
|
} = options;
|
|
26
39
|
const {
|
|
27
40
|
formsService
|
|
28
41
|
} = services;
|
|
42
|
+
const cacheService = new CacheService(server, cacheName);
|
|
43
|
+
|
|
44
|
+
// Paths array to tell `vision` and `nunjucks` where template files are stored.
|
|
45
|
+
// const path = [`${pluginPath}/${VIEW_PATH}`]
|
|
46
|
+
|
|
47
|
+
// await server.register({
|
|
48
|
+
// plugin: vision,
|
|
49
|
+
// options: {
|
|
50
|
+
// engines: {
|
|
51
|
+
// html: {
|
|
52
|
+
// compile: (
|
|
53
|
+
// path: string,
|
|
54
|
+
// compileOptions: { environment: Environment }
|
|
55
|
+
// ) => {
|
|
56
|
+
// const template = nunjucks.compile(
|
|
57
|
+
// path,
|
|
58
|
+
// compileOptions.environment
|
|
59
|
+
// )
|
|
60
|
+
|
|
61
|
+
// return (context: object | undefined) => {
|
|
62
|
+
// return template.render(context)
|
|
63
|
+
// }
|
|
64
|
+
// },
|
|
65
|
+
// prepare: (options: EngineConfigurationObject, next) => {
|
|
66
|
+
// // Nunjucks also needs an additional path configuration
|
|
67
|
+
// // to use the templates and macros from `govuk-frontend`
|
|
68
|
+
// const environment = nunjucks.configure([
|
|
69
|
+
// ...path,
|
|
70
|
+
// 'node_modules/govuk-frontend/dist'
|
|
71
|
+
// ])
|
|
72
|
+
|
|
73
|
+
// // Applies custom filters and globals for nunjucks
|
|
74
|
+
// // that are required by the `forms-engine-plugin`
|
|
75
|
+
// prepareNunjucksEnvironment(environment, filters)
|
|
76
|
+
|
|
77
|
+
// options.compileOptions.environment = environment
|
|
78
|
+
|
|
79
|
+
// next()
|
|
80
|
+
// }
|
|
81
|
+
// }
|
|
82
|
+
// },
|
|
83
|
+
// path,
|
|
84
|
+
// // Provides global context used with all templates
|
|
85
|
+
// context
|
|
86
|
+
// }
|
|
87
|
+
// })
|
|
88
|
+
|
|
89
|
+
server.expose('cacheService', cacheService);
|
|
29
90
|
server.app.model = model;
|
|
30
91
|
|
|
31
92
|
// In-memory cache of FormModel items, exposed
|
|
@@ -122,9 +183,7 @@ export const plugin = {
|
|
|
122
183
|
if (!model) {
|
|
123
184
|
throw Boom.notFound(`No model found for /${params.path}`);
|
|
124
185
|
}
|
|
125
|
-
const
|
|
126
|
-
cacheService
|
|
127
|
-
} = request.services([]);
|
|
186
|
+
const cacheService = getCacheService(request.server);
|
|
128
187
|
const page = getPage(model, request);
|
|
129
188
|
const state = await page.getState(request);
|
|
130
189
|
const flash = cacheService.getFlash(request);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":["hasFormComponents","slugSchema","Boom","isEqual","Joi","PREVIEW_PATH_PREFIX","checkEmailAddressForLiveFormSubmission","checkFormStatus","findPage","getPage","getStartPath","normalisePath","proceed","redirectPath","FormModel","SummaryViewModel","format","FileUploadPageController","RepeatPageController","getFormSubmissionData","defaultServices","getUploadStatus","actionSchema","confirmSchema","crumbSchema","itemIdSchema","pathSchema","stateSchema","httpService","plugin","name","dependencies","multiple","register","server","options","model","services","controllers","formsService","app","itemCache","Map","models","loadFormPreHandler","request","h","continue","params","path","slug","isPreview","state","formState","metadata","getFormMetadata","id","notFound","key","item","get","updatedAt","logger","info","definition","getFormDefinition","emailAddress","notificationEmail","outputEmail","basePath","substring","set","dispatchHandler","servicePath","redirectOrMakeHandler","makeHandler","cacheService","page","getState","flash","getFlash","context","getFormContext","errors","relevantPath","getRelevantPath","summaryPath","getSummaryPath","startsWith","isForceAccess","redirectTo","next","length","query","returnUrl","getHref","getHandler","events","onLoad","type","url","viewModel","items","details","payload","undefined","response","postJson","Object","assign","data","makeGetRouteHandler","postHandler","pageDef","href","makePostRouteHandler","dispatchRouteOptions","pre","method","route","handler","validate","object","keys","getRouteOptions","itemId","optional","postRouteOptions","parse","crumb","action","unknown","required","getListSummaryHandler","makeGetListSummaryRouteHandler","postListSummaryHandler","makePostListSummaryRouteHandler","getItemDeleteHandler","makeGetItemDeleteRouteHandler","postItemDeleteHandler","makePostItemDeleteRouteHandler","confirm","uploadId","status","error","code","plugins","string","guid"],"sources":["../../../../src/server/plugins/engine/plugin.ts"],"sourcesContent":["import { hasFormComponents, slugSchema } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport {\n type Plugin,\n type ResponseObject,\n type ResponseToolkit,\n type RouteOptions\n} from '@hapi/hapi'\nimport { isEqual } from 'date-fns'\nimport Joi from 'joi'\n\nimport { PREVIEW_PATH_PREFIX } from '~/src/server/constants.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus,\n findPage,\n getPage,\n getStartPath,\n normalisePath,\n proceed,\n redirectPath\n} from '~/src/server/plugins/engine/helpers.js'\nimport {\n FormModel,\n SummaryViewModel\n} from '~/src/server/plugins/engine/models/index.js'\nimport { format } from '~/src/server/plugins/engine/outputFormatters/machine/v1.js'\nimport { FileUploadPageController } from '~/src/server/plugins/engine/pageControllers/FileUploadPageController.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { RepeatPageController } from '~/src/server/plugins/engine/pageControllers/RepeatPageController.js'\nimport { getFormSubmissionData } from '~/src/server/plugins/engine/pageControllers/SummaryPageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport * as defaultServices from '~/src/server/plugins/engine/services/index.js'\nimport { getUploadStatus } from '~/src/server/plugins/engine/services/uploadService.js'\nimport { type FormContext } from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormRequestRefs\n} from '~/src/server/routes/types.js'\nimport {\n actionSchema,\n confirmSchema,\n crumbSchema,\n itemIdSchema,\n pathSchema,\n stateSchema\n} from '~/src/server/schemas/index.js'\nimport * as httpService from '~/src/server/services/httpService.js'\nimport { type Services } from '~/src/server/types.js'\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n}\n\nexport const plugin = {\n name: '@defra/forms-engine-plugin',\n dependencies: ['@hapi/vision', '@hapi/crumb', '@hapi/yar', 'hapi-pino'],\n multiple: true,\n register(server, options) {\n const { model, services = defaultServices, controllers } = options\n const { formsService } = services\n\n server.app.model = model\n\n // In-memory cache of FormModel items, exposed\n // (for testing purposes) through `server.app.models`\n const itemCache = new Map<string, { model: FormModel; updatedAt: Date }>()\n server.app.models = itemCache\n\n const loadFormPreHandler = async (\n request: FormRequest | FormRequestPayload,\n h: Pick<ResponseToolkit, 'continue'>\n ) => {\n if (server.app.model) {\n request.app.model = server.app.model\n\n return h.continue\n }\n\n const { params, path } = request\n const { slug } = params\n const { isPreview, state: formState } = checkFormStatus(path)\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 = itemCache.get(key)\n\n if (!item || !isEqual(item.updatedAt, state.updatedAt)) {\n server.logger.info(\n `Getting form definition ${id} (${slug}) ${formState}`\n )\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 =\n 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 = isPreview\n ? `${PREVIEW_PATH_PREFIX.substring(1)}/${formState}/${slug}`\n : slug\n\n // Construct the form model\n const model = new FormModel(\n definition,\n { basePath },\n services,\n controllers\n )\n\n // Create new item and add it to the item cache\n item = { model, updatedAt: state.updatedAt }\n itemCache.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 const dispatchHandler = (\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { model } = request.app\n\n const servicePath = model ? `/${model.basePath}` : ''\n return proceed(request, h, `${servicePath}${getStartPath(model)}`)\n }\n\n const redirectOrMakeHandler = async (\n request: FormRequest | FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>,\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 } = request.services([])\n const page = getPage(model, request)\n const state = await page.getState(request)\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 // 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\n const getHandler = (\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n if (normalisePath(params.path) === '') {\n return dispatchHandler(request, h)\n }\n\n return redirectOrMakeHandler(request, h, async (page, context) => {\n // Check for a page onLoad HTTP event and if one exists,\n // call it and assign the response to the context data\n const { events } = page\n const { model } = request.app\n\n if (!model) {\n throw Boom.notFound(`No model found for /${params.path}`)\n }\n\n if (events?.onLoad && events.onLoad.type === 'http') {\n const { options } = events.onLoad\n const { url } = options\n\n // TODO: Update structured data POST payload with when helper\n // is updated to removing the dependency on `SummaryViewModel` etc.\n const viewModel = new SummaryViewModel(request, page, context)\n const items = getFormSubmissionData(\n viewModel.context,\n viewModel.details\n )\n\n // @ts-expect-error - function signature will be refactored in the next iteration of the formatter\n const payload = format(items, model, undefined, undefined)\n\n const { payload: response } = await httpService.postJson(url, {\n payload\n })\n\n Object.assign(context.data, response)\n }\n\n return page.makeGetRouteHandler()(request, context, h)\n })\n }\n\n const postHandler = (\n request: FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { query } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n const { pageDef } = page\n const { isForceAccess } = context\n\n // Redirect to GET for preview URL direct access\n if (isForceAccess && !hasFormComponents(pageDef)) {\n return proceed(request, h, redirectPath(page.href, query))\n }\n\n return page.makePostRouteHandler()(request, context, h)\n })\n }\n\n const dispatchRouteOptions: RouteOptions<FormRequestRefs> = {\n pre: [\n {\n method: loadFormPreHandler\n }\n ]\n }\n\n server.route({\n method: 'get',\n path: '/{slug}',\n handler: dispatchHandler,\n options: {\n ...dispatchRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema\n })\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/preview/{state}/{slug}',\n handler: dispatchHandler,\n options: {\n ...dispatchRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema\n })\n }\n }\n })\n\n const getRouteOptions: RouteOptions<FormRequestRefs> = {\n pre: [\n {\n method: loadFormPreHandler\n }\n ]\n }\n\n server.route({\n method: 'get',\n path: '/{slug}/{path}/{itemId?}',\n handler: getHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n })\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/preview/{state}/{slug}/{path}/{itemId?}',\n handler: getHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n })\n }\n }\n })\n\n const postRouteOptions: RouteOptions<FormRequestPayloadRefs> = {\n payload: {\n parse: true\n },\n pre: [{ method: loadFormPreHandler }]\n }\n\n server.route({\n method: 'post',\n path: '/{slug}/{path}/{itemId?}',\n handler: postHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .unknown(true)\n .required()\n }\n }\n })\n\n server.route({\n method: 'post',\n path: '/preview/{state}/{slug}/{path}/{itemId?}',\n handler: postHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .unknown(true)\n .required()\n }\n }\n })\n\n /**\n * \"AddAnother\" repeat routes\n */\n\n // List summary GET route\n const getListSummaryHandler = (\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n if (!(page instanceof RepeatPageController)) {\n throw Boom.notFound(`No repeater page found for /${params.path}`)\n }\n\n return page.makeGetListSummaryRouteHandler()(request, context, h)\n })\n }\n\n server.route({\n method: 'get',\n path: '/{slug}/{path}/summary',\n handler: getListSummaryHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema\n })\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/preview/{state}/{slug}/{path}/summary',\n handler: getListSummaryHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema\n })\n }\n }\n })\n\n // List summary POST route\n const postListSummaryHandler = (\n request: FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n const { isForceAccess } = context\n\n if (isForceAccess || !(page instanceof RepeatPageController)) {\n throw Boom.notFound(`No repeater page found for /${params.path}`)\n }\n\n return page.makePostListSummaryRouteHandler()(request, context, h)\n })\n }\n\n server.route({\n method: 'post',\n path: '/{slug}/{path}/summary',\n handler: postListSummaryHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .required()\n }\n }\n })\n\n server.route({\n method: 'post',\n path: '/preview/{state}/{slug}/{path}/summary',\n handler: postListSummaryHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .required()\n }\n }\n })\n\n // Item delete GET route\n const getItemDeleteHandler = (\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n if (\n !(\n page instanceof RepeatPageController ||\n page instanceof FileUploadPageController\n )\n ) {\n throw Boom.notFound(`No page found for /${params.path}`)\n }\n\n return page.makeGetItemDeleteRouteHandler()(request, context, h)\n })\n }\n\n server.route({\n method: 'get',\n path: '/{slug}/{path}/{itemId}/confirm-delete',\n handler: getItemDeleteHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema\n })\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/preview/{state}/{slug}/{path}/{itemId}/confirm-delete',\n handler: getItemDeleteHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema\n })\n }\n }\n })\n\n // Item delete POST route\n const postItemDeleteHandler = (\n request: FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n const { isForceAccess } = context\n\n if (\n isForceAccess ||\n !(\n page instanceof RepeatPageController ||\n page instanceof FileUploadPageController\n )\n ) {\n throw Boom.notFound(`No page found for /${params.path}`)\n }\n\n return page.makePostItemDeleteRouteHandler()(request, context, h)\n })\n }\n\n server.route({\n method: 'post',\n path: '/{slug}/{path}/{itemId}/confirm-delete',\n handler: postItemDeleteHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema,\n confirm: confirmSchema\n })\n .required()\n }\n }\n })\n\n server.route({\n method: 'post',\n path: '/preview/{state}/{slug}/{path}/{itemId}/confirm-delete',\n handler: postItemDeleteHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema,\n confirm: confirmSchema\n })\n .required()\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/upload-status/{uploadId}',\n handler: async (request, h) => {\n try {\n const { uploadId } = request.params as { uploadId: string }\n const status = await getUploadStatus(uploadId)\n\n if (!status) {\n return h.response({ error: 'Status check failed' }).code(400)\n }\n\n return h.response(status)\n } catch (error) {\n request.logger.error(\n ['upload-status'],\n 'Upload status check failed',\n error\n )\n return h.response({ error: 'Status check error' }).code(500)\n }\n },\n options: {\n plugins: {\n crumb: false\n },\n validate: {\n params: Joi.object().keys({\n uploadId: Joi.string().guid().required()\n })\n }\n }\n })\n }\n} satisfies Plugin<PluginOptions>\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"plugin.js","names":["hasFormComponents","slugSchema","Boom","isEqual","Joi","PREVIEW_PATH_PREFIX","checkEmailAddressForLiveFormSubmission","checkFormStatus","findPage","getCacheService","getPage","getStartPath","normalisePath","proceed","redirectPath","FormModel","SummaryViewModel","format","FileUploadPageController","RepeatPageController","getFormSubmissionData","defaultServices","getUploadStatus","actionSchema","confirmSchema","crumbSchema","itemIdSchema","pathSchema","stateSchema","httpService","CacheService","plugin","name","dependencies","multiple","register","server","options","model","services","controllers","cacheName","formsService","cacheService","expose","app","itemCache","Map","models","loadFormPreHandler","request","h","continue","params","path","slug","isPreview","state","formState","metadata","getFormMetadata","id","notFound","key","item","get","updatedAt","logger","info","definition","getFormDefinition","emailAddress","notificationEmail","outputEmail","basePath","substring","set","dispatchHandler","servicePath","redirectOrMakeHandler","makeHandler","page","getState","flash","getFlash","context","getFormContext","errors","relevantPath","getRelevantPath","summaryPath","getSummaryPath","startsWith","isForceAccess","redirectTo","next","length","query","returnUrl","getHref","getHandler","events","onLoad","type","url","viewModel","items","details","payload","undefined","response","postJson","Object","assign","data","makeGetRouteHandler","postHandler","pageDef","href","makePostRouteHandler","dispatchRouteOptions","pre","method","route","handler","validate","object","keys","getRouteOptions","itemId","optional","postRouteOptions","parse","crumb","action","unknown","required","getListSummaryHandler","makeGetListSummaryRouteHandler","postListSummaryHandler","makePostListSummaryRouteHandler","getItemDeleteHandler","makeGetItemDeleteRouteHandler","postItemDeleteHandler","makePostItemDeleteRouteHandler","confirm","uploadId","status","error","code","plugins","string","guid"],"sources":["../../../../src/server/plugins/engine/plugin.ts"],"sourcesContent":["import { hasFormComponents, slugSchema } from '@defra/forms-model'\nimport Boom from '@hapi/boom'\nimport {\n type Plugin,\n type ResponseObject,\n type ResponseToolkit,\n type RouteOptions\n} from '@hapi/hapi'\n// import vision from '@hapi/vision'\nimport { isEqual } from 'date-fns'\nimport Joi from 'joi'\nimport { type Environment } from 'nunjucks'\n// import nunjucks, { type Environment } from 'nunjucks'\n\nimport { PREVIEW_PATH_PREFIX } from '~/src/server/constants.js'\nimport {\n checkEmailAddressForLiveFormSubmission,\n checkFormStatus,\n findPage,\n getCacheService,\n getPage,\n getStartPath,\n normalisePath,\n proceed,\n redirectPath\n} from '~/src/server/plugins/engine/helpers.js'\n// import {\n// PLUGIN_PATH,\n// VIEW_PATH,\n// context,\n// prepareNunjucksEnvironment\n// } from '~/src/server/plugins/engine/index.js'\nimport {\n FormModel,\n SummaryViewModel\n} from '~/src/server/plugins/engine/models/index.js'\nimport { format } from '~/src/server/plugins/engine/outputFormatters/machine/v1.js'\nimport { FileUploadPageController } from '~/src/server/plugins/engine/pageControllers/FileUploadPageController.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { RepeatPageController } from '~/src/server/plugins/engine/pageControllers/RepeatPageController.js'\nimport { getFormSubmissionData } from '~/src/server/plugins/engine/pageControllers/SummaryPageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport * as defaultServices from '~/src/server/plugins/engine/services/index.js'\nimport { getUploadStatus } from '~/src/server/plugins/engine/services/uploadService.js'\nimport {\n type FilterFunction,\n type FormContext\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload,\n type FormRequestPayloadRefs,\n type FormRequestRefs\n} from '~/src/server/routes/types.js'\nimport {\n actionSchema,\n confirmSchema,\n crumbSchema,\n itemIdSchema,\n pathSchema,\n stateSchema\n} from '~/src/server/schemas/index.js'\nimport * as httpService from '~/src/server/services/httpService.js'\nimport { CacheService } from '~/src/server/services/index.js'\nimport { type Services } from '~/src/server/types.js'\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n cacheName?: string\n pluginPath?: string\n filters?: Record<string, FilterFunction>\n}\n\nexport const plugin = {\n name: '@defra/forms-engine-plugin',\n dependencies: ['@hapi/crumb', '@hapi/yar', 'hapi-pino'],\n multiple: true,\n register(server, options) {\n const {\n model,\n services = defaultServices,\n controllers,\n cacheName\n // pluginPath = PLUGIN_PATH,\n // filters\n } = options\n const { formsService } = services\n const cacheService = new CacheService(server, cacheName)\n\n // Paths array to tell `vision` and `nunjucks` where template files are stored.\n // const path = [`${pluginPath}/${VIEW_PATH}`]\n\n // await server.register({\n // plugin: vision,\n // options: {\n // engines: {\n // html: {\n // compile: (\n // path: string,\n // compileOptions: { environment: Environment }\n // ) => {\n // const template = nunjucks.compile(\n // path,\n // compileOptions.environment\n // )\n\n // return (context: object | undefined) => {\n // return template.render(context)\n // }\n // },\n // prepare: (options: EngineConfigurationObject, next) => {\n // // Nunjucks also needs an additional path configuration\n // // to use the templates and macros from `govuk-frontend`\n // const environment = nunjucks.configure([\n // ...path,\n // 'node_modules/govuk-frontend/dist'\n // ])\n\n // // Applies custom filters and globals for nunjucks\n // // that are required by the `forms-engine-plugin`\n // prepareNunjucksEnvironment(environment, filters)\n\n // options.compileOptions.environment = environment\n\n // next()\n // }\n // }\n // },\n // path,\n // // Provides global context used with all templates\n // context\n // }\n // })\n\n server.expose('cacheService', cacheService)\n\n server.app.model = model\n\n // In-memory cache of FormModel items, exposed\n // (for testing purposes) through `server.app.models`\n const itemCache = new Map<string, { model: FormModel; updatedAt: Date }>()\n server.app.models = itemCache\n\n const loadFormPreHandler = async (\n request: FormRequest | FormRequestPayload,\n h: Pick<ResponseToolkit, 'continue'>\n ) => {\n if (server.app.model) {\n request.app.model = server.app.model\n\n return h.continue\n }\n\n const { params, path } = request\n const { slug } = params\n const { isPreview, state: formState } = checkFormStatus(path)\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 = itemCache.get(key)\n\n if (!item || !isEqual(item.updatedAt, state.updatedAt)) {\n server.logger.info(\n `Getting form definition ${id} (${slug}) ${formState}`\n )\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 =\n 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 = isPreview\n ? `${PREVIEW_PATH_PREFIX.substring(1)}/${formState}/${slug}`\n : slug\n\n // Construct the form model\n const model = new FormModel(\n definition,\n { basePath },\n services,\n controllers\n )\n\n // Create new item and add it to the item cache\n item = { model, updatedAt: state.updatedAt }\n itemCache.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 const dispatchHandler = (\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { model } = request.app\n\n const servicePath = model ? `/${model.basePath}` : ''\n return proceed(request, h, `${servicePath}${getStartPath(model)}`)\n }\n\n const redirectOrMakeHandler = async (\n request: FormRequest | FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>,\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 const state = await page.getState(request)\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 // 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\n const getHandler = (\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n if (normalisePath(params.path) === '') {\n return dispatchHandler(request, h)\n }\n\n return redirectOrMakeHandler(request, h, async (page, context) => {\n // Check for a page onLoad HTTP event and if one exists,\n // call it and assign the response to the context data\n const { events } = page\n const { model } = request.app\n\n if (!model) {\n throw Boom.notFound(`No model found for /${params.path}`)\n }\n\n if (events?.onLoad && events.onLoad.type === 'http') {\n const { options } = events.onLoad\n const { url } = options\n\n // TODO: Update structured data POST payload with when helper\n // is updated to removing the dependency on `SummaryViewModel` etc.\n const viewModel = new SummaryViewModel(request, page, context)\n const items = getFormSubmissionData(\n viewModel.context,\n viewModel.details\n )\n\n // @ts-expect-error - function signature will be refactored in the next iteration of the formatter\n const payload = format(items, model, undefined, undefined)\n\n const { payload: response } = await httpService.postJson(url, {\n payload\n })\n\n Object.assign(context.data, response)\n }\n\n return page.makeGetRouteHandler()(request, context, h)\n })\n }\n\n const postHandler = (\n request: FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { query } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n const { pageDef } = page\n const { isForceAccess } = context\n\n // Redirect to GET for preview URL direct access\n if (isForceAccess && !hasFormComponents(pageDef)) {\n return proceed(request, h, redirectPath(page.href, query))\n }\n\n return page.makePostRouteHandler()(request, context, h)\n })\n }\n\n const dispatchRouteOptions: RouteOptions<FormRequestRefs> = {\n pre: [\n {\n method: loadFormPreHandler\n }\n ]\n }\n\n server.route({\n method: 'get',\n path: '/{slug}',\n handler: dispatchHandler,\n options: {\n ...dispatchRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema\n })\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/preview/{state}/{slug}',\n handler: dispatchHandler,\n options: {\n ...dispatchRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema\n })\n }\n }\n })\n\n const getRouteOptions: RouteOptions<FormRequestRefs> = {\n pre: [\n {\n method: loadFormPreHandler\n }\n ]\n }\n\n server.route({\n method: 'get',\n path: '/{slug}/{path}/{itemId?}',\n handler: getHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n })\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/preview/{state}/{slug}/{path}/{itemId?}',\n handler: getHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n })\n }\n }\n })\n\n const postRouteOptions: RouteOptions<FormRequestPayloadRefs> = {\n payload: {\n parse: true\n },\n pre: [{ method: loadFormPreHandler }]\n }\n\n server.route({\n method: 'post',\n path: '/{slug}/{path}/{itemId?}',\n handler: postHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .unknown(true)\n .required()\n }\n }\n })\n\n server.route({\n method: 'post',\n path: '/preview/{state}/{slug}/{path}/{itemId?}',\n handler: postHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema.optional()\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .unknown(true)\n .required()\n }\n }\n })\n\n /**\n * \"AddAnother\" repeat routes\n */\n\n // List summary GET route\n const getListSummaryHandler = (\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n if (!(page instanceof RepeatPageController)) {\n throw Boom.notFound(`No repeater page found for /${params.path}`)\n }\n\n return page.makeGetListSummaryRouteHandler()(request, context, h)\n })\n }\n\n server.route({\n method: 'get',\n path: '/{slug}/{path}/summary',\n handler: getListSummaryHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema\n })\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/preview/{state}/{slug}/{path}/summary',\n handler: getListSummaryHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema\n })\n }\n }\n })\n\n // List summary POST route\n const postListSummaryHandler = (\n request: FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n const { isForceAccess } = context\n\n if (isForceAccess || !(page instanceof RepeatPageController)) {\n throw Boom.notFound(`No repeater page found for /${params.path}`)\n }\n\n return page.makePostListSummaryRouteHandler()(request, context, h)\n })\n }\n\n server.route({\n method: 'post',\n path: '/{slug}/{path}/summary',\n handler: postListSummaryHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .required()\n }\n }\n })\n\n server.route({\n method: 'post',\n path: '/preview/{state}/{slug}/{path}/summary',\n handler: postListSummaryHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema\n })\n .required()\n }\n }\n })\n\n // Item delete GET route\n const getItemDeleteHandler = (\n request: FormRequest,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n if (\n !(\n page instanceof RepeatPageController ||\n page instanceof FileUploadPageController\n )\n ) {\n throw Boom.notFound(`No page found for /${params.path}`)\n }\n\n return page.makeGetItemDeleteRouteHandler()(request, context, h)\n })\n }\n\n server.route({\n method: 'get',\n path: '/{slug}/{path}/{itemId}/confirm-delete',\n handler: getItemDeleteHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema\n })\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/preview/{state}/{slug}/{path}/{itemId}/confirm-delete',\n handler: getItemDeleteHandler,\n options: {\n ...getRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema\n })\n }\n }\n })\n\n // Item delete POST route\n const postItemDeleteHandler = (\n request: FormRequestPayload,\n h: Pick<ResponseToolkit, 'redirect' | 'view'>\n ) => {\n const { params } = request\n\n return redirectOrMakeHandler(request, h, (page, context) => {\n const { isForceAccess } = context\n\n if (\n isForceAccess ||\n !(\n page instanceof RepeatPageController ||\n page instanceof FileUploadPageController\n )\n ) {\n throw Boom.notFound(`No page found for /${params.path}`)\n }\n\n return page.makePostItemDeleteRouteHandler()(request, context, h)\n })\n }\n\n server.route({\n method: 'post',\n path: '/{slug}/{path}/{itemId}/confirm-delete',\n handler: postItemDeleteHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema,\n confirm: confirmSchema\n })\n .required()\n }\n }\n })\n\n server.route({\n method: 'post',\n path: '/preview/{state}/{slug}/{path}/{itemId}/confirm-delete',\n handler: postItemDeleteHandler,\n options: {\n ...postRouteOptions,\n validate: {\n params: Joi.object().keys({\n state: stateSchema,\n slug: slugSchema,\n path: pathSchema,\n itemId: itemIdSchema\n }),\n payload: Joi.object()\n .keys({\n crumb: crumbSchema,\n action: actionSchema,\n confirm: confirmSchema\n })\n .required()\n }\n }\n })\n\n server.route({\n method: 'get',\n path: '/upload-status/{uploadId}',\n handler: async (request, h) => {\n try {\n const { uploadId } = request.params as { uploadId: string }\n const status = await getUploadStatus(uploadId)\n\n if (!status) {\n return h.response({ error: 'Status check failed' }).code(400)\n }\n\n return h.response(status)\n } catch (error) {\n request.logger.error(\n ['upload-status'],\n 'Upload status check failed',\n error\n )\n return h.response({ error: 'Status check error' }).code(500)\n }\n },\n options: {\n plugins: {\n crumb: false\n },\n validate: {\n params: Joi.object().keys({\n uploadId: Joi.string().guid().required()\n })\n }\n }\n })\n }\n} satisfies Plugin<PluginOptions>\n\ninterface CompileOptions {\n environment: Environment\n}\n\nexport interface EngineConfigurationObject {\n compileOptions: CompileOptions\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":["UploadStatus","FileStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Item,\n type List,\n type Page\n} from '@defra/forms-model'\nimport { type ValidationErrorItem } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport { type FormAction, type FormRequest } from '~/src/server/routes/types.js'\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 FormParams {\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 = FormParams & 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}\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<FormRequest, 'app' | 'method' | 'params' | 'path' | 'query' | 'url'>\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport enum UploadStatus {\n initiated = 'initiated',\n pending = 'pending',\n ready = 'ready'\n}\n\nexport enum FileStatus {\n complete = 'complete',\n rejected = 'rejected',\n pending = 'pending'\n}\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}\n\nexport interface RepeaterSummaryPageViewModel extends PageViewModelBase {\n context: FormContext\n errors?: FormSubmissionError[]\n checkAnswers: CheckAnswers[]\n repeatTitle: string\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"],"mappings":"AAoBA;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;;AAiGA,WAAYA,YAAY,0BAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAA,OAAZA,YAAY;AAAA;AAMxB,WAAYC,UAAU,0BAAVA,UAAU;EAAVA,UAAU;EAAVA,UAAU;EAAVA,UAAU;EAAA,OAAVA,UAAU;AAAA","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"types.js","names":["UploadStatus","FileStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Item,\n type List,\n type Page\n} from '@defra/forms-model'\nimport { type ValidationErrorItem } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport { type FormAction, type FormRequest } from '~/src/server/routes/types.js'\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 FormParams {\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 = FormParams & 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}\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<FormRequest, 'app' | 'method' | 'params' | 'path' | 'query' | 'url'>\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport enum UploadStatus {\n initiated = 'initiated',\n pending = 'pending',\n ready = 'ready'\n}\n\nexport enum FileStatus {\n complete = 'complete',\n rejected = 'rejected',\n pending = 'pending'\n}\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}\n\nexport interface RepeaterSummaryPageViewModel extends PageViewModelBase {\n context: FormContext\n errors?: FormSubmissionError[]\n checkAnswers: CheckAnswers[]\n repeatTitle: string\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 FilterFunction = (value: unknown) => unknown\n"],"mappings":"AAoBA;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;;AAiGA,WAAYA,YAAY,0BAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAA,OAAZA,YAAY;AAAA;AAMxB,WAAYC,UAAU,0BAAVA,UAAU;EAAVA,UAAU;EAAVA,UAAU;EAAVA,UAAU;EAAA,OAAVA,UAAU;AAAA","ignoreList":[]}
|
package/.server/server/{views → plugins/engine/views}/components/service-banner/template.test.js
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { renderMacro } from "
|
|
1
|
+
import { renderMacro } from "../../../../../../../test/helpers/component-helpers.js";
|
|
2
2
|
describe('Service banner component', () => {
|
|
3
3
|
let $component = /** @type {HTMLElement | null} */null;
|
|
4
4
|
let $content = /** @type {HTMLElement | null} */null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.test.js","names":["renderMacro","describe","$component","$content","$text","beforeEach","container","document","params","title","text","getByRole","querySelector","it","expect","toBeInTheDocument","toHaveClass","toContainElement","toHaveAttribute","toHaveAccessibleName","toHaveTextContent"],"sources":["../../../../../../../src/server/plugins/engine/views/components/service-banner/template.test.js"],"sourcesContent":["import { renderMacro } from '~/test/helpers/component-helpers.js'\n\ndescribe('Service banner component', () => {\n let $component = /** @type {HTMLElement | null} */ (null)\n let $content = /** @type {HTMLElement | null} */ (null)\n let $text = /** @type {HTMLElement | null} */ (null)\n\n beforeEach(() => {\n const { container, document } = renderMacro(\n 'appServiceBanner',\n 'components/service-banner/macro.njk',\n {\n params: {\n title: 'Service status',\n text: 'This is a service status message'\n }\n }\n )\n\n $component = container.getByRole('complementary')\n $content = document.querySelector('.app-service-banner__content')\n $text = document.querySelector('.app-service-banner__text')\n })\n\n it('should render contents', () => {\n expect($component).toBeInTheDocument()\n expect($component).toHaveClass('app-service-banner')\n expect($component).toContainElement($content)\n expect($content).toContainElement($text)\n })\n\n it('should announce service message', () => {\n expect($component).toHaveAttribute('aria-live', 'polite')\n })\n\n it('should have accessible name', () => {\n expect($component).toHaveAccessibleName('Service status')\n })\n\n it('should have text content', () => {\n expect($text).toHaveTextContent('This is a service status message')\n })\n})\n"],"mappings":"AAAA,SAASA,WAAW;AAEpBC,QAAQ,CAAC,0BAA0B,EAAE,MAAM;EACzC,IAAIC,UAAU,GAAG,iCAAmC,IAAK;EACzD,IAAIC,QAAQ,GAAG,iCAAmC,IAAK;EACvD,IAAIC,KAAK,GAAG,iCAAmC,IAAK;EAEpDC,UAAU,CAAC,MAAM;IACf,MAAM;MAAEC,SAAS;MAAEC;IAAS,CAAC,GAAGP,WAAW,CACzC,kBAAkB,EAClB,qCAAqC,EACrC;MACEQ,MAAM,EAAE;QACNC,KAAK,EAAE,gBAAgB;QACvBC,IAAI,EAAE;MACR;IACF,CACF,CAAC;IAEDR,UAAU,GAAGI,SAAS,CAACK,SAAS,CAAC,eAAe,CAAC;IACjDR,QAAQ,GAAGI,QAAQ,CAACK,aAAa,CAAC,8BAA8B,CAAC;IACjER,KAAK,GAAGG,QAAQ,CAACK,aAAa,CAAC,2BAA2B,CAAC;EAC7D,CAAC,CAAC;EAEFC,EAAE,CAAC,wBAAwB,EAAE,MAAM;IACjCC,MAAM,CAACZ,UAAU,CAAC,CAACa,iBAAiB,CAAC,CAAC;IACtCD,MAAM,CAACZ,UAAU,CAAC,CAACc,WAAW,CAAC,oBAAoB,CAAC;IACpDF,MAAM,CAACZ,UAAU,CAAC,CAACe,gBAAgB,CAACd,QAAQ,CAAC;IAC7CW,MAAM,CAACX,QAAQ,CAAC,CAACc,gBAAgB,CAACb,KAAK,CAAC;EAC1C,CAAC,CAAC;EAEFS,EAAE,CAAC,iCAAiC,EAAE,MAAM;IAC1CC,MAAM,CAACZ,UAAU,CAAC,CAACgB,eAAe,CAAC,WAAW,EAAE,QAAQ,CAAC;EAC3D,CAAC,CAAC;EAEFL,EAAE,CAAC,6BAA6B,EAAE,MAAM;IACtCC,MAAM,CAACZ,UAAU,CAAC,CAACiB,oBAAoB,CAAC,gBAAgB,CAAC;EAC3D,CAAC,CAAC;EAEFN,EAAE,CAAC,0BAA0B,EAAE,MAAM;IACnCC,MAAM,CAACV,KAAK,CAAC,CAACgB,iBAAiB,CAAC,kCAAkC,CAAC;EACrE,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.test.js","names":["renderMacro","describe","each","text","env","colour","$component","beforeEach","container","params","getByRole","it","expect","toBeInTheDocument","toHaveClass","toHaveTextContent"],"sources":["../../../../../../../src/server/plugins/engine/views/components/tag-env/template.test.js"],"sourcesContent":["import { renderMacro } from '~/test/helpers/component-helpers.js'\n\ndescribe('Tag environment component', () => {\n describe.each([\n {\n text: 'Local',\n env: 'local',\n colour: 'green'\n },\n {\n text: 'Development',\n env: 'dev',\n colour: 'grey'\n },\n {\n text: 'Test',\n env: 'test',\n colour: 'yellow'\n },\n {\n text: 'External test',\n env: 'ext-test',\n colour: 'yellow'\n },\n {\n text: 'Performance test',\n env: 'perf-test',\n colour: 'yellow'\n },\n {\n text: 'Production',\n env: 'prod',\n colour: 'red'\n },\n {\n text: 'Unknown environment',\n env: 'unknown-environment',\n colour: 'grey'\n }\n ])('Environment: $text', ({ text, env, colour }) => {\n let $component = /** @type {HTMLElement | null} */ (null)\n\n beforeEach(() => {\n const { container } = renderMacro(\n 'appTagEnv',\n 'components/tag-env/macro.njk',\n { params: { env } }\n )\n\n $component = container.getByRole('strong')\n })\n\n it('should render contents', () => {\n expect($component).toBeInTheDocument()\n expect($component).toHaveClass('govuk-tag')\n })\n\n it('should have text content', () => {\n expect($component).toHaveTextContent(text)\n })\n\n it('should use environment colour', () => {\n expect($component).toHaveClass(`govuk-tag--${colour}`)\n })\n })\n})\n"],"mappings":"AAAA,SAASA,WAAW;AAEpBC,QAAQ,CAAC,2BAA2B,EAAE,MAAM;EAC1CA,QAAQ,CAACC,IAAI,CAAC,CACZ;IACEC,IAAI,EAAE,OAAO;IACbC,GAAG,EAAE,OAAO;IACZC,MAAM,EAAE;EACV,CAAC,EACD;IACEF,IAAI,EAAE,aAAa;IACnBC,GAAG,EAAE,KAAK;IACVC,MAAM,EAAE;EACV,CAAC,EACD;IACEF,IAAI,EAAE,MAAM;IACZC,GAAG,EAAE,MAAM;IACXC,MAAM,EAAE;EACV,CAAC,EACD;IACEF,IAAI,EAAE,eAAe;IACrBC,GAAG,EAAE,UAAU;IACfC,MAAM,EAAE;EACV,CAAC,EACD;IACEF,IAAI,EAAE,kBAAkB;IACxBC,GAAG,EAAE,WAAW;IAChBC,MAAM,EAAE;EACV,CAAC,EACD;IACEF,IAAI,EAAE,YAAY;IAClBC,GAAG,EAAE,MAAM;IACXC,MAAM,EAAE;EACV,CAAC,EACD;IACEF,IAAI,EAAE,qBAAqB;IAC3BC,GAAG,EAAE,qBAAqB;IAC1BC,MAAM,EAAE;EACV,CAAC,CACF,CAAC,CAAC,oBAAoB,EAAE,CAAC;IAAEF,IAAI;IAAEC,GAAG;IAAEC;EAAO,CAAC,KAAK;IAClD,IAAIC,UAAU,GAAG,iCAAmC,IAAK;IAEzDC,UAAU,CAAC,MAAM;MACf,MAAM;QAAEC;MAAU,CAAC,GAAGR,WAAW,CAC/B,WAAW,EACX,8BAA8B,EAC9B;QAAES,MAAM,EAAE;UAAEL;QAAI;MAAE,CACpB,CAAC;MAEDE,UAAU,GAAGE,SAAS,CAACE,SAAS,CAAC,QAAQ,CAAC;IAC5C,CAAC,CAAC;IAEFC,EAAE,CAAC,wBAAwB,EAAE,MAAM;MACjCC,MAAM,CAACN,UAAU,CAAC,CAACO,iBAAiB,CAAC,CAAC;MACtCD,MAAM,CAACN,UAAU,CAAC,CAACQ,WAAW,CAAC,WAAW,CAAC;IAC7C,CAAC,CAAC;IAEFH,EAAE,CAAC,0BAA0B,EAAE,MAAM;MACnCC,MAAM,CAACN,UAAU,CAAC,CAACS,iBAAiB,CAACZ,IAAI,CAAC;IAC5C,CAAC,CAAC;IAEFQ,EAAE,CAAC,+BAA+B,EAAE,MAAM;MACxCC,MAAM,CAACN,UAAU,CAAC,CAACQ,WAAW,CAAC,cAAcT,MAAM,EAAE,CAAC;IACxD,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
|
|
@@ -11,9 +11,12 @@ export class CacheService {
|
|
|
11
11
|
*/
|
|
12
12
|
cache;
|
|
13
13
|
logger;
|
|
14
|
-
constructor(server) {
|
|
14
|
+
constructor(server, cacheName) {
|
|
15
|
+
if (!cacheName) {
|
|
16
|
+
server.log('warn', 'You are using the default hapi cache. Please provide a cache name in plugin registration options.');
|
|
17
|
+
}
|
|
15
18
|
this.cache = server.cache({
|
|
16
|
-
cache:
|
|
19
|
+
cache: cacheName,
|
|
17
20
|
segment: 'formSubmission'
|
|
18
21
|
});
|
|
19
22
|
this.logger = server.logger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cacheService.js","names":["Hoek","config","partition","ADDITIONAL_IDENTIFIER","CacheService","cache","logger","constructor","server","segment","getState","request","cached","get","Key","setState","state","key","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 Request, 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 FormPayload,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload\n} from '~/src/server/routes/types.js'\n\nconst partition = 'cache'\n\nenum 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: Server) {\n this.cache = server.cache({ cache:
|
|
1
|
+
{"version":3,"file":"cacheService.js","names":["Hoek","config","partition","ADDITIONAL_IDENTIFIER","CacheService","cache","logger","constructor","server","cacheName","log","segment","getState","request","cached","get","Key","setState","state","key","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 Request, 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 FormPayload,\n type FormState,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport {\n type FormRequest,\n type FormRequestPayload\n} from '~/src/server/routes/types.js'\n\nconst partition = 'cache'\n\nenum 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: 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(\n request: Request | FormRequest | FormRequestPayload\n ): Promise<FormSubmissionState> {\n const cached = await this.cache.get(this.Key(request))\n\n return cached || {}\n }\n\n async setState(\n request: FormRequest | FormRequestPayload,\n state: FormSubmissionState\n ) {\n const key = this.Key(request)\n const ttl = config.get('sessionTimeout')\n\n await this.cache.set(key, state, ttl)\n return this.getState(request)\n }\n\n async getConfirmationState(\n request: FormRequest | FormRequestPayload\n ): Promise<{ confirmed?: true }> {\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: FormRequest | FormRequestPayload,\n confirmationState: { confirmed?: true }\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: FormRequest | FormRequestPayload) {\n if (request.yar.id) {\n await this.cache.drop(this.Key(request))\n }\n }\n\n getFlash(\n request: FormRequest | FormRequestPayload\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) as { errors: FormSubmissionError[] }\n }\n }\n\n setFlash(\n request: FormRequest | FormRequestPayload,\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(\n request: Request | FormRequest | FormRequestPayload,\n additionalIdentifier?: ADDITIONAL_IDENTIFIER\n ) {\n if (!request.yar.id) {\n throw Error('No session ID found')\n }\n return {\n segment: partition,\n id: `${request.yar.id}:${request.params.state ?? ''}:${request.params.slug ?? ''}:${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":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.js","names":[],"sources":["../../../src/typings/hapi/index.d.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unified-signatures */\n\nimport { type Plugin } from '@hapi/hapi'\nimport { type ServerYar, type Yar } from '@hapi/yar'\nimport { type Logger } from 'pino'\n\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport {\n type FormRequest,\n type FormRequestPayload\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/index.js'\n\ndeclare module '@hapi/hapi' {\n // Here we are decorating Hapi interface types with\n // props from plugins which doesn't export @types\n interface PluginProperties {\n crumb: {\n generate?: (request: Request | FormRequest | FormRequestPayload) => string\n }\n }\n\n interface PluginsStates {\n blankie?: {\n nonces?: {\n script?: string\n style?: string\n }\n }\n }\n\n interface Request {\n logger: Logger\n yar: Yar\n }\n\n interface RequestApplicationState {\n model?: FormModel\n }\n\n interface Server {\n logger: Logger\n yar: ServerYar\n }\n\n interface ServerApplicationState {\n model?: FormModel\n models: Map<string, { model: FormModel; updatedAt: Date }>\n }\n}\n\ndeclare module '@
|
|
1
|
+
{"version":3,"file":"index.d.js","names":[],"sources":["../../../src/typings/hapi/index.d.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unified-signatures */\n\nimport { type Plugin } from '@hapi/hapi'\nimport { type ServerYar, type Yar } from '@hapi/yar'\nimport { type Logger } from 'pino'\n\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport {\n type FormRequest,\n type FormRequestPayload\n} from '~/src/server/routes/types.js'\nimport { type CacheService } from '~/src/server/services/index.js'\n\ndeclare module '@hapi/hapi' {\n // Here we are decorating Hapi interface types with\n // props from plugins which doesn't export @types\n interface PluginProperties {\n crumb: {\n generate?: (request: Request | FormRequest | FormRequestPayload) => string\n }\n 'forms-engine-plugin': {\n cacheService: CacheService\n }\n }\n\n interface PluginsStates {\n blankie?: {\n nonces?: {\n script?: string\n style?: string\n }\n }\n }\n\n interface Request {\n logger: Logger\n yar: Yar\n }\n\n interface RequestApplicationState {\n model?: FormModel\n }\n\n interface Server {\n logger: Logger\n yar: ServerYar\n }\n\n interface ServerApplicationState {\n model?: FormModel\n models: Map<string, { model: FormModel; updatedAt: Date }>\n }\n}\n\ndeclare module '@hapi/scooter' {\n declare const hapiScooter: {\n plugin: Plugin\n }\n\n export = hapiScooter\n}\n\ndeclare module 'blankie' {\n declare const blankie: {\n plugin: Plugin<Record<string, boolean | string | string[]>>\n }\n\n export = blankie\n}\n\ndeclare module 'blipp' {\n declare const blipp: {\n plugin: Plugin\n }\n\n export = blipp\n}\n\ndeclare module 'hapi-pulse' {\n declare const hapiPulse: {\n plugin: Plugin<{\n timeout: number\n }>\n }\n\n export = hapiPulse\n}\n"],"mappings":"","ignoreList":[]}
|