@gov-cy/govcy-express-services 1.0.0-alpha.13 → 1.0.0-alpha.15

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/README.md CHANGED
@@ -12,10 +12,12 @@
12
12
  > You are responsible for ensuring your own compliance, security, and quality assurance processes.
13
13
 
14
14
  ## 📝 Description
15
- This project is an Express-based project that dynamically renders online service forms using `@gov-cy/govcy-frontend-renderer`. It is designed for developers building government services in Cyprus, enabling them to manage user authentication, form submissions, and OpenID authentication workflows in a timely manner.
15
+ This project is an Express-based project that dynamically renders online service forms using `@gov-cy/govcy-frontend-renderer`, handles data input, validations, renders a review page and submits the data via a submission API. It is designed for developers building government services in Cyprus, enabling them to manage user authentication, form submissions, and OpenID authentication workflows in a timely manner.
16
16
 
17
17
  The project is designed to support the [Linear structure](https://gov-cy.github.io/govcy-design-system-docs/patterns/service_structure/#variant-1---linear-structure) as described in the [Unified Design System](https://gov-cy.github.io/govcy-design-system-docs/).
18
18
 
19
+ The APIs used for submission, temporary save and file uploads are not part of this project. The project has been designed to work together with the **DSF Submission plarform** and all API calls are based on the **DSF Submission Platform APIs**. This readme file describes the definition of these APIs if you wish to develop your own for your own government back-end solution. For more details about the DSF Submission Platform [contact the DSF team](https://dsf.dmrid.gov.cy/contact/).
20
+
19
21
  ![govcy-express-services](express-services.png)
20
22
 
21
23
  ## Table of contents
@@ -45,7 +47,7 @@ The project is designed to support the [Linear structure](https://gov-cy.github.
45
47
 
46
48
  ## ✨ Features
47
49
  - Dynamic form rendering from JSON templates
48
- - Support for `textInput`, `textArea`, `select`, `radios`, `checkboxes`, `datePicker`, `dateInput`
50
+ - Support for `textInput`, `textArea`, `select`, `radios`, `checkboxes`, `datePicker`, `dateInput`, `fileInput` elements
49
51
  - Support for `conditional radios`
50
52
  - Dynamic creation of check your answers page
51
53
  - OpenID Connect authentication with CY Login
@@ -58,6 +60,7 @@ The project is designed to support the [Linear structure](https://gov-cy.github.
58
60
  - Site level API eligibility checks
59
61
  - API integration with retry logic for form submissions.
60
62
  - Optional temporary save of in-progress form data via configurable API endpoints
63
+ - Optional file uploads via API endpoints
61
64
 
62
65
  ## 📋 Prerequisites
63
66
  - Node.js 20+
@@ -749,8 +752,7 @@ Here's an example of a page defined in the JSON file:
749
752
  "element": "backLink",
750
753
  "params": {}
751
754
  }
752
- ],
753
- "params": {}
755
+ ]
754
756
  },
755
757
  {
756
758
  "name": "main",
@@ -1174,7 +1176,7 @@ Content-Type: application/json
1174
1176
  {
1175
1177
  "submission_username": "username",
1176
1178
  "submission_email": "email@example.com",
1177
- "submission_data": "{\"index\":{\"formData\":{\"certificate_select\":[\"birth\",\"permanent_residence\"]}}}",
1179
+ "submission_data": "{\"index\":{\"certificate_select\":[\"birth\",\"permanent_residence\"]}}",
1178
1180
  "submission_data_version": "1",
1179
1181
  "print_friendly_data": "[{\"pageUrl\":\"index\",\"pageTitle\":{\"el\":\"Επιλογή Εγγάφου\",\"en\":\"Document selection\",\"tr\":\"\"},\"fields\":[{\"id\":\"certificate_select\",\"name\":\"certificate_select\",\"label\":{\"el\":\"Τι έγγραφα επιθυμείτε να εκδώσετε;\",\"en\":\"What documents do you wish to issue?\"},\"value\":[\"birth\",\"permanent_residence\"],\"valueLabel\":[{\"el\":\"Πιστοποιητικό γέννησης​\",\"en\":\"Birth certificate\",\"tr\":\"\"},{\"el\":\"Βεβαίωση μόνιμης διαμονής​\",\"en\":\"Certificate of permanent residence\",\"tr\":\"\"}]}]}]",
1180
1182
  "renderer_data": "{\"element\":\"summaryList\",\"params\":{\"items\":[{\"key\":{\"el\":\"Επιλογή Εγγάφου\",\"en\":\"Document selection\",\"tr\":\"\"},\"value\":[{\"element\":\"summaryList\",\"params\":{\"items\":[{\"key\":{\"el\":\"Τι έγγραφα επιθυμείτε να εκδώσετε;\",\"en\":\"What documents do you wish to issue?\"},\"value\":[{\"element\":\"textElement\",\"params\":{\"text\":{\"en\":\"Birth certificate, Certificate of permanent residence\",\"el\":\"Birth certificate, Certificate of permanent residence\",\"tr\":\"Birth certificate, Certificate of permanent residence\"},\"type\":\"span\"}}]}]}}]}]}}",
@@ -1260,35 +1262,34 @@ The data is collected from the form elements and the data layer and are sent via
1260
1262
  "submission_data_version": "0.1", // Submission data version
1261
1263
  "submission_data": { // Submission raw data. Object, will be stringified
1262
1264
  "index": { // Page level
1263
- "formData": {
1264
- "id_select": ["id", "arc"], // field level. Could be string or array
1265
- "id_number": "654654",
1266
- "arc_number": "",
1267
- "aka": "232323"
1268
- }
1265
+ "id_select": ["id", "arc"], // field level. Could be string or array
1266
+ "id_number": "654654",
1267
+ "arc_number": "",
1268
+ "aka": "232323",
1269
+ "evidenceAttachments": // File attachments contains an object with `fileId` and `sha256`
1270
+ {
1271
+ "fileId": "1234567891234567890",
1272
+ "sha256": "123456789012345678901234567890123456789012345678901234567890123456"
1273
+ }
1269
1274
  },
1270
1275
  "appointment": {
1271
- "formData": {
1272
- "diorismos": "monimos",
1273
- "fileno_monimos": "3233",
1274
- "eidikotita_monimos": "1",
1275
- "fileno_sumvasiouxos": "",
1276
- "eidikotita_sumvasiouxos": "",
1277
- "fileno_aoristou": "",
1278
- "eidikotita_aoristou": "",
1279
- "program": "",
1280
- "fileno_orismenou": ""
1281
- }
1276
+ "diorismos": "monimos",
1277
+ "fileno_monimos": "3233",
1278
+ "eidikotita_monimos": "1",
1279
+ "fileno_sumvasiouxos": "",
1280
+ "eidikotita_sumvasiouxos": "",
1281
+ "fileno_aoristou": "",
1282
+ "eidikotita_aoristou": "",
1283
+ "program": "",
1284
+ "fileno_orismenou": ""
1282
1285
  },
1283
1286
  "takeover": {
1284
- "formData": {
1285
- "date_start_day": "11",
1286
- "date_start_month": "12",
1287
- "date_start_year": "2020",
1288
- "date_on_contract": "date_other",
1289
- "date_contract": "16/04/2025",
1290
- "reason": "24324dssf"
1291
- }
1287
+ "date_start_day": "11",
1288
+ "date_start_month": "12",
1289
+ "date_start_year": "2020",
1290
+ "date_on_contract": "date_other",
1291
+ "date_contract": "16/04/2025",
1292
+ "reason": "24324dssf"
1292
1293
  }
1293
1294
  },
1294
1295
  "submission_data_version": "1", // Submission data version
@@ -1687,6 +1688,7 @@ The project includes input validation for the following elements:
1687
1688
  - `checkboxes`
1688
1689
  - `datePicker`
1689
1690
  - `dateInput`
1691
+ - `fileInput` (only required check)
1690
1692
 
1691
1693
  The validation rules for each element are defined in the `"validations` array for each element. The project support the following validations:
1692
1694
 
@@ -2285,7 +2287,13 @@ Here is a sample code section of a page definition with a file input field:
2285
2287
  - **On a form page with an upload input field**:
2286
2288
  - **On first load**: the page displays the fileInput field to choose a file.
2287
2289
  - **On choosing a file**: the file is uploaded to the `fileUploadAPIEndpoint` endpoint.
2288
- - The `fileUploadAPIEndpoint` validates the input for allowed file types and file size. On validation error an error message is displayed.
2290
+ - The `fileUploadAPIEndpoint` validates the input for allowed file types and file size. On validation error an error message is displayed. The following validations are performed:
2291
+ - The fileInput element is defined in the JSON config
2292
+ - API endpoints and environment variables are defined
2293
+ - The page is not skiped because of conditional logic
2294
+ - The file is not empty
2295
+ - The file size must be less than 5MB
2296
+ - The file type must be one of the following: pdf, jpg, jpeg, png
2289
2297
  - If `fileUploadAPIEndpoint` returns an success, the file is uploaded temporarilly and the `fileView` element is displayed, with links to `View` or `Delete` the file. The file infomation are store in the data layer of the page.
2290
2298
  - **On a form page after upload**:
2291
2299
  - The `fileView` element is displayed with links to `View` or `Delete` the file.
@@ -2300,7 +2308,7 @@ Here is a sample code section of a page definition with a file input field:
2300
2308
 
2301
2309
 
2302
2310
  #### `fileUploadAPIEndpoint` `POST` API Request and Response
2303
- This API is used to temporarily store the file uploaded by the user.
2311
+ This API is used to temporarily store the file uploaded by the user. The API connects the file with a temporary saved submission, for the specific user and service. It does not create a connection with the actual field on the specific page, that is done by the `submissionPutAPIEndpoint` API.
2304
2312
 
2305
2313
  **Request:**
2306
2314
 
@@ -2457,7 +2465,7 @@ To help back-end systems recognize the field as a file, the field's element name
2457
2465
  ```
2458
2466
 
2459
2467
  #### File uploads backward compatibility
2460
- If these endpoints are not defined in the service JSON, the temporary save/load logic is skipped entirely.
2468
+ If these endpoints are not defined in the service JSON, the file upload logic is skipped entirely.
2461
2469
  Existing services will continue to work without modification.
2462
2470
 
2463
2471
  ### 🛣️ Routes
@@ -2550,10 +2558,13 @@ TEST_SUBMISSION_API_CLIENT_KEY=12345678901234567890123456789000
2550
2558
  TEST_SUBMISSION_API_SERVIVE_ID=123
2551
2559
  TEST_SUBMISSION_DSF_GTW_KEY=12345678901234567890123456789000
2552
2560
 
2553
- # Optional Temporary Save GET and PUT endpoint (test service)
2561
+ # Optional Temporary Save GET and PUT endpoints (test service)
2554
2562
  TEST_SUBMISSION_GET_API_URL=http://localhost:3002/getTempSubmission
2555
2563
  TEST_SUBMISSION_PUT_API_URL=http://localhost:3002/save
2556
2564
 
2565
+ # Optional File Upload and download endpoints (test service)
2566
+ TEST_FILE_UPLOAD_API_URL=http://localhost:3002/fileUpload
2567
+ TEST_FILE_DOWNLOAD_API_URL=http://localhost:3002/fileDownload
2557
2568
 
2558
2569
  # Eligibility checks (optional test APIs)
2559
2570
  TEST_ELIGIBILITY_1_API_URL=http://localhost:3002/eligibility1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gov-cy/govcy-express-services",
3
- "version": "1.0.0-alpha.13",
3
+ "version": "1.0.0-alpha.15",
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,8 @@ export function prepareSubmissionData(req, siteId, service) {
48
48
 
49
49
  if (!formElement) continue; // ⛔ Skip pages without a <form> element
50
50
 
51
- submissionData[pageUrl] = { formData: {} }; // ✅ Now initialize only if a form is present
51
+ // submissionData[pageUrl] = { formData: {} }; // ✅ Now initialize only if a form is present
52
+ submissionData[pageUrl] = {}; // ✅ Now initialize only if a form is present
52
53
 
53
54
  // Traverse the form elements inside the form
54
55
  for (const element of formElement.params.elements || []) {
@@ -64,13 +65,16 @@ export function prepareSubmissionData(req, siteId, service) {
64
65
  const value = getValue(element, pageUrl, req, siteId) ?? "";
65
66
 
66
67
  // Store in submissionData
67
- submissionData[pageUrl].formData[elId] = value;
68
+ // submissionData[pageUrl].formData[elId] = value;
69
+ submissionData[pageUrl][elId] = value;
68
70
 
69
71
  // handle fileInput
70
72
  if (elType === "fileInput") {
71
73
  // change the name of the key to include "Attachment" at the end but not have the original key
72
- submissionData[pageUrl].formData[elId + "Attachment"] = value;
73
- delete submissionData[pageUrl].formData[elId];
74
+ // submissionData[pageUrl].formData[elId + "Attachment"] = value;
75
+ submissionData[pageUrl][elId + "Attachment"] = value;
76
+ // delete submissionData[pageUrl].formData[elId];
77
+ delete submissionData[pageUrl][elId];
74
78
  }
75
79
 
76
80
  // 🔄 If radios with conditionalElements, walk ALL options
@@ -90,12 +94,15 @@ export function prepareSubmissionData(req, siteId, service) {
90
94
  const condValue = getValue(condElement, pageUrl, req, siteId) ?? "";
91
95
 
92
96
  // Store even if the field was not visible to user
93
- submissionData[pageUrl].formData[condId] = condValue;
97
+ // submissionData[pageUrl].formData[condId] = condValue;
98
+ submissionData[pageUrl][condId] = condValue;
94
99
  // handle fileInput
95
100
  if (condType === "fileInput") {
96
101
  // change the name of the key to include "Attachment" at the end but not have the original key
97
- submissionData[pageUrl].formData[condId + "Attachment"] = condValue;
98
- delete submissionData[pageUrl].formData[condId];
102
+ // submissionData[pageUrl].formData[condId + "Attachment"] = condValue;
103
+ submissionData[pageUrl][condId + "Attachment"] = condValue;
104
+ // delete submissionData[pageUrl].formData[condId];
105
+ delete submissionData[pageUrl][condId];
99
106
  }
100
107
  }
101
108
  }