@gov-cy/govcy-express-services 1.0.0-alpha.2 → 1.0.0-alpha.20
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 +1051 -83
- package/package.json +10 -3
- package/src/auth/cyLoginAuth.mjs +2 -1
- package/src/index.mjs +20 -1
- package/src/middleware/cyLoginAuth.mjs +11 -1
- package/src/middleware/govcyCsrf.mjs +15 -1
- package/src/middleware/govcyFileDeleteHandler.mjs +320 -0
- package/src/middleware/govcyFileUpload.mjs +36 -0
- package/src/middleware/govcyFileViewHandler.mjs +161 -0
- package/src/middleware/govcyFormsPostHandler.mjs +1 -1
- package/src/middleware/govcyHttpErrorHandler.mjs +4 -3
- package/src/middleware/govcyPDFRender.mjs +3 -1
- package/src/middleware/govcyPageHandler.mjs +3 -3
- package/src/middleware/govcyPageRender.mjs +10 -0
- package/src/middleware/govcyReviewPageHandler.mjs +4 -1
- package/src/middleware/govcyReviewPostHandler.mjs +1 -1
- package/src/middleware/govcySuccessPageHandler.mjs +2 -3
- package/src/public/js/govcyFiles.js +299 -0
- package/src/public/js/govcyForms.js +19 -8
- package/src/resources/govcyResources.mjs +85 -4
- package/src/utils/govcyApiDetection.mjs +17 -0
- package/src/utils/govcyApiRequest.mjs +30 -5
- package/src/utils/govcyApiResponse.mjs +31 -0
- package/src/utils/govcyConstants.mjs +5 -1
- package/src/utils/govcyDataLayer.mjs +211 -11
- package/src/utils/govcyExpressions.mjs +1 -1
- package/src/utils/govcyFormHandling.mjs +81 -5
- package/src/utils/govcyHandleFiles.mjs +307 -0
- package/src/utils/govcyLoadSubmissionDataAPIs.mjs +10 -3
- package/src/utils/govcySubmitData.mjs +186 -106
- package/src/utils/govcyTempSave.mjs +2 -1
- package/src/utils/govcyValidator.mjs +7 -0
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|

|
|
4
4
|
[](https://github.com/gov-cy/govcy-express-services/actions/workflows/unit-test.yml)
|
|
5
5
|
[](https://github.com/gov-cy/govcy-express-services/actions/workflows/tag-and-publish-on-version-change.yml)
|
|
6
|
+

|
|
6
7
|
|
|
7
8
|
> ⚠️ **Warning:**
|
|
8
9
|
> This package is **under active development** and is not a finished product. It is intended for testing, acceptance, integration, and browser testing purposes only.
|
|
@@ -12,10 +13,12 @@
|
|
|
12
13
|
> You are responsible for ensuring your own compliance, security, and quality assurance processes.
|
|
13
14
|
|
|
14
15
|
## 📝 Description
|
|
15
|
-
This project is an Express-based project that dynamically renders online service forms using `@gov-cy/govcy-frontend-renderer
|
|
16
|
+
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
17
|
|
|
17
18
|
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
19
|
|
|
20
|
+
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/).
|
|
21
|
+
|
|
19
22
|

|
|
20
23
|
|
|
21
24
|
## Table of contents
|
|
@@ -27,14 +30,15 @@ The project is designed to support the [Linear structure](https://gov-cy.github.
|
|
|
27
30
|
- [✅ Best Practices](#-best-practices)
|
|
28
31
|
- [📦 Full installation guide](#-full-installation-guide)
|
|
29
32
|
- [🛠️ Usage](#%EF%B8%8F-usage)
|
|
30
|
-
- [🧩 Dynamic services
|
|
33
|
+
- [🧩 Dynamic services](#-dynamic-services)
|
|
31
34
|
- [🛡️ Site eligibility checks](#%EF%B8%8F-site-eligibility-checks)
|
|
32
35
|
- [📤 Site submissions](#-site-submissions)
|
|
33
36
|
- [✅ Input validations](#-input-validations)
|
|
34
|
-
- [
|
|
35
|
-
- [💾 Temporary save](#-temporary-save)
|
|
37
|
+
- [🔀 Conditional logic](#-conditional-logic)
|
|
38
|
+
- [💾 Temporary save feature](#-temporary-save-feature)
|
|
39
|
+
- [🗃️ Files uploads feature](#%EF%B8%8F-files-uploads-feature)
|
|
36
40
|
- [🛣️ Routes](#%EF%B8%8F-routes)
|
|
37
|
-
- [👨💻
|
|
41
|
+
- [👨💻 Environment variables](#-environment-variables)
|
|
38
42
|
- [🔒 Security note](#-security-note)
|
|
39
43
|
- [❓ Troubleshooting / FAQ](#-troubleshooting--faq)
|
|
40
44
|
- [🙏 Credits](#-credits)
|
|
@@ -44,7 +48,7 @@ The project is designed to support the [Linear structure](https://gov-cy.github.
|
|
|
44
48
|
|
|
45
49
|
## ✨ Features
|
|
46
50
|
- Dynamic form rendering from JSON templates
|
|
47
|
-
- Support for `textInput`, `textArea`, `select`, `radios`, `checkboxes`, `datePicker`, `dateInput`
|
|
51
|
+
- Support for `textInput`, `textArea`, `select`, `radios`, `checkboxes`, `datePicker`, `dateInput`, `fileInput` elements
|
|
48
52
|
- Support for `conditional radios`
|
|
49
53
|
- Dynamic creation of check your answers page
|
|
50
54
|
- OpenID Connect authentication with CY Login
|
|
@@ -57,6 +61,7 @@ The project is designed to support the [Linear structure](https://gov-cy.github.
|
|
|
57
61
|
- Site level API eligibility checks
|
|
58
62
|
- API integration with retry logic for form submissions.
|
|
59
63
|
- Optional temporary save of in-progress form data via configurable API endpoints
|
|
64
|
+
- Optional file uploads via API endpoints
|
|
60
65
|
|
|
61
66
|
## 📋 Prerequisites
|
|
62
67
|
- Node.js 20+
|
|
@@ -137,9 +142,555 @@ The CY Login tokens are used to also connect with the various APIs through [cyCo
|
|
|
137
142
|
|
|
138
143
|
The CY Login settings are configured in the `secrets/.env` file.
|
|
139
144
|
|
|
140
|
-
### 🧩 Dynamic Services
|
|
145
|
+
### 🧩 Dynamic Services
|
|
141
146
|
Services are rendered dynamically using JSON templates stored in the `/data` folder. All the service configuration, pages, routes, and logic is stored in the JSON files. The service will load `data/:siteId.json` to get the form data when a user visits `/:siteId/:pageUrl`. Checkout the [express-service-shema.json](express-service-shema.json) and the example JSON structure of the **[test.json](data/test.json)** file for more details.
|
|
142
147
|
|
|
148
|
+
Here is an example JSON config:
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"site": {
|
|
153
|
+
"id": "test",
|
|
154
|
+
"lang": "el", //<-- Default language
|
|
155
|
+
"languages": [ //<-- Supported languages
|
|
156
|
+
{
|
|
157
|
+
"code": "el",
|
|
158
|
+
"label": "EL",
|
|
159
|
+
"alt": "Ελληνική γλώσσα",
|
|
160
|
+
"href": "?lang=el"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"code": "en",
|
|
164
|
+
"label": "EN",
|
|
165
|
+
"alt": "English language",
|
|
166
|
+
"href": "?lang=en"
|
|
167
|
+
}
|
|
168
|
+
],
|
|
169
|
+
"footerLinks": [ //<-- Links on the footer
|
|
170
|
+
{
|
|
171
|
+
"label": {
|
|
172
|
+
"el": "Δήλωση απορρήτου",
|
|
173
|
+
"en": "Privacy statement",
|
|
174
|
+
"tr": "Privacy statement"
|
|
175
|
+
},
|
|
176
|
+
"href": "test/privacy-statement"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"label": {
|
|
180
|
+
"el": "Cookies",
|
|
181
|
+
"en": "Cookies",
|
|
182
|
+
"tr": "Cookies"
|
|
183
|
+
},
|
|
184
|
+
"href": "test/cookie-policy"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"label": {
|
|
188
|
+
"el": "Προσβασιμότητα",
|
|
189
|
+
"en": "Accessibility",
|
|
190
|
+
"tr": "Accessibility"
|
|
191
|
+
},
|
|
192
|
+
"href": "test/accessibility-statement"
|
|
193
|
+
}
|
|
194
|
+
],
|
|
195
|
+
"footerIcons": [ //<-- Icons on the footer
|
|
196
|
+
{
|
|
197
|
+
"target": "_blank",
|
|
198
|
+
"src": {
|
|
199
|
+
"el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EL.png",
|
|
200
|
+
"en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EN.png",
|
|
201
|
+
"tr": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EN.png"
|
|
202
|
+
},
|
|
203
|
+
"alt": {
|
|
204
|
+
"el": "Χρηματοδοτείται από την ΕΕ Next Generation EU",
|
|
205
|
+
"en": "Funded by the EU Next Generation EU",
|
|
206
|
+
"tr": "Funded by the EU Next Generation EU"
|
|
207
|
+
},
|
|
208
|
+
"href": {
|
|
209
|
+
"el": "https://europa.eu/",
|
|
210
|
+
"en": "https://europa.eu/",
|
|
211
|
+
"tr": "https://europa.eu/"
|
|
212
|
+
},
|
|
213
|
+
"title": {
|
|
214
|
+
"el": "Μετάβαση στην ιστοσελίδα της ΕΕ",
|
|
215
|
+
"en": "Go to EU website",
|
|
216
|
+
"tr": "Go to EU website"
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"target": "_blank",
|
|
221
|
+
"src": {
|
|
222
|
+
"el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EL.png",
|
|
223
|
+
"en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EN.png",
|
|
224
|
+
"tr": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EN.png"
|
|
225
|
+
},
|
|
226
|
+
"alt": {
|
|
227
|
+
"el": "Κύπρος το Αύριο, σχέδιο ανάκαμψης και ανθεντικότητας",
|
|
228
|
+
"en": "Cyprus tomorrow, recovery and resilience plan",
|
|
229
|
+
"tr": "Cyprus tomorrow, recovery and resilience plan"
|
|
230
|
+
},
|
|
231
|
+
"href": {
|
|
232
|
+
"el": "http://www.cyprus-tomorrow.gov.cy/",
|
|
233
|
+
"en": "http://www.cyprus-tomorrow.gov.cy/",
|
|
234
|
+
"tr": "http://www.cyprus-tomorrow.gov.cy/"
|
|
235
|
+
},
|
|
236
|
+
"title": {
|
|
237
|
+
"el": "Μετάβαση στην ιστοσελίδα Κύπρος το Αύριο",
|
|
238
|
+
"en": "Go to Cyprus Tomorrow website",
|
|
239
|
+
"tr": "Go to Cyprus Tomorrow website"
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
],
|
|
243
|
+
"menu": { //<-- Menu altext
|
|
244
|
+
"el": "Μενού",
|
|
245
|
+
"en": "Menu",
|
|
246
|
+
"tr": "Menu"
|
|
247
|
+
},
|
|
248
|
+
"title": { //<-- Service title (meta)
|
|
249
|
+
"el": "Υπηρεσία τεστ",
|
|
250
|
+
"en": "Test service",
|
|
251
|
+
"tr": ""
|
|
252
|
+
},
|
|
253
|
+
"headerTitle": { // <-- The header title settings
|
|
254
|
+
"title": { //<-- Service title (as it apears in the header)
|
|
255
|
+
"el": "[Το ΟΝΟΜΑ της υπηρεσίας που θα φαίνεται στις φόρμες]",
|
|
256
|
+
"en": "[The NAME of the service as it will appear on forms]",
|
|
257
|
+
"tr": ""
|
|
258
|
+
},
|
|
259
|
+
"href": { // <-- The relative URL of the header title link (for each language)
|
|
260
|
+
"el":"/service-id",
|
|
261
|
+
"en":"/service-id",
|
|
262
|
+
"tr":"/service-id"
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
"description": { //<-- Service description (meta)
|
|
266
|
+
"el": "[Υποβάλετε αίτηση για ...]",
|
|
267
|
+
"en": "[Submit an application ...]",
|
|
268
|
+
"tr": ""
|
|
269
|
+
},
|
|
270
|
+
"url": "https://gov.cy", //<-- URL in (meta, for example `og:url`)
|
|
271
|
+
"cdn": { //<-- CDN URL and integrity
|
|
272
|
+
"dist": "https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@3.2.0/dist",
|
|
273
|
+
"cssIntegrity": "sha384-qjx16YXHG+Vq/NVtwU2aDTc7DoLOyaVNuOHrwA3aTrckpM/ycxZoR5dx7ezNJ/Lv",
|
|
274
|
+
"jsIntegrity": "sha384-tqEyCdi3GS4uDXctplAd7ODjiK5fo2Xlqv65e8w/cVvrcBf89tsxXFHXXNiUDyM7"
|
|
275
|
+
},
|
|
276
|
+
"submission_data_version": "1", //<-- Submission data version
|
|
277
|
+
"renderer_version": "1.16.1", //<-- govcy-frontend-renderer version
|
|
278
|
+
"design_systems_version": "3.2.0", //<-- govcy-design-system version
|
|
279
|
+
"homeRedirectPage": { //<-- Home redirect page
|
|
280
|
+
"el": "https://www.gov.cy/service/aitisi-gia-taftotita/",
|
|
281
|
+
"en": "https://www.gov.cy/en/service/issue-an-id-card/",
|
|
282
|
+
"tr": "https://www.gov.cy/en/service/issue-an-id-card/"
|
|
283
|
+
},
|
|
284
|
+
"copyrightText": { //<-- Copyright text
|
|
285
|
+
"el": "Κυπριακή Δημοκρατία, 2025",
|
|
286
|
+
"en": "Republic of Cyprus, 2025",
|
|
287
|
+
"tr": "Republic of Cyprus, 2025"
|
|
288
|
+
},
|
|
289
|
+
"submissionAPIEndpoint": { //<-- Submission API endpoint
|
|
290
|
+
"url": "TEST_SUBMISSION_API_URL",
|
|
291
|
+
"method": "POST",
|
|
292
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
293
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
294
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY",
|
|
295
|
+
"response": {
|
|
296
|
+
"errorResponse": {
|
|
297
|
+
"102": {
|
|
298
|
+
"error": "user not administrator",
|
|
299
|
+
"page": "/test/user-not-admin"
|
|
300
|
+
},
|
|
301
|
+
"105": {
|
|
302
|
+
"error": "user not registration",
|
|
303
|
+
"page": "/test/user-not-registered"
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
"submissionGetAPIEndpoint": { //<-- Submission GET API endpoint for temporary saving
|
|
309
|
+
"url": "TEST_SUBMISSION_GET_API_URL",
|
|
310
|
+
"method": "GET",
|
|
311
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
312
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
313
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY"
|
|
314
|
+
},
|
|
315
|
+
"submissionPutAPIEndpoint": { //<-- Submission PUT API endpoint for temporary saving
|
|
316
|
+
"url": "TEST_SUBMISSION_PUT_API_URL",
|
|
317
|
+
"method": "PUT",
|
|
318
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
319
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
320
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY"
|
|
321
|
+
},
|
|
322
|
+
"fileUploadAPIEndpoint": { //<-- File upload API endpoint
|
|
323
|
+
"url": "TEST_UPLOAD_FILE_API_URL",
|
|
324
|
+
"method": "POST",
|
|
325
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
326
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
327
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY"
|
|
328
|
+
},
|
|
329
|
+
"fileDownloadAPIEndpoint": { //<-- File download API endpoint
|
|
330
|
+
"url": "TEST_DOWNLOAD_FILE_API_URL",
|
|
331
|
+
"method": "GET",
|
|
332
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
333
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
334
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY"
|
|
335
|
+
},
|
|
336
|
+
"fileDeleteAPIEndpoint": { //<-- File delete API endpoint
|
|
337
|
+
"url": "TEST_DELETE_FILE_API_URL",
|
|
338
|
+
"method": "DELETE",
|
|
339
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
340
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
341
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY"
|
|
342
|
+
},
|
|
343
|
+
"eligibilityAPIEndpoints": [ //<-- Eligibility API endpoints
|
|
344
|
+
{
|
|
345
|
+
"url": "TEST_ELIGIBILITY_2_API_URL",
|
|
346
|
+
"method": "GET",
|
|
347
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
348
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
349
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY",
|
|
350
|
+
"cashingTimeoutMinutes": "60",
|
|
351
|
+
"params": {},
|
|
352
|
+
"response": {
|
|
353
|
+
"errorResponse": {
|
|
354
|
+
"105": {
|
|
355
|
+
"error": "user not registration",
|
|
356
|
+
"page": "/test/user-not-registered"
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
]
|
|
362
|
+
},
|
|
363
|
+
"pages": [ //<-- Pages
|
|
364
|
+
{
|
|
365
|
+
"pageData": { //<-- 1st Page's data (form)
|
|
366
|
+
"url": "index", // Page URL
|
|
367
|
+
"title": { // Page title
|
|
368
|
+
"el": "Επιλογή Εγγάφου",
|
|
369
|
+
"en": "Document selection",
|
|
370
|
+
"tr": ""
|
|
371
|
+
},
|
|
372
|
+
"layout": "layouts/govcyBase.njk", // Page layout
|
|
373
|
+
"mainLayout": "two-third", // Page main layout
|
|
374
|
+
"nextPage": "data-entry-radios" // The next page's URL
|
|
375
|
+
},
|
|
376
|
+
"pageTemplate": { //<-- Page template
|
|
377
|
+
"sections": [ //<-- Page sections
|
|
378
|
+
{
|
|
379
|
+
"name": "main", //<-- Main section
|
|
380
|
+
"elements": [ //<-- Main section elements
|
|
381
|
+
{
|
|
382
|
+
"element": "form", // Form element
|
|
383
|
+
"params": {
|
|
384
|
+
"elements": [ // Elements inside the form
|
|
385
|
+
{
|
|
386
|
+
"element": "checkboxes", // Checkboxes element
|
|
387
|
+
"params": { // Checkboxes parameters
|
|
388
|
+
"id": "certificate_select",
|
|
389
|
+
"name": "certificate_select",
|
|
390
|
+
"legend": {
|
|
391
|
+
"el": "Τι έγγραφα επιθυμείτε να εκδώσετε;",
|
|
392
|
+
"en": "What documents do you wish to issue?"
|
|
393
|
+
},
|
|
394
|
+
"items": [
|
|
395
|
+
{
|
|
396
|
+
"value": "birth",
|
|
397
|
+
"text": {
|
|
398
|
+
"el": "Πιστοποιητικό γέννησης",
|
|
399
|
+
"en": "Birth certificate",
|
|
400
|
+
"tr": ""
|
|
401
|
+
},
|
|
402
|
+
"hint": {
|
|
403
|
+
"el": "Αν η γέννηση έγινε στην Κύπρο ή στο εξωτερικό και έχει ενημερωθεί το μητρώο του Αρχείου Πληθυσμού ",
|
|
404
|
+
"en": "For a birth in Cyprus or abroad which Civil Registry is updated with "
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
"value": "permanent_residence",
|
|
409
|
+
"text": {
|
|
410
|
+
"el": "Βεβαίωση μόνιμης διαμονής",
|
|
411
|
+
"en": "Certificate of permanent residence",
|
|
412
|
+
"tr": ""
|
|
413
|
+
},
|
|
414
|
+
"hint": {
|
|
415
|
+
"el": "Για όσους είναι εγγεγραμμένοι στον εκλογικό κατάλογο",
|
|
416
|
+
"en": "For those registered in the electoral list"
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
"value": "student_proof_of_origin",
|
|
421
|
+
"text": {
|
|
422
|
+
"el": "Βεβαίωση καταγωγής",
|
|
423
|
+
"en": "Certificate of origin",
|
|
424
|
+
"tr": ""
|
|
425
|
+
},
|
|
426
|
+
"hint": {
|
|
427
|
+
"el": "Για αίτηση σε πανεπιστήμια στην Ελλάδα",
|
|
428
|
+
"en": "To apply to a university in Greece"
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
],
|
|
432
|
+
"isPageHeading": true,
|
|
433
|
+
"hint": {
|
|
434
|
+
"el": "Επιλέξτε ένα ή περισσότερα έγγραφα",
|
|
435
|
+
"en": "Select one or more documents",
|
|
436
|
+
"tr": ""
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
"validations": [ // Checkboxes validations
|
|
440
|
+
{
|
|
441
|
+
"check": "required",
|
|
442
|
+
"params": {
|
|
443
|
+
"checkValue": "",
|
|
444
|
+
"message": {
|
|
445
|
+
"el": "Επιλέξετε ένα ή περισσότερα έγγραφα",
|
|
446
|
+
"en": "Select one or more documents",
|
|
447
|
+
"tr": ""
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
]
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"element": "button",
|
|
455
|
+
"params": {
|
|
456
|
+
"id": "continue",
|
|
457
|
+
"variant": "primary",
|
|
458
|
+
"text": {
|
|
459
|
+
"el": "Συνέχεια",
|
|
460
|
+
"en": "Continue"
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
]
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
]
|
|
468
|
+
}
|
|
469
|
+
]
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"pageData": { //<-- 2nd Page's data (form)
|
|
474
|
+
"url": "data-entry-radios",
|
|
475
|
+
"title": {
|
|
476
|
+
"el": "Στοιχεία επικοινωνίας ",
|
|
477
|
+
"en": "Contact details",
|
|
478
|
+
"tr": ""
|
|
479
|
+
},
|
|
480
|
+
"layout": "layouts/govcyBase.njk",
|
|
481
|
+
"mainLayout": "two-third",
|
|
482
|
+
"nextPage": "review"
|
|
483
|
+
},
|
|
484
|
+
"pageTemplate": {
|
|
485
|
+
"sections": [
|
|
486
|
+
{
|
|
487
|
+
"name": "beforeMain",
|
|
488
|
+
"elements": [
|
|
489
|
+
{
|
|
490
|
+
"element": "backLink",
|
|
491
|
+
"params": {}
|
|
492
|
+
}
|
|
493
|
+
]
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
"name": "main",
|
|
497
|
+
"elements": [
|
|
498
|
+
{
|
|
499
|
+
"element": "form",
|
|
500
|
+
"params": {
|
|
501
|
+
"elements": [
|
|
502
|
+
{
|
|
503
|
+
"element": "radios",
|
|
504
|
+
"params": {
|
|
505
|
+
"id": "mobile_select",
|
|
506
|
+
"name": "mobile_select",
|
|
507
|
+
"legend": {
|
|
508
|
+
"el": "Σε ποιο κινητό μπορούμε να επικοινωνήσουμε μαζί σας;",
|
|
509
|
+
"en": "What mobile number can we use to contact you?"
|
|
510
|
+
},
|
|
511
|
+
"items": [
|
|
512
|
+
{
|
|
513
|
+
"value": "mobile",
|
|
514
|
+
"text": {
|
|
515
|
+
"el": "Στο [99 123456]",
|
|
516
|
+
"en": "You can use [99 123456]",
|
|
517
|
+
"tr": ""
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
"value": "other",
|
|
522
|
+
"text": {
|
|
523
|
+
"el": "Θα δώσω άλλο αριθμό",
|
|
524
|
+
"en": "I will give a different number",
|
|
525
|
+
"tr": ""
|
|
526
|
+
},
|
|
527
|
+
"conditionalElements": [
|
|
528
|
+
{
|
|
529
|
+
"element": "fileInput",
|
|
530
|
+
"params": {
|
|
531
|
+
"id": "proof",
|
|
532
|
+
"name": "proof",
|
|
533
|
+
"label": {
|
|
534
|
+
"el": "Αποδεικτικό τηλεφώνου",
|
|
535
|
+
"en": "Telephone proof",
|
|
536
|
+
"tr": ""
|
|
537
|
+
},
|
|
538
|
+
"isPageHeading": false,
|
|
539
|
+
"hint": {
|
|
540
|
+
"el": "PDF, JPG, JPEG, PNG, είναι οι αποδεκτές μορφές",
|
|
541
|
+
"en": "PDF, JPG, JPEG, PNG are the acceptable formats",
|
|
542
|
+
"tr": ""
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
"validations": [
|
|
546
|
+
{
|
|
547
|
+
"check": "required",
|
|
548
|
+
"params": {
|
|
549
|
+
"checkValue": "",
|
|
550
|
+
"message": {
|
|
551
|
+
"el": "Ανεβάστε τον αποδεικτικό τηλεφώνου",
|
|
552
|
+
"en": "Upload the telephone proof",
|
|
553
|
+
"tr": ""
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
]
|
|
558
|
+
}
|
|
559
|
+
]
|
|
560
|
+
}
|
|
561
|
+
],
|
|
562
|
+
"isPageHeading": true
|
|
563
|
+
},
|
|
564
|
+
"validations": [
|
|
565
|
+
{
|
|
566
|
+
"check": "required",
|
|
567
|
+
"params": {
|
|
568
|
+
"checkValue": "",
|
|
569
|
+
"message": {
|
|
570
|
+
"el": "Επιλέξετε αν θέλετε να χρησιμοποιήσετε το τηλέφωνο που φαίνεται εδώ, ή κάποιο άλλο",
|
|
571
|
+
"en": "Choose if you'd like to use the phone number shown here, or a different one",
|
|
572
|
+
"tr": ""
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
]
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
"element": "button",
|
|
580
|
+
"params": {
|
|
581
|
+
"id": "continue",
|
|
582
|
+
"variant": "primary",
|
|
583
|
+
"text": {
|
|
584
|
+
"el": "Συνέχεια",
|
|
585
|
+
"en": "Continue"
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
]
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
]
|
|
593
|
+
}
|
|
594
|
+
]
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
"pageData": { //<-- 3rd Page's data (not a form)
|
|
599
|
+
"url": "user-not-registered",
|
|
600
|
+
"title": {
|
|
601
|
+
"el": "Δεν είστε εγγεγραμμένοι ",
|
|
602
|
+
"en": "You are not an registered",
|
|
603
|
+
"tr": ""
|
|
604
|
+
},
|
|
605
|
+
"layout": "layouts/govcyBase.njk",
|
|
606
|
+
"mainLayout": "two-third"
|
|
607
|
+
},
|
|
608
|
+
"pageTemplate": {
|
|
609
|
+
"sections": [
|
|
610
|
+
{
|
|
611
|
+
"name": "beforeMain",
|
|
612
|
+
"elements": []
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
"name": "main",
|
|
616
|
+
"elements": [
|
|
617
|
+
{
|
|
618
|
+
"element": "textElement",
|
|
619
|
+
"params": {
|
|
620
|
+
"id": "title",
|
|
621
|
+
"type": "h1",
|
|
622
|
+
"text": {
|
|
623
|
+
"el": "Δεν είστε εγγεγραμμένοι",
|
|
624
|
+
"en": "You are not registered"
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
"element": "htmlElement",
|
|
630
|
+
"params": {
|
|
631
|
+
"id": "body",
|
|
632
|
+
"text": {
|
|
633
|
+
"el": "<p>Για να υποβάλετε σε υπηρεσία αυτή, χρειάζεται να είστε εγγεγραμμένοι στο ΧΥΖ.</p>",
|
|
634
|
+
"en": "<p>To submit in this service you need to be registered at XYZ.</p>"
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
]
|
|
639
|
+
}
|
|
640
|
+
]
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
"pageData": { //<-- 4th Page's data (not a form)
|
|
645
|
+
"url": "user-not-admin",
|
|
646
|
+
"title": {
|
|
647
|
+
"el": "Δεν είστε διαχειριστής ",
|
|
648
|
+
"en": "You are not an administrator",
|
|
649
|
+
"tr": ""
|
|
650
|
+
},
|
|
651
|
+
"layout": "layouts/govcyBase.njk",
|
|
652
|
+
"mainLayout": "two-third"
|
|
653
|
+
},
|
|
654
|
+
"pageTemplate": {
|
|
655
|
+
"sections": [
|
|
656
|
+
{
|
|
657
|
+
"name": "beforeMain",
|
|
658
|
+
"elements": []
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
"name": "main",
|
|
662
|
+
"elements": [
|
|
663
|
+
{
|
|
664
|
+
"element": "textElement",
|
|
665
|
+
"params": {
|
|
666
|
+
"id": "title",
|
|
667
|
+
"type": "h1",
|
|
668
|
+
"text": {
|
|
669
|
+
"el": "Δεν είστε διαχειριστής ",
|
|
670
|
+
"en": "You are not an administrator"
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
"element": "htmlElement",
|
|
676
|
+
"params": {
|
|
677
|
+
"id": "body",
|
|
678
|
+
"text": {
|
|
679
|
+
"el": "<p>Για να υποβάλετε σε υπηρεσία αυτή, χρειάζεται να είστε διαχειριστής στο ΧΥΖ.</p>",
|
|
680
|
+
"en": "<p>To submit in this service you need to be an administrator of XYZ.</p>"
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
]
|
|
685
|
+
}
|
|
686
|
+
]
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
]
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
```
|
|
693
|
+
|
|
143
694
|
Here are some details explaining the JSON structure:
|
|
144
695
|
|
|
145
696
|
- `site` object: Contains information about the site, including the site ID, language, and footer links. See [govcy-frontend-renderer](https://github.com/gov-cy/govcy-frontend-renderer/tree/main#site-and-page-meta-data-explained) for more details. Some fields that are only specific to the govcy-express-forms project are the following:
|
|
@@ -155,8 +706,14 @@ Here are some details explaining the JSON structure:
|
|
|
155
706
|
```
|
|
156
707
|
- `eligibilityAPIEndpoints` : An array of API endpoints, to be used for service eligibility. See more on the [Eligibility API Endoints](#%EF%B8%8F-site-eligibility-checks) section below.
|
|
157
708
|
- `submissionAPIEndpoint`: The submission API endpoint, to be used for submitting the form. See more on the [Submission API Endoint](#-site-submissions) section below.
|
|
709
|
+
- `submissionGetAPIEndpoint`: The submission get API endpoint, to be used for getting the submission data. See more on the [temporary save feature](#-temporary-save-feature) section below.
|
|
710
|
+
- `submissionPutAPIEndpoint`: The submission put API endpoint, to be used for temporary saving the submission data. See more on the [temporary save feature](#-temporary-save-feature) section below.
|
|
711
|
+
- `fileUploadAPIEndpoint`: The file upload API endpoint, to be used for uploading files. See more on the [file upload feature](#%EF%B8%8F-files-uploads-feature) section below.
|
|
712
|
+
- `fileDownloadAPIEndpoint`: The file download API endpoint, to be used for downloading files. See more on the [file upload feature](#%EF%B8%8F-files-uploads-feature) section below.
|
|
713
|
+
- `fileDeleteAPIEndpoint`: The file delete API endpoint, to be used for deleting files. See more on the [file upload feature](#%EF%B8%8F-files-uploads-feature) section below.
|
|
158
714
|
- `pages` array: An array of page objects, each representing a page in the site.
|
|
159
715
|
- `pageData` object: Contains the metadata to be rendered on the page. See [govcy-frontend-renderer](https://github.com/gov-cy/govcy-frontend-renderer/tree/main#site-and-page-meta-data-explained) for more details
|
|
716
|
+
- `nextPage`: The URL of the next page to be rendered after the user clicks the `continue` button.
|
|
160
717
|
- `pageTemplate` object: Contains the page template to be rendered on the page. See [govcy-frontend-renderer](https://github.com/gov-cy/govcy-frontend-renderer/tree/main#json-input-template) for more details
|
|
161
718
|
- `elements` array: An array of elements to be rendered on the page. See all supported [govcy-frontend-renderer elements](https://github.com/gov-cy/govcy-frontend-renderer/blob/main/DESIGN_ELEMENTS.md) for more details
|
|
162
719
|
|
|
@@ -211,8 +768,7 @@ Here's an example of a page defined in the JSON file:
|
|
|
211
768
|
"element": "backLink",
|
|
212
769
|
"params": {}
|
|
213
770
|
}
|
|
214
|
-
]
|
|
215
|
-
"params": {}
|
|
771
|
+
]
|
|
216
772
|
},
|
|
217
773
|
{
|
|
218
774
|
"name": "main",
|
|
@@ -297,14 +853,24 @@ Lets break down the JSON config for this page:
|
|
|
297
853
|
- `pageData.nextPage` is the next page to redirect to when the user clicks the `continue` button and all validations pass, in this case it will redirect to `/:siteId/telephone-number`
|
|
298
854
|
- `pageData.conditions` is the array that defines the [conditional logic](#-conditional-logic)
|
|
299
855
|
- **pageTemplate** is the page's template, which is a JSON object that contains the sections and elements of the page. Check out the [govcy-frontend-renderer's documentation](https://github.com/gov-cy/govcy-frontend-renderer/blob/main/README.md) for more details.
|
|
856
|
+
- `sections` is an array of sections, which is an array of elements. Sections allowed: `beforeMain`, `main`, `afterMain`.
|
|
857
|
+
- `elements` is an array of elements for the said section. Seem more details on the [govcy-frontend-renderer's design elements documentation](https://github.com/gov-cy/govcy-frontend-renderer/blob/main/DESIGN_ELEMENTS.md).
|
|
300
858
|
|
|
301
859
|
**Forms vs static content**
|
|
302
860
|
|
|
303
861
|
- If the `pageTemplate` includes a `form` element in the `main` section and `button` element, the system will treat it as form and will:
|
|
304
862
|
- Perform the eligibility checks
|
|
305
863
|
- Display the form
|
|
306
|
-
- Collect the form data
|
|
307
|
-
|
|
864
|
+
- Collect the form data for the following input elements (more details on the [govcy-frontend-renderer's design elements documentation](https://github.com/gov-cy/govcy-frontend-renderer/blob/main/DESIGN_ELEMENTS.md)):
|
|
865
|
+
- `textInput`
|
|
866
|
+
- `textArea`
|
|
867
|
+
- `select`
|
|
868
|
+
- `radios`
|
|
869
|
+
- `checkboxes`
|
|
870
|
+
- `datePicker`
|
|
871
|
+
- `dateInput`
|
|
872
|
+
- `fileInput`: the file upload feature must be enabled to use this element (see more on the [file upload feature](#%EF%B8%8F-files-uploads-feature) section below)
|
|
873
|
+
- Validate the form data (see more on the [Input validations](#-input-validations) section below)
|
|
308
874
|
- Store the form data in the systems data layer
|
|
309
875
|
- Redirect the user to the next page (or `review` page if the user came from the review page)
|
|
310
876
|
- Else if the `pageTemplate` does not include a `form` element in the `main` section, the system will treat it as static content and will:
|
|
@@ -494,7 +1060,9 @@ Content-Type: application/json
|
|
|
494
1060
|
The API is expected to return a JSON response with the following structure (see [govcyApiRequest.mjs](src/utils/govcyApiRequest.mjs) for normalization):
|
|
495
1061
|
|
|
496
1062
|
**On Success:**
|
|
497
|
-
```
|
|
1063
|
+
```http
|
|
1064
|
+
HTTP/1.1 200 OK
|
|
1065
|
+
|
|
498
1066
|
{
|
|
499
1067
|
"Succeeded": true,
|
|
500
1068
|
"ErrorCode": 0,
|
|
@@ -503,7 +1071,9 @@ The API is expected to return a JSON response with the following structure (see
|
|
|
503
1071
|
```
|
|
504
1072
|
|
|
505
1073
|
**On Failure:**
|
|
506
|
-
```
|
|
1074
|
+
```http
|
|
1075
|
+
HTTP/1.1 200 OK
|
|
1076
|
+
|
|
507
1077
|
{
|
|
508
1078
|
"Succeeded": false,
|
|
509
1079
|
"ErrorCode": 102,
|
|
@@ -620,14 +1190,14 @@ Accept: text/plain
|
|
|
620
1190
|
Content-Type: application/json
|
|
621
1191
|
|
|
622
1192
|
{
|
|
623
|
-
"
|
|
624
|
-
"
|
|
625
|
-
"
|
|
626
|
-
"
|
|
627
|
-
"
|
|
628
|
-
"
|
|
629
|
-
"
|
|
630
|
-
"
|
|
1193
|
+
"submissionUsername": "username",
|
|
1194
|
+
"submissionEmail": "email@example.com",
|
|
1195
|
+
"submissionData": "{\"index\":{\"certificate_select\":[\"birth\",\"permanent_residence\"]}}",
|
|
1196
|
+
"submissionDataVersion": "1",
|
|
1197
|
+
"printFriendlyData": "[{\"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\":\"\"}]}]}]",
|
|
1198
|
+
"rendererData": "{\"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\"}}]}]}}]}]}}",
|
|
1199
|
+
"rendererVersion": "1.14.3",
|
|
1200
|
+
"designSystemsVersion": "3.2.0",
|
|
631
1201
|
"service": "{\"id\":\"test\",\"title\":{\"el\":\"Υπηρεσία τεστ\",\"en\":\"Test service\",\"tr\":\"\"}}"
|
|
632
1202
|
}
|
|
633
1203
|
```
|
|
@@ -637,7 +1207,9 @@ Content-Type: application/json
|
|
|
637
1207
|
The API is expected to return a JSON response with the following structure (see [govcyApiRequest.mjs](src/utils/govcyApiRequest.mjs) for normalization):
|
|
638
1208
|
|
|
639
1209
|
**On Success:**
|
|
640
|
-
```
|
|
1210
|
+
```http
|
|
1211
|
+
HTTP/1.1 200 OK
|
|
1212
|
+
|
|
641
1213
|
{
|
|
642
1214
|
"Succeeded": true,
|
|
643
1215
|
"ErrorCode": 0,
|
|
@@ -649,7 +1221,9 @@ The API is expected to return a JSON response with the following structure (see
|
|
|
649
1221
|
```
|
|
650
1222
|
|
|
651
1223
|
**On Failure:**
|
|
652
|
-
```
|
|
1224
|
+
```http
|
|
1225
|
+
HTTP/1.1 200 OK
|
|
1226
|
+
|
|
653
1227
|
{
|
|
654
1228
|
"Succeeded": false,
|
|
655
1229
|
"ErrorCode": 102,
|
|
@@ -674,15 +1248,15 @@ The API is expected to return a JSON response with the following structure (see
|
|
|
674
1248
|
The data is collected from the form elements and the data layer and are sent via the submission API in the following format:
|
|
675
1249
|
|
|
676
1250
|
```json
|
|
677
|
-
|
|
678
|
-
"
|
|
679
|
-
"
|
|
680
|
-
"
|
|
681
|
-
"
|
|
682
|
-
"
|
|
683
|
-
"
|
|
684
|
-
"
|
|
685
|
-
"
|
|
1251
|
+
{
|
|
1252
|
+
"submissionUsername" : "", // User's username
|
|
1253
|
+
"submissionEmail" : "", // User's email
|
|
1254
|
+
"submissionData": "{}", // Raw data as submitted by the user in each page
|
|
1255
|
+
"submissionDataVersion": "",// The submission data version
|
|
1256
|
+
"printFriendlyData": "[]", // Print friendly data
|
|
1257
|
+
"rendererData" :"{}", // Renderer data of the summary list
|
|
1258
|
+
"rendererVersion": "", // The renderer version
|
|
1259
|
+
"designSystemsVersion": "", // The design systems version
|
|
686
1260
|
"service": "{}" // Service info
|
|
687
1261
|
}
|
|
688
1262
|
```
|
|
@@ -693,50 +1267,49 @@ The data is collected from the form elements and the data layer and are sent via
|
|
|
693
1267
|
|
|
694
1268
|
> ℹ️ **Note:**
|
|
695
1269
|
>
|
|
696
|
-
> When sent to the API, the fields `
|
|
1270
|
+
> When sent to the API, the fields `submissionData`, `rendererData`, `printFriendlyData`, and `service` are stringified using `JSON.stringify()`.
|
|
697
1271
|
>
|
|
698
1272
|
> The sample below shows the structure **before** stringification for clarity.
|
|
699
1273
|
|
|
700
1274
|
```json
|
|
701
1275
|
{
|
|
702
|
-
"
|
|
703
|
-
"
|
|
704
|
-
"
|
|
705
|
-
"
|
|
1276
|
+
"submissionUsername": "username", // User's username
|
|
1277
|
+
"submissionEmail": "email@example.com", // User's email
|
|
1278
|
+
"submissionDataVersion": "0.1", // Submission data version
|
|
1279
|
+
"submissionData": { // Submission raw data. Object, will be stringified
|
|
706
1280
|
"index": { // Page level
|
|
707
|
-
"
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
1281
|
+
"id_select": ["id", "arc"], // field level: checkboxes are ALWAYS arrays (may be []); radios/select/text are strings
|
|
1282
|
+
"id_number": "654654",
|
|
1283
|
+
"arc_number": "",
|
|
1284
|
+
"aka": "232323",
|
|
1285
|
+
"evidenceAttachment": // File attachments contains an object with `fileId` and `sha256`
|
|
1286
|
+
{
|
|
1287
|
+
"fileId": "1234567891234567890",
|
|
1288
|
+
"sha256": "123456789012345678901234567890123456789012345678901234567890123456"
|
|
1289
|
+
}
|
|
713
1290
|
},
|
|
714
1291
|
"appointment": {
|
|
715
|
-
"
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
"fileno_orismenou": ""
|
|
725
|
-
}
|
|
1292
|
+
"diorismos": "monimos",
|
|
1293
|
+
"fileno_monimos": "3233",
|
|
1294
|
+
"eidikotita_monimos": "1",
|
|
1295
|
+
"fileno_sumvasiouxos": "",
|
|
1296
|
+
"eidikotita_sumvasiouxos": "",
|
|
1297
|
+
"fileno_aoristou": "",
|
|
1298
|
+
"eidikotita_aoristou": "",
|
|
1299
|
+
"program": "",
|
|
1300
|
+
"fileno_orismenou": ""
|
|
726
1301
|
},
|
|
727
1302
|
"takeover": {
|
|
728
|
-
"
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
"reason": "24324dssf"
|
|
735
|
-
}
|
|
1303
|
+
"date_start_day": "11",
|
|
1304
|
+
"date_start_month": "12",
|
|
1305
|
+
"date_start_year": "2020",
|
|
1306
|
+
"date_on_contract": "date_other",
|
|
1307
|
+
"date_contract": "16/04/2025",
|
|
1308
|
+
"reason": "24324dssf"
|
|
736
1309
|
}
|
|
737
1310
|
},
|
|
738
|
-
"
|
|
739
|
-
"
|
|
1311
|
+
"submissionDataVersion": "1", // Submission data version
|
|
1312
|
+
"rendererData": { // Summary list renderer data ready for rendering . Object, will be stringified
|
|
740
1313
|
"element": "summaryList",
|
|
741
1314
|
"params": {
|
|
742
1315
|
"items": [
|
|
@@ -943,7 +1516,7 @@ The data is collected from the form elements and the data layer and are sent via
|
|
|
943
1516
|
]
|
|
944
1517
|
}
|
|
945
1518
|
},
|
|
946
|
-
"
|
|
1519
|
+
"printFriendlyData": [ // Print friendly data. Object, will be stringified
|
|
947
1520
|
{
|
|
948
1521
|
"pageUrl": "index", // Page URL
|
|
949
1522
|
"pageTitle": { // Page title
|
|
@@ -958,8 +1531,8 @@ The data is collected from the form elements and the data layer and are sent via
|
|
|
958
1531
|
"el": "Ταυτοποίηση",
|
|
959
1532
|
"en": "Identification"
|
|
960
1533
|
},
|
|
961
|
-
"value": ["id", "arc"], // Field value.
|
|
962
|
-
"valueLabel": [ // Field value label
|
|
1534
|
+
"value": ["id", "arc"], // Field value. // field level: checkboxes are ALWAYS arrays (may be []); radios/select/text are strings
|
|
1535
|
+
"valueLabel": [ // Field value label
|
|
963
1536
|
{
|
|
964
1537
|
"el": "Ταυτότητα",
|
|
965
1538
|
"en": "ID",
|
|
@@ -1106,8 +1679,8 @@ The data is collected from the form elements and the data layer and are sent via
|
|
|
1106
1679
|
]
|
|
1107
1680
|
}
|
|
1108
1681
|
],
|
|
1109
|
-
"
|
|
1110
|
-
"
|
|
1682
|
+
"rendererVersion": "1.14.1", // Renderer version
|
|
1683
|
+
"designSystemsVersion": "3.1.0", // Design systems version
|
|
1111
1684
|
"service": { // Service metadata. Object, will be stringified
|
|
1112
1685
|
"id": "takeover",
|
|
1113
1686
|
"title": {
|
|
@@ -1131,6 +1704,7 @@ The project includes input validation for the following elements:
|
|
|
1131
1704
|
- `checkboxes`
|
|
1132
1705
|
- `datePicker`
|
|
1133
1706
|
- `dateInput`
|
|
1707
|
+
- `fileInput` (only required check)
|
|
1134
1708
|
|
|
1135
1709
|
The validation rules for each element are defined in the `"validations` array for each element. The project support the following validations:
|
|
1136
1710
|
|
|
@@ -1186,7 +1760,7 @@ Example:
|
|
|
1186
1760
|
]
|
|
1187
1761
|
```
|
|
1188
1762
|
|
|
1189
|
-
###
|
|
1763
|
+
### 🔀 Conditional logic
|
|
1190
1764
|
|
|
1191
1765
|
The project supports conditional logic on pages. Conditional logic is evaluated using a custom `govcyExpressions.mjs` module, which executes expressions in a safe and scoped context using `new Function`. Only safe data access through the `dataLayer` is allowed. The system uses expressions and session data from the service's [data layer](NOTES.md#data-layer) to decide if a page will be shown or not.
|
|
1192
1766
|
|
|
@@ -1414,12 +1988,12 @@ Explanation:
|
|
|
1414
1988
|
- `[].concat(...)`: safely flattens a string or array into an array.
|
|
1415
1989
|
- `.includes('value1')`: checks if the value is selected.
|
|
1416
1990
|
|
|
1417
|
-
### 💾 Temporary save
|
|
1991
|
+
### 💾 Temporary save feature
|
|
1418
1992
|
|
|
1419
1993
|
The **temporary save** feature allows user progress to be stored in an external API and automatically reloaded on the next visit.
|
|
1420
1994
|
This is useful for long forms or cases where users may leave and return later.
|
|
1421
1995
|
|
|
1422
|
-
#### How to configure temporary save
|
|
1996
|
+
#### How to enable and configure temporary save
|
|
1423
1997
|
To use this feature, configure the config JSON file. In your service’s `site` object, add both a `submissionGetAPIEndpoint` and `submissionPutAPIEndpoint` entry:
|
|
1424
1998
|
|
|
1425
1999
|
```json
|
|
@@ -1456,7 +2030,7 @@ TEST_SUBMISSION_API_SERVICE_ID=123
|
|
|
1456
2030
|
3. If not found, call the PUT endpoint to create a new temporary record.
|
|
1457
2031
|
- **On every form POST**, after successful validation:
|
|
1458
2032
|
- The `submissionPutAPIEndpoint` will fire-and-forget a `PUT` request to update the saved submission with the latest form data.
|
|
1459
|
-
- The payload includes all required submission fields with `
|
|
2033
|
+
- The payload includes all required submission fields with `submissionData` JSON-stringified.
|
|
1460
2034
|
|
|
1461
2035
|
#### `submissionGetAPIEndpoint` `GET` API Request and Response
|
|
1462
2036
|
This API is used to retrieve the saved submission data.
|
|
@@ -1492,7 +2066,9 @@ The API is expected to return a JSON response with the following structure:
|
|
|
1492
2066
|
|
|
1493
2067
|
**When temporary submission data are found:**
|
|
1494
2068
|
|
|
1495
|
-
```
|
|
2069
|
+
```http
|
|
2070
|
+
HTTP/1.1 200 OK
|
|
2071
|
+
|
|
1496
2072
|
{
|
|
1497
2073
|
"Succeeded": true,
|
|
1498
2074
|
"ErrorCode": 0,
|
|
@@ -1505,7 +2081,9 @@ The API is expected to return a JSON response with the following structure:
|
|
|
1505
2081
|
|
|
1506
2082
|
**When temporary submission data are NOT found:**
|
|
1507
2083
|
|
|
1508
|
-
```
|
|
2084
|
+
```http
|
|
2085
|
+
HTTP/1.1 404 Not Found
|
|
2086
|
+
|
|
1509
2087
|
{
|
|
1510
2088
|
"Succeeded": true,
|
|
1511
2089
|
"ErrorCode": 0,
|
|
@@ -1516,7 +2094,9 @@ The API is expected to return a JSON response with the following structure:
|
|
|
1516
2094
|
|
|
1517
2095
|
**When temporary submission retreival fails:**
|
|
1518
2096
|
|
|
1519
|
-
```
|
|
2097
|
+
```http
|
|
2098
|
+
HTTP/1.1 200 OK
|
|
2099
|
+
|
|
1520
2100
|
{
|
|
1521
2101
|
"Succeeded": false,
|
|
1522
2102
|
"ErrorCode": 401,
|
|
@@ -1551,7 +2131,7 @@ Accept: text/plain
|
|
|
1551
2131
|
Content-Type: application/json
|
|
1552
2132
|
|
|
1553
2133
|
{
|
|
1554
|
-
"
|
|
2134
|
+
"submissionData" : "{\"index\":{\"formData\":{\"certificate_select\":[\"birth\",\"permanent_residence\"]}},\"data-entry-radios\":{\"formData\":{\"mobile_select\":\"other\",\"mobileTxt\":\"+35799484967\"}}}"
|
|
1555
2135
|
}
|
|
1556
2136
|
```
|
|
1557
2137
|
|
|
@@ -1561,7 +2141,9 @@ The API is expected to return a JSON response with the following structure:
|
|
|
1561
2141
|
|
|
1562
2142
|
**On success:**
|
|
1563
2143
|
|
|
1564
|
-
```
|
|
2144
|
+
```http
|
|
2145
|
+
HTTP/1.1 200 OK
|
|
2146
|
+
|
|
1565
2147
|
{
|
|
1566
2148
|
"Succeeded": true,
|
|
1567
2149
|
"ErrorCode": 0,
|
|
@@ -1574,7 +2156,9 @@ The API is expected to return a JSON response with the following structure:
|
|
|
1574
2156
|
|
|
1575
2157
|
**On failure:**
|
|
1576
2158
|
|
|
1577
|
-
```
|
|
2159
|
+
```http
|
|
2160
|
+
HTTP/1.1 401 Unauthorized
|
|
2161
|
+
|
|
1578
2162
|
{
|
|
1579
2163
|
"Succeeded": false,
|
|
1580
2164
|
"ErrorCode": 401,
|
|
@@ -1590,6 +2174,384 @@ The API is expected to return a JSON response with the following structure:
|
|
|
1590
2174
|
If these endpoints are not defined in the service JSON, the temporary save/load logic is skipped entirely.
|
|
1591
2175
|
Existing services will continue to work without modification.
|
|
1592
2176
|
|
|
2177
|
+
### 🗃️ Files uploads feature
|
|
2178
|
+
|
|
2179
|
+
The **Files uploads** feature allows user progress to upload, remove and download files. The files will be stored in an external API and automatically reloaded on the next visit.
|
|
2180
|
+
|
|
2181
|
+
#### Pre-requisites for the files uploads feature
|
|
2182
|
+
The [💾 Temporary save feature](#-temporary-save-feature) must be enabled for the file uploads feature to work.
|
|
2183
|
+
|
|
2184
|
+
|
|
2185
|
+
#### How to enable and configure file uploads
|
|
2186
|
+
To use this feature, configure the config JSON file. In your service’s `site` object, add a `fileUploadAPIEndpoint`, `fileDownloadAPIEndpoint`and `fileDeleteAPIEndpoint` entry:
|
|
2187
|
+
|
|
2188
|
+
```json
|
|
2189
|
+
"fileUploadAPIEndpoint": {
|
|
2190
|
+
"url": "TEST_UPLOAD_FILE_API_URL",
|
|
2191
|
+
"method": "POST",
|
|
2192
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
2193
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID"
|
|
2194
|
+
},
|
|
2195
|
+
"fileDownloadAPIEndpoint": {
|
|
2196
|
+
"url": "TEST_DOWNLOAD_FILE_API_URL",
|
|
2197
|
+
"method": "GET",
|
|
2198
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
2199
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID"
|
|
2200
|
+
},
|
|
2201
|
+
"fileDeleteAPIEndpoint": {
|
|
2202
|
+
"url": "TEST_DELETE_FILE_API_URL",
|
|
2203
|
+
"method": "DELETE",
|
|
2204
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
2205
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID"
|
|
2206
|
+
}
|
|
2207
|
+
```
|
|
2208
|
+
|
|
2209
|
+
These values should point to environment variables that hold your real endpoint URLs and credentials.
|
|
2210
|
+
|
|
2211
|
+
In your `secrets/.env` file (and staging/production configs), define the variables referenced above:
|
|
2212
|
+
|
|
2213
|
+
```dotenv
|
|
2214
|
+
TEST_UPLOAD_FILE_API_URL=https://example.com/api/fileUpload
|
|
2215
|
+
TEST_DOWNLOAD_FILE_API_URL=https://example.com/api/fileDownload
|
|
2216
|
+
TEST_SUBMISSION_API_CLIENT_KEY=12345678901234567890123456789000
|
|
2217
|
+
TEST_SUBMISSION_API_SERVICE_ID=123
|
|
2218
|
+
```
|
|
2219
|
+
|
|
2220
|
+
|
|
2221
|
+
#### How to define the file input field in the JSON config
|
|
2222
|
+
The files input field is defined under the `pages[i].pageTemplate.sections["main"].elements[0].elements` array. Basically it must exist in the page template of a page inside a form.
|
|
2223
|
+
|
|
2224
|
+
The element type for files input is `fileInput` (see it's definition in [govcy-frontend-renderer](https://github.com/gov-cy/govcy-frontend-renderer/blob/main/DESIGN_ELEMENTS.md))
|
|
2225
|
+
|
|
2226
|
+
Here is a sample code section of a page definition with a file input field:
|
|
2227
|
+
|
|
2228
|
+
```json
|
|
2229
|
+
{
|
|
2230
|
+
"pageData": {
|
|
2231
|
+
"url": "data-entry-file",
|
|
2232
|
+
"title": {
|
|
2233
|
+
"el": "Λογαριασμός κινήσεως",
|
|
2234
|
+
"en": "Utility bill"
|
|
2235
|
+
},
|
|
2236
|
+
"layout": "layouts/govcyBase.njk",
|
|
2237
|
+
"mainLayout": "two-third",
|
|
2238
|
+
"nextPage": "data-entry-all"
|
|
2239
|
+
},
|
|
2240
|
+
"pageTemplate": {
|
|
2241
|
+
"sections": [
|
|
2242
|
+
{
|
|
2243
|
+
"name": "beforeMain",
|
|
2244
|
+
"elements": [
|
|
2245
|
+
{
|
|
2246
|
+
"element": "backLink",
|
|
2247
|
+
"params": {}
|
|
2248
|
+
}
|
|
2249
|
+
]
|
|
2250
|
+
},
|
|
2251
|
+
{
|
|
2252
|
+
"name": "main",
|
|
2253
|
+
"elements": [
|
|
2254
|
+
{
|
|
2255
|
+
"element": "form",
|
|
2256
|
+
"params": {
|
|
2257
|
+
"elements": [
|
|
2258
|
+
{
|
|
2259
|
+
"element": "fileInput", //<-- this is the file input
|
|
2260
|
+
"params": {
|
|
2261
|
+
"id": "utility",
|
|
2262
|
+
"name": "utility",
|
|
2263
|
+
"label": {
|
|
2264
|
+
"el": "Λογαριασμός κινήσεως",
|
|
2265
|
+
"en": "Utility bill"
|
|
2266
|
+
},
|
|
2267
|
+
"isPageHeading": true,
|
|
2268
|
+
"hint": {
|
|
2269
|
+
"el": "PDF, JPG, JPEG, PNG, είναι οι αποδεκτές μορφές",
|
|
2270
|
+
"en": "PDF, JPG, JPEG, PNG are the acceptable formats"
|
|
2271
|
+
}
|
|
2272
|
+
},
|
|
2273
|
+
"validations": [ //<-- this is the file input validations
|
|
2274
|
+
{
|
|
2275
|
+
"check": "required",
|
|
2276
|
+
"params": {
|
|
2277
|
+
"checkValue": "",
|
|
2278
|
+
"message": {
|
|
2279
|
+
"el": "Ανεβάστε τον λογαριασμό κινήσεως",
|
|
2280
|
+
"en": "Upload the utility bill"
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
]
|
|
2285
|
+
},
|
|
2286
|
+
{
|
|
2287
|
+
"element": "button",
|
|
2288
|
+
"params": {
|
|
2289
|
+
"id": "continue",
|
|
2290
|
+
"variant": "primary",
|
|
2291
|
+
"text": {
|
|
2292
|
+
"el": "Συνέχεια",
|
|
2293
|
+
"en": "Continue"
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
]
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
]
|
|
2301
|
+
}
|
|
2302
|
+
]
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
```
|
|
2306
|
+
|
|
2307
|
+
#### How file uploads works
|
|
2308
|
+
|
|
2309
|
+
- **On a form page with an upload input field**:
|
|
2310
|
+
- **On first load**: the page displays the fileInput field to choose a file.
|
|
2311
|
+
- **On choosing a file**: the file is uploaded to the `fileUploadAPIEndpoint` endpoint.
|
|
2312
|
+
- 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:
|
|
2313
|
+
- The fileInput element is defined in the JSON config
|
|
2314
|
+
- API endpoints and environment variables are defined
|
|
2315
|
+
- The page is not skiped because of conditional logic
|
|
2316
|
+
- The file is not empty
|
|
2317
|
+
- The file size must be less than 5MB
|
|
2318
|
+
- The file type must be one of the following: pdf, jpg, jpeg, png
|
|
2319
|
+
- 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.
|
|
2320
|
+
- **On a form page after upload**:
|
|
2321
|
+
- The `fileView` element is displayed with links to `View` or `Delete` the file.
|
|
2322
|
+
- **When clinking `view`**:
|
|
2323
|
+
- The file is downloaded using the `fileDownloadAPIEndpoint` and opened in a new tab.
|
|
2324
|
+
- **When clinking `delete`**:
|
|
2325
|
+
- A confimation page is displayed asking the user to confirm the deletion. If the user confirms (clicks `Yes`):
|
|
2326
|
+
- The file is deleted using the `fileDeleteAPIEndpoint`
|
|
2327
|
+
- The file is deleted from the data layer and the `fileView` element is removed from the page.
|
|
2328
|
+
- If the same file is used on another page (with the same `fileId` and `sha256`), they are also removed from the data layer
|
|
2329
|
+
- **On the `review` page after upload**:
|
|
2330
|
+
- The element is displayed with a link to `View file`. A `Change` link is also displayed for the whole page.
|
|
2331
|
+
- **On the `success` page and email after upload**:
|
|
2332
|
+
- The element is displayed with links a marking `File uploaded`.
|
|
2333
|
+
|
|
2334
|
+
|
|
2335
|
+
#### `fileUploadAPIEndpoint` `POST` API Request and Response
|
|
2336
|
+
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.
|
|
2337
|
+
|
|
2338
|
+
**Request:**
|
|
2339
|
+
|
|
2340
|
+
- **HTTP Method**: POST
|
|
2341
|
+
- **URL**: Resolved from the url property in your config (from the environment variable) concatenated with `/:tag` which defines the type of the file (for example `passport`). For example `https://example.com/api/fileUpload/:tag`
|
|
2342
|
+
- **Headers**:
|
|
2343
|
+
- **Authorization**: `Bearer <access_token>` (form user's cyLogin access token)
|
|
2344
|
+
- **client-key**: `<clientKey>` (from config/env)
|
|
2345
|
+
- **service-id**: `<serviceId>` (from config/env)
|
|
2346
|
+
- **Accept**: `application/json`
|
|
2347
|
+
- **Content-Type**: `multipart/form-data` (typically automatically set when using FormData in the browser)
|
|
2348
|
+
- **Body (multipart/form-data)**: The body the actual file to be uploaded (PDF, JPEG, etc.)
|
|
2349
|
+
|
|
2350
|
+
**Example Request:**
|
|
2351
|
+
|
|
2352
|
+
``` bash
|
|
2353
|
+
curl --location 'https://example.gov.cy/api/v1/files/upload/passport' \
|
|
2354
|
+
--header 'client-key: 12345678901234567890123456789000' \
|
|
2355
|
+
--header 'service-id: 123' \
|
|
2356
|
+
--header 'Authorization: Bearer eyJhbGciOi...' \
|
|
2357
|
+
--form 'file=@"/path/to/file.pdf"'
|
|
2358
|
+
```
|
|
2359
|
+
|
|
2360
|
+
**Response:**
|
|
2361
|
+
|
|
2362
|
+
The API is expected to return a JSON response with the following structure:
|
|
2363
|
+
|
|
2364
|
+
**On success:**
|
|
2365
|
+
|
|
2366
|
+
```http
|
|
2367
|
+
HTTP/1.1 200 OK
|
|
2368
|
+
|
|
2369
|
+
{
|
|
2370
|
+
"ErrorCode": 0,
|
|
2371
|
+
"ErrorMessage": null,
|
|
2372
|
+
"Data": {
|
|
2373
|
+
"fileId": "6899adac8864bf90a90047c3",
|
|
2374
|
+
"fileName": "passport.pdf",
|
|
2375
|
+
"contentType": "application/pdf",
|
|
2376
|
+
"fileSize": 4721123,
|
|
2377
|
+
"sha256": "8adb79e0e782280dad8beb227333a21796b8e01d019ab1e84cfea89a523b0e7d",
|
|
2378
|
+
"description": "passport.pdf",
|
|
2379
|
+
"tag": "passport"
|
|
2380
|
+
},
|
|
2381
|
+
"Succeeded": true
|
|
2382
|
+
}
|
|
2383
|
+
```
|
|
2384
|
+
|
|
2385
|
+
**On failure:**
|
|
2386
|
+
|
|
2387
|
+
```http
|
|
2388
|
+
HTTP/1.1 400
|
|
2389
|
+
|
|
2390
|
+
{
|
|
2391
|
+
"ErrorCode": 400,
|
|
2392
|
+
"ErrorMessage": "SUBMISSION_REQUIRED",
|
|
2393
|
+
"Data": null,
|
|
2394
|
+
"Succeeded": false
|
|
2395
|
+
}
|
|
2396
|
+
```
|
|
2397
|
+
|
|
2398
|
+
#### `fileDownloadAPIEndpoint` `GET` API Request and Response
|
|
2399
|
+
This API is used to download the file uploaded by the user. It returns the file data in Base64.
|
|
2400
|
+
|
|
2401
|
+
**Request:**
|
|
2402
|
+
|
|
2403
|
+
- **HTTP Method**: GET
|
|
2404
|
+
- **URL**: Resolved from the url property in your config (from the environment variable) concatenated with `/:refernceValue/:fileid/:sha256`. For example `https://example.com/api/fileDownload/1234567890/123456789123456/12345678901234567890123`:
|
|
2405
|
+
- `referenceValue` is the `referenceValue` of the file current temporary saved instance (see more [💾 Temporary save feature](#-temporary-save-feature)).
|
|
2406
|
+
- `fileid` is the `fileId` of the file uploaded by the user.
|
|
2407
|
+
- `sha256` is the `sha256` of the file uploaded by the user.
|
|
2408
|
+
- **Headers**:
|
|
2409
|
+
- **Authorization**: `Bearer <access_token>` (form user's cyLogin access token)
|
|
2410
|
+
- **client-key**: `<clientKey>` (from config/env)
|
|
2411
|
+
- **service-id**: `<serviceId>` (from config/env)
|
|
2412
|
+
- **Accept**: `text/plain`
|
|
2413
|
+
|
|
2414
|
+
**Example Request:**
|
|
2415
|
+
|
|
2416
|
+
```http
|
|
2417
|
+
GET fileDownload/1234567890/123456789123456/12345678901234567890123 HTTP/1.1
|
|
2418
|
+
Host: localhost:3002
|
|
2419
|
+
Authorization: Bearer eyJhbGciOi...
|
|
2420
|
+
client-key: 12345678901234567890123456789000
|
|
2421
|
+
service-id: 123
|
|
2422
|
+
Accept: text/plain
|
|
2423
|
+
Content-Type: application/json
|
|
2424
|
+
```
|
|
2425
|
+
|
|
2426
|
+
**Response:**
|
|
2427
|
+
|
|
2428
|
+
The API is expected to return a JSON response with the following structure:
|
|
2429
|
+
|
|
2430
|
+
**When file is found:**
|
|
2431
|
+
|
|
2432
|
+
```http
|
|
2433
|
+
HTTP/1.1 200 OK
|
|
2434
|
+
|
|
2435
|
+
{
|
|
2436
|
+
"ErrorCode": 0,
|
|
2437
|
+
"ErrorMessage": null,
|
|
2438
|
+
"Data": {
|
|
2439
|
+
"fileId": "123456789123456",
|
|
2440
|
+
"fileName": "passport.pdf",
|
|
2441
|
+
"contentType": "application/pdf",
|
|
2442
|
+
"fileSize": 1872,
|
|
2443
|
+
"sha256": "12345678901234567890123456789012345678901234567890123456789012345",
|
|
2444
|
+
"base64": "JVBERi0xLjMKJZOMi54gUm....
|
|
2445
|
+
",
|
|
2446
|
+
"description": null,
|
|
2447
|
+
"uid": null,
|
|
2448
|
+
"tag": "Passport"
|
|
2449
|
+
},
|
|
2450
|
+
"Succeeded": true
|
|
2451
|
+
}
|
|
2452
|
+
```
|
|
2453
|
+
|
|
2454
|
+
**When file is NOT found:**
|
|
2455
|
+
|
|
2456
|
+
```http
|
|
2457
|
+
HTTP/1.1 404 Not Found
|
|
2458
|
+
|
|
2459
|
+
{
|
|
2460
|
+
"ErrorCode": 404,
|
|
2461
|
+
"ErrorMessage": "File not found",
|
|
2462
|
+
"InformationMessage": null,
|
|
2463
|
+
"Data": null,
|
|
2464
|
+
"Succeeded": false
|
|
2465
|
+
}
|
|
2466
|
+
```
|
|
2467
|
+
|
|
2468
|
+
#### `fileDeleteAPIEndpoint` `DELETE` API Request and Response
|
|
2469
|
+
This API is used to delete the file uploaded by the user. It returns the file data in Base64.
|
|
2470
|
+
> ⚠️ **Important note:**
|
|
2471
|
+
> If the same file (same `fileId` and `sha256`) is used for other fields in the same application for the same service and the same user, when deleted it will be removed from all instances in the data layer. A warning will appear in the user's delete confirmation page to warn the users in such cases.
|
|
2472
|
+
|
|
2473
|
+
**Request:**
|
|
2474
|
+
|
|
2475
|
+
- **HTTP Method**: DELETE
|
|
2476
|
+
- **URL**: Resolved from the url property in your config (from the environment variable) concatenated with `/:fileid/:sha256`. For example `https://example.com/api/fileDelete/123456789123456/12345678901234567890123`:
|
|
2477
|
+
- `fileid` is the `fileId` of the file uploaded by the user.
|
|
2478
|
+
- `sha256` is the `sha256` of the file uploaded by the user.
|
|
2479
|
+
- **Headers**:
|
|
2480
|
+
- **Authorization**: `Bearer <access_token>` (form user's cyLogin access token)
|
|
2481
|
+
- **client-key**: `<clientKey>` (from config/env)
|
|
2482
|
+
- **service-id**: `<serviceId>` (from config/env)
|
|
2483
|
+
- **Accept**: `text/plain`
|
|
2484
|
+
|
|
2485
|
+
**Example Request:**
|
|
2486
|
+
|
|
2487
|
+
```http
|
|
2488
|
+
DELETE fileDelete/123456789123456/12345678901234567890123 HTTP/1.1
|
|
2489
|
+
Host: localhost:3002
|
|
2490
|
+
Authorization: Bearer eyJhbGciOi...
|
|
2491
|
+
client-key: 12345678901234567890123456789000
|
|
2492
|
+
service-id: 123
|
|
2493
|
+
Accept: text/plain
|
|
2494
|
+
Content-Type: application/json
|
|
2495
|
+
```
|
|
2496
|
+
|
|
2497
|
+
**Response:**
|
|
2498
|
+
|
|
2499
|
+
The API is expected to return a JSON response with the following structure:
|
|
2500
|
+
|
|
2501
|
+
**When file is found and deleted:**
|
|
2502
|
+
|
|
2503
|
+
```http
|
|
2504
|
+
HTTP/1.1 200 OK
|
|
2505
|
+
|
|
2506
|
+
{
|
|
2507
|
+
"ErrorCode": 0,
|
|
2508
|
+
"ErrorMessage": null,
|
|
2509
|
+
"Succeeded": true
|
|
2510
|
+
}
|
|
2511
|
+
```
|
|
2512
|
+
|
|
2513
|
+
**When file is NOT found:**
|
|
2514
|
+
|
|
2515
|
+
```http
|
|
2516
|
+
HTTP/1.1 404 Not Found
|
|
2517
|
+
|
|
2518
|
+
{
|
|
2519
|
+
"ErrorCode": 404,
|
|
2520
|
+
"ErrorMessage": "File not found",
|
|
2521
|
+
"InformationMessage": null,
|
|
2522
|
+
"Data": null,
|
|
2523
|
+
"Succeeded": false
|
|
2524
|
+
}
|
|
2525
|
+
```
|
|
2526
|
+
|
|
2527
|
+
#### File uploads in the data layer
|
|
2528
|
+
The system uses the `fileId` and `sha256` to identify the file uploaded by the user. The file information are stored in the data layer in the following format:
|
|
2529
|
+
|
|
2530
|
+
```json
|
|
2531
|
+
{
|
|
2532
|
+
"fileId": "1234567891234567890",
|
|
2533
|
+
"sha256": "123456789012345678901234567890123456789012345678901234567890123456"
|
|
2534
|
+
}
|
|
2535
|
+
```
|
|
2536
|
+
|
|
2537
|
+
#### File uploads when submitted
|
|
2538
|
+
When the user submits the service through the submission API endpoint, the system will use the `fileId` and `sha256` to identify the file uploaded by the user. The actuall file is already uploaded via the `fileUploadAPIEndpoint`.
|
|
2539
|
+
|
|
2540
|
+
To help back-end systems recognize the field as a file, the field's element name is concatenated with `Attachment`. For example, if for the field `passport`, the data will be submitted as follows:
|
|
2541
|
+
|
|
2542
|
+
```json
|
|
2543
|
+
{
|
|
2544
|
+
"passportAttachment": {
|
|
2545
|
+
"fileId": "1234567891234567890",
|
|
2546
|
+
"sha256": "123456789012345678901234567890123456789012345678901234567890123456"
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
```
|
|
2550
|
+
|
|
2551
|
+
#### File uploads backward compatibility
|
|
2552
|
+
If these endpoints are not defined in the service JSON, the file upload logic is skipped entirely.
|
|
2553
|
+
Existing services will continue to work without modification.
|
|
2554
|
+
|
|
1593
2555
|
### 🛣️ Routes
|
|
1594
2556
|
The project uses express.js to serve the following routes:
|
|
1595
2557
|
|
|
@@ -1598,16 +2560,18 @@ The project uses express.js to serve the following routes:
|
|
|
1598
2560
|
- **`/:siteId/:pageUrl`**: Requires **cyLogin** authentication for **authorized individual users**. Based on `/data/:siteId.json`, Renders the specified page template. Validates page and saves data to session. If validation fails, errors are displayed with links to the inputs.
|
|
1599
2561
|
- **`/:siteId/review`**: Requires **cyLogin** authentication for **authorized individual users**. Renders the check your answers page template. Validates all pages in the service and submits the data to the configured API endpoint. If validation fails, errors are displayed with links to the relevant pages.
|
|
1600
2562
|
- **`/:siteId/success`**: Requires **cyLogin** authentication for **authorized individual users**. Renders latest successful submission.
|
|
1601
|
-
- **`/:siteId/
|
|
2563
|
+
- **`/:siteId/:pageUrl/view-file/:elementName`**: Requires **cyLogin** authentication for **authorized individual users**. Renders the specified file in a new tab.
|
|
2564
|
+
- **`/:siteId/:pageUrl/delete-file/:elementName`**: Requires **cyLogin** authentication for **authorized individual users**. Renders the delete confirmation page and handles the file delete.
|
|
1602
2565
|
|
|
1603
2566
|
#### Authentication routes:
|
|
1604
2567
|
- **`/signin-oidc`**: CY Login authentication endpoint.
|
|
1605
2568
|
- **`/login`**: Redirect to CY Login login page.
|
|
1606
2569
|
- **`/logout`**: CY Login logout endpoint.
|
|
1607
2570
|
|
|
1608
|
-
|
|
2571
|
+
#### API routes:
|
|
2572
|
+
- **`/apis/:siteId/:pageUrl/upload`**: Uploads a file. Used from the client side JS.
|
|
1609
2573
|
|
|
1610
|
-
### 👨💻
|
|
2574
|
+
### 👨💻 Environment variables
|
|
1611
2575
|
The environment variables are defined in:
|
|
1612
2576
|
- **Secret environment variables**: These are secret variables and MUSR NOT be saved in version control. The are saved locally in the `secrets/.env` file and they control the server configuration, authentication, integrations, and development behavior. These variables vary depending on the environment and are defined through the deployment prosses for `staging` and `production`.
|
|
1613
2577
|
- **Non secret environment variables**: These are non secret enviromentat variables and can be saved in version control. These are stored in the root folder of the project:
|
|
@@ -1678,10 +2642,14 @@ TEST_SUBMISSION_API_CLIENT_KEY=12345678901234567890123456789000
|
|
|
1678
2642
|
TEST_SUBMISSION_API_SERVIVE_ID=123
|
|
1679
2643
|
TEST_SUBMISSION_DSF_GTW_KEY=12345678901234567890123456789000
|
|
1680
2644
|
|
|
1681
|
-
# Optional Temporary Save GET and PUT
|
|
2645
|
+
# Optional Temporary Save GET and PUT endpoints (test service)
|
|
1682
2646
|
TEST_SUBMISSION_GET_API_URL=http://localhost:3002/getTempSubmission
|
|
1683
2647
|
TEST_SUBMISSION_PUT_API_URL=http://localhost:3002/save
|
|
1684
2648
|
|
|
2649
|
+
# Optional File Upload and download endpoints (test service)
|
|
2650
|
+
TEST_FILE_UPLOAD_API_URL=http://localhost:3002/fileUpload
|
|
2651
|
+
TEST_FILE_DOWNLOAD_API_URL=http://localhost:3002/fileDownload
|
|
2652
|
+
TEST_FILE_DELETE_API_URL=http://localhost:3002/fileDelete
|
|
1685
2653
|
|
|
1686
2654
|
# Eligibility checks (optional test APIs)
|
|
1687
2655
|
TEST_ELIGIBILITY_1_API_URL=http://localhost:3002/eligibility1
|