@gov-cy/govcy-express-services 1.2.0 → 1.3.0-alpha.1
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 +1 -0
- package/package.json +6 -2
- package/src/index.mjs +190 -49
- package/src/middleware/govcyConfigSiteData.mjs +4 -0
- package/src/middleware/govcyFileDeleteHandler.mjs +41 -19
- package/src/middleware/govcyFileUpload.mjs +14 -1
- package/src/middleware/govcyFileViewHandler.mjs +20 -1
- package/src/middleware/govcyFormsPostHandler.mjs +76 -47
- package/src/middleware/govcyHttpErrorHandler.mjs +2 -0
- package/src/middleware/govcyMultipleThingsDeleteHandler.mjs +233 -0
- package/src/middleware/govcyMultipleThingsHubHandler.mjs +247 -0
- package/src/middleware/govcyMultipleThingsItemPage.mjs +460 -0
- package/src/middleware/govcyPageHandler.mjs +17 -5
- package/src/middleware/govcyPageRender.mjs +8 -0
- package/src/middleware/govcyReviewPageHandler.mjs +58 -32
- package/src/middleware/govcyReviewPostHandler.mjs +47 -23
- package/src/middleware/govcyRoutePageHandler.mjs +3 -1
- package/src/middleware/govcySuccessPageHandler.mjs +0 -5
- package/src/public/css/govcyExpress.css +33 -0
- package/src/public/img/Plus_24x24.svg +8 -0
- package/src/public/js/govcyFiles.js +92 -71
- package/src/resources/govcyResources.mjs +128 -0
- package/src/utils/govcyApiDetection.mjs +1 -1
- package/src/utils/govcyDataLayer.mjs +208 -67
- package/src/utils/govcyFormHandling.mjs +100 -27
- package/src/utils/govcyHandleFiles.mjs +58 -13
- package/src/utils/govcyMultipleThingsValidation.mjs +132 -0
- package/src/utils/govcySubmitData.mjs +221 -88
- package/src/utils/govcyValidator.mjs +19 -7
package/README.md
CHANGED
|
@@ -1740,6 +1740,7 @@ The validation rules for each element are defined in the `"validations` array fo
|
|
|
1740
1740
|
- `date`: Date input (DD/MM/YYYY)
|
|
1741
1741
|
- `dateISO`: ISO date input `YYYY-M-D`
|
|
1742
1742
|
- `dateDMY`: European/Common Format date input `D/M/YYYY`
|
|
1743
|
+
- `maxCurrentYear`: Maximum current year input
|
|
1743
1744
|
- `required`: Checks if the value is not null, undefined, or an empty string (after trimming).
|
|
1744
1745
|
- `length`: Checks if the value has a maximum length passed in the `checkValue` parameter.
|
|
1745
1746
|
- `regCheck`: Checks if the value matches the specified regular expression passed in the `checkValue` parameter.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gov-cy/govcy-express-services",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0-alpha.1",
|
|
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",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@gov-cy/dsf-email-templates": "^2.1.0",
|
|
55
|
-
"@gov-cy/govcy-frontend-renderer": "^1.
|
|
55
|
+
"@gov-cy/govcy-frontend-renderer": "^1.26.0",
|
|
56
56
|
"axios": "^1.9.0",
|
|
57
57
|
"cookie-parser": "^1.4.7",
|
|
58
58
|
"dotenv": "^16.3.1",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"express-session": "^1.17.3",
|
|
61
61
|
"form-data": "^4.0.4",
|
|
62
62
|
"multer": "^2.0.2",
|
|
63
|
+
"nunjucks": "^3.2.4",
|
|
63
64
|
"openid-client": "^6.3.4",
|
|
64
65
|
"puppeteer": "^24.6.0"
|
|
65
66
|
},
|
|
@@ -76,5 +77,8 @@
|
|
|
76
77
|
},
|
|
77
78
|
"engines": {
|
|
78
79
|
"node": ">=18.0.0"
|
|
80
|
+
},
|
|
81
|
+
"overrides": {
|
|
82
|
+
"tar-fs": "^3.1.1"
|
|
79
83
|
}
|
|
80
84
|
}
|
package/src/index.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import { govcyCsrfMiddleware } from './middleware/govcyCsrf.mjs';
|
|
|
18
18
|
import { govcySessionData } from './middleware/govcySessionData.mjs';
|
|
19
19
|
import { govcyHttpErrorHandler } from './middleware/govcyHttpErrorHandler.mjs';
|
|
20
20
|
import { govcyLanguageMiddleware } from './middleware/govcyLanguageMiddleware.mjs';
|
|
21
|
-
import { requireAuth, naturalPersonPolicy,handleLoginRoute, handleSigninOidc, handleLogout } from './middleware/cyLoginAuth.mjs';
|
|
21
|
+
import { requireAuth, naturalPersonPolicy, handleLoginRoute, handleSigninOidc, handleLogout } from './middleware/cyLoginAuth.mjs';
|
|
22
22
|
import { serviceConfigDataMiddleware } from './middleware/govcyConfigSiteData.mjs';
|
|
23
23
|
import { govcyManifestHandler } from './middleware/govcyManifestHandler.mjs';
|
|
24
24
|
import { govcyRoutePageHandler } from './middleware/govcyRoutePageHandler.mjs';
|
|
@@ -27,32 +27,34 @@ import { govcyLoadSubmissionData } from './middleware/govcyLoadSubmissionData.mj
|
|
|
27
27
|
import { govcyFileUpload } from './middleware/govcyFileUpload.mjs';
|
|
28
28
|
import { govcyFileDeletePageHandler, govcyFileDeletePostHandler } from './middleware/govcyFileDeleteHandler.mjs';
|
|
29
29
|
import { govcyFileViewHandler } from './middleware/govcyFileViewHandler.mjs';
|
|
30
|
-
import {
|
|
30
|
+
import { govcyMultipleThingsAddHandler, govcyMultipleThingsEditHandler, govcyMultipleThingsAddPostHandler, govcyMultipleThingsEditPostHandler } from './middleware/govcyMultipleThingsItemPage.mjs';
|
|
31
|
+
import { govcyMultipleThingsDeletePageHandler, govcyMultipleThingsDeletePostHandler } from './middleware/govcyMultipleThingsDeleteHandler.mjs';
|
|
32
|
+
import { isProdOrStaging, getEnvVariable, whatsIsMyEnvironment } from './utils/govcyEnvVariables.mjs';
|
|
31
33
|
import { logger } from "./utils/govcyLogger.mjs";
|
|
32
34
|
|
|
33
35
|
import fs from 'fs';
|
|
34
36
|
|
|
35
|
-
export default function initializeGovCyExpressService(){
|
|
37
|
+
export default function initializeGovCyExpressService() {
|
|
36
38
|
const app = express();
|
|
37
39
|
|
|
38
40
|
// Add this line before session middleware
|
|
39
41
|
app.set('trust proxy', 1);
|
|
40
|
-
|
|
42
|
+
|
|
41
43
|
// Get the directory name of the current module
|
|
42
44
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
43
45
|
// Construct the absolute path to local certificate files
|
|
44
46
|
logger.debug('Current directory:', __dirname);
|
|
45
47
|
logger.debug('Current working directory:', process.cwd());
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
+
const certPath = join(process.cwd(), 'server');
|
|
49
|
+
|
|
48
50
|
// Determine environment settings
|
|
49
51
|
const ENV = whatsIsMyEnvironment();
|
|
50
52
|
// Set port
|
|
51
53
|
const PORT = getEnvVariable('PORT') || 44319;
|
|
52
54
|
// Use HTTPS if isProdOrStaging or certificate files exist
|
|
53
55
|
const USE_HTTPS = isProdOrStaging() || (fs.existsSync(certPath + '.cert') && fs.existsSync(certPath + '.key'));
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
|
|
57
|
+
|
|
56
58
|
// Middleware
|
|
57
59
|
// Enable parsing of URL-encoded data (data from HTML form submissions with application/x-www-form-urlencoded encoding)
|
|
58
60
|
app.use(express.urlencoded({ extended: true }));
|
|
@@ -64,39 +66,39 @@ export default function initializeGovCyExpressService(){
|
|
|
64
66
|
secret: getEnvVariable('SESSION_SECRET'), // Use environment variable or fallback for dev. To generate a secret, run: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'));"`
|
|
65
67
|
resave: false, // Prevents unnecessary session updates
|
|
66
68
|
saveUninitialized: false, // Don't save empty sessions
|
|
67
|
-
cookie: {
|
|
69
|
+
cookie: {
|
|
68
70
|
secure: false, // Secure cookies only if HTTPS is used
|
|
69
71
|
httpOnly: true, // Prevents XSS attacks
|
|
70
72
|
maxAge: 1800000, // Session expires after 30 mins
|
|
71
|
-
sameSite:
|
|
72
|
-
}
|
|
73
|
+
sameSite: 'lax' // Prevents CSRF by default
|
|
74
|
+
}
|
|
73
75
|
})
|
|
74
76
|
);
|
|
75
77
|
// Enable cookie parsing
|
|
76
|
-
app.use(cookieParser());
|
|
78
|
+
app.use(cookieParser());
|
|
77
79
|
// Apply language middleware
|
|
78
|
-
app.use(govcyLanguageMiddleware);
|
|
80
|
+
app.use(govcyLanguageMiddleware);
|
|
79
81
|
// Add request timing middleware
|
|
80
82
|
app.use(requestTimer);
|
|
81
83
|
// add csrf middleware
|
|
82
84
|
app.use(govcyCsrfMiddleware);
|
|
83
85
|
// Enable security headers
|
|
84
86
|
app.use(noCacheAndSecurityHeaders);
|
|
85
|
-
|
|
87
|
+
|
|
86
88
|
// 🔒 cyLogin ----------------------------------------
|
|
87
|
-
|
|
89
|
+
|
|
88
90
|
// 🔒 -- ROUTE: Redirect to Login
|
|
89
|
-
app.get('/login', handleLoginRoute()
|
|
90
|
-
|
|
91
|
+
app.get('/login', handleLoginRoute());
|
|
92
|
+
|
|
91
93
|
// 🔒 -- ROUTE: Handle login Callback
|
|
92
|
-
app.get('/signin-oidc', handleSigninOidc()
|
|
93
|
-
|
|
94
|
+
app.get('/signin-oidc', handleSigninOidc());
|
|
95
|
+
|
|
94
96
|
// 🔒 -- ROUTE: Handle Logout
|
|
95
|
-
app.get('/logout', handleLogout()
|
|
96
|
-
|
|
97
|
+
app.get('/logout', handleLogout());
|
|
98
|
+
|
|
97
99
|
//----------------------------------------------------------------------
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
|
|
101
|
+
|
|
100
102
|
// 🛠️ Debugging routes -----------------------------------------------------
|
|
101
103
|
// 🙍🏻♂️ -- ROUTE: Debugging route Protected Route
|
|
102
104
|
// if (!isProdOrStaging()) {
|
|
@@ -114,72 +116,211 @@ export default function initializeGovCyExpressService(){
|
|
|
114
116
|
// });
|
|
115
117
|
// }
|
|
116
118
|
//----------------------------------------------------------------------
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
|
|
120
|
+
|
|
119
121
|
// ✅ Ensures session structure exists
|
|
120
|
-
app.use(govcySessionData);
|
|
122
|
+
app.use(govcySessionData);
|
|
121
123
|
// add logger middleware
|
|
122
124
|
app.use(requestLogger);
|
|
123
|
-
|
|
125
|
+
|
|
124
126
|
// Construct the absolute path to the public directory
|
|
125
127
|
const publicPath = join(__dirname, 'public');
|
|
126
128
|
// 🌐 -- ROUTE: Serve static files in the public directory. Route for `/js/`
|
|
127
129
|
app.use(express.static(publicPath));
|
|
128
|
-
|
|
130
|
+
|
|
129
131
|
// 🏡 -- ROUTE: handle the route `/`
|
|
130
|
-
|
|
132
|
+
app.get('/', govcyRoutePageHandler);
|
|
131
133
|
|
|
132
134
|
// 📝 -- ROUTE: Serve manifest.json dynamically for each site
|
|
133
135
|
app.get('/:siteId/manifest.json', serviceConfigDataMiddleware, govcyManifestHandler());
|
|
134
136
|
|
|
135
137
|
// 🗃️ -- ROUTE: Handle POST requests for file uploads for a page.
|
|
136
|
-
app.post('/apis/:siteId/:pageUrl/upload',
|
|
137
|
-
serviceConfigDataMiddleware,
|
|
138
|
+
app.post('/apis/:siteId/:pageUrl/upload',
|
|
139
|
+
serviceConfigDataMiddleware,
|
|
138
140
|
requireAuth, // UNCOMMENT
|
|
139
141
|
naturalPersonPolicy, // UNCOMMENT
|
|
140
142
|
govcyServiceEligibilityHandler(true), // UNCOMMENT
|
|
141
143
|
govcyFileUpload);
|
|
142
|
-
|
|
144
|
+
|
|
145
|
+
// 🗃️ -- ROUTE: Handle POST requests for file uploads inside multipleThings (add)
|
|
146
|
+
app.post('/apis/:siteId/:pageUrl/multiple/add/upload',
|
|
147
|
+
serviceConfigDataMiddleware,
|
|
148
|
+
requireAuth, // UNCOMMENT
|
|
149
|
+
naturalPersonPolicy, // UNCOMMENT
|
|
150
|
+
govcyServiceEligibilityHandler(true), // UNCOMMENT
|
|
151
|
+
govcyFileUpload
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
// 🗃️ -- ROUTE: Handle POST requests for file uploads inside multipleThings (edit)
|
|
155
|
+
app.post('/apis/:siteId/:pageUrl/multiple/edit/:index/upload',
|
|
156
|
+
serviceConfigDataMiddleware,
|
|
157
|
+
requireAuth, // UNCOMMENT
|
|
158
|
+
naturalPersonPolicy, // UNCOMMENT
|
|
159
|
+
govcyServiceEligibilityHandler(true), // UNCOMMENT
|
|
160
|
+
govcyFileUpload
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// View (multipleThings draft)
|
|
164
|
+
app.get('/:siteId/:pageUrl/multiple/add/view-file/:elementName',
|
|
165
|
+
serviceConfigDataMiddleware,
|
|
166
|
+
requireAuth,
|
|
167
|
+
naturalPersonPolicy,
|
|
168
|
+
govcyServiceEligibilityHandler(true),
|
|
169
|
+
govcyFileViewHandler());
|
|
170
|
+
|
|
171
|
+
// ❌🗃️ -- ROUTE: Delete file during multipleThings ADD (before dynamic route)
|
|
172
|
+
app.get('/:siteId/:pageUrl/multiple/add/delete-file/:elementName',
|
|
173
|
+
serviceConfigDataMiddleware,
|
|
174
|
+
requireAuth,
|
|
175
|
+
naturalPersonPolicy,
|
|
176
|
+
govcyServiceEligibilityHandler(),
|
|
177
|
+
govcyLoadSubmissionData(),
|
|
178
|
+
govcyFileDeletePageHandler(),
|
|
179
|
+
renderGovcyPage()
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// ❌🗃️ -- ROUTE: Delete file during multipleThings EDIT (before dynamic route)
|
|
183
|
+
app.get('/:siteId/:pageUrl/multiple/edit/:index/delete-file/:elementName',
|
|
184
|
+
serviceConfigDataMiddleware,
|
|
185
|
+
requireAuth,
|
|
186
|
+
naturalPersonPolicy,
|
|
187
|
+
govcyServiceEligibilityHandler(),
|
|
188
|
+
govcyLoadSubmissionData(),
|
|
189
|
+
govcyFileDeletePageHandler(),
|
|
190
|
+
renderGovcyPage()
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
// ❌🗃️📥 -- ROUTE: Handle POST requests for delete file in multipleThings ADD
|
|
195
|
+
app.post('/:siteId/:pageUrl/multiple/add/delete-file/:elementName',
|
|
196
|
+
serviceConfigDataMiddleware,
|
|
197
|
+
requireAuth,
|
|
198
|
+
naturalPersonPolicy,
|
|
199
|
+
govcyServiceEligibilityHandler(true),
|
|
200
|
+
govcyFileDeletePostHandler()
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// ❌🗃️📥 -- ROUTE: Handle POST requests for delete file in multipleThings EDIT
|
|
204
|
+
app.post('/:siteId/:pageUrl/multiple/edit/:index/delete-file/:elementName',
|
|
205
|
+
serviceConfigDataMiddleware,
|
|
206
|
+
requireAuth,
|
|
207
|
+
naturalPersonPolicy,
|
|
208
|
+
govcyServiceEligibilityHandler(true),
|
|
209
|
+
govcyFileDeletePostHandler()
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
// View (multipleThings edit)
|
|
214
|
+
app.get('/:siteId/:pageUrl/multiple/edit/:index/view-file/:elementName',
|
|
215
|
+
serviceConfigDataMiddleware,
|
|
216
|
+
requireAuth,
|
|
217
|
+
naturalPersonPolicy,
|
|
218
|
+
govcyServiceEligibilityHandler(true),
|
|
219
|
+
govcyFileViewHandler());
|
|
220
|
+
|
|
143
221
|
// 🏠 -- ROUTE: Handle route with only siteId (/:siteId or /:siteId/)
|
|
144
|
-
app.get('/:siteId', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(true),govcyLoadSubmissionData(),govcyPageHandler(), renderGovcyPage());
|
|
145
|
-
|
|
222
|
+
app.get('/:siteId', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(true), govcyLoadSubmissionData(), govcyPageHandler(), renderGovcyPage());
|
|
223
|
+
|
|
146
224
|
// 👀 -- ROUTE: Add Review Page Route (BEFORE the dynamic route)
|
|
147
|
-
app.get('/:siteId/review',serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(),govcyLoadSubmissionData(), govcyReviewPageHandler(), renderGovcyPage());
|
|
148
|
-
|
|
225
|
+
app.get('/:siteId/review', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcyLoadSubmissionData(), govcyReviewPageHandler(), renderGovcyPage());
|
|
226
|
+
|
|
149
227
|
// ✅📄 -- ROUTE: Add Success PDF Route (BEFORE the dynamic route)
|
|
150
|
-
app.get('/:siteId/success/pdf',serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcySuccessPageHandler(true), govcyPDFRender());
|
|
151
|
-
|
|
228
|
+
app.get('/:siteId/success/pdf', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcySuccessPageHandler(true), govcyPDFRender());
|
|
229
|
+
|
|
152
230
|
// ✅ -- ROUTE: Add Success Page Route (BEFORE the dynamic route)
|
|
153
|
-
app.get('/:siteId/success',serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcySuccessPageHandler(), renderGovcyPage());
|
|
154
|
-
|
|
231
|
+
app.get('/:siteId/success', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcySuccessPageHandler(), renderGovcyPage());
|
|
232
|
+
|
|
233
|
+
|
|
155
234
|
// 👀🗃️ -- ROUTE: View file (BEFORE the dynamic route)
|
|
156
235
|
app.get('/:siteId/:pageUrl/view-file/:elementName', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcyLoadSubmissionData(), govcyFileViewHandler());
|
|
157
236
|
|
|
158
237
|
// ❌🗃️ -- ROUTE: Delete file (BEFORE the dynamic route)
|
|
159
238
|
app.get('/:siteId/:pageUrl/delete-file/:elementName', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcyLoadSubmissionData(), govcyFileDeletePageHandler(), renderGovcyPage());
|
|
160
|
-
|
|
239
|
+
|
|
240
|
+
// ➕ -- ROUTE: Add item page (BEFORE the generic dynamic route)
|
|
241
|
+
app.get('/:siteId/:pageUrl/multiple/add',
|
|
242
|
+
serviceConfigDataMiddleware,
|
|
243
|
+
requireAuth,
|
|
244
|
+
naturalPersonPolicy,
|
|
245
|
+
govcyServiceEligibilityHandler(true),
|
|
246
|
+
govcyLoadSubmissionData(),
|
|
247
|
+
govcyMultipleThingsAddHandler(),
|
|
248
|
+
renderGovcyPage()
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
// ➕ -- ROUTE: Add item POST (BEFORE the generic POST)
|
|
253
|
+
app.post('/:siteId/:pageUrl/multiple/add',
|
|
254
|
+
serviceConfigDataMiddleware,
|
|
255
|
+
requireAuth,
|
|
256
|
+
naturalPersonPolicy,
|
|
257
|
+
govcyServiceEligibilityHandler(true),
|
|
258
|
+
govcyMultipleThingsAddPostHandler()
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// ✏️ -- ROUTE: Edit item page (BEFORE the generic dynamic route)
|
|
262
|
+
app.get('/:siteId/:pageUrl/multiple/edit/:index',
|
|
263
|
+
serviceConfigDataMiddleware,
|
|
264
|
+
requireAuth,
|
|
265
|
+
naturalPersonPolicy,
|
|
266
|
+
govcyServiceEligibilityHandler(true),
|
|
267
|
+
govcyLoadSubmissionData(),
|
|
268
|
+
govcyMultipleThingsEditHandler(),
|
|
269
|
+
renderGovcyPage()
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
// 🗃️ -- ROUTE: Handle POST requests for multipleThings EDIT item
|
|
273
|
+
app.post('/:siteId/:pageUrl/multiple/edit/:index',
|
|
274
|
+
serviceConfigDataMiddleware,
|
|
275
|
+
requireAuth,
|
|
276
|
+
naturalPersonPolicy,
|
|
277
|
+
govcyServiceEligibilityHandler(true),
|
|
278
|
+
govcyMultipleThingsEditPostHandler()
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
// ❌🗃️ -- ROUTE: Delete multipleThings item (BEFORE the dynamic route)
|
|
282
|
+
app.get('/:siteId/:pageUrl/multiple/delete/:index',
|
|
283
|
+
serviceConfigDataMiddleware,
|
|
284
|
+
requireAuth,
|
|
285
|
+
naturalPersonPolicy,
|
|
286
|
+
govcyServiceEligibilityHandler(),
|
|
287
|
+
govcyLoadSubmissionData(),
|
|
288
|
+
govcyMultipleThingsDeletePageHandler(),
|
|
289
|
+
renderGovcyPage()
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
// ❌🗃️📥 -- ROUTE: Handle POST requests for delete multipleThings item
|
|
293
|
+
app.post('/:siteId/:pageUrl/multiple/delete/:index',
|
|
294
|
+
serviceConfigDataMiddleware,
|
|
295
|
+
requireAuth,
|
|
296
|
+
naturalPersonPolicy,
|
|
297
|
+
govcyServiceEligibilityHandler(true),
|
|
298
|
+
govcyMultipleThingsDeletePostHandler()
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
|
|
161
302
|
// 📝 -- ROUTE: Dynamic route to render pages based on siteId and pageUrl, using govcyPageHandler middleware
|
|
162
303
|
app.get('/:siteId/:pageUrl', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(true), govcyLoadSubmissionData(), govcyPageHandler(), renderGovcyPage());
|
|
163
|
-
|
|
304
|
+
|
|
164
305
|
// ❌🗃️📥 -- ROUTE: Handle POST requests for delete file
|
|
165
306
|
app.post('/:siteId/:pageUrl/delete-file/:elementName', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(true), govcyFileDeletePostHandler());
|
|
166
|
-
|
|
307
|
+
|
|
167
308
|
// 📥 -- ROUTE: Handle POST requests for review page. The `submit` action
|
|
168
309
|
app.post('/:siteId/review', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcyReviewPostHandler());
|
|
169
|
-
|
|
310
|
+
|
|
170
311
|
// 👀📥 -- ROUTE: Handle POST requests (Form Submissions) based on siteId and pageUrl, using govcyFormsPostHandler middleware
|
|
171
312
|
app.post('/:siteId/:pageUrl', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(true), govcyFormsPostHandler());
|
|
172
|
-
|
|
313
|
+
|
|
173
314
|
// post for /:siteId/review
|
|
174
|
-
|
|
315
|
+
|
|
175
316
|
// 🔹 Catch 404 errors (must be after all routes)
|
|
176
317
|
app.use((req, res, next) => {
|
|
177
318
|
next({ status: 404, message: "Page not found" });
|
|
178
319
|
});
|
|
179
|
-
|
|
320
|
+
|
|
180
321
|
// 🔹 Centralized error handling (must be the LAST middleware)
|
|
181
322
|
app.use(govcyHttpErrorHandler);
|
|
182
|
-
|
|
323
|
+
|
|
183
324
|
let server = null;
|
|
184
325
|
|
|
185
326
|
return {
|
|
@@ -199,7 +340,7 @@ export default function initializeGovCyExpressService(){
|
|
|
199
340
|
logger.info(`⚡ Server running at http://localhost:${PORT} (${ENV})`);
|
|
200
341
|
});
|
|
201
342
|
}
|
|
202
|
-
},
|
|
343
|
+
},
|
|
203
344
|
stopServer: () => {
|
|
204
345
|
if (server) {
|
|
205
346
|
server.close(() => {
|
|
@@ -47,14 +47,16 @@ export function govcyFileDeletePageHandler() {
|
|
|
47
47
|
return handleMiddlewareError(`File input [${elementName}] does not have a label`, 404, next);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
//
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
// --- Resolve file element data (normal + multipleThings add/edit) ---
|
|
51
|
+
const { index } = req.params;
|
|
52
|
+
const elementData = dataLayer.getFormDataValue(req.session, siteId, pageUrl, elementName, index);
|
|
53
|
+
|
|
54
|
+
// Guard if still nothing found
|
|
55
|
+
if (!elementData || !elementData.fileId || !elementData.sha256) {
|
|
55
56
|
return handleMiddlewareError(`File input [${elementName}] data not found on this page`, 404, next);
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
|
|
58
60
|
// Deep copy page title (so we don’t mutate template)
|
|
59
61
|
const pageTitle = JSON.parse(JSON.stringify(govcyResources.staticResources.text.deleteFileTitle));
|
|
60
62
|
|
|
@@ -92,7 +94,7 @@ export function govcyFileDeletePageHandler() {
|
|
|
92
94
|
const showSameFileWarning = dataLayer.isFileUsedInSiteInputDataAgain(
|
|
93
95
|
req.session,
|
|
94
96
|
siteId,
|
|
95
|
-
elementData
|
|
97
|
+
elementData
|
|
96
98
|
);
|
|
97
99
|
|
|
98
100
|
// Construct page title
|
|
@@ -119,12 +121,23 @@ export function govcyFileDeletePageHandler() {
|
|
|
119
121
|
}
|
|
120
122
|
};
|
|
121
123
|
//-------------
|
|
122
|
-
|
|
124
|
+
// Build proper action based on context (normal / multiple add / multiple edit)
|
|
125
|
+
let actionPath;
|
|
126
|
+
if (typeof req.params.index !== "undefined") {
|
|
127
|
+
// multiple edit
|
|
128
|
+
actionPath = `${pageUrl}/multiple/edit/${req.params.index}/delete-file/${elementName}`;
|
|
129
|
+
} else if (req.originalUrl.includes("/multiple/add")) {
|
|
130
|
+
// multiple add
|
|
131
|
+
actionPath = `${pageUrl}/multiple/add/delete-file/${elementName}`;
|
|
132
|
+
} else {
|
|
133
|
+
// normal page
|
|
134
|
+
actionPath = `${pageUrl}/delete-file/${elementName}`;
|
|
135
|
+
}
|
|
123
136
|
// Construct submit button
|
|
124
137
|
const formElement = {
|
|
125
138
|
element: "form",
|
|
126
139
|
params: {
|
|
127
|
-
action: govcyResources.constructPageUrl(siteId,
|
|
140
|
+
action: govcyResources.constructPageUrl(siteId, actionPath, (req.query.route === "review" ? "review" : "")),
|
|
128
141
|
method: "POST",
|
|
129
142
|
elements: [
|
|
130
143
|
pageRadios,
|
|
@@ -159,11 +172,6 @@ export function govcyFileDeletePageHandler() {
|
|
|
159
172
|
// Append generated summary list to the page template
|
|
160
173
|
pageTemplate.sections.push({ name: "main", elements: mainElements });
|
|
161
174
|
|
|
162
|
-
//if user is logged in add he user bane section in the page template
|
|
163
|
-
if (dataLayer.getUser(req.session)) {
|
|
164
|
-
pageTemplate.sections.push(govcyResources.userNameSection(dataLayer.getUser(req.session).name)); // Add user name section
|
|
165
|
-
}
|
|
166
|
-
|
|
167
175
|
//prepare pageData
|
|
168
176
|
pageData.site = serviceCopy.site;
|
|
169
177
|
pageData.pageData.title = pageTitle;
|
|
@@ -215,16 +223,30 @@ export function govcyFileDeletePostHandler() {
|
|
|
215
223
|
return handleMiddlewareError(`File input [${elementName}] not allowed on this page`, 404, next);
|
|
216
224
|
}
|
|
217
225
|
|
|
218
|
-
//
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
// --- Resolve file element data (normal + multipleThings add/edit) ---
|
|
227
|
+
const { index } = req.params;
|
|
228
|
+
const elementData = dataLayer.getFormDataValue(req.session, siteId, pageUrl, elementName, index);
|
|
229
|
+
|
|
230
|
+
// Guard if still nothing found
|
|
231
|
+
if (!elementData || !elementData.fileId || !elementData.sha256) {
|
|
223
232
|
return handleMiddlewareError(`File input [${elementName}] data not found on this page`, 404, next);
|
|
224
233
|
}
|
|
225
234
|
|
|
235
|
+
// Build proper action based on context (normal / multiple add / multiple edit)
|
|
236
|
+
let actionPath;
|
|
237
|
+
if (typeof req.params.index !== "undefined") {
|
|
238
|
+
// multiple edit
|
|
239
|
+
actionPath = `${pageUrl}/multiple/edit/${req.params.index}`;
|
|
240
|
+
} else if (req.originalUrl.includes("/multiple/add")) {
|
|
241
|
+
// multiple add
|
|
242
|
+
actionPath = `${pageUrl}/multiple/add`;
|
|
243
|
+
} else {
|
|
244
|
+
// normal page
|
|
245
|
+
actionPath = `${pageUrl}`;
|
|
246
|
+
}
|
|
247
|
+
|
|
226
248
|
// the page base return url
|
|
227
|
-
const pageBaseReturnUrl = `http://localhost:3000/${siteId}/${
|
|
249
|
+
const pageBaseReturnUrl = `http://localhost:3000/${siteId}/${actionPath}`;
|
|
228
250
|
|
|
229
251
|
//check if input `deleteFile` has a value
|
|
230
252
|
if (!req?.body?.deleteFile ||
|
|
@@ -17,13 +17,26 @@ export const govcyFileUpload = [
|
|
|
17
17
|
upload.single('file'), // multer parses the uploaded file and stores it in req.file
|
|
18
18
|
|
|
19
19
|
async function govcyUploadHandler(req, res) {
|
|
20
|
+
let mode = "single";
|
|
21
|
+
let index = null;
|
|
22
|
+
|
|
23
|
+
// Detect MultipleThings modes based on URL
|
|
24
|
+
if (req.originalUrl.includes("/multiple/add")) {
|
|
25
|
+
mode = "multipleThingsDraft";
|
|
26
|
+
} else if (req.originalUrl.includes("/multiple/edit/")) {
|
|
27
|
+
mode = "multipleThingsEdit";
|
|
28
|
+
index = parseInt(req.params.index, 10);
|
|
29
|
+
}
|
|
30
|
+
|
|
20
31
|
const result = await handleFileUpload({
|
|
21
32
|
service: req.serviceData,
|
|
22
33
|
store: req.session,
|
|
23
34
|
siteId: req.params.siteId,
|
|
24
35
|
pageUrl: req.params.pageUrl,
|
|
25
36
|
elementName: req.body?.elementName,
|
|
26
|
-
file: req.file
|
|
37
|
+
file: req.file,
|
|
38
|
+
mode,
|
|
39
|
+
index
|
|
27
40
|
});
|
|
28
41
|
|
|
29
42
|
if (result.status !== 200) {
|
|
@@ -13,6 +13,17 @@ export function govcyFileViewHandler() {
|
|
|
13
13
|
try {
|
|
14
14
|
const { siteId, pageUrl, elementName } = req.params;
|
|
15
15
|
|
|
16
|
+
// Detect MultipleThings modes based on URL
|
|
17
|
+
let mode = "single";
|
|
18
|
+
let index = null;
|
|
19
|
+
|
|
20
|
+
if (req.originalUrl.includes("/multiple/add")) {
|
|
21
|
+
mode = "multipleThingsDraft";
|
|
22
|
+
} else if (req.originalUrl.includes("/multiple/edit/")) {
|
|
23
|
+
mode = "multipleThingsEdit";
|
|
24
|
+
index = parseInt(req.params.index, 10);
|
|
25
|
+
}
|
|
26
|
+
|
|
16
27
|
// Create a deep copy of the service to avoid modifying the original
|
|
17
28
|
let serviceCopy = req.serviceData;
|
|
18
29
|
|
|
@@ -64,7 +75,15 @@ export function govcyFileViewHandler() {
|
|
|
64
75
|
}
|
|
65
76
|
|
|
66
77
|
//get element data
|
|
67
|
-
|
|
78
|
+
let elementData;
|
|
79
|
+
if (mode === "single") {
|
|
80
|
+
elementData = dataLayer.getFormDataValue(req.session, siteId, pageUrl, elementName);
|
|
81
|
+
} else if (mode === "multipleThingsDraft") {
|
|
82
|
+
elementData = dataLayer.getMultipleDraft(req.session, siteId, pageUrl)?.[elementName];
|
|
83
|
+
} else if (mode === "multipleThingsEdit") {
|
|
84
|
+
const items = dataLayer.getPageData(req.session, siteId, pageUrl) || [];
|
|
85
|
+
elementData = items[index]?.[elementName];
|
|
86
|
+
}
|
|
68
87
|
|
|
69
88
|
// If the element data is not found, return an error response
|
|
70
89
|
if (!elementData || !elementData?.sha256 || !elementData?.fileId) {
|