@gov-cy/govcy-express-services 1.0.0-alpha.11 → 1.0.0-alpha.13
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 +861 -7
- package/package.json +2 -2
- package/src/resources/govcyResources.mjs +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,8 @@ The project is designed to support the [Linear structure](https://gov-cy.github.
|
|
|
32
32
|
- [📤 Site submissions](#-site-submissions)
|
|
33
33
|
- [✅ Input validations](#-input-validations)
|
|
34
34
|
- [✅ Conditional logic](#-conditional-logic)
|
|
35
|
-
- [💾 Temporary save](#-temporary-save)
|
|
35
|
+
- [💾 Temporary save feature](#-temporary-save-feature)
|
|
36
|
+
- [🗃️ Files uploads feature](#%EF%B8%8F-files-uploads-feature)
|
|
36
37
|
- [🛣️ Routes](#%EF%B8%8F-routes)
|
|
37
38
|
- [👨💻 Enviromental variables](#-enviromental-variables)
|
|
38
39
|
- [🔒 Security note](#-security-note)
|
|
@@ -140,6 +141,538 @@ The CY Login settings are configured in the `secrets/.env` file.
|
|
|
140
141
|
### 🧩 Dynamic Services Rendering
|
|
141
142
|
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
143
|
|
|
144
|
+
Here is an example JSON config:
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"site": {
|
|
149
|
+
"id": "test",
|
|
150
|
+
"lang": "el", //<-- Default language
|
|
151
|
+
"languages": [ //<-- Supported languages
|
|
152
|
+
{
|
|
153
|
+
"code": "el",
|
|
154
|
+
"label": "EL",
|
|
155
|
+
"alt": "Ελληνική γλώσσα",
|
|
156
|
+
"href": "?lang=el"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"code": "en",
|
|
160
|
+
"label": "EN",
|
|
161
|
+
"alt": "English language",
|
|
162
|
+
"href": "?lang=en"
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
"footerLinks": [ //<-- Links on the footer
|
|
166
|
+
{
|
|
167
|
+
"label": {
|
|
168
|
+
"el": "Δήλωση απορρήτου",
|
|
169
|
+
"en": "Privacy statement",
|
|
170
|
+
"tr": "Privacy statement"
|
|
171
|
+
},
|
|
172
|
+
"href": "test/privacy-statement"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"label": {
|
|
176
|
+
"el": "Cookies",
|
|
177
|
+
"en": "Cookies",
|
|
178
|
+
"tr": "Cookies"
|
|
179
|
+
},
|
|
180
|
+
"href": "test/cookie-policy"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"label": {
|
|
184
|
+
"el": "Προσβασιμότητα",
|
|
185
|
+
"en": "Accessibility",
|
|
186
|
+
"tr": "Accessibility"
|
|
187
|
+
},
|
|
188
|
+
"href": "test/accessibility-statement"
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
"footerIcons": [ //<-- Icons on the footer
|
|
192
|
+
{
|
|
193
|
+
"target": "_blank",
|
|
194
|
+
"src": {
|
|
195
|
+
"el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EL.png",
|
|
196
|
+
"en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EN.png",
|
|
197
|
+
"tr": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/FundedbyEU_NextGeneration_H53-EN.png"
|
|
198
|
+
},
|
|
199
|
+
"alt": {
|
|
200
|
+
"el": "Χρηματοδοτείται από την ΕΕ Next Generation EU",
|
|
201
|
+
"en": "Funded by the EU Next Generation EU",
|
|
202
|
+
"tr": "Funded by the EU Next Generation EU"
|
|
203
|
+
},
|
|
204
|
+
"href": {
|
|
205
|
+
"el": "https://europa.eu/",
|
|
206
|
+
"en": "https://europa.eu/",
|
|
207
|
+
"tr": "https://europa.eu/"
|
|
208
|
+
},
|
|
209
|
+
"title": {
|
|
210
|
+
"el": "Μετάβαση στην ιστοσελίδα της ΕΕ",
|
|
211
|
+
"en": "Go to EU website",
|
|
212
|
+
"tr": "Go to EU website"
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"target": "_blank",
|
|
217
|
+
"src": {
|
|
218
|
+
"el": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EL.png",
|
|
219
|
+
"en": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EN.png",
|
|
220
|
+
"tr": "https://cdn.jsdelivr.net/gh/gov-cy/govdesign@main/CYpros%20to%20aurio%20logo%20eng_H53_EN.png"
|
|
221
|
+
},
|
|
222
|
+
"alt": {
|
|
223
|
+
"el": "Κύπρος το Αύριο, σχέδιο ανάκαμψης και ανθεντικότητας",
|
|
224
|
+
"en": "Cyprus tomorrow, recovery and resilience plan",
|
|
225
|
+
"tr": "Cyprus tomorrow, recovery and resilience plan"
|
|
226
|
+
},
|
|
227
|
+
"href": {
|
|
228
|
+
"el": "http://www.cyprus-tomorrow.gov.cy/",
|
|
229
|
+
"en": "http://www.cyprus-tomorrow.gov.cy/",
|
|
230
|
+
"tr": "http://www.cyprus-tomorrow.gov.cy/"
|
|
231
|
+
},
|
|
232
|
+
"title": {
|
|
233
|
+
"el": "Μετάβαση στην ιστοσελίδα Κύπρος το Αύριο",
|
|
234
|
+
"en": "Go to Cyprus Tomorrow website",
|
|
235
|
+
"tr": "Go to Cyprus Tomorrow website"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
],
|
|
239
|
+
"menu": { //<-- Menu altext
|
|
240
|
+
"el": "Μενού",
|
|
241
|
+
"en": "Menu",
|
|
242
|
+
"tr": "Menu"
|
|
243
|
+
},
|
|
244
|
+
"title": { //<-- Service title (meta)
|
|
245
|
+
"el": "Υπηρεσία τεστ",
|
|
246
|
+
"en": "Test service",
|
|
247
|
+
"tr": ""
|
|
248
|
+
},
|
|
249
|
+
"headerTitle": { //<-- Service title (as it apears in the header)
|
|
250
|
+
"el": "[Το ΟΝΟΜΑ της υπηρεσίας που θα φαίνεται στις φόρμες]",
|
|
251
|
+
"en": "[The NAME of the service as it will appear on forms]",
|
|
252
|
+
"tr": ""
|
|
253
|
+
},
|
|
254
|
+
"description": { //<-- Service description (meta)
|
|
255
|
+
"el": "[Υποβάλετε αίτηση για ...]",
|
|
256
|
+
"en": "[Submit an application ...]",
|
|
257
|
+
"tr": ""
|
|
258
|
+
},
|
|
259
|
+
"url": "https://gov.cy", //<-- URL in (meta, for example `og:url`)
|
|
260
|
+
"cdn": { //<-- CDN URL and integrity
|
|
261
|
+
"dist": "https://cdn.jsdelivr.net/gh/gov-cy/govcy-design-system@3.2.0/dist",
|
|
262
|
+
"cssIntegrity": "sha384-qjx16YXHG+Vq/NVtwU2aDTc7DoLOyaVNuOHrwA3aTrckpM/ycxZoR5dx7ezNJ/Lv",
|
|
263
|
+
"jsIntegrity": "sha384-tqEyCdi3GS4uDXctplAd7ODjiK5fo2Xlqv65e8w/cVvrcBf89tsxXFHXXNiUDyM7"
|
|
264
|
+
},
|
|
265
|
+
"submission_data_version": "1", //<-- Submission data version
|
|
266
|
+
"renderer_version": "1.16.1", //<-- govcy-frontend-renderer version
|
|
267
|
+
"design_systems_version": "3.2.0", //<-- govcy-design-system version
|
|
268
|
+
"homeRedirectPage": { //<-- Home redirect page
|
|
269
|
+
"el": "https://www.gov.cy/service/aitisi-gia-taftotita/",
|
|
270
|
+
"en": "https://www.gov.cy/en/service/issue-an-id-card/",
|
|
271
|
+
"tr": "https://www.gov.cy/en/service/issue-an-id-card/"
|
|
272
|
+
},
|
|
273
|
+
"copyrightText": { //<-- Copyright text
|
|
274
|
+
"el": "Κυπριακή Δημοκρατία, 2025",
|
|
275
|
+
"en": "Republic of Cyprus, 2025",
|
|
276
|
+
"tr": "Republic of Cyprus, 2025"
|
|
277
|
+
},
|
|
278
|
+
"submissionAPIEndpoint": { //<-- Submission API endpoint
|
|
279
|
+
"url": "TEST_SUBMISSION_API_URL",
|
|
280
|
+
"method": "POST",
|
|
281
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
282
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
283
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY",
|
|
284
|
+
"response": {
|
|
285
|
+
"errorResponse": {
|
|
286
|
+
"102": {
|
|
287
|
+
"error": "user not administrator",
|
|
288
|
+
"page": "/test/user-not-admin"
|
|
289
|
+
},
|
|
290
|
+
"105": {
|
|
291
|
+
"error": "user not registration",
|
|
292
|
+
"page": "/test/user-not-registered"
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
"submissionGetAPIEndpoint": { //<-- Submission GET API endpoint for temporary saving
|
|
298
|
+
"url": "TEST_SUBMISSION_GET_API_URL",
|
|
299
|
+
"method": "GET",
|
|
300
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
301
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
302
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY"
|
|
303
|
+
},
|
|
304
|
+
"submissionPutAPIEndpoint": { //<-- Submission PUT API endpoint for temporary saving
|
|
305
|
+
"url": "TEST_SUBMISSION_PUT_API_URL",
|
|
306
|
+
"method": "PUT",
|
|
307
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
308
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
309
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY"
|
|
310
|
+
},
|
|
311
|
+
"fileUploadAPIEndpoint": { //<-- File upload API endpoint
|
|
312
|
+
"url": "TEST_UPLOAD_FILE_API_URL",
|
|
313
|
+
"method": "POST",
|
|
314
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
315
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
316
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY"
|
|
317
|
+
},
|
|
318
|
+
"fileDownloadAPIEndpoint": { //<-- File download API endpoint
|
|
319
|
+
"url": "TEST_DOWNLOAD_FILE_API_URL",
|
|
320
|
+
"method": "GET",
|
|
321
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
322
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
323
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY"
|
|
324
|
+
},
|
|
325
|
+
"eligibilityAPIEndpoints": [ //<-- Eligibility API endpoints
|
|
326
|
+
{
|
|
327
|
+
"url": "TEST_ELIGIBILITY_2_API_URL",
|
|
328
|
+
"method": "GET",
|
|
329
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
330
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID",
|
|
331
|
+
"dsfgtwApiKey": "TEST_SUBMISSION_DSF_GTW_KEY",
|
|
332
|
+
"cashingTimeoutMinutes": "60",
|
|
333
|
+
"params": {},
|
|
334
|
+
"response": {
|
|
335
|
+
"errorResponse": {
|
|
336
|
+
"105": {
|
|
337
|
+
"error": "user not registration",
|
|
338
|
+
"page": "/test/user-not-registered"
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
]
|
|
344
|
+
},
|
|
345
|
+
"pages": [ //<-- Pages
|
|
346
|
+
{
|
|
347
|
+
"pageData": { //<-- 1st Page's data (form)
|
|
348
|
+
"url": "index", // Page URL
|
|
349
|
+
"title": { // Page title
|
|
350
|
+
"el": "Επιλογή Εγγάφου",
|
|
351
|
+
"en": "Document selection",
|
|
352
|
+
"tr": ""
|
|
353
|
+
},
|
|
354
|
+
"layout": "layouts/govcyBase.njk", // Page layout
|
|
355
|
+
"mainLayout": "two-third", // Page main layout
|
|
356
|
+
"nextPage": "data-entry-radios" // The next page's URL
|
|
357
|
+
},
|
|
358
|
+
"pageTemplate": { //<-- Page template
|
|
359
|
+
"sections": [ //<-- Page sections
|
|
360
|
+
{
|
|
361
|
+
"name": "main", //<-- Main section
|
|
362
|
+
"elements": [ //<-- Main section elements
|
|
363
|
+
{
|
|
364
|
+
"element": "form", // Form element
|
|
365
|
+
"params": {
|
|
366
|
+
"elements": [ // Elements inside the form
|
|
367
|
+
{
|
|
368
|
+
"element": "checkboxes", // Checkboxes element
|
|
369
|
+
"params": { // Checkboxes parameters
|
|
370
|
+
"id": "certificate_select",
|
|
371
|
+
"name": "certificate_select",
|
|
372
|
+
"legend": {
|
|
373
|
+
"el": "Τι έγγραφα επιθυμείτε να εκδώσετε;",
|
|
374
|
+
"en": "What documents do you wish to issue?"
|
|
375
|
+
},
|
|
376
|
+
"items": [
|
|
377
|
+
{
|
|
378
|
+
"value": "birth",
|
|
379
|
+
"text": {
|
|
380
|
+
"el": "Πιστοποιητικό γέννησης",
|
|
381
|
+
"en": "Birth certificate",
|
|
382
|
+
"tr": ""
|
|
383
|
+
},
|
|
384
|
+
"hint": {
|
|
385
|
+
"el": "Αν η γέννηση έγινε στην Κύπρο ή στο εξωτερικό και έχει ενημερωθεί το μητρώο του Αρχείου Πληθυσμού ",
|
|
386
|
+
"en": "For a birth in Cyprus or abroad which Civil Registry is updated with "
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"value": "permanent_residence",
|
|
391
|
+
"text": {
|
|
392
|
+
"el": "Βεβαίωση μόνιμης διαμονής",
|
|
393
|
+
"en": "Certificate of permanent residence",
|
|
394
|
+
"tr": ""
|
|
395
|
+
},
|
|
396
|
+
"hint": {
|
|
397
|
+
"el": "Για όσους είναι εγγεγραμμένοι στον εκλογικό κατάλογο",
|
|
398
|
+
"en": "For those registered in the electoral list"
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
"value": "student_proof_of_origin",
|
|
403
|
+
"text": {
|
|
404
|
+
"el": "Βεβαίωση καταγωγής",
|
|
405
|
+
"en": "Certificate of origin",
|
|
406
|
+
"tr": ""
|
|
407
|
+
},
|
|
408
|
+
"hint": {
|
|
409
|
+
"el": "Για αίτηση σε πανεπιστήμια στην Ελλάδα",
|
|
410
|
+
"en": "To apply to a university in Greece"
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
],
|
|
414
|
+
"isPageHeading": true,
|
|
415
|
+
"hint": {
|
|
416
|
+
"el": "Επιλέξτε ένα ή περισσότερα έγγραφα",
|
|
417
|
+
"en": "Select one or more documents",
|
|
418
|
+
"tr": ""
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
"validations": [ // Checkboxes validations
|
|
422
|
+
{
|
|
423
|
+
"check": "required",
|
|
424
|
+
"params": {
|
|
425
|
+
"checkValue": "",
|
|
426
|
+
"message": {
|
|
427
|
+
"el": "Επιλέξετε ένα ή περισσότερα έγγραφα",
|
|
428
|
+
"en": "Select one or more documents",
|
|
429
|
+
"tr": ""
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
]
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"element": "button",
|
|
437
|
+
"params": {
|
|
438
|
+
"id": "continue",
|
|
439
|
+
"variant": "primary",
|
|
440
|
+
"text": {
|
|
441
|
+
"el": "Συνέχεια",
|
|
442
|
+
"en": "Continue"
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
]
|
|
450
|
+
}
|
|
451
|
+
]
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"pageData": { //<-- 2nd Page's data (form)
|
|
456
|
+
"url": "data-entry-radios",
|
|
457
|
+
"title": {
|
|
458
|
+
"el": "Στοιχεία επικοινωνίας ",
|
|
459
|
+
"en": "Contact details",
|
|
460
|
+
"tr": ""
|
|
461
|
+
},
|
|
462
|
+
"layout": "layouts/govcyBase.njk",
|
|
463
|
+
"mainLayout": "two-third",
|
|
464
|
+
"nextPage": "review"
|
|
465
|
+
},
|
|
466
|
+
"pageTemplate": {
|
|
467
|
+
"sections": [
|
|
468
|
+
{
|
|
469
|
+
"name": "beforeMain",
|
|
470
|
+
"elements": [
|
|
471
|
+
{
|
|
472
|
+
"element": "backLink",
|
|
473
|
+
"params": {}
|
|
474
|
+
}
|
|
475
|
+
]
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
"name": "main",
|
|
479
|
+
"elements": [
|
|
480
|
+
{
|
|
481
|
+
"element": "form",
|
|
482
|
+
"params": {
|
|
483
|
+
"elements": [
|
|
484
|
+
{
|
|
485
|
+
"element": "radios",
|
|
486
|
+
"params": {
|
|
487
|
+
"id": "mobile_select",
|
|
488
|
+
"name": "mobile_select",
|
|
489
|
+
"legend": {
|
|
490
|
+
"el": "Σε ποιο κινητό μπορούμε να επικοινωνήσουμε μαζί σας;",
|
|
491
|
+
"en": "What mobile number can we use to contact you?"
|
|
492
|
+
},
|
|
493
|
+
"items": [
|
|
494
|
+
{
|
|
495
|
+
"value": "mobile",
|
|
496
|
+
"text": {
|
|
497
|
+
"el": "Στο [99 123456]",
|
|
498
|
+
"en": "You can use [99 123456]",
|
|
499
|
+
"tr": ""
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
"value": "other",
|
|
504
|
+
"text": {
|
|
505
|
+
"el": "Θα δώσω άλλο αριθμό",
|
|
506
|
+
"en": "I will give a different number",
|
|
507
|
+
"tr": ""
|
|
508
|
+
},
|
|
509
|
+
"conditionalElements": [
|
|
510
|
+
{
|
|
511
|
+
"element": "fileInput",
|
|
512
|
+
"params": {
|
|
513
|
+
"id": "proof",
|
|
514
|
+
"name": "proof",
|
|
515
|
+
"label": {
|
|
516
|
+
"el": "Αποδεικτικό τηλεφώνου",
|
|
517
|
+
"en": "Telephone proof",
|
|
518
|
+
"tr": ""
|
|
519
|
+
},
|
|
520
|
+
"isPageHeading": false,
|
|
521
|
+
"hint": {
|
|
522
|
+
"el": "PDF, JPG, JPEG, PNG, είναι οι αποδεκτές μορφές",
|
|
523
|
+
"en": "PDF, JPG, JPEG, PNG are the acceptable formats",
|
|
524
|
+
"tr": ""
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
"validations": [
|
|
528
|
+
{
|
|
529
|
+
"check": "required",
|
|
530
|
+
"params": {
|
|
531
|
+
"checkValue": "",
|
|
532
|
+
"message": {
|
|
533
|
+
"el": "Ανεβάστε τον αποδεικτικό τηλεφώνου",
|
|
534
|
+
"en": "Upload the telephone proof",
|
|
535
|
+
"tr": ""
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
]
|
|
540
|
+
}
|
|
541
|
+
]
|
|
542
|
+
}
|
|
543
|
+
],
|
|
544
|
+
"isPageHeading": true
|
|
545
|
+
},
|
|
546
|
+
"validations": [
|
|
547
|
+
{
|
|
548
|
+
"check": "required",
|
|
549
|
+
"params": {
|
|
550
|
+
"checkValue": "",
|
|
551
|
+
"message": {
|
|
552
|
+
"el": "Επιλέξετε αν θέλετε να χρησιμοποιήσετε το τηλέφωνο που φαίνεται εδώ, ή κάποιο άλλο",
|
|
553
|
+
"en": "Choose if you'd like to use the phone number shown here, or a different one",
|
|
554
|
+
"tr": ""
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
]
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
"element": "button",
|
|
562
|
+
"params": {
|
|
563
|
+
"id": "continue",
|
|
564
|
+
"variant": "primary",
|
|
565
|
+
"text": {
|
|
566
|
+
"el": "Συνέχεια",
|
|
567
|
+
"en": "Continue"
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
]
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
]
|
|
575
|
+
}
|
|
576
|
+
]
|
|
577
|
+
}
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
"pageData": { //<-- 3rd Page's data (not a form)
|
|
581
|
+
"url": "user-not-registered",
|
|
582
|
+
"title": {
|
|
583
|
+
"el": "Δεν είστε εγγεγραμμένοι ",
|
|
584
|
+
"en": "You are not an registered",
|
|
585
|
+
"tr": ""
|
|
586
|
+
},
|
|
587
|
+
"layout": "layouts/govcyBase.njk",
|
|
588
|
+
"mainLayout": "two-third"
|
|
589
|
+
},
|
|
590
|
+
"pageTemplate": {
|
|
591
|
+
"sections": [
|
|
592
|
+
{
|
|
593
|
+
"name": "beforeMain",
|
|
594
|
+
"elements": []
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
"name": "main",
|
|
598
|
+
"elements": [
|
|
599
|
+
{
|
|
600
|
+
"element": "textElement",
|
|
601
|
+
"params": {
|
|
602
|
+
"id": "title",
|
|
603
|
+
"type": "h1",
|
|
604
|
+
"text": {
|
|
605
|
+
"el": "Δεν είστε εγγεγραμμένοι",
|
|
606
|
+
"en": "You are not registered"
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
"element": "htmlElement",
|
|
612
|
+
"params": {
|
|
613
|
+
"id": "body",
|
|
614
|
+
"text": {
|
|
615
|
+
"el": "<p>Για να υποβάλετε σε υπηρεσία αυτή, χρειάζεται να είστε εγγεγραμμένοι στο ΧΥΖ.</p>",
|
|
616
|
+
"en": "<p>To submit in this service you need to be registered at XYZ.</p>"
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
]
|
|
621
|
+
}
|
|
622
|
+
]
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
"pageData": { //<-- 4th Page's data (not a form)
|
|
627
|
+
"url": "user-not-admin",
|
|
628
|
+
"title": {
|
|
629
|
+
"el": "Δεν είστε διαχειριστής ",
|
|
630
|
+
"en": "You are not an administrator",
|
|
631
|
+
"tr": ""
|
|
632
|
+
},
|
|
633
|
+
"layout": "layouts/govcyBase.njk",
|
|
634
|
+
"mainLayout": "two-third"
|
|
635
|
+
},
|
|
636
|
+
"pageTemplate": {
|
|
637
|
+
"sections": [
|
|
638
|
+
{
|
|
639
|
+
"name": "beforeMain",
|
|
640
|
+
"elements": []
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
"name": "main",
|
|
644
|
+
"elements": [
|
|
645
|
+
{
|
|
646
|
+
"element": "textElement",
|
|
647
|
+
"params": {
|
|
648
|
+
"id": "title",
|
|
649
|
+
"type": "h1",
|
|
650
|
+
"text": {
|
|
651
|
+
"el": "Δεν είστε διαχειριστής ",
|
|
652
|
+
"en": "You are not an administrator"
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
"element": "htmlElement",
|
|
658
|
+
"params": {
|
|
659
|
+
"id": "body",
|
|
660
|
+
"text": {
|
|
661
|
+
"el": "<p>Για να υποβάλετε σε υπηρεσία αυτή, χρειάζεται να είστε διαχειριστής στο ΧΥΖ.</p>",
|
|
662
|
+
"en": "<p>To submit in this service you need to be an administrator of XYZ.</p>"
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
]
|
|
667
|
+
}
|
|
668
|
+
]
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
]
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
```
|
|
675
|
+
|
|
143
676
|
Here are some details explaining the JSON structure:
|
|
144
677
|
|
|
145
678
|
- `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 +688,13 @@ Here are some details explaining the JSON structure:
|
|
|
155
688
|
```
|
|
156
689
|
- `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
690
|
- `submissionAPIEndpoint`: The submission API endpoint, to be used for submitting the form. See more on the [Submission API Endoint](#-site-submissions) section below.
|
|
691
|
+
- `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.
|
|
692
|
+
- `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.
|
|
693
|
+
- `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.
|
|
694
|
+
- `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.
|
|
158
695
|
- `pages` array: An array of page objects, each representing a page in the site.
|
|
159
696
|
- `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
|
|
697
|
+
- `nextPage`: The URL of the next page to be rendered after the user clicks the `continue` button.
|
|
160
698
|
- `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
699
|
- `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
700
|
|
|
@@ -297,14 +835,24 @@ Lets break down the JSON config for this page:
|
|
|
297
835
|
- `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
836
|
- `pageData.conditions` is the array that defines the [conditional logic](#-conditional-logic)
|
|
299
837
|
- **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.
|
|
838
|
+
- `sections` is an array of sections, which is an array of elements. Sections allowed: `beforeMain`, `main`, `afterMain`.
|
|
839
|
+
- `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
840
|
|
|
301
841
|
**Forms vs static content**
|
|
302
842
|
|
|
303
843
|
- If the `pageTemplate` includes a `form` element in the `main` section and `button` element, the system will treat it as form and will:
|
|
304
844
|
- Perform the eligibility checks
|
|
305
845
|
- Display the form
|
|
306
|
-
- Collect the form data
|
|
307
|
-
|
|
846
|
+
- 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)):
|
|
847
|
+
- `textInput`
|
|
848
|
+
- `textArea`
|
|
849
|
+
- `select`
|
|
850
|
+
- `radios`
|
|
851
|
+
- `checkboxes`
|
|
852
|
+
- `datePicker`
|
|
853
|
+
- `dateInput`
|
|
854
|
+
- `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)
|
|
855
|
+
- Validate the form data (see more on the [Input validations](#-input-validations) section below)
|
|
308
856
|
- Store the form data in the systems data layer
|
|
309
857
|
- Redirect the user to the next page (or `review` page if the user came from the review page)
|
|
310
858
|
- Else if the `pageTemplate` does not include a `form` element in the `main` section, the system will treat it as static content and will:
|
|
@@ -1422,12 +1970,12 @@ Explanation:
|
|
|
1422
1970
|
- `[].concat(...)`: safely flattens a string or array into an array.
|
|
1423
1971
|
- `.includes('value1')`: checks if the value is selected.
|
|
1424
1972
|
|
|
1425
|
-
### 💾 Temporary save
|
|
1973
|
+
### 💾 Temporary save feature
|
|
1426
1974
|
|
|
1427
1975
|
The **temporary save** feature allows user progress to be stored in an external API and automatically reloaded on the next visit.
|
|
1428
1976
|
This is useful for long forms or cases where users may leave and return later.
|
|
1429
1977
|
|
|
1430
|
-
#### How to configure temporary save
|
|
1978
|
+
#### How to enable and configure temporary save
|
|
1431
1979
|
To use this feature, configure the config JSON file. In your service’s `site` object, add both a `submissionGetAPIEndpoint` and `submissionPutAPIEndpoint` entry:
|
|
1432
1980
|
|
|
1433
1981
|
```json
|
|
@@ -1608,6 +2156,310 @@ HTTP/1.1 401 Unauthorized
|
|
|
1608
2156
|
If these endpoints are not defined in the service JSON, the temporary save/load logic is skipped entirely.
|
|
1609
2157
|
Existing services will continue to work without modification.
|
|
1610
2158
|
|
|
2159
|
+
### 🗃️ Files uploads feature
|
|
2160
|
+
|
|
2161
|
+
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.
|
|
2162
|
+
|
|
2163
|
+
#### Pre-requisites for the files uploads feature
|
|
2164
|
+
The [💾 Temporary save feature](#-temporary-save-feature) must be enabled for the file uploads feature to work.
|
|
2165
|
+
|
|
2166
|
+
|
|
2167
|
+
#### How to enable and configure file uploads
|
|
2168
|
+
To use this feature, configure the config JSON file. In your service’s `site` object, add both a `fileUploadAPIEndpoint` and `fileDownloadAPIEndpoint` entry:
|
|
2169
|
+
|
|
2170
|
+
```json
|
|
2171
|
+
"fileUploadAPIEndpoint": {
|
|
2172
|
+
"url": "TEST_UPLOAD_FILE_API_URL",
|
|
2173
|
+
"method": "POST",
|
|
2174
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
2175
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID"
|
|
2176
|
+
},
|
|
2177
|
+
"fileDownloadAPIEndpoint": {
|
|
2178
|
+
"url": "TEST_DOWNLOAD_FILE_API_URL",
|
|
2179
|
+
"method": "GET",
|
|
2180
|
+
"clientKey": "TEST_SUBMISSION_API_CLIENT_KEY",
|
|
2181
|
+
"serviceId": "TEST_SUBMISSION_API_SERVIVE_ID"
|
|
2182
|
+
}
|
|
2183
|
+
```
|
|
2184
|
+
|
|
2185
|
+
These values should point to environment variables that hold your real endpoint URLs and credentials.
|
|
2186
|
+
|
|
2187
|
+
In your `secrets/.env` file (and staging/production configs), define the variables referenced above:
|
|
2188
|
+
|
|
2189
|
+
```dotenv
|
|
2190
|
+
TEST_UPLOAD_FILE_API_URL=https://example.com/api/fileUpload
|
|
2191
|
+
TEST_DOWNLOAD_FILE_API_URL=https://example.com/api/fileDownload
|
|
2192
|
+
TEST_SUBMISSION_API_CLIENT_KEY=12345678901234567890123456789000
|
|
2193
|
+
TEST_SUBMISSION_API_SERVICE_ID=123
|
|
2194
|
+
```
|
|
2195
|
+
|
|
2196
|
+
|
|
2197
|
+
#### How to define the file input field in the JSON config
|
|
2198
|
+
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.
|
|
2199
|
+
|
|
2200
|
+
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))
|
|
2201
|
+
|
|
2202
|
+
Here is a sample code section of a page definition with a file input field:
|
|
2203
|
+
|
|
2204
|
+
```json
|
|
2205
|
+
{
|
|
2206
|
+
"pageData": {
|
|
2207
|
+
"url": "data-entry-file",
|
|
2208
|
+
"title": {
|
|
2209
|
+
"el": "Λογαριασμός κινήσεως",
|
|
2210
|
+
"en": "Utility bill"
|
|
2211
|
+
},
|
|
2212
|
+
"layout": "layouts/govcyBase.njk",
|
|
2213
|
+
"mainLayout": "two-third",
|
|
2214
|
+
"nextPage": "data-entry-all"
|
|
2215
|
+
},
|
|
2216
|
+
"pageTemplate": {
|
|
2217
|
+
"sections": [
|
|
2218
|
+
{
|
|
2219
|
+
"name": "beforeMain",
|
|
2220
|
+
"elements": [
|
|
2221
|
+
{
|
|
2222
|
+
"element": "backLink",
|
|
2223
|
+
"params": {}
|
|
2224
|
+
}
|
|
2225
|
+
]
|
|
2226
|
+
},
|
|
2227
|
+
{
|
|
2228
|
+
"name": "main",
|
|
2229
|
+
"elements": [
|
|
2230
|
+
{
|
|
2231
|
+
"element": "form",
|
|
2232
|
+
"params": {
|
|
2233
|
+
"elements": [
|
|
2234
|
+
{
|
|
2235
|
+
"element": "fileInput", //<-- this is the file input
|
|
2236
|
+
"params": {
|
|
2237
|
+
"id": "utility",
|
|
2238
|
+
"name": "utility",
|
|
2239
|
+
"label": {
|
|
2240
|
+
"el": "Λογαριασμός κινήσεως",
|
|
2241
|
+
"en": "Utility bill"
|
|
2242
|
+
},
|
|
2243
|
+
"isPageHeading": true,
|
|
2244
|
+
"hint": {
|
|
2245
|
+
"el": "PDF, JPG, JPEG, PNG, είναι οι αποδεκτές μορφές",
|
|
2246
|
+
"en": "PDF, JPG, JPEG, PNG are the acceptable formats"
|
|
2247
|
+
}
|
|
2248
|
+
},
|
|
2249
|
+
"validations": [ //<-- this is the file input validations
|
|
2250
|
+
{
|
|
2251
|
+
"check": "required",
|
|
2252
|
+
"params": {
|
|
2253
|
+
"checkValue": "",
|
|
2254
|
+
"message": {
|
|
2255
|
+
"el": "Ανεβάστε τον λογαριασμό κινήσεως",
|
|
2256
|
+
"en": "Upload the utility bill"
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
]
|
|
2261
|
+
},
|
|
2262
|
+
{
|
|
2263
|
+
"element": "button",
|
|
2264
|
+
"params": {
|
|
2265
|
+
"id": "continue",
|
|
2266
|
+
"variant": "primary",
|
|
2267
|
+
"text": {
|
|
2268
|
+
"el": "Συνέχεια",
|
|
2269
|
+
"en": "Continue"
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
]
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
]
|
|
2277
|
+
}
|
|
2278
|
+
]
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
```
|
|
2282
|
+
|
|
2283
|
+
#### How file uploads works
|
|
2284
|
+
|
|
2285
|
+
- **On a form page with an upload input field**:
|
|
2286
|
+
- **On first load**: the page displays the fileInput field to choose a file.
|
|
2287
|
+
- **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.
|
|
2289
|
+
- 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
|
+
- **On a form page after upload**:
|
|
2291
|
+
- The `fileView` element is displayed with links to `View` or `Delete` the file.
|
|
2292
|
+
- **When clinking `view`**:
|
|
2293
|
+
- The file is downloaded using the `fileDownloadAPIEndpoint` and opened in a new tab.
|
|
2294
|
+
- **When clinking `delete`**:
|
|
2295
|
+
- A confimation page is displayed asking the user to confirm the deletion. If the user confirms, the file is deleted from the data layer and the `fileView` element is removed from the page.
|
|
2296
|
+
- **On the `review` page after upload**:
|
|
2297
|
+
- The element is displayed with a link to `View file`. A `Change` link is also displayed for the whole page.
|
|
2298
|
+
- **On the `success` page and email after upload**:
|
|
2299
|
+
- The element is displayed with links a marking `File uploaded`.
|
|
2300
|
+
|
|
2301
|
+
|
|
2302
|
+
#### `fileUploadAPIEndpoint` `POST` API Request and Response
|
|
2303
|
+
This API is used to temporarily store the file uploaded by the user.
|
|
2304
|
+
|
|
2305
|
+
**Request:**
|
|
2306
|
+
|
|
2307
|
+
- **HTTP Method**: POST
|
|
2308
|
+
- **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`
|
|
2309
|
+
- **Headers**:
|
|
2310
|
+
- **Authorization**: `Bearer <access_token>` (form user's cyLogin access token)
|
|
2311
|
+
- **client-key**: `<clientKey>` (from config/env)
|
|
2312
|
+
- **service-id**: `<serviceId>` (from config/env)
|
|
2313
|
+
- **Accept**: `application/json`
|
|
2314
|
+
- **Content-Type**: `multipart/form-data` (typically automatically set when using FormData in the browser)
|
|
2315
|
+
- **Body (multipart/form-data)**: The body the actual file to be uploaded (PDF, JPEG, etc.)
|
|
2316
|
+
|
|
2317
|
+
**Example Request:**
|
|
2318
|
+
|
|
2319
|
+
``` bash
|
|
2320
|
+
curl --location 'https://example.gov.cy/api/v1/files/upload/passport' \
|
|
2321
|
+
--header 'client-key: 12345678901234567890123456789000' \
|
|
2322
|
+
--header 'service-id: 123' \
|
|
2323
|
+
--header 'Authorization: Bearer eyJhbGciOi...' \
|
|
2324
|
+
--form 'file=@"/path/to/file.pdf"'
|
|
2325
|
+
```
|
|
2326
|
+
|
|
2327
|
+
**Response:**
|
|
2328
|
+
|
|
2329
|
+
The API is expected to return a JSON response with the following structure:
|
|
2330
|
+
|
|
2331
|
+
**On success:**
|
|
2332
|
+
|
|
2333
|
+
```http
|
|
2334
|
+
HTTP/1.1 200 OK
|
|
2335
|
+
|
|
2336
|
+
{
|
|
2337
|
+
"ErrorCode": 0,
|
|
2338
|
+
"ErrorMessage": null,
|
|
2339
|
+
"Data": {
|
|
2340
|
+
"fileId": "6899adac8864bf90a90047c3",
|
|
2341
|
+
"fileName": "passport.pdf",
|
|
2342
|
+
"contentType": "application/pdf",
|
|
2343
|
+
"fileSize": 4721123,
|
|
2344
|
+
"sha256": "8adb79e0e782280dad8beb227333a21796b8e01d019ab1e84cfea89a523b0e7d",
|
|
2345
|
+
"description": "passport.pdf",
|
|
2346
|
+
"tag": "passport"
|
|
2347
|
+
},
|
|
2348
|
+
"Succeeded": true
|
|
2349
|
+
}
|
|
2350
|
+
```
|
|
2351
|
+
|
|
2352
|
+
**On failure:**
|
|
2353
|
+
|
|
2354
|
+
```http
|
|
2355
|
+
HTTP/1.1 400
|
|
2356
|
+
|
|
2357
|
+
{
|
|
2358
|
+
"ErrorCode": 400,
|
|
2359
|
+
"ErrorMessage": "SUBMISSION_REQUIRED",
|
|
2360
|
+
"Data": null,
|
|
2361
|
+
"Succeeded": false
|
|
2362
|
+
}
|
|
2363
|
+
```
|
|
2364
|
+
|
|
2365
|
+
#### `fileDownloadAPIEndpoint` `GET` API Request and Response
|
|
2366
|
+
This API is used to download the file uploaded by the user. It returns the file data in Base64.
|
|
2367
|
+
|
|
2368
|
+
**Request:**
|
|
2369
|
+
|
|
2370
|
+
- **HTTP Method**: GET
|
|
2371
|
+
- **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`:
|
|
2372
|
+
- `referenceValue` is the `referenceValue` of the file current temporary saved instance (see more [💾 Temporary save feature](#-temporary-save-feature)).
|
|
2373
|
+
- `fileid` is the `fileId` of the file uploaded by the user.
|
|
2374
|
+
- `sha256` is the `sha256` of the file uploaded by the user.
|
|
2375
|
+
- **Headers**:
|
|
2376
|
+
- **Authorization**: `Bearer <access_token>` (form user's cyLogin access token)
|
|
2377
|
+
- **client-key**: `<clientKey>` (from config/env)
|
|
2378
|
+
- **service-id**: `<serviceId>` (from config/env)
|
|
2379
|
+
- **Accept**: `text/plain`
|
|
2380
|
+
|
|
2381
|
+
**Example Request:**
|
|
2382
|
+
|
|
2383
|
+
```http
|
|
2384
|
+
GET fileDownload/1234567890/123456789123456/12345678901234567890123 HTTP/1.1
|
|
2385
|
+
Host: localhost:3002
|
|
2386
|
+
Authorization: Bearer eyJhbGciOi...
|
|
2387
|
+
client-key: 12345678901234567890123456789000
|
|
2388
|
+
service-id: 123
|
|
2389
|
+
Accept: text/plain
|
|
2390
|
+
Content-Type: application/json
|
|
2391
|
+
```
|
|
2392
|
+
|
|
2393
|
+
**Response:**
|
|
2394
|
+
|
|
2395
|
+
The API is expected to return a JSON response with the following structure:
|
|
2396
|
+
|
|
2397
|
+
**When file is found:**
|
|
2398
|
+
|
|
2399
|
+
```http
|
|
2400
|
+
HTTP/1.1 200 OK
|
|
2401
|
+
|
|
2402
|
+
{
|
|
2403
|
+
"ErrorCode": 0,
|
|
2404
|
+
"ErrorMessage": null,
|
|
2405
|
+
"Data": {
|
|
2406
|
+
"fileId": "123456789123456",
|
|
2407
|
+
"fileName": "passport.pdf",
|
|
2408
|
+
"contentType": "application/pdf",
|
|
2409
|
+
"fileSize": 1872,
|
|
2410
|
+
"sha256": "12345678901234567890123456789012345678901234567890123456789012345",
|
|
2411
|
+
"base64": "JVBERi0xLjMKJZOMi54gUm....
|
|
2412
|
+
",
|
|
2413
|
+
"description": null,
|
|
2414
|
+
"uid": null,
|
|
2415
|
+
"tag": "Passport"
|
|
2416
|
+
},
|
|
2417
|
+
"Succeeded": true
|
|
2418
|
+
}
|
|
2419
|
+
```
|
|
2420
|
+
|
|
2421
|
+
**When file is NOT found:**
|
|
2422
|
+
|
|
2423
|
+
```http
|
|
2424
|
+
HTTP/1.1 404 Not Found
|
|
2425
|
+
|
|
2426
|
+
{
|
|
2427
|
+
"ErrorCode": 404,
|
|
2428
|
+
"ErrorMessage": "File not found",
|
|
2429
|
+
"InformationMessage": null,
|
|
2430
|
+
"Data": null,
|
|
2431
|
+
"Succeeded": false
|
|
2432
|
+
}
|
|
2433
|
+
```
|
|
2434
|
+
|
|
2435
|
+
#### File uploads in the data layer
|
|
2436
|
+
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:
|
|
2437
|
+
|
|
2438
|
+
```json
|
|
2439
|
+
{
|
|
2440
|
+
"fileId": "1234567891234567890",
|
|
2441
|
+
"sha256": "123456789012345678901234567890123456789012345678901234567890123456"
|
|
2442
|
+
}
|
|
2443
|
+
```
|
|
2444
|
+
|
|
2445
|
+
#### File uploads when submitted
|
|
2446
|
+
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`.
|
|
2447
|
+
|
|
2448
|
+
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:
|
|
2449
|
+
|
|
2450
|
+
```json
|
|
2451
|
+
{
|
|
2452
|
+
"passportAttachment": {
|
|
2453
|
+
"fileId": "1234567891234567890",
|
|
2454
|
+
"sha256": "123456789012345678901234567890123456789012345678901234567890123456"
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
```
|
|
2458
|
+
|
|
2459
|
+
#### File uploads backward compatibility
|
|
2460
|
+
If these endpoints are not defined in the service JSON, the temporary save/load logic is skipped entirely.
|
|
2461
|
+
Existing services will continue to work without modification.
|
|
2462
|
+
|
|
1611
2463
|
### 🛣️ Routes
|
|
1612
2464
|
The project uses express.js to serve the following routes:
|
|
1613
2465
|
|
|
@@ -1616,14 +2468,16 @@ The project uses express.js to serve the following routes:
|
|
|
1616
2468
|
- **`/: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.
|
|
1617
2469
|
- **`/: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.
|
|
1618
2470
|
- **`/:siteId/success`**: Requires **cyLogin** authentication for **authorized individual users**. Renders latest successful submission.
|
|
1619
|
-
- **`/:siteId/
|
|
2471
|
+
- **`/:siteId/:pageUrl/view-file/:elementName`**: Requires **cyLogin** authentication for **authorized individual users**. Renders the specified file in a new tab.
|
|
2472
|
+
- **`/:siteId/:pageUrl/delete-file/:elementName`**: Requires **cyLogin** authentication for **authorized individual users**. Renders the delete confirmation page and handles the file delete.
|
|
1620
2473
|
|
|
1621
2474
|
#### Authentication routes:
|
|
1622
2475
|
- **`/signin-oidc`**: CY Login authentication endpoint.
|
|
1623
2476
|
- **`/login`**: Redirect to CY Login login page.
|
|
1624
2477
|
- **`/logout`**: CY Login logout endpoint.
|
|
1625
2478
|
|
|
1626
|
-
|
|
2479
|
+
#### API routes:
|
|
2480
|
+
- **`/apis/:siteId/:pageUrl/upload`**: Uploads a file. Used from the client side JS.
|
|
1627
2481
|
|
|
1628
2482
|
### 👨💻 Enviromental variables
|
|
1629
2483
|
The environment variables are defined in:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gov-cy/govcy-express-services",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.13",
|
|
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",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"test:package": "mocha --recursive tests/package/**/*.test.mjs",
|
|
46
46
|
"test:functional": "mocha --timeout 30000 --recursive tests/functional/**/*.test.mjs",
|
|
47
47
|
"test:watch": "mocha --watch --timeout 60000 tests/**/*.test.mjs",
|
|
48
|
-
"coverage": "c8 --reporter=html --reporter=text --reporter=lcov npm test",
|
|
48
|
+
"coverage": "c8 --reporter=html --reporter=text --reporter=lcov --reporter=cobertura npm test",
|
|
49
49
|
"coverage:report": "c8 report"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
@@ -59,7 +59,7 @@ export const staticResources = {
|
|
|
59
59
|
errorPage403NaturalOnlyPolicyBody: {
|
|
60
60
|
el: "<p>Η πρόσβαση επιτρέπεται μόνο σε φυσικά πρόσωπα με επιβεβαιωμένο προφίλ. <a href=\"/logout\">Αποσυνδεθείτε</a> και δοκιμάστε ξανά αργότερα.</p>",
|
|
61
61
|
en: "<p>Access is only allowed to individuals with a verified profile.<a href=\"/logout\">Sign out</a> and try again later.</p>",
|
|
62
|
-
tr: "<p>Access is only allowed to individuals with a
|
|
62
|
+
tr: "<p>Access is only allowed to individuals with a verified profile.<a href=\"/logout\">Giriş yapmadan</a> sonra tekrar deneyiniz.</p>"
|
|
63
63
|
},
|
|
64
64
|
errorPage500Title: {
|
|
65
65
|
el: "Λυπούμαστε, υπάρχει πρόβλημα με την υπηρεσία",
|