@gov-cy/govcy-express-services 1.6.1 → 1.6.3
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": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
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",
|
|
@@ -181,4 +181,16 @@ export function cyLoginPolicy(req, res, next) {
|
|
|
181
181
|
next
|
|
182
182
|
);
|
|
183
183
|
}
|
|
184
|
-
/************************************************************************/
|
|
184
|
+
/************************************************************************/
|
|
185
|
+
|
|
186
|
+
export function getUniqueIdentifier(req) {
|
|
187
|
+
// https://dev.azure.com/cyprus-gov-cds/Documentation/_wiki/wikis/Documentation/82/Available-Scopes-and-Claims
|
|
188
|
+
const user = req?.session?.user || {};
|
|
189
|
+
|
|
190
|
+
const id =
|
|
191
|
+
user.unique_identifier ??
|
|
192
|
+
user.legal_unique_identifier ??
|
|
193
|
+
"";
|
|
194
|
+
|
|
195
|
+
return String(id);
|
|
196
|
+
}
|
|
@@ -184,7 +184,7 @@ export function govcyReviewPostHandler() {
|
|
|
184
184
|
const submissionData = prepareSubmissionData(req, siteId, service);
|
|
185
185
|
|
|
186
186
|
// Prepare submission data for API
|
|
187
|
-
const submissionDataAPI = prepareSubmissionDataAPI(submissionData, service);
|
|
187
|
+
const submissionDataAPI = prepareSubmissionDataAPI(submissionData, service, req);
|
|
188
188
|
|
|
189
189
|
logger.debug("Prepared submission data for API:", submissionDataAPI);
|
|
190
190
|
|
|
@@ -437,10 +437,13 @@ export const staticResources = {
|
|
|
437
437
|
{
|
|
438
438
|
check: "valid",
|
|
439
439
|
params: {
|
|
440
|
-
checkValue: "
|
|
440
|
+
checkValue: "nameCY",
|
|
441
441
|
message: {
|
|
442
|
-
el: "Το
|
|
443
|
-
en: "Your name
|
|
442
|
+
// el: "Το όνομά σας μπορεί να περιέχει μόνο γράμματα, κενά, παύλες (-), αποστρόφους (’ ‘ ʼ) και τελείες (.)",
|
|
443
|
+
// en: "Your name can only include letters, spaces, hyphens (-), apostrophes (’ ‘ ʼ) and dots (.)",
|
|
444
|
+
// tr: ""
|
|
445
|
+
el: "Το όνομά σας μπορεί να περιέχει μόνο γράμματα, κενά, παύλες (-), αποστρόφους (’ ‘ ʼ) και τελείες (.)",
|
|
446
|
+
en: "Your name can only include letters, spaces, hyphens (-), curly apostrophes (’ ‘ ʼ) and dots (.)",
|
|
444
447
|
tr: ""
|
|
445
448
|
}
|
|
446
449
|
}
|
|
@@ -8,6 +8,7 @@ import { getServiceConfigData, getPageConfigData } from "./govcyLoadConfigData.m
|
|
|
8
8
|
import { getMultipleThingsEmptyFormData } from "./govcyFormHandling.mjs";
|
|
9
9
|
import { logger } from "./govcyLogger.mjs";
|
|
10
10
|
import { createUmdManualPageTemplate } from "../middleware/govcyUpdateMyDetails.mjs"
|
|
11
|
+
import { getUniqueIdentifier } from "../middleware/cyLoginAuth.mjs"
|
|
11
12
|
import nunjucks from "nunjucks";
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -101,11 +102,19 @@ export function prepareSubmissionData(req, siteId, service) {
|
|
|
101
102
|
// radios conditional elements
|
|
102
103
|
if (el.element === "radios") {
|
|
103
104
|
for (const radioItem of el.params.items || []) {
|
|
105
|
+
|
|
106
|
+
const isSelected = radioItem.value === value; // 🔸 to decide to populate only selected
|
|
107
|
+
|
|
104
108
|
for (const condEl of radioItem.conditionalElements || []) {
|
|
105
109
|
if (!ALLOWED_FORM_ELEMENTS.includes(condEl.element)) continue;
|
|
106
110
|
const condId = condEl.params?.id || condEl.params?.name;
|
|
107
111
|
if (!condId) continue;
|
|
108
|
-
|
|
112
|
+
|
|
113
|
+
// 🔸only populate if selected, otherwise empty string
|
|
114
|
+
let condValue = isSelected
|
|
115
|
+
? getValue(condEl, pageUrl, req, siteId, idx)
|
|
116
|
+
: ""; // 🔸 Empty if conditional radio is not selected
|
|
117
|
+
|
|
109
118
|
itemData[condId] = condValue;
|
|
110
119
|
|
|
111
120
|
if (condEl.element === "fileInput") {
|
|
@@ -156,6 +165,8 @@ export function prepareSubmissionData(req, siteId, service) {
|
|
|
156
165
|
const condEls = radioItem.conditionalElements;
|
|
157
166
|
if (!Array.isArray(condEls)) continue;
|
|
158
167
|
|
|
168
|
+
const isSelected = radioItem.value === value; // 🔸 to decide to populate only selected
|
|
169
|
+
|
|
159
170
|
for (const condElement of condEls) {
|
|
160
171
|
const condType = condElement.element;
|
|
161
172
|
if (!ALLOWED_FORM_ELEMENTS.includes(condType)) continue;
|
|
@@ -164,7 +175,10 @@ export function prepareSubmissionData(req, siteId, service) {
|
|
|
164
175
|
if (!condId) continue;
|
|
165
176
|
|
|
166
177
|
// Again: read from session or fallback to ""
|
|
167
|
-
|
|
178
|
+
// 🔸 only populate if selected; otherwise keep empty string
|
|
179
|
+
const condValue = isSelected
|
|
180
|
+
? getValue(condElement, pageUrl, req, siteId) ?? ""
|
|
181
|
+
: ""; // 🔸 Empty if conditional radio is not selected
|
|
168
182
|
|
|
169
183
|
// Store even if the field was not visible to user
|
|
170
184
|
// submissionData[pageUrl].formData[condId] = condValue;
|
|
@@ -255,9 +269,10 @@ export function prepareSubmissionData(req, siteId, service) {
|
|
|
255
269
|
*
|
|
256
270
|
* @param {object} data data prepared by `prepareSubmissionData`\
|
|
257
271
|
* @param {object} service service config data
|
|
272
|
+
* @param {object} req request object
|
|
258
273
|
* @returns {object} The API-ready submission data object with all fields as strings
|
|
259
274
|
*/
|
|
260
|
-
export function prepareSubmissionDataAPI(data, service) {
|
|
275
|
+
export function prepareSubmissionDataAPI(data, service, req) {
|
|
261
276
|
|
|
262
277
|
//deep copy data to avoid mutating the original
|
|
263
278
|
let dataObj = JSON.parse(JSON.stringify(data));
|
|
@@ -277,12 +292,20 @@ export function prepareSubmissionDataAPI(data, service) {
|
|
|
277
292
|
let pageEmptyData = getMultipleThingsEmptyFormData(page);
|
|
278
293
|
//replace the dataObj.submissionData[key] with the empty data
|
|
279
294
|
dataObj.submissionData[key] = [pageEmptyData];
|
|
280
|
-
|
|
295
|
+
|
|
281
296
|
} catch (error) {
|
|
282
297
|
logger.error('Error getting pageConfigData:', key);
|
|
283
298
|
}
|
|
284
299
|
}
|
|
285
300
|
}
|
|
301
|
+
// get the Unique Identifier of the user
|
|
302
|
+
const uniqueIdentifier = getUniqueIdentifier(req);
|
|
303
|
+
|
|
304
|
+
// Insert unique identifier as the first item in the array
|
|
305
|
+
dataObj.submissionData = {
|
|
306
|
+
cylogin_unique_identifier: uniqueIdentifier,
|
|
307
|
+
...(dataObj.submissionData || {})
|
|
308
|
+
};
|
|
286
309
|
}
|
|
287
310
|
|
|
288
311
|
return {
|
|
@@ -923,7 +946,7 @@ export function generateSubmitEmail(service, submissionData, submissionId, req)
|
|
|
923
946
|
// Custom page
|
|
924
947
|
// ==========================================================
|
|
925
948
|
// 🆕 Check for custom pages that should appear after this one
|
|
926
|
-
for (const [customKey, customPage] of
|
|
949
|
+
for (const [customKey, customPage] of customPageEntries) {
|
|
927
950
|
const insertAfter = customPage.insertAfterPageUrl;
|
|
928
951
|
if (insertAfter && insertAfter === pageUrl && Array.isArray(customPage.email)) {
|
|
929
952
|
pagesInBody.push(customPage.pageUrl); // Track custom page key for later
|
|
@@ -939,7 +962,7 @@ export function generateSubmitEmail(service, submissionData, submissionId, req)
|
|
|
939
962
|
body.push(...customPage.email);
|
|
940
963
|
}
|
|
941
964
|
}
|
|
942
|
-
|
|
965
|
+
|
|
943
966
|
// ==========================================================
|
|
944
967
|
}
|
|
945
968
|
|
|
@@ -29,7 +29,8 @@ function validateValue(value, rules) {
|
|
|
29
29
|
alphaNum: (val) => /^[A-Za-zΑ-Ωα-ω\u0370-\u03ff\u1f00-\u1fff0-9\s]+$/.test(val),
|
|
30
30
|
noSpecialChars: (val) => /^([0-9]|[A-Z]|[a-z]|[α-ω]|[Α-Ω]|[,]|[.]|[-]|[(]|[)]|[?]|[!]|[;]|[:]|[\n]|[\r]|[ _]|[\u0370-\u03ff\u1f00-\u1fff])+$/.test(val),
|
|
31
31
|
noSpecialCharsEl: (val) => /^([0-9]|[α-ω]|[Α-Ω]|[,]|[.]|[-]|[(]|[)]|[?]|[!]|[;]|[:]|[\n]|[\r]|[ _]|[\u0370-\u03ff\u1f00-\u1fff])+$/.test(val),
|
|
32
|
-
name: (val) => /^[
|
|
32
|
+
name: (val) => /^[\p{L}\p{M}\s’‘ʼ.-]+$/u.test(val),
|
|
33
|
+
nameCY: (val) => /^[A-Za-zΑ-Ωα-ωΆ-Ώά-ώΪΫϊΐϋΰÇĞİIŞÖÜçğışöü\s.’‘ʼ-]*$/u.test(val),
|
|
33
34
|
tel: (val) => /^(?:\+|00)?[\d\s\-()]{8,20}$/.test(val.replace(/[\s\-()]/g, '')),
|
|
34
35
|
mobile: (val) => /^(?:\+|00)?[\d\s\-()]{8,20}$/.test(val.replace(/[\s\-()]/g, '')),
|
|
35
36
|
// telCY: (val) => /^(?:\+|00)?357[-\s]?(2|9)\d{7}$/.test(val.replace(/[\s\-()]/g, '')),
|