@gov-cy/govcy-express-services 0.2.12 → 0.2.14
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gov-cy/govcy-express-services",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "An Express-based system that dynamically renders services using @gov-cy/govcy-frontend-renderer and posts data to a submission API.",
|
|
5
5
|
"author": "DMRID - DSF Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@gov-cy/dsf-email-templates": "^2.1.0",
|
|
51
|
-
"@gov-cy/govcy-frontend-renderer": "^1.
|
|
51
|
+
"@gov-cy/govcy-frontend-renderer": "^1.18.0",
|
|
52
52
|
"axios": "^1.9.0",
|
|
53
53
|
"cookie-parser": "^1.4.7",
|
|
54
54
|
"dotenv": "^16.3.1",
|
|
@@ -85,6 +85,8 @@ export function govcyReviewPostHandler() {
|
|
|
85
85
|
// Prepare submission data for API
|
|
86
86
|
const submissionDataAPI = prepareSubmissionDataAPI(submissionData);
|
|
87
87
|
|
|
88
|
+
logger.debug("Prepared submission data for API:", submissionDataAPI);
|
|
89
|
+
|
|
88
90
|
// Call the API to submit the data
|
|
89
91
|
const response = await govcyApiRequest(
|
|
90
92
|
"post", // Use POST method
|
|
@@ -4,6 +4,7 @@ import * as dataLayer from "./govcyDataLayer.mjs";
|
|
|
4
4
|
import { DSFEmailRenderer } from '@gov-cy/dsf-email-templates';
|
|
5
5
|
import { ALLOWED_FORM_ELEMENTS } from "./govcyConstants.mjs";
|
|
6
6
|
import { evaluatePageConditions } from "./govcyExpressions.mjs";
|
|
7
|
+
import { logger } from "./govcyLogger.mjs";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Prepares the submission data for the service, including raw data, print-friendly data, and renderer data.
|
|
@@ -19,17 +20,78 @@ export function prepareSubmissionData(req, siteId, service) {
|
|
|
19
20
|
|
|
20
21
|
// ----- Conditional logic comes here
|
|
21
22
|
// Filter site input data based on active pages only
|
|
22
|
-
const rawData = {};
|
|
23
|
+
// const rawData = {};
|
|
24
|
+
// for (const page of service.pages) {
|
|
25
|
+
// const shouldInclude = evaluatePageConditions(page, req.session, siteId, req).result === true;
|
|
26
|
+
// if (shouldInclude) {
|
|
27
|
+
// const pageUrl = page.pageData.url;
|
|
28
|
+
// const formData = dataLayer.getPageData(req.session, siteId, pageUrl);
|
|
29
|
+
// if (formData && Object.keys(formData).length > 0) {
|
|
30
|
+
// rawData[pageUrl] = { formData };
|
|
31
|
+
// }
|
|
32
|
+
// }
|
|
33
|
+
// }
|
|
34
|
+
|
|
35
|
+
// ----- consistent data model for submission_data (CONFIG-BASED)
|
|
36
|
+
const submissionData = {};
|
|
37
|
+
|
|
38
|
+
// Loop through every page in the service definition
|
|
23
39
|
for (const page of service.pages) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
40
|
+
const pageUrl = page.pageData.url || "";
|
|
41
|
+
|
|
42
|
+
// Find the <form> element in the page
|
|
43
|
+
let formElement = null;
|
|
44
|
+
for (const section of page.pageTemplate.sections || []) {
|
|
45
|
+
formElement = section.elements.find(el => el.element === "form");
|
|
46
|
+
if (formElement) break;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!formElement) continue; // ⛔ Skip pages without a <form> element
|
|
50
|
+
|
|
51
|
+
submissionData[pageUrl] = { formData: {} }; // ✅ Now initialize only if a form is present
|
|
52
|
+
|
|
53
|
+
// Traverse the form elements inside the form
|
|
54
|
+
for (const element of formElement.params.elements || []) {
|
|
55
|
+
const elType = element.element;
|
|
56
|
+
|
|
57
|
+
// ✅ Skip non-input elements like buttons
|
|
58
|
+
if (!ALLOWED_FORM_ELEMENTS.includes(elType)) continue;
|
|
59
|
+
|
|
60
|
+
const elId = element.params?.id || element.params?.name;
|
|
61
|
+
if (!elId) continue; // ⛔ Skip elements with no id/name
|
|
62
|
+
|
|
63
|
+
// 🟢 Use helper to get session value (or "" fallback if missing)
|
|
64
|
+
const value = getValue(element, pageUrl, req, siteId) ?? "";
|
|
65
|
+
|
|
66
|
+
// Store in submissionData
|
|
67
|
+
submissionData[pageUrl].formData[elId] = value;
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
// 🔄 If radios with conditionalElements, walk ALL options
|
|
71
|
+
if (elType === "radios" && Array.isArray(element.params?.items)) {
|
|
72
|
+
for (const radioItem of element.params.items) {
|
|
73
|
+
const condEls = radioItem.conditionalElements;
|
|
74
|
+
if (!Array.isArray(condEls)) continue;
|
|
75
|
+
|
|
76
|
+
for (const condElement of condEls) {
|
|
77
|
+
const condType = condElement.element;
|
|
78
|
+
if (!ALLOWED_FORM_ELEMENTS.includes(condType)) continue;
|
|
79
|
+
|
|
80
|
+
const condId = condElement.params?.id || condElement.params?.name;
|
|
81
|
+
if (!condId) continue;
|
|
82
|
+
|
|
83
|
+
// Again: read from session or fallback to ""
|
|
84
|
+
const condValue = getValue(condElement, pageUrl, req, siteId) ?? "";
|
|
85
|
+
|
|
86
|
+
// Store even if the field was not visible to user
|
|
87
|
+
submissionData[pageUrl].formData[condId] = condValue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
30
91
|
}
|
|
31
92
|
}
|
|
32
|
-
|
|
93
|
+
logger.debug("Submission Data prepared:", submissionData);
|
|
94
|
+
// ----- END config-based stable submission_data block
|
|
33
95
|
|
|
34
96
|
// Get the print-friendly data from the session store
|
|
35
97
|
const printFriendlyData = preparePrintFriendlyData(req, siteId, service);
|
|
@@ -40,7 +102,7 @@ export function prepareSubmissionData(req, siteId, service) {
|
|
|
40
102
|
return {
|
|
41
103
|
submission_username: dataLayer.getUser(req.session).name,
|
|
42
104
|
submission_email: dataLayer.getUser(req.session).email,
|
|
43
|
-
submission_data:
|
|
105
|
+
submission_data: submissionData, // Raw data as submitted by the user in each page
|
|
44
106
|
submission_data_version: service.site?.submission_data_version || "", // The submission data version
|
|
45
107
|
print_friendly_data: printFriendlyData, // Print-friendly data
|
|
46
108
|
renderer_data: reviewSummaryList, // Renderer data of the summary list
|
|
@@ -89,123 +151,6 @@ export function preparePrintFriendlyData(req, siteId, service) {
|
|
|
89
151
|
|
|
90
152
|
const allowedElements = ALLOWED_FORM_ELEMENTS;
|
|
91
153
|
|
|
92
|
-
/**
|
|
93
|
-
* Helper function to retrieve date raw input.
|
|
94
|
-
*
|
|
95
|
-
* @param {string} pageUrl The page URL
|
|
96
|
-
* @param {string} name The name of the form element
|
|
97
|
-
* @returns {string} The raw date input in ISO format (YYYY-MM-DD) or an empty string if not found
|
|
98
|
-
*/
|
|
99
|
-
function getDateInputISO(pageUrl, name) {
|
|
100
|
-
const day = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_day`);
|
|
101
|
-
const month = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_month`);
|
|
102
|
-
const year = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_year`);
|
|
103
|
-
if (!day || !month || !year) return "";
|
|
104
|
-
|
|
105
|
-
// Pad day and month with leading zero if needed
|
|
106
|
-
const paddedDay = String(day).padStart(2, "0");
|
|
107
|
-
const paddedMonth = String(month).padStart(2, "0");
|
|
108
|
-
|
|
109
|
-
return `${year}-${paddedMonth}-${paddedDay}`; // ISO format: YYYY-MM-DD
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Helper function to retrieve date input in DMY format.
|
|
114
|
-
*
|
|
115
|
-
* @param {string} pageUrl The page URL
|
|
116
|
-
* @param {string} name The name of the form element
|
|
117
|
-
* @returns {string} The raw date input in DMY format (DD/MM/YYYY) or an empty string if not found
|
|
118
|
-
*/
|
|
119
|
-
function getDateInputDMY(pageUrl, name) {
|
|
120
|
-
const day = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_day`);
|
|
121
|
-
const month = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_month`);
|
|
122
|
-
const year = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_year`);
|
|
123
|
-
if (!day || !month || !year) return "";
|
|
124
|
-
return `${day}/${month}/${year}`; // EU format: DD/MM/YYYY
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Helper function to create a field object.
|
|
129
|
-
*
|
|
130
|
-
* @param {object} formElement The form element object
|
|
131
|
-
* @param {string} value The value of the form element
|
|
132
|
-
* @param {object} valueLabel The label of the form element
|
|
133
|
-
* @returns {object} The field object containing id, label, value, and valueLabel
|
|
134
|
-
*/
|
|
135
|
-
function createFieldObject(formElement, value, valueLabel) {
|
|
136
|
-
return {
|
|
137
|
-
id: formElement.params?.id || "",
|
|
138
|
-
name: formElement.params?.name || "",
|
|
139
|
-
label: formElement.params.label
|
|
140
|
-
|| formElement.params.legend
|
|
141
|
-
|| govcyResources.getSameMultilingualObject(service.site.languages, formElement.params.name),
|
|
142
|
-
value: value,
|
|
143
|
-
valueLabel: valueLabel
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Helper function to retrieve the value of a form element from the session.
|
|
149
|
-
*
|
|
150
|
-
* @param {object} formElement The form element object
|
|
151
|
-
* @param {string} pageUrl The page URL
|
|
152
|
-
* @returns {string} The value of the form element from the session or an empty string if not found
|
|
153
|
-
*/
|
|
154
|
-
function getValue(formElement, pageUrl) {
|
|
155
|
-
// handle raw value
|
|
156
|
-
let value = ""
|
|
157
|
-
if (formElement.element === "dateInput") {
|
|
158
|
-
value = getDateInputISO(pageUrl, formElement.params.name);
|
|
159
|
-
} else {
|
|
160
|
-
value = dataLayer.getFormDataValue(req.session, siteId, pageUrl, formElement.params.name);
|
|
161
|
-
}
|
|
162
|
-
return value;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Helper function to get the label of a form element based on its value and type.
|
|
167
|
-
*
|
|
168
|
-
* @param {object} formElement The form element object
|
|
169
|
-
* @param {string} value The value of the form element
|
|
170
|
-
* @param {string} pageUrl The page URL
|
|
171
|
-
* @returns {object} The label of the form element based on the value and element type
|
|
172
|
-
*/
|
|
173
|
-
function getValueLabel(formElement, value, pageUrl) {
|
|
174
|
-
//handle checkboxes label
|
|
175
|
-
if (formElement.element === "checkboxes") {
|
|
176
|
-
if (Array.isArray(value)) {
|
|
177
|
-
// loop through each value and find the corresponding item
|
|
178
|
-
return value.map(v => {
|
|
179
|
-
// find the item
|
|
180
|
-
const item = formElement.params.items.find(i => i.value === v);
|
|
181
|
-
return item?.text || govcyResources.getSameMultilingualObject(service.site.languages, "");
|
|
182
|
-
});
|
|
183
|
-
} else if (typeof value === "string") {
|
|
184
|
-
const matchedItem = formElement.params.items.find(item => item.value === value);
|
|
185
|
-
if (matchedItem) {
|
|
186
|
-
return matchedItem.text;
|
|
187
|
-
} else {
|
|
188
|
-
return govcyResources.getSameMultilingualObject(service.site.languages, "")
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// handle radios and select labels
|
|
194
|
-
if (formElement.element === "radios" || formElement.element === "select") {
|
|
195
|
-
const item = formElement.params.items.find(i => i.value === value);
|
|
196
|
-
return item?.text || govcyResources.getSameMultilingualObject(service.site.languages, "");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// handle dateInput
|
|
200
|
-
if (formElement.element === "dateInput") {
|
|
201
|
-
const formattedDate = getDateInputDMY(pageUrl, formElement.params.name);
|
|
202
|
-
return govcyResources.getSameMultilingualObject(service.site.languages, formattedDate);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// textInput, textArea, etc.
|
|
206
|
-
return govcyResources.getSameMultilingualObject(service.site.languages, value);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
154
|
// loop through each page in the service
|
|
210
155
|
// and extract the form data from the session
|
|
211
156
|
for (const page of service.pages) {
|
|
@@ -228,11 +173,11 @@ export function preparePrintFriendlyData(req, siteId, service) {
|
|
|
228
173
|
if (!allowedElements.includes(formElement.element)) continue;
|
|
229
174
|
|
|
230
175
|
// handle raw value
|
|
231
|
-
let rawValue = getValue(formElement, page.pageData.url);
|
|
176
|
+
let rawValue = getValue(formElement, page.pageData.url, req, siteId);
|
|
232
177
|
|
|
233
178
|
//create the field object and push it to the fields array
|
|
234
179
|
// value of the field is handled by getValueLabel function
|
|
235
|
-
const field = createFieldObject(formElement, rawValue, getValueLabel(formElement, rawValue, page.pageData.url));
|
|
180
|
+
const field = createFieldObject(formElement, rawValue, getValueLabel(formElement, rawValue, page.pageData.url, req, siteId, service), service);
|
|
236
181
|
fields.push(field);
|
|
237
182
|
|
|
238
183
|
// Handle conditional elements (only for radios for now)
|
|
@@ -246,11 +191,11 @@ export function preparePrintFriendlyData(req, siteId, service) {
|
|
|
246
191
|
if (!allowedElements.includes(condEl.element)) continue;
|
|
247
192
|
|
|
248
193
|
// handle raw value
|
|
249
|
-
let condValue = getValue(condEl, page.pageData.url);
|
|
194
|
+
let condValue = getValue(condEl, page.pageData.url, req, siteId);
|
|
250
195
|
|
|
251
196
|
//create the field object and push it to the fields array
|
|
252
197
|
// value of the field is handled by getValueLabel function
|
|
253
|
-
const field = createFieldObject(condEl, condValue, getValueLabel(condEl, condValue, page.pageData.url));
|
|
198
|
+
const field = createFieldObject(condEl, condValue, getValueLabel(condEl, condValue, page.pageData.url, req, siteId, service), service);
|
|
254
199
|
fields.push(field);
|
|
255
200
|
}
|
|
256
201
|
}
|
|
@@ -272,6 +217,132 @@ export function preparePrintFriendlyData(req, siteId, service) {
|
|
|
272
217
|
}
|
|
273
218
|
|
|
274
219
|
//------------------------------- Helper Functions -------------------------------//
|
|
220
|
+
/**
|
|
221
|
+
* Helper function to retrieve date raw input.
|
|
222
|
+
*
|
|
223
|
+
* @param {string} pageUrl The page URL
|
|
224
|
+
* @param {string} name The name of the form element
|
|
225
|
+
* @param {object} req The request object
|
|
226
|
+
* @param {string} siteId The site ID
|
|
227
|
+
* @returns {string} The raw date input in ISO format (YYYY-MM-DD) or an empty string if not found
|
|
228
|
+
*/
|
|
229
|
+
function getDateInputISO(pageUrl, name, req, siteId) {
|
|
230
|
+
const day = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_day`);
|
|
231
|
+
const month = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_month`);
|
|
232
|
+
const year = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_year`);
|
|
233
|
+
if (!day || !month || !year) return "";
|
|
234
|
+
|
|
235
|
+
// Pad day and month with leading zero if needed
|
|
236
|
+
const paddedDay = String(day).padStart(2, "0");
|
|
237
|
+
const paddedMonth = String(month).padStart(2, "0");
|
|
238
|
+
|
|
239
|
+
return `${year}-${paddedMonth}-${paddedDay}`; // ISO format: YYYY-MM-DD
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Helper function to retrieve date input in DMY format.
|
|
244
|
+
*
|
|
245
|
+
* @param {string} pageUrl The page URL
|
|
246
|
+
* @param {string} name The name of the form element
|
|
247
|
+
* @param {object} req The request object
|
|
248
|
+
* @param {string} siteId The site ID
|
|
249
|
+
* @returns {string} The raw date input in DMY format (DD/MM/YYYY) or an empty string if not found
|
|
250
|
+
*/
|
|
251
|
+
function getDateInputDMY(pageUrl, name, req, siteId) {
|
|
252
|
+
const day = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_day`);
|
|
253
|
+
const month = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_month`);
|
|
254
|
+
const year = dataLayer.getFormDataValue(req.session, siteId, pageUrl, `${name}_year`);
|
|
255
|
+
if (!day || !month || !year) return "";
|
|
256
|
+
return `${day}/${month}/${year}`; // EU format: DD/MM/YYYY
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Helper function to create a field object.
|
|
261
|
+
*
|
|
262
|
+
* @param {object} formElement The form element object
|
|
263
|
+
* @param {string} value The value of the form element
|
|
264
|
+
* @param {object} valueLabel The label of the form element
|
|
265
|
+
* @param {object} service The service object
|
|
266
|
+
* @returns {object} The field object containing id, label, value, and valueLabel
|
|
267
|
+
*/
|
|
268
|
+
function createFieldObject(formElement, value, valueLabel, service) {
|
|
269
|
+
return {
|
|
270
|
+
id: formElement.params?.id || "",
|
|
271
|
+
name: formElement.params?.name || "",
|
|
272
|
+
label: formElement.params.label
|
|
273
|
+
|| formElement.params.legend
|
|
274
|
+
|| govcyResources.getSameMultilingualObject(service.site.languages, formElement.params.name),
|
|
275
|
+
value: value,
|
|
276
|
+
valueLabel: valueLabel
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Helper function to retrieve the value of a form element from the session.
|
|
282
|
+
*
|
|
283
|
+
* @param {object} formElement The form element object
|
|
284
|
+
* @param {string} pageUrl The page URL
|
|
285
|
+
* @param {object} req The request object
|
|
286
|
+
* @param {string} siteId The site ID
|
|
287
|
+
* @returns {string} The value of the form element from the session or an empty string if not found
|
|
288
|
+
*/
|
|
289
|
+
function getValue(formElement, pageUrl, req, siteId) {
|
|
290
|
+
// handle raw value
|
|
291
|
+
let value = ""
|
|
292
|
+
if (formElement.element === "dateInput") {
|
|
293
|
+
value = getDateInputISO(pageUrl, formElement.params.name, req, siteId);
|
|
294
|
+
} else {
|
|
295
|
+
value = dataLayer.getFormDataValue(req.session, siteId, pageUrl, formElement.params.name);
|
|
296
|
+
}
|
|
297
|
+
return value;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Helper function to get the label of a form element based on its value and type.
|
|
302
|
+
*
|
|
303
|
+
* @param {object} formElement The form element object
|
|
304
|
+
* @param {string} value The value of the form element
|
|
305
|
+
* @param {string} pageUrl The page URL
|
|
306
|
+
* @param {object} req The request object
|
|
307
|
+
* @param {string} siteId The site ID
|
|
308
|
+
* @param {object} service The service object
|
|
309
|
+
* @returns {object} The label of the form element based on the value and element type
|
|
310
|
+
*/
|
|
311
|
+
function getValueLabel(formElement, value, pageUrl, req, siteId, service) {
|
|
312
|
+
//handle checkboxes label
|
|
313
|
+
if (formElement.element === "checkboxes") {
|
|
314
|
+
if (Array.isArray(value)) {
|
|
315
|
+
// loop through each value and find the corresponding item
|
|
316
|
+
return value.map(v => {
|
|
317
|
+
// find the item
|
|
318
|
+
const item = formElement.params.items.find(i => i.value === v);
|
|
319
|
+
return item?.text || govcyResources.getSameMultilingualObject(service.site.languages, "");
|
|
320
|
+
});
|
|
321
|
+
} else if (typeof value === "string") {
|
|
322
|
+
const matchedItem = formElement.params.items.find(item => item.value === value);
|
|
323
|
+
if (matchedItem) {
|
|
324
|
+
return matchedItem.text;
|
|
325
|
+
} else {
|
|
326
|
+
return govcyResources.getSameMultilingualObject(service.site.languages, "")
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// handle radios and select labels
|
|
332
|
+
if (formElement.element === "radios" || formElement.element === "select") {
|
|
333
|
+
const item = formElement.params.items.find(i => i.value === value);
|
|
334
|
+
return item?.text || govcyResources.getSameMultilingualObject(service.site.languages, "");
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// handle dateInput
|
|
338
|
+
if (formElement.element === "dateInput") {
|
|
339
|
+
const formattedDate = getDateInputDMY(pageUrl, formElement.params.name, req, siteId);
|
|
340
|
+
return govcyResources.getSameMultilingualObject(service.site.languages, formattedDate);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// textInput, textArea, etc.
|
|
344
|
+
return govcyResources.getSameMultilingualObject(service.site.languages, value);
|
|
345
|
+
}
|
|
275
346
|
|
|
276
347
|
/**
|
|
277
348
|
* Helper function to get the item value of checkboxes based on the selected value.
|