@defra/forms-engine-plugin 2.1.8 → 2.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js +27 -12
- package/.server/server/plugins/engine/outputFormatters/adapter/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +1 -4
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js +10 -9
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
- package/.server/server/plugins/engine/types/index.d.ts +0 -1
- package/.server/server/plugins/engine/types/index.js.map +1 -1
- package/.server/server/plugins/engine/types/schema.d.ts +2 -1
- package/.server/server/plugins/engine/types/schema.js +13 -2
- package/.server/server/plugins/engine/types/schema.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +24 -3
- package/.server/server/plugins/engine/types.js +4 -0
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/package.json +1 -1
- package/src/server/plugins/engine/outputFormatters/adapter/v1.test.ts +192 -2
- package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +38 -12
- package/src/server/plugins/engine/outputFormatters/machine/v2.test.ts +2 -0
- package/src/server/plugins/engine/outputFormatters/machine/v2.ts +18 -28
- package/src/server/plugins/engine/types/index.ts +0 -2
- package/src/server/plugins/engine/types/schema.test.ts +68 -60
- package/src/server/plugins/engine/types/schema.ts +23 -2
- package/src/server/plugins/engine/types.ts +33 -3
|
@@ -4,20 +4,35 @@ import { FormStatus } from "../../../../routes/types.js";
|
|
|
4
4
|
export function format(context, items, model, submitResponse, formStatus, formMetadata) {
|
|
5
5
|
const v2DataString = machineV2(context, items, model, submitResponse, formStatus);
|
|
6
6
|
const v2DataParsed = JSON.parse(v2DataString);
|
|
7
|
+
const csvFiles = extractCsvFiles(submitResponse);
|
|
8
|
+
const transformedData = v2DataParsed.data;
|
|
9
|
+
const meta = {
|
|
10
|
+
schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
|
|
11
|
+
timestamp: new Date(),
|
|
12
|
+
referenceNumber: context.referenceNumber,
|
|
13
|
+
formName: model.name,
|
|
14
|
+
formId: formMetadata?.id ?? '',
|
|
15
|
+
formSlug: formMetadata?.slug ?? '',
|
|
16
|
+
status: formStatus.isPreview ? FormStatus.Draft : FormStatus.Live,
|
|
17
|
+
isPreview: formStatus.isPreview,
|
|
18
|
+
notificationEmail: formMetadata?.notificationEmail ?? ''
|
|
19
|
+
};
|
|
20
|
+
const data = transformedData;
|
|
21
|
+
const result = {
|
|
22
|
+
files: csvFiles
|
|
23
|
+
};
|
|
7
24
|
const payload = {
|
|
8
|
-
meta
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
referenceNumber: context.referenceNumber,
|
|
12
|
-
formName: model.name,
|
|
13
|
-
formId: formMetadata?.id ?? '',
|
|
14
|
-
formSlug: formMetadata?.slug ?? '',
|
|
15
|
-
status: formStatus.isPreview ? FormStatus.Draft : FormStatus.Live,
|
|
16
|
-
isPreview: formStatus.isPreview,
|
|
17
|
-
notificationEmail: formMetadata?.notificationEmail ?? ''
|
|
18
|
-
},
|
|
19
|
-
data: v2DataParsed.data
|
|
25
|
+
meta,
|
|
26
|
+
data,
|
|
27
|
+
result
|
|
20
28
|
};
|
|
21
29
|
return JSON.stringify(payload);
|
|
22
30
|
}
|
|
31
|
+
function extractCsvFiles(submitResponse) {
|
|
32
|
+
const result = submitResponse.result;
|
|
33
|
+
return {
|
|
34
|
+
main: result.files?.main ?? '',
|
|
35
|
+
repeaters: result.files?.repeaters ?? {}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
23
38
|
//# sourceMappingURL=v1.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"v1.js","names":["format","machineV2","FormAdapterSubmissionSchemaVersion","FormStatus","context","items","model","submitResponse","formStatus","formMetadata","v2DataString","v2DataParsed","JSON","parse","
|
|
1
|
+
{"version":3,"file":"v1.js","names":["format","machineV2","FormAdapterSubmissionSchemaVersion","FormStatus","context","items","model","submitResponse","formStatus","formMetadata","v2DataString","v2DataParsed","JSON","parse","csvFiles","extractCsvFiles","transformedData","data","meta","schemaVersion","V1","timestamp","Date","referenceNumber","formName","name","formId","id","formSlug","slug","status","isPreview","Draft","Live","notificationEmail","result","files","payload","stringify","main","repeaters"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/adapter/v1.ts"],"sourcesContent":["import {\n type FormMetadata,\n type SubmitResponsePayload\n} from '@defra/forms-model'\n\nimport { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'\nimport { type DetailItem } from '~/src/server/plugins/engine/models/types.js'\nimport { format as machineV2 } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload,\n type FormAdapterSubmissionMessageResult,\n type FormContext\n} from '~/src/server/plugins/engine/types.js'\nimport { FormStatus } from '~/src/server/routes/types.js'\n\nexport function format(\n context: FormContext,\n items: DetailItem[],\n model: FormModel,\n submitResponse: SubmitResponsePayload,\n formStatus: ReturnType<typeof checkFormStatus>,\n formMetadata?: FormMetadata\n): string {\n const v2DataString = machineV2(\n context,\n items,\n model,\n submitResponse,\n formStatus\n )\n const v2DataParsed = JSON.parse(v2DataString) as {\n data: FormAdapterSubmissionMessageData\n }\n\n const csvFiles = extractCsvFiles(submitResponse)\n\n const transformedData = v2DataParsed.data\n\n const meta: FormAdapterSubmissionMessageMeta = {\n schemaVersion: FormAdapterSubmissionSchemaVersion.V1,\n timestamp: new Date(),\n referenceNumber: context.referenceNumber,\n formName: model.name,\n formId: formMetadata?.id ?? '',\n formSlug: formMetadata?.slug ?? '',\n status: formStatus.isPreview ? FormStatus.Draft : FormStatus.Live,\n isPreview: formStatus.isPreview,\n notificationEmail: formMetadata?.notificationEmail ?? ''\n }\n const data: FormAdapterSubmissionMessageData = transformedData\n\n const result: FormAdapterSubmissionMessageResult = {\n files: csvFiles\n }\n\n const payload: FormAdapterSubmissionMessagePayload = {\n meta,\n data,\n result\n }\n\n return JSON.stringify(payload)\n}\n\nfunction extractCsvFiles(\n submitResponse: SubmitResponsePayload\n): FormAdapterSubmissionMessageResult['files'] {\n const result =\n submitResponse.result as Partial<FormAdapterSubmissionMessageResult>\n\n return {\n main: result.files?.main ?? '',\n repeaters: result.files?.repeaters ?? {}\n }\n}\n"],"mappings":"AAQA,SAASA,MAAM,IAAIC,SAAS;AAC5B,SAASC,kCAAkC;AAQ3C,SAASC,UAAU;AAEnB,OAAO,SAASH,MAAMA,CACpBI,OAAoB,EACpBC,KAAmB,EACnBC,KAAgB,EAChBC,cAAqC,EACrCC,UAA8C,EAC9CC,YAA2B,EACnB;EACR,MAAMC,YAAY,GAAGT,SAAS,CAC5BG,OAAO,EACPC,KAAK,EACLC,KAAK,EACLC,cAAc,EACdC,UACF,CAAC;EACD,MAAMG,YAAY,GAAGC,IAAI,CAACC,KAAK,CAACH,YAAY,CAE3C;EAED,MAAMI,QAAQ,GAAGC,eAAe,CAACR,cAAc,CAAC;EAEhD,MAAMS,eAAe,GAAGL,YAAY,CAACM,IAAI;EAEzC,MAAMC,IAAsC,GAAG;IAC7CC,aAAa,EAAEjB,kCAAkC,CAACkB,EAAE;IACpDC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC;IACrBC,eAAe,EAAEnB,OAAO,CAACmB,eAAe;IACxCC,QAAQ,EAAElB,KAAK,CAACmB,IAAI;IACpBC,MAAM,EAAEjB,YAAY,EAAEkB,EAAE,IAAI,EAAE;IAC9BC,QAAQ,EAAEnB,YAAY,EAAEoB,IAAI,IAAI,EAAE;IAClCC,MAAM,EAAEtB,UAAU,CAACuB,SAAS,GAAG5B,UAAU,CAAC6B,KAAK,GAAG7B,UAAU,CAAC8B,IAAI;IACjEF,SAAS,EAAEvB,UAAU,CAACuB,SAAS;IAC/BG,iBAAiB,EAAEzB,YAAY,EAAEyB,iBAAiB,IAAI;EACxD,CAAC;EACD,MAAMjB,IAAsC,GAAGD,eAAe;EAE9D,MAAMmB,MAA0C,GAAG;IACjDC,KAAK,EAAEtB;EACT,CAAC;EAED,MAAMuB,OAA4C,GAAG;IACnDnB,IAAI;IACJD,IAAI;IACJkB;EACF,CAAC;EAED,OAAOvB,IAAI,CAAC0B,SAAS,CAACD,OAAO,CAAC;AAChC;AAEA,SAAStB,eAAeA,CACtBR,cAAqC,EACQ;EAC7C,MAAM4B,MAAM,GACV5B,cAAc,CAAC4B,MAAqD;EAEtE,OAAO;IACLI,IAAI,EAAEJ,MAAM,CAACC,KAAK,EAAEG,IAAI,IAAI,EAAE;IAC9BC,SAAS,EAAEL,MAAM,CAACC,KAAK,EAAEI,SAAS,IAAI,CAAC;EACzC,CAAC;AACH","ignoreList":[]}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { type SubmitResponsePayload } from '@defra/forms-model';
|
|
2
|
-
import { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js';
|
|
3
|
-
import { type DatePartsState, type MonthYearState } from '~/src/server/plugins/engine/components/types.js';
|
|
4
2
|
import { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js';
|
|
5
3
|
import { type FormModel } from '~/src/server/plugins/engine/models/index.js';
|
|
6
4
|
import { type DetailItem } from '~/src/server/plugins/engine/models/types.js';
|
|
7
|
-
import { type FormContext
|
|
5
|
+
import { type FormContext } from '~/src/server/plugins/engine/types.js';
|
|
8
6
|
export declare function format(context: FormContext, items: DetailItem[], model: FormModel, _submitResponse: SubmitResponsePayload, _formStatus: ReturnType<typeof checkFormStatus>): string;
|
|
9
|
-
export type RichFormValue = FormValue | FormPayload | DatePartsState | MonthYearState | UkAddressState;
|
|
@@ -38,7 +38,8 @@ export function format(context, items, model, _submitResponse, _formStatus) {
|
|
|
38
38
|
* fileComponentName: [
|
|
39
39
|
* {
|
|
40
40
|
* fileId: '123-456-789',
|
|
41
|
-
*
|
|
41
|
+
* fileName: 'example.pdf',
|
|
42
|
+
* userDownloadLink: 'https://forms-designer/file-download/123-456-789'
|
|
42
43
|
* }
|
|
43
44
|
* ]
|
|
44
45
|
* }
|
|
@@ -93,19 +94,19 @@ function extractRepeaters(item) {
|
|
|
93
94
|
* @returns the file upload data
|
|
94
95
|
*/
|
|
95
96
|
function extractFileUploads(item) {
|
|
96
|
-
const fileUploadState = item.field.
|
|
97
|
-
return fileUploadState.map(
|
|
97
|
+
const fileUploadState = item.field.getFormValueFromState(item.state) ?? [];
|
|
98
|
+
return fileUploadState.map(fileState => {
|
|
99
|
+
const {
|
|
100
|
+
file
|
|
101
|
+
} = fileState.status.form;
|
|
98
102
|
return {
|
|
99
|
-
fileId,
|
|
100
|
-
|
|
103
|
+
fileId: file.fileId,
|
|
104
|
+
fileName: file.filename,
|
|
105
|
+
userDownloadLink: `${designerUrl}/file-download/${file.fileId}`
|
|
101
106
|
};
|
|
102
107
|
});
|
|
103
108
|
}
|
|
104
109
|
function isFileUploadFieldItem(item) {
|
|
105
110
|
return item.field instanceof FileUploadField;
|
|
106
111
|
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* A detail item specifically for files
|
|
110
|
-
*/
|
|
111
112
|
//# sourceMappingURL=v2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"v2.js","names":["config","FileUploadField","designerUrl","get","format","context","items","model","_submitResponse","_formStatus","now","Date","categorisedData","categoriseData","data","meta","schemaVersion","timestamp","toISOString","definition","def","referenceNumber","body","JSON","stringify","output","main","repeaters","files","forEach","item","name","state","extractRepeaters","isFileUploadFieldItem","extractFileUploads","field","getFormValueFromState","subItems","inputRepeaterItem","outputRepeaterItem","repeaterComponent","push","fileUploadState","
|
|
1
|
+
{"version":3,"file":"v2.js","names":["config","FileUploadField","designerUrl","get","format","context","items","model","_submitResponse","_formStatus","now","Date","categorisedData","categoriseData","data","meta","schemaVersion","timestamp","toISOString","definition","def","referenceNumber","body","JSON","stringify","output","main","repeaters","files","forEach","item","name","state","extractRepeaters","isFileUploadFieldItem","extractFileUploads","field","getFormValueFromState","subItems","inputRepeaterItem","outputRepeaterItem","repeaterComponent","push","fileUploadState","map","fileState","file","status","form","fileId","fileName","filename","userDownloadLink"],"sources":["../../../../../../src/server/plugins/engine/outputFormatters/machine/v2.ts"],"sourcesContent":["import { type SubmitResponsePayload } from '@defra/forms-model'\n\nimport { config } from '~/src/config/index.js'\nimport { FileUploadField } from '~/src/server/plugins/engine/components/index.js'\nimport { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport {\n type DetailItem,\n type DetailItemField,\n type DetailItemRepeat\n} from '~/src/server/plugins/engine/models/types.js'\nimport {\n type FileUploadFieldDetailitem,\n type FormAdapterFile,\n type FormContext,\n type RichFormValue\n} from '~/src/server/plugins/engine/types.js'\n\nconst designerUrl = config.get('designerUrl')\n\nexport function format(\n context: FormContext,\n items: DetailItem[],\n model: FormModel,\n _submitResponse: SubmitResponsePayload,\n _formStatus: ReturnType<typeof checkFormStatus>\n) {\n const now = new Date()\n\n const categorisedData = categoriseData(items)\n\n const data = {\n meta: {\n schemaVersion: '2',\n timestamp: now.toISOString(),\n definition: model.def,\n referenceNumber: context.referenceNumber\n },\n data: categorisedData\n }\n\n const body = JSON.stringify(data)\n\n return body\n}\n\n/**\n * Categories the form submission data into the \"main\" body and \"repeaters\".\n *\n * {\n * main: {\n * componentName: 'componentValue',\n * },\n * repeaters: {\n * repeaterName: [\n * {\n * textComponentName: 'componentValue'\n * },\n * {\n * richComponentName: { foo: 'bar', 'baz': true }\n * }\n * ]\n * },\n * files: {\n * fileComponentName: [\n * {\n * fileId: '123-456-789',\n * fileName: 'example.pdf',\n * userDownloadLink: 'https://forms-designer/file-download/123-456-789'\n * }\n * ]\n * }\n * }\n */\nfunction categoriseData(items: DetailItem[]) {\n const output: {\n main: Record<string, RichFormValue>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<\n string,\n { fileId: string; fileName: string; userDownloadLink: string }[]\n >\n } = { main: {}, repeaters: {}, files: {} }\n\n items.forEach((item) => {\n const { name, state } = item\n\n if ('subItems' in item) {\n output.repeaters[name] = extractRepeaters(item)\n } else if (isFileUploadFieldItem(item)) {\n output.files[name] = extractFileUploads(item)\n } else {\n output.main[name] = item.field.getFormValueFromState(state)\n }\n })\n\n return output\n}\n\n/**\n * Returns the \"repeaters\" section of the response body\n * @param item - the repeater item\n * @returns the repeater item\n */\nfunction extractRepeaters(item: DetailItemRepeat) {\n const repeaters: Record<string, RichFormValue>[] = []\n\n item.subItems.forEach((inputRepeaterItem) => {\n const outputRepeaterItem: Record<string, RichFormValue> = {}\n\n inputRepeaterItem.forEach((repeaterComponent) => {\n const { field, state } = repeaterComponent\n\n outputRepeaterItem[repeaterComponent.name] =\n field.getFormValueFromState(state)\n })\n\n repeaters.push(outputRepeaterItem)\n })\n\n return repeaters\n}\n\n/**\n * Returns the \"files\" section of the response body\n * @param item - the file upload item in the form\n * @returns the file upload data\n */\nfunction extractFileUploads(\n item: FileUploadFieldDetailitem\n): FormAdapterFile[] {\n const fileUploadState = item.field.getFormValueFromState(item.state) ?? []\n\n return fileUploadState.map((fileState) => {\n const { file } = fileState.status.form\n return {\n fileId: file.fileId,\n fileName: file.filename,\n userDownloadLink: `${designerUrl}/file-download/${file.fileId}`\n }\n })\n}\n\nfunction isFileUploadFieldItem(\n item: DetailItemField\n): item is FileUploadFieldDetailitem {\n return item.field instanceof FileUploadField\n}\n"],"mappings":"AAEA,SAASA,MAAM;AACf,SAASC,eAAe;AAexB,MAAMC,WAAW,GAAGF,MAAM,CAACG,GAAG,CAAC,aAAa,CAAC;AAE7C,OAAO,SAASC,MAAMA,CACpBC,OAAoB,EACpBC,KAAmB,EACnBC,KAAgB,EAChBC,eAAsC,EACtCC,WAA+C,EAC/C;EACA,MAAMC,GAAG,GAAG,IAAIC,IAAI,CAAC,CAAC;EAEtB,MAAMC,eAAe,GAAGC,cAAc,CAACP,KAAK,CAAC;EAE7C,MAAMQ,IAAI,GAAG;IACXC,IAAI,EAAE;MACJC,aAAa,EAAE,GAAG;MAClBC,SAAS,EAAEP,GAAG,CAACQ,WAAW,CAAC,CAAC;MAC5BC,UAAU,EAAEZ,KAAK,CAACa,GAAG;MACrBC,eAAe,EAAEhB,OAAO,CAACgB;IAC3B,CAAC;IACDP,IAAI,EAAEF;EACR,CAAC;EAED,MAAMU,IAAI,GAAGC,IAAI,CAACC,SAAS,CAACV,IAAI,CAAC;EAEjC,OAAOQ,IAAI;AACb;;AAEA;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,SAAST,cAAcA,CAACP,KAAmB,EAAE;EAC3C,MAAMmB,MAOL,GAAG;IAAEC,IAAI,EAAE,CAAC,CAAC;IAAEC,SAAS,EAAE,CAAC,CAAC;IAAEC,KAAK,EAAE,CAAC;EAAE,CAAC;EAE1CtB,KAAK,CAACuB,OAAO,CAAEC,IAAI,IAAK;IACtB,MAAM;MAAEC,IAAI;MAAEC;IAAM,CAAC,GAAGF,IAAI;IAE5B,IAAI,UAAU,IAAIA,IAAI,EAAE;MACtBL,MAAM,CAACE,SAAS,CAACI,IAAI,CAAC,GAAGE,gBAAgB,CAACH,IAAI,CAAC;IACjD,CAAC,MAAM,IAAII,qBAAqB,CAACJ,IAAI,CAAC,EAAE;MACtCL,MAAM,CAACG,KAAK,CAACG,IAAI,CAAC,GAAGI,kBAAkB,CAACL,IAAI,CAAC;IAC/C,CAAC,MAAM;MACLL,MAAM,CAACC,IAAI,CAACK,IAAI,CAAC,GAAGD,IAAI,CAACM,KAAK,CAACC,qBAAqB,CAACL,KAAK,CAAC;IAC7D;EACF,CAAC,CAAC;EAEF,OAAOP,MAAM;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA,SAASQ,gBAAgBA,CAACH,IAAsB,EAAE;EAChD,MAAMH,SAA0C,GAAG,EAAE;EAErDG,IAAI,CAACQ,QAAQ,CAACT,OAAO,CAAEU,iBAAiB,IAAK;IAC3C,MAAMC,kBAAiD,GAAG,CAAC,CAAC;IAE5DD,iBAAiB,CAACV,OAAO,CAAEY,iBAAiB,IAAK;MAC/C,MAAM;QAAEL,KAAK;QAAEJ;MAAM,CAAC,GAAGS,iBAAiB;MAE1CD,kBAAkB,CAACC,iBAAiB,CAACV,IAAI,CAAC,GACxCK,KAAK,CAACC,qBAAqB,CAACL,KAAK,CAAC;IACtC,CAAC,CAAC;IAEFL,SAAS,CAACe,IAAI,CAACF,kBAAkB,CAAC;EACpC,CAAC,CAAC;EAEF,OAAOb,SAAS;AAClB;;AAEA;AACA;AACA;AACA;AACA;AACA,SAASQ,kBAAkBA,CACzBL,IAA+B,EACZ;EACnB,MAAMa,eAAe,GAAGb,IAAI,CAACM,KAAK,CAACC,qBAAqB,CAACP,IAAI,CAACE,KAAK,CAAC,IAAI,EAAE;EAE1E,OAAOW,eAAe,CAACC,GAAG,CAAEC,SAAS,IAAK;IACxC,MAAM;MAAEC;IAAK,CAAC,GAAGD,SAAS,CAACE,MAAM,CAACC,IAAI;IACtC,OAAO;MACLC,MAAM,EAAEH,IAAI,CAACG,MAAM;MACnBC,QAAQ,EAAEJ,IAAI,CAACK,QAAQ;MACvBC,gBAAgB,EAAE,GAAGlD,WAAW,kBAAkB4C,IAAI,CAACG,MAAM;IAC/D,CAAC;EACH,CAAC,CAAC;AACJ;AAEA,SAASf,qBAAqBA,CAC5BJ,IAAqB,EACc;EACnC,OAAOA,IAAI,CAACM,KAAK,YAAYnC,eAAe;AAC9C","ignoreList":[]}
|
|
@@ -6,6 +6,5 @@ export type { UkAddressState } from '~/src/server/plugins/engine/components/UkAd
|
|
|
6
6
|
export type { FormParams, FormQuery, FormRequest, FormRequestPayload, FormRequestPayloadRefs, FormRequestRefs } from '~/src/server/routes/types.js';
|
|
7
7
|
export { FormAction, FormStatus } from '~/src/server/routes/types.js';
|
|
8
8
|
export type { FormSubmissionService, FormsService, OutputService, RouteConfig, Services } from '~/src/server/types.js';
|
|
9
|
-
export type { RichFormValue } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js';
|
|
10
9
|
export * from '~/src/server/plugins/engine/types/schema.js';
|
|
11
10
|
export { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["FileStatus","UploadStatus","FormAction","FormStatus","FormAdapterSubmissionSchemaVersion"],"sources":["../../../../../src/server/plugins/engine/types/index.ts"],"sourcesContent":["export type {\n CheckAnswers,\n ErrorMessageTemplate,\n ErrorMessageTemplateList,\n FeaturedFormPageViewModel,\n FileState,\n FilterFunction,\n FormAdapterSubmissionMessage,\n FormAdapterSubmissionMessageData,\n FormAdapterSubmissionMessageMeta,\n FormAdapterSubmissionMessageMetaSerialised,\n FormAdapterSubmissionMessagePayload,\n FormAdapterSubmissionService,\n FormContext,\n FormContextRequest,\n FormPageViewModel,\n FormPayload,\n FormPayloadParams,\n FormState,\n FormStateValue,\n FormSubmissionError,\n FormSubmissionState,\n FormValidationResult,\n FormValue,\n GlobalFunction,\n ItemDeletePageViewModel,\n OnRequestCallback,\n PageViewModel,\n PageViewModelBase,\n PluginOptions,\n PreparePageEventRequestOptions,\n RepeatItemState,\n RepeatListState,\n RepeaterSummaryPageViewModel,\n SummaryList,\n SummaryListAction,\n SummaryListRow,\n TempFileState,\n UploadInitiateResponse,\n UploadStatusFileResponse,\n UploadStatusResponse\n} from '~/src/server/plugins/engine/types.js'\n\nexport { FileStatus, UploadStatus } from '~/src/server/plugins/engine/types.js'\n\nexport type {\n Detail,\n DetailItem,\n DetailItemBase,\n DetailItemField,\n DetailItemRepeat,\n ExecutableCondition\n} from '~/src/server/plugins/engine/models/types.js'\n\nexport type {\n BackLink,\n ComponentText,\n ComponentViewModel,\n Content,\n DateInputItem,\n DatePartsState,\n Label,\n ListItem,\n ListItemLabel,\n MonthYearState,\n ViewModel\n} from '~/src/server/plugins/engine/components/types.js'\n\nexport type { UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\n\nexport type {\n FormParams,\n FormQuery,\n FormRequest,\n FormRequestPayload,\n FormRequestPayloadRefs,\n FormRequestRefs\n} from '~/src/server/routes/types.js'\n\nexport { FormAction, FormStatus } from '~/src/server/routes/types.js'\n\nexport type {\n FormSubmissionService,\n FormsService,\n OutputService,\n RouteConfig,\n Services\n} from '~/src/server/types.js'\n\nexport
|
|
1
|
+
{"version":3,"file":"index.js","names":["FileStatus","UploadStatus","FormAction","FormStatus","FormAdapterSubmissionSchemaVersion"],"sources":["../../../../../src/server/plugins/engine/types/index.ts"],"sourcesContent":["export type {\n CheckAnswers,\n ErrorMessageTemplate,\n ErrorMessageTemplateList,\n FeaturedFormPageViewModel,\n FileState,\n FilterFunction,\n FormAdapterSubmissionMessage,\n FormAdapterSubmissionMessageData,\n FormAdapterSubmissionMessageMeta,\n FormAdapterSubmissionMessageMetaSerialised,\n FormAdapterSubmissionMessagePayload,\n FormAdapterSubmissionService,\n FormContext,\n FormContextRequest,\n FormPageViewModel,\n FormPayload,\n FormPayloadParams,\n FormState,\n FormStateValue,\n FormSubmissionError,\n FormSubmissionState,\n FormValidationResult,\n FormValue,\n GlobalFunction,\n ItemDeletePageViewModel,\n OnRequestCallback,\n PageViewModel,\n PageViewModelBase,\n PluginOptions,\n PreparePageEventRequestOptions,\n RepeatItemState,\n RepeatListState,\n RepeaterSummaryPageViewModel,\n SummaryList,\n SummaryListAction,\n SummaryListRow,\n TempFileState,\n UploadInitiateResponse,\n UploadStatusFileResponse,\n UploadStatusResponse\n} from '~/src/server/plugins/engine/types.js'\n\nexport { FileStatus, UploadStatus } from '~/src/server/plugins/engine/types.js'\n\nexport type {\n Detail,\n DetailItem,\n DetailItemBase,\n DetailItemField,\n DetailItemRepeat,\n ExecutableCondition\n} from '~/src/server/plugins/engine/models/types.js'\n\nexport type {\n BackLink,\n ComponentText,\n ComponentViewModel,\n Content,\n DateInputItem,\n DatePartsState,\n Label,\n ListItem,\n ListItemLabel,\n MonthYearState,\n ViewModel\n} from '~/src/server/plugins/engine/components/types.js'\n\nexport type { UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\n\nexport type {\n FormParams,\n FormQuery,\n FormRequest,\n FormRequestPayload,\n FormRequestPayloadRefs,\n FormRequestRefs\n} from '~/src/server/routes/types.js'\n\nexport { FormAction, FormStatus } from '~/src/server/routes/types.js'\n\nexport type {\n FormSubmissionService,\n FormsService,\n OutputService,\n RouteConfig,\n Services\n} from '~/src/server/types.js'\n\nexport * from '~/src/server/plugins/engine/types/schema.js'\nexport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\n"],"mappings":"AA2CA,SAASA,UAAU,EAAEC,YAAY;AAoCjC,SAASC,UAAU,EAAEC,UAAU;AAU/B;AACA,SAASC,kCAAkC","ignoreList":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Joi from 'joi';
|
|
2
|
-
import { type FormAdapterSubmissionMessageData, type FormAdapterSubmissionMessageMeta, type FormAdapterSubmissionMessagePayload } from '~/src/server/plugins/engine/types.js';
|
|
2
|
+
import { type FormAdapterSubmissionMessageData, type FormAdapterSubmissionMessageMeta, type FormAdapterSubmissionMessagePayload, type FormAdapterSubmissionMessageResult } from '~/src/server/plugins/engine/types.js';
|
|
3
3
|
export declare const formAdapterSubmissionMessageMetaSchema: Joi.ObjectSchema<FormAdapterSubmissionMessageMeta>;
|
|
4
4
|
export declare const formAdapterSubmissionMessageDataSchema: Joi.ObjectSchema<FormAdapterSubmissionMessageData>;
|
|
5
|
+
export declare const formAdapterSubmissionMessageResultSchema: Joi.ObjectSchema<FormAdapterSubmissionMessageResult>;
|
|
5
6
|
export declare const formAdapterSubmissionMessagePayloadSchema: Joi.ObjectSchema<FormAdapterSubmissionMessagePayload>;
|
|
@@ -15,10 +15,21 @@ export const formAdapterSubmissionMessageMetaSchema = Joi.object().keys({
|
|
|
15
15
|
export const formAdapterSubmissionMessageDataSchema = Joi.object().keys({
|
|
16
16
|
main: Joi.object(),
|
|
17
17
|
repeaters: Joi.object(),
|
|
18
|
-
files: Joi.object()
|
|
18
|
+
files: Joi.object().pattern(Joi.string(), Joi.array().items(Joi.object().keys({
|
|
19
|
+
fileName: Joi.string().required(),
|
|
20
|
+
fileId: Joi.string().required(),
|
|
21
|
+
userDownloadLink: Joi.string().required()
|
|
22
|
+
})))
|
|
23
|
+
});
|
|
24
|
+
export const formAdapterSubmissionMessageResultSchema = Joi.object().keys({
|
|
25
|
+
files: Joi.object().keys({
|
|
26
|
+
main: Joi.string().required(),
|
|
27
|
+
repeaters: Joi.object()
|
|
28
|
+
}).required()
|
|
19
29
|
});
|
|
20
30
|
export const formAdapterSubmissionMessagePayloadSchema = Joi.object().keys({
|
|
21
31
|
meta: formAdapterSubmissionMessageMetaSchema.required(),
|
|
22
|
-
data: formAdapterSubmissionMessageDataSchema.required()
|
|
32
|
+
data: formAdapterSubmissionMessageDataSchema.required(),
|
|
33
|
+
result: formAdapterSubmissionMessageResultSchema.required()
|
|
23
34
|
});
|
|
24
35
|
//# sourceMappingURL=schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":["FormStatus","idSchema","notificationEmailAddressSchema","slugSchema","titleSchema","Joi","FormAdapterSubmissionSchemaVersion","formAdapterSubmissionMessageMetaSchema","object","keys","schemaVersion","string","valid","Object","values","timestamp","date","required","referenceNumber","formName","formId","formSlug","status","isPreview","boolean","notificationEmail","formAdapterSubmissionMessageDataSchema","main","repeaters","files","formAdapterSubmissionMessagePayloadSchema","meta","data"],"sources":["../../../../../src/server/plugins/engine/types/schema.ts"],"sourcesContent":["import {\n FormStatus,\n idSchema,\n notificationEmailAddressSchema,\n slugSchema,\n titleSchema\n} from '@defra/forms-model'\nimport Joi from 'joi'\n\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload\n} from '~/src/server/plugins/engine/types.js'\n\nexport const formAdapterSubmissionMessageMetaSchema =\n Joi.object<FormAdapterSubmissionMessageMeta>().keys({\n schemaVersion: Joi.string().valid(\n ...Object.values(FormAdapterSubmissionSchemaVersion)\n ),\n timestamp: Joi.date().required(),\n referenceNumber: Joi.string().required(),\n formName: titleSchema,\n formId: idSchema,\n formSlug: slugSchema,\n status: Joi.string()\n .valid(...Object.values(FormStatus))\n .required(),\n isPreview: Joi.boolean().required(),\n notificationEmail: notificationEmailAddressSchema.required()\n })\n\nexport const formAdapterSubmissionMessageDataSchema =\n Joi.object<FormAdapterSubmissionMessageData>().keys({\n main: Joi.object(),\n repeaters: Joi.object(),\n files: Joi.object()\n })\n\nexport const formAdapterSubmissionMessagePayloadSchema =\n Joi.object<FormAdapterSubmissionMessagePayload>().keys({\n meta: formAdapterSubmissionMessageMetaSchema.required(),\n data: formAdapterSubmissionMessageDataSchema.required()\n })\n"],"mappings":"AAAA,SACEA,UAAU,EACVC,QAAQ,EACRC,8BAA8B,EAC9BC,UAAU,EACVC,WAAW,QACN,oBAAoB;AAC3B,OAAOC,GAAG,MAAM,KAAK;AAErB,SAASC,kCAAkC;
|
|
1
|
+
{"version":3,"file":"schema.js","names":["FormStatus","idSchema","notificationEmailAddressSchema","slugSchema","titleSchema","Joi","FormAdapterSubmissionSchemaVersion","formAdapterSubmissionMessageMetaSchema","object","keys","schemaVersion","string","valid","Object","values","timestamp","date","required","referenceNumber","formName","formId","formSlug","status","isPreview","boolean","notificationEmail","formAdapterSubmissionMessageDataSchema","main","repeaters","files","pattern","array","items","fileName","fileId","userDownloadLink","formAdapterSubmissionMessageResultSchema","formAdapterSubmissionMessagePayloadSchema","meta","data","result"],"sources":["../../../../../src/server/plugins/engine/types/schema.ts"],"sourcesContent":["import {\n FormStatus,\n idSchema,\n notificationEmailAddressSchema,\n slugSchema,\n titleSchema\n} from '@defra/forms-model'\nimport Joi from 'joi'\n\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload,\n type FormAdapterSubmissionMessageResult\n} from '~/src/server/plugins/engine/types.js'\n\nexport const formAdapterSubmissionMessageMetaSchema =\n Joi.object<FormAdapterSubmissionMessageMeta>().keys({\n schemaVersion: Joi.string().valid(\n ...Object.values(FormAdapterSubmissionSchemaVersion)\n ),\n timestamp: Joi.date().required(),\n referenceNumber: Joi.string().required(),\n formName: titleSchema,\n formId: idSchema,\n formSlug: slugSchema,\n status: Joi.string()\n .valid(...Object.values(FormStatus))\n .required(),\n isPreview: Joi.boolean().required(),\n notificationEmail: notificationEmailAddressSchema.required()\n })\n\nexport const formAdapterSubmissionMessageDataSchema =\n Joi.object<FormAdapterSubmissionMessageData>().keys({\n main: Joi.object(),\n repeaters: Joi.object(),\n files: Joi.object().pattern(\n Joi.string(),\n Joi.array().items(\n Joi.object().keys({\n fileName: Joi.string().required(),\n fileId: Joi.string().required(),\n userDownloadLink: Joi.string().required()\n })\n )\n )\n })\n\nexport const formAdapterSubmissionMessageResultSchema =\n Joi.object<FormAdapterSubmissionMessageResult>().keys({\n files: Joi.object()\n .keys({\n main: Joi.string().required(),\n repeaters: Joi.object()\n })\n .required()\n })\n\nexport const formAdapterSubmissionMessagePayloadSchema =\n Joi.object<FormAdapterSubmissionMessagePayload>().keys({\n meta: formAdapterSubmissionMessageMetaSchema.required(),\n data: formAdapterSubmissionMessageDataSchema.required(),\n result: formAdapterSubmissionMessageResultSchema.required()\n })\n"],"mappings":"AAAA,SACEA,UAAU,EACVC,QAAQ,EACRC,8BAA8B,EAC9BC,UAAU,EACVC,WAAW,QACN,oBAAoB;AAC3B,OAAOC,GAAG,MAAM,KAAK;AAErB,SAASC,kCAAkC;AAQ3C,OAAO,MAAMC,sCAAsC,GACjDF,GAAG,CAACG,MAAM,CAAmC,CAAC,CAACC,IAAI,CAAC;EAClDC,aAAa,EAAEL,GAAG,CAACM,MAAM,CAAC,CAAC,CAACC,KAAK,CAC/B,GAAGC,MAAM,CAACC,MAAM,CAACR,kCAAkC,CACrD,CAAC;EACDS,SAAS,EAAEV,GAAG,CAACW,IAAI,CAAC,CAAC,CAACC,QAAQ,CAAC,CAAC;EAChCC,eAAe,EAAEb,GAAG,CAACM,MAAM,CAAC,CAAC,CAACM,QAAQ,CAAC,CAAC;EACxCE,QAAQ,EAAEf,WAAW;EACrBgB,MAAM,EAAEnB,QAAQ;EAChBoB,QAAQ,EAAElB,UAAU;EACpBmB,MAAM,EAAEjB,GAAG,CAACM,MAAM,CAAC,CAAC,CACjBC,KAAK,CAAC,GAAGC,MAAM,CAACC,MAAM,CAACd,UAAU,CAAC,CAAC,CACnCiB,QAAQ,CAAC,CAAC;EACbM,SAAS,EAAElB,GAAG,CAACmB,OAAO,CAAC,CAAC,CAACP,QAAQ,CAAC,CAAC;EACnCQ,iBAAiB,EAAEvB,8BAA8B,CAACe,QAAQ,CAAC;AAC7D,CAAC,CAAC;AAEJ,OAAO,MAAMS,sCAAsC,GACjDrB,GAAG,CAACG,MAAM,CAAmC,CAAC,CAACC,IAAI,CAAC;EAClDkB,IAAI,EAAEtB,GAAG,CAACG,MAAM,CAAC,CAAC;EAClBoB,SAAS,EAAEvB,GAAG,CAACG,MAAM,CAAC,CAAC;EACvBqB,KAAK,EAAExB,GAAG,CAACG,MAAM,CAAC,CAAC,CAACsB,OAAO,CACzBzB,GAAG,CAACM,MAAM,CAAC,CAAC,EACZN,GAAG,CAAC0B,KAAK,CAAC,CAAC,CAACC,KAAK,CACf3B,GAAG,CAACG,MAAM,CAAC,CAAC,CAACC,IAAI,CAAC;IAChBwB,QAAQ,EAAE5B,GAAG,CAACM,MAAM,CAAC,CAAC,CAACM,QAAQ,CAAC,CAAC;IACjCiB,MAAM,EAAE7B,GAAG,CAACM,MAAM,CAAC,CAAC,CAACM,QAAQ,CAAC,CAAC;IAC/BkB,gBAAgB,EAAE9B,GAAG,CAACM,MAAM,CAAC,CAAC,CAACM,QAAQ,CAAC;EAC1C,CAAC,CACH,CACF;AACF,CAAC,CAAC;AAEJ,OAAO,MAAMmB,wCAAwC,GACnD/B,GAAG,CAACG,MAAM,CAAqC,CAAC,CAACC,IAAI,CAAC;EACpDoB,KAAK,EAAExB,GAAG,CAACG,MAAM,CAAC,CAAC,CAChBC,IAAI,CAAC;IACJkB,IAAI,EAAEtB,GAAG,CAACM,MAAM,CAAC,CAAC,CAACM,QAAQ,CAAC,CAAC;IAC7BW,SAAS,EAAEvB,GAAG,CAACG,MAAM,CAAC;EACxB,CAAC,CAAC,CACDS,QAAQ,CAAC;AACd,CAAC,CAAC;AAEJ,OAAO,MAAMoB,yCAAyC,GACpDhC,GAAG,CAACG,MAAM,CAAsC,CAAC,CAACC,IAAI,CAAC;EACrD6B,IAAI,EAAE/B,sCAAsC,CAACU,QAAQ,CAAC,CAAC;EACvDsB,IAAI,EAAEb,sCAAsC,CAACT,QAAQ,CAAC,CAAC;EACvDuB,MAAM,EAAEJ,wCAAwC,CAACnB,QAAQ,CAAC;AAC5D,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { type ComponentDef, type Event, type FormDefinition, type FormMetadata, type Item, type List, type Page } from '@defra/forms-model';
|
|
2
2
|
import { type PluginProperties, type Request } from '@hapi/hapi';
|
|
3
3
|
import { type JoiExpression, type ValidationErrorItem } from 'joi';
|
|
4
|
+
import { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js';
|
|
4
5
|
import { type Component } from '~/src/server/plugins/engine/components/helpers/components.js';
|
|
5
|
-
import { type
|
|
6
|
+
import { type FileUploadField } from '~/src/server/plugins/engine/components/index.js';
|
|
7
|
+
import { type BackLink, type ComponentText, type ComponentViewModel, type DatePartsState, type MonthYearState } from '~/src/server/plugins/engine/components/types.js';
|
|
6
8
|
import { type FormModel } from '~/src/server/plugins/engine/models/index.js';
|
|
7
|
-
import { type
|
|
9
|
+
import { type DetailItemField } from '~/src/server/plugins/engine/models/types.js';
|
|
8
10
|
import { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js';
|
|
9
11
|
import { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js';
|
|
10
12
|
import { type FileStatus, type FormAdapterSubmissionSchemaVersion, type UploadStatus } from '~/src/server/plugins/engine/types/enums.js';
|
|
@@ -294,14 +296,33 @@ export type FormAdapterSubmissionMessageMetaSerialised = Omit<FormAdapterSubmiss
|
|
|
294
296
|
status: string;
|
|
295
297
|
timestamp: string;
|
|
296
298
|
};
|
|
299
|
+
export interface FormAdapterFile {
|
|
300
|
+
fileName: string;
|
|
301
|
+
fileId: string;
|
|
302
|
+
userDownloadLink: string;
|
|
303
|
+
}
|
|
304
|
+
export interface FormAdapterSubmissionMessageResult {
|
|
305
|
+
files: {
|
|
306
|
+
main: string;
|
|
307
|
+
repeaters: Record<string, string>;
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* A detail item specifically for files
|
|
312
|
+
*/
|
|
313
|
+
export type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {
|
|
314
|
+
field: FileUploadField;
|
|
315
|
+
};
|
|
316
|
+
export type RichFormValue = FormValue | FormPayload | DatePartsState | MonthYearState | UkAddressState;
|
|
297
317
|
export interface FormAdapterSubmissionMessageData {
|
|
298
318
|
main: Record<string, RichFormValue>;
|
|
299
319
|
repeaters: Record<string, Record<string, RichFormValue>[]>;
|
|
300
|
-
files: Record<string,
|
|
320
|
+
files: Record<string, FormAdapterFile[]>;
|
|
301
321
|
}
|
|
302
322
|
export interface FormAdapterSubmissionMessagePayload {
|
|
303
323
|
meta: FormAdapterSubmissionMessageMeta;
|
|
304
324
|
data: FormAdapterSubmissionMessageData;
|
|
325
|
+
result: FormAdapterSubmissionMessageResult;
|
|
305
326
|
}
|
|
306
327
|
export interface FormAdapterSubmissionMessage extends FormAdapterSubmissionMessagePayload {
|
|
307
328
|
messageId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":["FileStatus","UploadStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Event,\n type FormDefinition,\n type FormMetadata,\n type Item,\n type List,\n type Page\n} from '@defra/forms-model'\nimport { type PluginProperties, type Request } from '@hapi/hapi'\nimport { type JoiExpression, 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/components.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type RichFormValue } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport {\n type FileStatus,\n type FormAdapterSubmissionSchemaVersion,\n type UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport {\n type FormAction,\n type FormParams,\n type FormRequest,\n type FormRequestPayload,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type RequestOptions } from '~/src/server/services/httpService.js'\nimport { type Services } from '~/src/server/types.js'\n\ntype RequestType = Request | FormRequest | FormRequestPayload\n\n/**\n * Form submission state stores the following in Redis:\n * Props containing user's submitted values as `{ [inputId]: value }` or as `{ [sectionName]: { [inputName]: value } }`\n * a) . e.g:\n * ```ts\n * {\n * _C9PRHmsgt: 'Ben',\n * WfLk9McjzX: 'Music',\n * IK7jkUFCBL: 'Royal Academy of Music'\n * }\n * ```\n *\n * b)\n * ```ts\n * {\n * checkBeforeYouStart: { ukPassport: true },\n * applicantDetails: {\n * numberOfApplicants: 1,\n * phoneNumber: '77777777',\n * emailAddress: 'aaa@aaa.com'\n * },\n * applicantOneDetails: {\n * firstName: 'a',\n * middleName: 'a',\n * lastName: 'a',\n * address: { addressLine1: 'a', addressLine2: 'a', town: 'a', postcode: 'a' }\n * }\n * }\n * ```\n */\n\n/**\n * Form submission state\n */\nexport type FormSubmissionState = {\n upload?: Record<string, TempFileState>\n} & FormState\n\nexport interface FormSubmissionError\n extends Pick<ValidationErrorItem, 'context' | 'path'> {\n href: string // e.g: '#dateField__day'\n name: string // e.g: 'dateField__day'\n text: string // e.g: 'Date field must be a real date'\n}\n\nexport interface FormPayloadParams {\n action?: FormAction\n confirm?: true\n crumb?: string\n itemId?: string\n}\n\n/**\n * Form POST for question pages\n * (after Joi has converted value types)\n */\nexport type FormPayload = FormPayloadParams & Partial<Record<string, FormValue>>\n\nexport type FormValue =\n | Item['value']\n | Item['value'][]\n | UploadState\n | RepeatListState\n | undefined\n\nexport type FormState = Partial<Record<string, FormStateValue>>\nexport type FormStateValue = Exclude<FormValue, undefined> | null\n\nexport interface FormValidationResult<\n ValueType extends FormPayload | FormSubmissionState\n> {\n value: ValueType\n errors: FormSubmissionError[] | undefined\n}\n\nexport interface FormContext {\n /**\n * Evaluation form state only (filtered by visited paths),\n * with values formatted for condition evaluation using\n * {@link FormComponent.getContextValueFromState}\n */\n evaluationState: FormState\n\n /**\n * Relevant form state only (filtered by visited paths)\n */\n relevantState: FormState\n\n /**\n * Relevant pages only (filtered by visited paths)\n */\n relevantPages: PageControllerClass[]\n\n /**\n * Form submission payload (single page)\n */\n payload: FormPayload\n\n /**\n * Form submission state (entire form)\n */\n state: FormSubmissionState\n\n /**\n * Validation errors (entire form)\n */\n errors?: FormSubmissionError[]\n\n /**\n * Visited paths evaluated from form state\n */\n paths: string[]\n\n /**\n * Preview URL direct access is allowed\n */\n isForceAccess: boolean\n\n /**\n * Miscellaneous extra data from event responses\n */\n data: object\n\n pageDefMap: Map<string, Page>\n listDefMap: Map<string, List>\n componentDefMap: Map<string, ComponentDef>\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n referenceNumber: string\n}\n\nexport type FormContextRequest = (\n | {\n method: 'get'\n payload?: undefined\n }\n | {\n method: 'post'\n payload: FormPayload\n }\n | {\n method: FormRequest['method']\n payload?: object | undefined\n }\n) &\n Pick<\n FormRequest,\n 'app' | 'method' | 'params' | 'path' | 'query' | 'url' | 'server'\n >\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport {\n FileStatus,\n UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\n\nexport type UploadState = FileState[]\n\nexport type FileUpload = {\n fileId: string\n filename: string\n contentLength: number\n} & (\n | {\n fileStatus: FileStatus.complete | FileStatus.rejected | FileStatus.pending\n errorMessage?: string\n }\n | {\n fileStatus: FileStatus.complete\n errorMessage?: undefined\n }\n)\n\nexport interface FileUploadMetadata {\n retrievalKey: string\n}\n\nexport type UploadStatusResponse =\n | {\n uploadStatus: UploadStatus.initiated\n metadata: FileUploadMetadata\n form: { file?: undefined }\n }\n | {\n uploadStatus: UploadStatus.pending | UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles?: number\n }\n | {\n uploadStatus: UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles: 0\n }\n\nexport type UploadStatusFileResponse = Exclude<\n UploadStatusResponse,\n { uploadStatus: UploadStatus.initiated }\n>\n\nexport interface FileState {\n uploadId: string\n status: UploadStatusFileResponse\n}\n\nexport interface TempFileState {\n upload?: UploadInitiateResponse\n files: UploadState\n}\n\nexport interface RepeatItemState extends FormPayload {\n itemId: string\n}\n\nexport type RepeatListState = RepeatItemState[]\n\nexport interface CheckAnswers {\n title?: ComponentText\n summaryList: SummaryList\n}\n\nexport interface SummaryList {\n classes?: string\n rows: SummaryListRow[]\n}\n\nexport interface SummaryListRow {\n key: ComponentText\n value: ComponentText\n actions?: { items: SummaryListAction[] }\n}\n\nexport type SummaryListAction = ComponentText & {\n href: string\n visuallyHiddenText: string\n}\n\nexport interface PageViewModelBase extends Partial<ViewContext> {\n page: PageController\n name?: string\n pageTitle: string\n sectionTitle?: string\n showTitle: boolean\n isStartPage: boolean\n backLink?: BackLink\n feedbackLink?: string\n serviceUrl: string\n phaseTag?: string\n}\n\nexport interface ItemDeletePageViewModel extends PageViewModelBase {\n context: FormContext\n itemTitle: string\n confirmation?: ComponentText\n buttonConfirm: ComponentText\n buttonCancel: ComponentText\n}\n\nexport interface FormPageViewModel extends PageViewModelBase {\n components: ComponentViewModel[]\n context: FormContext\n errors?: FormSubmissionError[]\n hasMissingNotificationEmail?: boolean\n allowSaveAndReturn: 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 GlobalFunction = (value: unknown) => unknown\nexport type FilterFunction = (value: unknown) => unknown\nexport interface ErrorMessageTemplate {\n type: string\n template: JoiExpression\n}\n\nexport interface ErrorMessageTemplateList {\n baseErrors: ErrorMessageTemplate[]\n advancedSettingsErrors: ErrorMessageTemplate[]\n}\n\nexport type PreparePageEventRequestOptions = (\n options: RequestOptions,\n event: Event,\n page: PageControllerClass,\n context: FormContext\n) => void\n\nexport type OnRequestCallback = (\n request: FormRequest | FormRequestPayload,\n params: FormParams,\n definition: FormDefinition,\n metadata: FormMetadata\n) => void\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n cacheName?: string\n globals?: Record<string, GlobalFunction>\n filters?: Record<string, FilterFunction>\n saveAndReturn?: {\n keyGenerator: (request: RequestType) => string\n sessionHydrator: (request: RequestType) => Promise<FormSubmissionState>\n sessionPersister: (\n state: FormSubmissionState,\n request: RequestType\n ) => Promise<void>\n }\n pluginPath?: string\n nunjucks: {\n baseLayoutPath: string\n paths: string[]\n }\n viewContext: PluginProperties['forms-engine-plugin']['viewContext']\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n baseUrl: string // base URL of the application, protocol and hostname e.g. \"https://myapp.com\"\n}\n\nexport interface FormAdapterSubmissionMessageMeta {\n schemaVersion: FormAdapterSubmissionSchemaVersion\n timestamp: Date\n referenceNumber: string\n formName: string\n formId: string\n formSlug: string\n status: FormStatus\n isPreview: boolean\n notificationEmail: string\n}\n\nexport type FormAdapterSubmissionMessageMetaSerialised = Omit<\n FormAdapterSubmissionMessageMeta,\n 'schemaVersion' | 'timestamp' | 'status'\n> & {\n schemaVersion: number\n status: string\n timestamp: string\n}\n\nexport interface FormAdapterSubmissionMessageData {\n main: Record<string, RichFormValue>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<string, Record<string, string>[]>\n}\n\nexport interface FormAdapterSubmissionMessagePayload {\n meta: FormAdapterSubmissionMessageMeta\n data: FormAdapterSubmissionMessageData\n}\n\nexport interface FormAdapterSubmissionMessage\n extends FormAdapterSubmissionMessagePayload {\n messageId: string\n recordCreatedAt: Date\n}\n\nexport interface FormAdapterSubmissionService {\n handleFormSubmission: (\n submissionMessage: FormAdapterSubmissionMessage\n ) => unknown\n}\n"],"mappings":"AAyCA;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;;AAqGA,SACEA,UAAU,EACVC,YAAY","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"types.js","names":["FileStatus","UploadStatus"],"sources":["../../../../src/server/plugins/engine/types.ts"],"sourcesContent":["import {\n type ComponentDef,\n type Event,\n type FormDefinition,\n type FormMetadata,\n type Item,\n type List,\n type Page\n} from '@defra/forms-model'\nimport { type PluginProperties, type Request } from '@hapi/hapi'\nimport { type JoiExpression, type ValidationErrorItem } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'\nimport { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'\nimport { type FileUploadField } from '~/src/server/plugins/engine/components/index.js'\nimport {\n type BackLink,\n type ComponentText,\n type ComponentViewModel,\n type DatePartsState,\n type MonthYearState\n} from '~/src/server/plugins/engine/components/types.js'\nimport { type FormModel } from '~/src/server/plugins/engine/models/index.js'\nimport { type DetailItemField } from '~/src/server/plugins/engine/models/types.js'\nimport { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'\nimport { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'\nimport {\n type FileStatus,\n type FormAdapterSubmissionSchemaVersion,\n type UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\nimport { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'\nimport {\n type FormAction,\n type FormParams,\n type FormRequest,\n type FormRequestPayload,\n type FormStatus\n} from '~/src/server/routes/types.js'\nimport { type RequestOptions } from '~/src/server/services/httpService.js'\nimport { type Services } from '~/src/server/types.js'\n\ntype RequestType = Request | FormRequest | FormRequestPayload\n\n/**\n * Form submission state stores the following in Redis:\n * Props containing user's submitted values as `{ [inputId]: value }` or as `{ [sectionName]: { [inputName]: value } }`\n * a) . e.g:\n * ```ts\n * {\n * _C9PRHmsgt: 'Ben',\n * WfLk9McjzX: 'Music',\n * IK7jkUFCBL: 'Royal Academy of Music'\n * }\n * ```\n *\n * b)\n * ```ts\n * {\n * checkBeforeYouStart: { ukPassport: true },\n * applicantDetails: {\n * numberOfApplicants: 1,\n * phoneNumber: '77777777',\n * emailAddress: 'aaa@aaa.com'\n * },\n * applicantOneDetails: {\n * firstName: 'a',\n * middleName: 'a',\n * lastName: 'a',\n * address: { addressLine1: 'a', addressLine2: 'a', town: 'a', postcode: 'a' }\n * }\n * }\n * ```\n */\n\n/**\n * Form submission state\n */\nexport type FormSubmissionState = {\n upload?: Record<string, TempFileState>\n} & FormState\n\nexport interface FormSubmissionError\n extends Pick<ValidationErrorItem, 'context' | 'path'> {\n href: string // e.g: '#dateField__day'\n name: string // e.g: 'dateField__day'\n text: string // e.g: 'Date field must be a real date'\n}\n\nexport interface FormPayloadParams {\n action?: FormAction\n confirm?: true\n crumb?: string\n itemId?: string\n}\n\n/**\n * Form POST for question pages\n * (after Joi has converted value types)\n */\nexport type FormPayload = FormPayloadParams & Partial<Record<string, FormValue>>\n\nexport type FormValue =\n | Item['value']\n | Item['value'][]\n | UploadState\n | RepeatListState\n | undefined\n\nexport type FormState = Partial<Record<string, FormStateValue>>\nexport type FormStateValue = Exclude<FormValue, undefined> | null\n\nexport interface FormValidationResult<\n ValueType extends FormPayload | FormSubmissionState\n> {\n value: ValueType\n errors: FormSubmissionError[] | undefined\n}\n\nexport interface FormContext {\n /**\n * Evaluation form state only (filtered by visited paths),\n * with values formatted for condition evaluation using\n * {@link FormComponent.getContextValueFromState}\n */\n evaluationState: FormState\n\n /**\n * Relevant form state only (filtered by visited paths)\n */\n relevantState: FormState\n\n /**\n * Relevant pages only (filtered by visited paths)\n */\n relevantPages: PageControllerClass[]\n\n /**\n * Form submission payload (single page)\n */\n payload: FormPayload\n\n /**\n * Form submission state (entire form)\n */\n state: FormSubmissionState\n\n /**\n * Validation errors (entire form)\n */\n errors?: FormSubmissionError[]\n\n /**\n * Visited paths evaluated from form state\n */\n paths: string[]\n\n /**\n * Preview URL direct access is allowed\n */\n isForceAccess: boolean\n\n /**\n * Miscellaneous extra data from event responses\n */\n data: object\n\n pageDefMap: Map<string, Page>\n listDefMap: Map<string, List>\n componentDefMap: Map<string, ComponentDef>\n pageMap: Map<string, PageControllerClass>\n componentMap: Map<string, Component>\n referenceNumber: string\n}\n\nexport type FormContextRequest = (\n | {\n method: 'get'\n payload?: undefined\n }\n | {\n method: 'post'\n payload: FormPayload\n }\n | {\n method: FormRequest['method']\n payload?: object | undefined\n }\n) &\n Pick<\n FormRequest,\n 'app' | 'method' | 'params' | 'path' | 'query' | 'url' | 'server'\n >\n\nexport interface UploadInitiateResponse {\n uploadId: string\n uploadUrl: string\n statusUrl: string\n}\n\nexport {\n FileStatus,\n UploadStatus\n} from '~/src/server/plugins/engine/types/enums.js'\n\nexport type UploadState = FileState[]\n\nexport type FileUpload = {\n fileId: string\n filename: string\n contentLength: number\n} & (\n | {\n fileStatus: FileStatus.complete | FileStatus.rejected | FileStatus.pending\n errorMessage?: string\n }\n | {\n fileStatus: FileStatus.complete\n errorMessage?: undefined\n }\n)\n\nexport interface FileUploadMetadata {\n retrievalKey: string\n}\n\nexport type UploadStatusResponse =\n | {\n uploadStatus: UploadStatus.initiated\n metadata: FileUploadMetadata\n form: { file?: undefined }\n }\n | {\n uploadStatus: UploadStatus.pending | UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles?: number\n }\n | {\n uploadStatus: UploadStatus.ready\n metadata: FileUploadMetadata\n form: { file: FileUpload }\n numberOfRejectedFiles: 0\n }\n\nexport type UploadStatusFileResponse = Exclude<\n UploadStatusResponse,\n { uploadStatus: UploadStatus.initiated }\n>\n\nexport interface FileState {\n uploadId: string\n status: UploadStatusFileResponse\n}\n\nexport interface TempFileState {\n upload?: UploadInitiateResponse\n files: UploadState\n}\n\nexport interface RepeatItemState extends FormPayload {\n itemId: string\n}\n\nexport type RepeatListState = RepeatItemState[]\n\nexport interface CheckAnswers {\n title?: ComponentText\n summaryList: SummaryList\n}\n\nexport interface SummaryList {\n classes?: string\n rows: SummaryListRow[]\n}\n\nexport interface SummaryListRow {\n key: ComponentText\n value: ComponentText\n actions?: { items: SummaryListAction[] }\n}\n\nexport type SummaryListAction = ComponentText & {\n href: string\n visuallyHiddenText: string\n}\n\nexport interface PageViewModelBase extends Partial<ViewContext> {\n page: PageController\n name?: string\n pageTitle: string\n sectionTitle?: string\n showTitle: boolean\n isStartPage: boolean\n backLink?: BackLink\n feedbackLink?: string\n serviceUrl: string\n phaseTag?: string\n}\n\nexport interface ItemDeletePageViewModel extends PageViewModelBase {\n context: FormContext\n itemTitle: string\n confirmation?: ComponentText\n buttonConfirm: ComponentText\n buttonCancel: ComponentText\n}\n\nexport interface FormPageViewModel extends PageViewModelBase {\n components: ComponentViewModel[]\n context: FormContext\n errors?: FormSubmissionError[]\n hasMissingNotificationEmail?: boolean\n allowSaveAndReturn: 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 GlobalFunction = (value: unknown) => unknown\nexport type FilterFunction = (value: unknown) => unknown\nexport interface ErrorMessageTemplate {\n type: string\n template: JoiExpression\n}\n\nexport interface ErrorMessageTemplateList {\n baseErrors: ErrorMessageTemplate[]\n advancedSettingsErrors: ErrorMessageTemplate[]\n}\n\nexport type PreparePageEventRequestOptions = (\n options: RequestOptions,\n event: Event,\n page: PageControllerClass,\n context: FormContext\n) => void\n\nexport type OnRequestCallback = (\n request: FormRequest | FormRequestPayload,\n params: FormParams,\n definition: FormDefinition,\n metadata: FormMetadata\n) => void\n\nexport interface PluginOptions {\n model?: FormModel\n services?: Services\n controllers?: Record<string, typeof PageController>\n cacheName?: string\n globals?: Record<string, GlobalFunction>\n filters?: Record<string, FilterFunction>\n saveAndReturn?: {\n keyGenerator: (request: RequestType) => string\n sessionHydrator: (request: RequestType) => Promise<FormSubmissionState>\n sessionPersister: (\n state: FormSubmissionState,\n request: RequestType\n ) => Promise<void>\n }\n pluginPath?: string\n nunjucks: {\n baseLayoutPath: string\n paths: string[]\n }\n viewContext: PluginProperties['forms-engine-plugin']['viewContext']\n preparePageEventRequestOptions?: PreparePageEventRequestOptions\n onRequest?: OnRequestCallback\n baseUrl: string // base URL of the application, protocol and hostname e.g. \"https://myapp.com\"\n}\n\nexport interface FormAdapterSubmissionMessageMeta {\n schemaVersion: FormAdapterSubmissionSchemaVersion\n timestamp: Date\n referenceNumber: string\n formName: string\n formId: string\n formSlug: string\n status: FormStatus\n isPreview: boolean\n notificationEmail: string\n}\n\nexport type FormAdapterSubmissionMessageMetaSerialised = Omit<\n FormAdapterSubmissionMessageMeta,\n 'schemaVersion' | 'timestamp' | 'status'\n> & {\n schemaVersion: number\n status: string\n timestamp: string\n}\nexport interface FormAdapterFile {\n fileName: string\n fileId: string\n userDownloadLink: string\n}\n\nexport interface FormAdapterSubmissionMessageResult {\n files: {\n main: string\n repeaters: Record<string, string>\n }\n}\n\n/**\n * A detail item specifically for files\n */\nexport type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {\n field: FileUploadField\n}\nexport type RichFormValue =\n | FormValue\n | FormPayload\n | DatePartsState\n | MonthYearState\n | UkAddressState\n\nexport interface FormAdapterSubmissionMessageData {\n main: Record<string, RichFormValue>\n repeaters: Record<string, Record<string, RichFormValue>[]>\n files: Record<string, FormAdapterFile[]>\n}\n\nexport interface FormAdapterSubmissionMessagePayload {\n meta: FormAdapterSubmissionMessageMeta\n data: FormAdapterSubmissionMessageData\n result: FormAdapterSubmissionMessageResult\n}\n\nexport interface FormAdapterSubmissionMessage\n extends FormAdapterSubmissionMessagePayload {\n messageId: string\n recordCreatedAt: Date\n}\n\nexport interface FormAdapterSubmissionService {\n handleFormSubmission: (\n submissionMessage: FormAdapterSubmissionMessage\n ) => unknown\n}\n"],"mappings":"AA6CA;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;;AAqGA,SACEA,UAAU,EACVC,YAAY;;AA6Nd;AACA;AACA","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type FormMetadata,
|
|
3
|
+
type SubmitResponsePayload
|
|
4
|
+
} from '@defra/forms-model'
|
|
2
5
|
|
|
3
6
|
import { FileUploadField } from '~/src/server/plugins/engine/components/FileUploadField.js'
|
|
4
7
|
import { type Field } from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
@@ -26,7 +29,7 @@ const submitResponse = {
|
|
|
26
29
|
files: {
|
|
27
30
|
main: '00000000-0000-0000-0000-000000000000',
|
|
28
31
|
repeaters: {
|
|
29
|
-
|
|
32
|
+
exampleRepeat: '11111111-1111-1111-1111-111111111111'
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
35
|
}
|
|
@@ -258,15 +261,26 @@ describe('Adapter v1 formatter', () => {
|
|
|
258
261
|
exampleFile1: [
|
|
259
262
|
{
|
|
260
263
|
fileId: '123-456-789',
|
|
264
|
+
fileName: 'foobar.txt',
|
|
261
265
|
userDownloadLink: 'https://forms-designer/file-download/123-456-789'
|
|
262
266
|
},
|
|
263
267
|
{
|
|
264
268
|
fileId: '456-789-123',
|
|
269
|
+
fileName: 'bazbuzz.txt',
|
|
265
270
|
userDownloadLink: 'https://forms-designer/file-download/456-789-123'
|
|
266
271
|
}
|
|
267
272
|
]
|
|
268
273
|
}
|
|
269
274
|
})
|
|
275
|
+
|
|
276
|
+
expect(parsedBody.result).toEqual({
|
|
277
|
+
files: {
|
|
278
|
+
main: '00000000-0000-0000-0000-000000000000',
|
|
279
|
+
repeaters: {
|
|
280
|
+
exampleRepeat: '11111111-1111-1111-1111-111111111111'
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
})
|
|
270
284
|
})
|
|
271
285
|
|
|
272
286
|
it('should handle preview form status correctly', () => {
|
|
@@ -385,6 +399,14 @@ describe('Adapter v1 formatter', () => {
|
|
|
385
399
|
expect(parsedBody.data.main).toEqual({})
|
|
386
400
|
expect(parsedBody.data.repeaters).toEqual({})
|
|
387
401
|
expect(parsedBody.data.files).toEqual({})
|
|
402
|
+
expect(parsedBody.result).toEqual({
|
|
403
|
+
files: {
|
|
404
|
+
main: '00000000-0000-0000-0000-000000000000',
|
|
405
|
+
repeaters: {
|
|
406
|
+
exampleRepeat: '11111111-1111-1111-1111-111111111111'
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
})
|
|
388
410
|
})
|
|
389
411
|
|
|
390
412
|
it('should handle different form statuses', () => {
|
|
@@ -503,4 +525,172 @@ describe('Adapter v1 formatter', () => {
|
|
|
503
525
|
expect(parsedBody.meta.formSlug).toBe('')
|
|
504
526
|
expect(parsedBody.meta.notificationEmail).toBe('only-email@example.com')
|
|
505
527
|
})
|
|
528
|
+
|
|
529
|
+
it('should include CSV file IDs from submitResponse.result.files', () => {
|
|
530
|
+
const formStatus = {
|
|
531
|
+
isPreview: false,
|
|
532
|
+
state: FormStatus.Live
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const body = format(context, items, model, submitResponse, formStatus)
|
|
536
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
537
|
+
|
|
538
|
+
expect(parsedBody.data.main).toEqual({
|
|
539
|
+
exampleField: 'hello world',
|
|
540
|
+
exampleField2: 'hello world'
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
expect(parsedBody.data.repeaters.exampleRepeat).toEqual([
|
|
544
|
+
{
|
|
545
|
+
subItem1_1: 'hello world',
|
|
546
|
+
subItem1_2: 'hello world'
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
subItem2_1: 'hello world'
|
|
550
|
+
}
|
|
551
|
+
])
|
|
552
|
+
|
|
553
|
+
expect(parsedBody.data.files.exampleFile1).toEqual([
|
|
554
|
+
{
|
|
555
|
+
fileId: '123-456-789',
|
|
556
|
+
fileName: 'foobar.txt',
|
|
557
|
+
userDownloadLink: 'https://forms-designer/file-download/123-456-789'
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
fileId: '456-789-123',
|
|
561
|
+
fileName: 'bazbuzz.txt',
|
|
562
|
+
userDownloadLink: 'https://forms-designer/file-download/456-789-123'
|
|
563
|
+
}
|
|
564
|
+
])
|
|
565
|
+
|
|
566
|
+
expect(parsedBody.result).toEqual({
|
|
567
|
+
files: {
|
|
568
|
+
main: '00000000-0000-0000-0000-000000000000',
|
|
569
|
+
repeaters: {
|
|
570
|
+
exampleRepeat: '11111111-1111-1111-1111-111111111111'
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
})
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
it('should handle submitResponse without CSV file IDs gracefully', () => {
|
|
577
|
+
const submitResponseWithoutFiles = {
|
|
578
|
+
message: 'Submit completed',
|
|
579
|
+
result: {
|
|
580
|
+
files: {
|
|
581
|
+
main: '',
|
|
582
|
+
repeaters: {}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const formStatus = {
|
|
588
|
+
isPreview: false,
|
|
589
|
+
state: FormStatus.Live
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const body = format(
|
|
593
|
+
context,
|
|
594
|
+
items,
|
|
595
|
+
model,
|
|
596
|
+
submitResponseWithoutFiles,
|
|
597
|
+
formStatus
|
|
598
|
+
)
|
|
599
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
600
|
+
|
|
601
|
+
expect(parsedBody.data.main).toEqual({
|
|
602
|
+
exampleField: 'hello world',
|
|
603
|
+
exampleField2: 'hello world'
|
|
604
|
+
})
|
|
605
|
+
|
|
606
|
+
expect(parsedBody.data.repeaters.exampleRepeat).toEqual([
|
|
607
|
+
{
|
|
608
|
+
subItem1_1: 'hello world',
|
|
609
|
+
subItem1_2: 'hello world'
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
subItem2_1: 'hello world'
|
|
613
|
+
}
|
|
614
|
+
])
|
|
615
|
+
})
|
|
616
|
+
|
|
617
|
+
it('should handle submitResponse with only main CSV file ID', () => {
|
|
618
|
+
const submitResponseWithMainOnly = {
|
|
619
|
+
message: 'Submit completed',
|
|
620
|
+
result: {
|
|
621
|
+
files: {
|
|
622
|
+
main: 'main-only-file-id',
|
|
623
|
+
repeaters: {}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const formStatus = {
|
|
629
|
+
isPreview: false,
|
|
630
|
+
state: FormStatus.Live
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const body = format(
|
|
634
|
+
context,
|
|
635
|
+
items,
|
|
636
|
+
model,
|
|
637
|
+
submitResponseWithMainOnly,
|
|
638
|
+
formStatus
|
|
639
|
+
)
|
|
640
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
641
|
+
|
|
642
|
+
expect(parsedBody.data.main).toEqual({
|
|
643
|
+
exampleField: 'hello world',
|
|
644
|
+
exampleField2: 'hello world'
|
|
645
|
+
})
|
|
646
|
+
|
|
647
|
+
expect(parsedBody.data.repeaters.exampleRepeat).toEqual([
|
|
648
|
+
{
|
|
649
|
+
subItem1_1: 'hello world',
|
|
650
|
+
subItem1_2: 'hello world'
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
subItem2_1: 'hello world'
|
|
654
|
+
}
|
|
655
|
+
])
|
|
656
|
+
|
|
657
|
+
expect(parsedBody.result).toEqual({
|
|
658
|
+
files: {
|
|
659
|
+
main: 'main-only-file-id',
|
|
660
|
+
repeaters: {}
|
|
661
|
+
}
|
|
662
|
+
})
|
|
663
|
+
})
|
|
664
|
+
|
|
665
|
+
it('should handle submitResponse with missing repeaters property', () => {
|
|
666
|
+
const submitResponseWithoutRepeaters = {
|
|
667
|
+
message: 'Submit completed',
|
|
668
|
+
result: {
|
|
669
|
+
files: {
|
|
670
|
+
main: 'main-only-file-id'
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const formStatus = {
|
|
676
|
+
isPreview: false,
|
|
677
|
+
state: FormStatus.Live
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const body = format(
|
|
681
|
+
context,
|
|
682
|
+
items,
|
|
683
|
+
model,
|
|
684
|
+
submitResponseWithoutRepeaters as unknown as SubmitResponsePayload,
|
|
685
|
+
formStatus
|
|
686
|
+
)
|
|
687
|
+
const parsedBody = JSON.parse(body) as FormAdapterSubmissionMessagePayload
|
|
688
|
+
|
|
689
|
+
expect(parsedBody.result).toEqual({
|
|
690
|
+
files: {
|
|
691
|
+
main: 'main-only-file-id',
|
|
692
|
+
repeaters: {}
|
|
693
|
+
}
|
|
694
|
+
})
|
|
695
|
+
})
|
|
506
696
|
})
|
|
@@ -10,7 +10,9 @@ import { format as machineV2 } from '~/src/server/plugins/engine/outputFormatter
|
|
|
10
10
|
import { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'
|
|
11
11
|
import {
|
|
12
12
|
type FormAdapterSubmissionMessageData,
|
|
13
|
+
type FormAdapterSubmissionMessageMeta,
|
|
13
14
|
type FormAdapterSubmissionMessagePayload,
|
|
15
|
+
type FormAdapterSubmissionMessageResult,
|
|
14
16
|
type FormContext
|
|
15
17
|
} from '~/src/server/plugins/engine/types.js'
|
|
16
18
|
import { FormStatus } from '~/src/server/routes/types.js'
|
|
@@ -34,20 +36,44 @@ export function format(
|
|
|
34
36
|
data: FormAdapterSubmissionMessageData
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
const csvFiles = extractCsvFiles(submitResponse)
|
|
40
|
+
|
|
41
|
+
const transformedData = v2DataParsed.data
|
|
42
|
+
|
|
43
|
+
const meta: FormAdapterSubmissionMessageMeta = {
|
|
44
|
+
schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
|
|
45
|
+
timestamp: new Date(),
|
|
46
|
+
referenceNumber: context.referenceNumber,
|
|
47
|
+
formName: model.name,
|
|
48
|
+
formId: formMetadata?.id ?? '',
|
|
49
|
+
formSlug: formMetadata?.slug ?? '',
|
|
50
|
+
status: formStatus.isPreview ? FormStatus.Draft : FormStatus.Live,
|
|
51
|
+
isPreview: formStatus.isPreview,
|
|
52
|
+
notificationEmail: formMetadata?.notificationEmail ?? ''
|
|
53
|
+
}
|
|
54
|
+
const data: FormAdapterSubmissionMessageData = transformedData
|
|
55
|
+
|
|
56
|
+
const result: FormAdapterSubmissionMessageResult = {
|
|
57
|
+
files: csvFiles
|
|
58
|
+
}
|
|
59
|
+
|
|
37
60
|
const payload: FormAdapterSubmissionMessagePayload = {
|
|
38
|
-
meta
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
referenceNumber: context.referenceNumber,
|
|
42
|
-
formName: model.name,
|
|
43
|
-
formId: formMetadata?.id ?? '',
|
|
44
|
-
formSlug: formMetadata?.slug ?? '',
|
|
45
|
-
status: formStatus.isPreview ? FormStatus.Draft : FormStatus.Live,
|
|
46
|
-
isPreview: formStatus.isPreview,
|
|
47
|
-
notificationEmail: formMetadata?.notificationEmail ?? ''
|
|
48
|
-
},
|
|
49
|
-
data: v2DataParsed.data
|
|
61
|
+
meta,
|
|
62
|
+
data,
|
|
63
|
+
result
|
|
50
64
|
}
|
|
51
65
|
|
|
52
66
|
return JSON.stringify(payload)
|
|
53
67
|
}
|
|
68
|
+
|
|
69
|
+
function extractCsvFiles(
|
|
70
|
+
submitResponse: SubmitResponsePayload
|
|
71
|
+
): FormAdapterSubmissionMessageResult['files'] {
|
|
72
|
+
const result =
|
|
73
|
+
submitResponse.result as Partial<FormAdapterSubmissionMessageResult>
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
main: result.files?.main ?? '',
|
|
77
|
+
repeaters: result.files?.repeaters ?? {}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -249,10 +249,12 @@ describe('getPersonalisation', () => {
|
|
|
249
249
|
exampleFile1: [
|
|
250
250
|
{
|
|
251
251
|
fileId: '123-456-789',
|
|
252
|
+
fileName: 'foobar.txt',
|
|
252
253
|
userDownloadLink: 'https://forms-designer/file-download/123-456-789'
|
|
253
254
|
},
|
|
254
255
|
{
|
|
255
256
|
fileId: '456-789-123',
|
|
257
|
+
fileName: 'bazbuzz.txt',
|
|
256
258
|
userDownloadLink: 'https://forms-designer/file-download/456-789-123'
|
|
257
259
|
}
|
|
258
260
|
]
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { type SubmitResponsePayload } from '@defra/forms-model'
|
|
2
2
|
|
|
3
3
|
import { config } from '~/src/config/index.js'
|
|
4
|
-
import { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'
|
|
5
4
|
import { FileUploadField } from '~/src/server/plugins/engine/components/index.js'
|
|
6
|
-
import {
|
|
7
|
-
type DatePartsState,
|
|
8
|
-
type MonthYearState
|
|
9
|
-
} from '~/src/server/plugins/engine/components/types.js'
|
|
10
5
|
import { type checkFormStatus } from '~/src/server/plugins/engine/helpers.js'
|
|
11
6
|
import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
|
|
12
7
|
import {
|
|
@@ -15,9 +10,10 @@ import {
|
|
|
15
10
|
type DetailItemRepeat
|
|
16
11
|
} from '~/src/server/plugins/engine/models/types.js'
|
|
17
12
|
import {
|
|
13
|
+
type FileUploadFieldDetailitem,
|
|
14
|
+
type FormAdapterFile,
|
|
18
15
|
type FormContext,
|
|
19
|
-
type
|
|
20
|
-
type FormValue
|
|
16
|
+
type RichFormValue
|
|
21
17
|
} from '~/src/server/plugins/engine/types.js'
|
|
22
18
|
|
|
23
19
|
const designerUrl = config.get('designerUrl')
|
|
@@ -69,7 +65,8 @@ export function format(
|
|
|
69
65
|
* fileComponentName: [
|
|
70
66
|
* {
|
|
71
67
|
* fileId: '123-456-789',
|
|
72
|
-
*
|
|
68
|
+
* fileName: 'example.pdf',
|
|
69
|
+
* userDownloadLink: 'https://forms-designer/file-download/123-456-789'
|
|
73
70
|
* }
|
|
74
71
|
* ]
|
|
75
72
|
* }
|
|
@@ -79,7 +76,10 @@ function categoriseData(items: DetailItem[]) {
|
|
|
79
76
|
const output: {
|
|
80
77
|
main: Record<string, RichFormValue>
|
|
81
78
|
repeaters: Record<string, Record<string, RichFormValue>[]>
|
|
82
|
-
files: Record<
|
|
79
|
+
files: Record<
|
|
80
|
+
string,
|
|
81
|
+
{ fileId: string; fileName: string; userDownloadLink: string }[]
|
|
82
|
+
>
|
|
83
83
|
} = { main: {}, repeaters: {}, files: {} }
|
|
84
84
|
|
|
85
85
|
items.forEach((item) => {
|
|
@@ -126,13 +126,17 @@ function extractRepeaters(item: DetailItemRepeat) {
|
|
|
126
126
|
* @param item - the file upload item in the form
|
|
127
127
|
* @returns the file upload data
|
|
128
128
|
*/
|
|
129
|
-
function extractFileUploads(
|
|
130
|
-
|
|
129
|
+
function extractFileUploads(
|
|
130
|
+
item: FileUploadFieldDetailitem
|
|
131
|
+
): FormAdapterFile[] {
|
|
132
|
+
const fileUploadState = item.field.getFormValueFromState(item.state) ?? []
|
|
131
133
|
|
|
132
|
-
return fileUploadState.map((
|
|
134
|
+
return fileUploadState.map((fileState) => {
|
|
135
|
+
const { file } = fileState.status.form
|
|
133
136
|
return {
|
|
134
|
-
fileId,
|
|
135
|
-
|
|
137
|
+
fileId: file.fileId,
|
|
138
|
+
fileName: file.filename,
|
|
139
|
+
userDownloadLink: `${designerUrl}/file-download/${file.fileId}`
|
|
136
140
|
}
|
|
137
141
|
})
|
|
138
142
|
}
|
|
@@ -142,17 +146,3 @@ function isFileUploadFieldItem(
|
|
|
142
146
|
): item is FileUploadFieldDetailitem {
|
|
143
147
|
return item.field instanceof FileUploadField
|
|
144
148
|
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* A detail item specifically for files
|
|
148
|
-
*/
|
|
149
|
-
type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {
|
|
150
|
-
field: FileUploadField
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export type RichFormValue =
|
|
154
|
-
| FormValue
|
|
155
|
-
| FormPayload
|
|
156
|
-
| DatePartsState
|
|
157
|
-
| MonthYearState
|
|
158
|
-
| UkAddressState
|
|
@@ -87,7 +87,5 @@ export type {
|
|
|
87
87
|
Services
|
|
88
88
|
} from '~/src/server/types.js'
|
|
89
89
|
|
|
90
|
-
export type { RichFormValue } from '~/src/server/plugins/engine/outputFormatters/machine/v2.js'
|
|
91
|
-
|
|
92
90
|
export * from '~/src/server/plugins/engine/types/schema.js'
|
|
93
91
|
export { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'
|
|
@@ -9,10 +9,56 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
type FormAdapterSubmissionMessageData,
|
|
11
11
|
type FormAdapterSubmissionMessageMeta,
|
|
12
|
-
type FormAdapterSubmissionMessagePayload
|
|
12
|
+
type FormAdapterSubmissionMessagePayload,
|
|
13
|
+
type RichFormValue
|
|
13
14
|
} from '~/src/server/plugins/engine/types.js'
|
|
14
15
|
|
|
15
16
|
describe('Schema validation', () => {
|
|
17
|
+
const main: Record<string, RichFormValue> = {
|
|
18
|
+
QMwMir: 'Roman Pizza',
|
|
19
|
+
duOEvZ: 'Small',
|
|
20
|
+
DzEODf: ['Mozzarella'],
|
|
21
|
+
juiCfC: ['Pepperoni', 'Sausage', 'Onions', 'Basil'],
|
|
22
|
+
YEpypP: 'None',
|
|
23
|
+
JumNVc: 'Joe Bloggs',
|
|
24
|
+
ALNehP: '+441234567890',
|
|
25
|
+
vAqTmg: {
|
|
26
|
+
addressLine1: '1 Anywhere Street',
|
|
27
|
+
town: 'Anywhereville',
|
|
28
|
+
postcode: 'AN1 2WH'
|
|
29
|
+
},
|
|
30
|
+
IbXVGY: {
|
|
31
|
+
day: 22,
|
|
32
|
+
month: 8,
|
|
33
|
+
year: 2025
|
|
34
|
+
},
|
|
35
|
+
HGBWLt: ['Garlic sauce']
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const value1: Record<string, RichFormValue> = {
|
|
39
|
+
IEKzko: 'dsfsdfsdf'
|
|
40
|
+
}
|
|
41
|
+
const value2: Record<string, RichFormValue> = {
|
|
42
|
+
IEKzko: 'dfghfgh'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const validData: FormAdapterSubmissionMessageData = {
|
|
46
|
+
main,
|
|
47
|
+
repeaters: {
|
|
48
|
+
qLVLgb: [value1, value2]
|
|
49
|
+
},
|
|
50
|
+
files: {
|
|
51
|
+
dLzALM: [
|
|
52
|
+
{
|
|
53
|
+
fileId: '489ecc1b-a145-4618-ba5a-b4a0d5ee2dbd',
|
|
54
|
+
fileName: 'file-name.json',
|
|
55
|
+
userDownloadLink:
|
|
56
|
+
'http://localhost:3005/file-download/489ecc1b-a145-4618-ba5a-b4a0d5ee2dbd'
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
16
62
|
describe('formAdapterSubmissionMessageMetaSchema', () => {
|
|
17
63
|
const validMeta: FormAdapterSubmissionMessageMeta = {
|
|
18
64
|
schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
|
|
@@ -49,31 +95,6 @@ describe('Schema validation', () => {
|
|
|
49
95
|
})
|
|
50
96
|
|
|
51
97
|
describe('formAdapterSubmissionMessageDataSchema', () => {
|
|
52
|
-
const validData: FormAdapterSubmissionMessageData = {
|
|
53
|
-
main: {
|
|
54
|
-
QMwMir: 'Roman Pizza',
|
|
55
|
-
duOEvZ: 'Small',
|
|
56
|
-
DzEODf: ['Mozzarella'],
|
|
57
|
-
juiCfC: ['Pepperoni', 'Sausage', 'Onions', 'Basil'],
|
|
58
|
-
YEpypP: 'None',
|
|
59
|
-
JumNVc: 'Joe Bloggs',
|
|
60
|
-
ALNehP: '+441234567890',
|
|
61
|
-
vAqTmg: {
|
|
62
|
-
addressLine1: '1 Anywhere Street',
|
|
63
|
-
town: 'Anywhereville',
|
|
64
|
-
postcode: 'AN1 2WH'
|
|
65
|
-
},
|
|
66
|
-
IbXVGY: {
|
|
67
|
-
day: 22,
|
|
68
|
-
month: 8,
|
|
69
|
-
year: 2025
|
|
70
|
-
},
|
|
71
|
-
HGBWLt: ['Garlic sauce']
|
|
72
|
-
},
|
|
73
|
-
repeaters: {},
|
|
74
|
-
files: {}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
98
|
it('should validate valid data object', () => {
|
|
78
99
|
const { error } =
|
|
79
100
|
formAdapterSubmissionMessageDataSchema.validate(validData)
|
|
@@ -89,41 +110,28 @@ describe('Schema validation', () => {
|
|
|
89
110
|
})
|
|
90
111
|
|
|
91
112
|
describe('formAdapterSubmissionMessagePayloadSchema', () => {
|
|
113
|
+
const meta: FormAdapterSubmissionMessageMeta = {
|
|
114
|
+
schemaVersion: FormAdapterSubmissionSchemaVersion.V1,
|
|
115
|
+
timestamp: new Date('2025-08-22T18:15:10.785Z'),
|
|
116
|
+
referenceNumber: '576-225-943',
|
|
117
|
+
formName: 'Order a pizza',
|
|
118
|
+
formId: '68a8b0449ab460290c28940a',
|
|
119
|
+
formSlug: 'order-a-pizza',
|
|
120
|
+
status: FormStatus.Live,
|
|
121
|
+
isPreview: false,
|
|
122
|
+
notificationEmail: 'info@example.com'
|
|
123
|
+
}
|
|
124
|
+
|
|
92
125
|
const validPayload: FormAdapterSubmissionMessagePayload = {
|
|
93
|
-
meta
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
notificationEmail: 'info@example.com'
|
|
103
|
-
},
|
|
104
|
-
data: {
|
|
105
|
-
main: {
|
|
106
|
-
QMwMir: 'Roman Pizza',
|
|
107
|
-
duOEvZ: 'Small',
|
|
108
|
-
DzEODf: ['Mozzarella'],
|
|
109
|
-
juiCfC: ['Pepperoni', 'Sausage', 'Onions', 'Basil'],
|
|
110
|
-
YEpypP: 'None',
|
|
111
|
-
JumNVc: 'Joe Bloggs',
|
|
112
|
-
ALNehP: '+441234567890',
|
|
113
|
-
vAqTmg: {
|
|
114
|
-
addressLine1: '1 Anywhere Street',
|
|
115
|
-
town: 'Anywhereville',
|
|
116
|
-
postcode: 'AN1 2WH'
|
|
117
|
-
},
|
|
118
|
-
IbXVGY: {
|
|
119
|
-
day: 22,
|
|
120
|
-
month: 8,
|
|
121
|
-
year: 2025
|
|
122
|
-
},
|
|
123
|
-
HGBWLt: ['Garlic sauce']
|
|
124
|
-
},
|
|
125
|
-
repeaters: {},
|
|
126
|
-
files: {}
|
|
126
|
+
meta,
|
|
127
|
+
data: validData,
|
|
128
|
+
result: {
|
|
129
|
+
files: {
|
|
130
|
+
main: '3d289230-83a3-4852-a68a-cb3569e9b0fe',
|
|
131
|
+
repeaters: {
|
|
132
|
+
ImxIOP: 'Joe Bloggs'
|
|
133
|
+
}
|
|
134
|
+
}
|
|
127
135
|
}
|
|
128
136
|
}
|
|
129
137
|
|
|
@@ -11,7 +11,8 @@ import { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/
|
|
|
11
11
|
import {
|
|
12
12
|
type FormAdapterSubmissionMessageData,
|
|
13
13
|
type FormAdapterSubmissionMessageMeta,
|
|
14
|
-
type FormAdapterSubmissionMessagePayload
|
|
14
|
+
type FormAdapterSubmissionMessagePayload,
|
|
15
|
+
type FormAdapterSubmissionMessageResult
|
|
15
16
|
} from '~/src/server/plugins/engine/types.js'
|
|
16
17
|
|
|
17
18
|
export const formAdapterSubmissionMessageMetaSchema =
|
|
@@ -35,11 +36,31 @@ export const formAdapterSubmissionMessageDataSchema =
|
|
|
35
36
|
Joi.object<FormAdapterSubmissionMessageData>().keys({
|
|
36
37
|
main: Joi.object(),
|
|
37
38
|
repeaters: Joi.object(),
|
|
39
|
+
files: Joi.object().pattern(
|
|
40
|
+
Joi.string(),
|
|
41
|
+
Joi.array().items(
|
|
42
|
+
Joi.object().keys({
|
|
43
|
+
fileName: Joi.string().required(),
|
|
44
|
+
fileId: Joi.string().required(),
|
|
45
|
+
userDownloadLink: Joi.string().required()
|
|
46
|
+
})
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
export const formAdapterSubmissionMessageResultSchema =
|
|
52
|
+
Joi.object<FormAdapterSubmissionMessageResult>().keys({
|
|
38
53
|
files: Joi.object()
|
|
54
|
+
.keys({
|
|
55
|
+
main: Joi.string().required(),
|
|
56
|
+
repeaters: Joi.object()
|
|
57
|
+
})
|
|
58
|
+
.required()
|
|
39
59
|
})
|
|
40
60
|
|
|
41
61
|
export const formAdapterSubmissionMessagePayloadSchema =
|
|
42
62
|
Joi.object<FormAdapterSubmissionMessagePayload>().keys({
|
|
43
63
|
meta: formAdapterSubmissionMessageMetaSchema.required(),
|
|
44
|
-
data: formAdapterSubmissionMessageDataSchema.required()
|
|
64
|
+
data: formAdapterSubmissionMessageDataSchema.required(),
|
|
65
|
+
result: formAdapterSubmissionMessageResultSchema.required()
|
|
45
66
|
})
|
|
@@ -11,14 +11,18 @@ import { type PluginProperties, type Request } from '@hapi/hapi'
|
|
|
11
11
|
import { type JoiExpression, type ValidationErrorItem } from 'joi'
|
|
12
12
|
|
|
13
13
|
import { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'
|
|
14
|
+
import { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js'
|
|
14
15
|
import { type Component } from '~/src/server/plugins/engine/components/helpers/components.js'
|
|
16
|
+
import { type FileUploadField } from '~/src/server/plugins/engine/components/index.js'
|
|
15
17
|
import {
|
|
16
18
|
type BackLink,
|
|
17
19
|
type ComponentText,
|
|
18
|
-
type ComponentViewModel
|
|
20
|
+
type ComponentViewModel,
|
|
21
|
+
type DatePartsState,
|
|
22
|
+
type MonthYearState
|
|
19
23
|
} from '~/src/server/plugins/engine/components/types.js'
|
|
20
24
|
import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
|
|
21
|
-
import { type
|
|
25
|
+
import { type DetailItemField } from '~/src/server/plugins/engine/models/types.js'
|
|
22
26
|
import { type PageController } from '~/src/server/plugins/engine/pageControllers/PageController.js'
|
|
23
27
|
import { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'
|
|
24
28
|
import {
|
|
@@ -405,16 +409,42 @@ export type FormAdapterSubmissionMessageMetaSerialised = Omit<
|
|
|
405
409
|
status: string
|
|
406
410
|
timestamp: string
|
|
407
411
|
}
|
|
412
|
+
export interface FormAdapterFile {
|
|
413
|
+
fileName: string
|
|
414
|
+
fileId: string
|
|
415
|
+
userDownloadLink: string
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export interface FormAdapterSubmissionMessageResult {
|
|
419
|
+
files: {
|
|
420
|
+
main: string
|
|
421
|
+
repeaters: Record<string, string>
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* A detail item specifically for files
|
|
427
|
+
*/
|
|
428
|
+
export type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {
|
|
429
|
+
field: FileUploadField
|
|
430
|
+
}
|
|
431
|
+
export type RichFormValue =
|
|
432
|
+
| FormValue
|
|
433
|
+
| FormPayload
|
|
434
|
+
| DatePartsState
|
|
435
|
+
| MonthYearState
|
|
436
|
+
| UkAddressState
|
|
408
437
|
|
|
409
438
|
export interface FormAdapterSubmissionMessageData {
|
|
410
439
|
main: Record<string, RichFormValue>
|
|
411
440
|
repeaters: Record<string, Record<string, RichFormValue>[]>
|
|
412
|
-
files: Record<string,
|
|
441
|
+
files: Record<string, FormAdapterFile[]>
|
|
413
442
|
}
|
|
414
443
|
|
|
415
444
|
export interface FormAdapterSubmissionMessagePayload {
|
|
416
445
|
meta: FormAdapterSubmissionMessageMeta
|
|
417
446
|
data: FormAdapterSubmissionMessageData
|
|
447
|
+
result: FormAdapterSubmissionMessageResult
|
|
418
448
|
}
|
|
419
449
|
|
|
420
450
|
export interface FormAdapterSubmissionMessage
|