@reldens/cms 0.16.0 → 0.19.0

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.
Files changed (38) hide show
  1. package/README.md +92 -9
  2. package/admin/reldens-admin-client.css +55 -0
  3. package/admin/reldens-admin-client.js +24 -0
  4. package/admin/templates/cache-clean-button.html +4 -0
  5. package/admin/templates/clear-all-cache-button.html +18 -0
  6. package/admin/templates/fields/view/textarea.html +1 -1
  7. package/bin/reldens-cms-generate-entities.js +85 -18
  8. package/bin/reldens-cms.js +6 -6
  9. package/lib/admin-manager/contents-builder.js +257 -0
  10. package/lib/admin-manager/router-contents.js +618 -0
  11. package/lib/admin-manager/router.js +208 -0
  12. package/lib/admin-manager-validator.js +2 -1
  13. package/lib/admin-manager.js +116 -990
  14. package/lib/admin-translations.js +9 -1
  15. package/lib/cache/add-cache-button-subscriber.js +149 -0
  16. package/lib/cache/cache-manager.js +168 -0
  17. package/lib/cache/cache-routes-handler.js +99 -0
  18. package/lib/cms-pages-route-manager.js +45 -21
  19. package/lib/frontend.js +288 -71
  20. package/lib/installer.js +5 -2
  21. package/lib/json-fields-parser.js +74 -0
  22. package/lib/manager.js +49 -4
  23. package/lib/pagination-handler.js +243 -0
  24. package/lib/search-renderer.js +116 -0
  25. package/lib/search.js +344 -0
  26. package/lib/template-engine/collections-single-transformer.js +53 -0
  27. package/lib/template-engine/collections-transformer-base.js +84 -0
  28. package/lib/template-engine/collections-transformer.js +353 -0
  29. package/lib/template-engine/entities-transformer.js +65 -0
  30. package/lib/template-engine/partials-transformer.js +171 -0
  31. package/lib/template-engine.js +53 -387
  32. package/lib/templates-list.js +2 -0
  33. package/migrations/default-homepage.sql +6 -6
  34. package/migrations/install.sql +21 -20
  35. package/package.json +4 -4
  36. package/templates/page.html +19 -2
  37. package/templates/partials/entriesListView.html +14 -0
  38. package/templates/partials/pagedCollection.html +33 -0
@@ -4,8 +4,13 @@
4
4
  *
5
5
  */
6
6
 
7
- const { UploaderFactory, FileHandler } = require('@reldens/server-utils');
8
- const { PageRangeProvider, ValidatorInterface, Logger, sc } = require('@reldens/utils');
7
+ const { UploaderFactory } = require('@reldens/server-utils');
8
+ const { ValidatorInterface, Logger, sc } = require('@reldens/utils');
9
+ const { ContentsBuilder } = require('./admin-manager/contents-builder');
10
+ const { Router } = require('./admin-manager/router');
11
+ const { RouterContents } = require('./admin-manager/router-contents');
12
+ const { CacheRoutesHandler } = require('./cache/cache-routes-handler');
13
+ const { AddCacheButtonSubscriber } = require('./cache/add-cache-button-subscriber');
9
14
 
10
15
  class AdminManager
11
16
  {
@@ -35,6 +40,7 @@ class AdminManager
35
40
  this.autoSyncDistCallback = sc.get(configData, 'autoSyncDistCallback', false);
36
41
  this.branding = sc.get(configData, 'branding', {});
37
42
  this.entities = sc.get(configData, 'entities', {});
43
+ this.cacheManager = sc.get(configData, 'cacheManager', false);
38
44
  this.logoutPath = '/logout';
39
45
  this.loginPath = '/login';
40
46
  this.viewPath = '/view';
@@ -48,8 +54,92 @@ class AdminManager
48
54
  allowedExtensions: this.allowedExtensions,
49
55
  applySecureFileNames: sc.get(configData, 'applySecureFileNames', false)
50
56
  }));
51
- this.adminContents = {};
52
57
  this.blackList = {};
58
+ this.emitEvent = (eventName, eventData = {}) => this.events.emit(eventName, {adminManager: this, ...eventData});
59
+ this.contentsBuilder = new ContentsBuilder({
60
+ renderCallback: this.renderCallback,
61
+ adminFilesContents: this.adminFilesContents,
62
+ stylesFilePath: this.stylesFilePath,
63
+ scriptsFilePath: this.scriptsFilePath,
64
+ rootPath: this.rootPath,
65
+ branding: this.branding,
66
+ translations: this.translations,
67
+ resources: () => this.resources,
68
+ buildAdminCssOnActivation: this.buildAdminCssOnActivation,
69
+ buildAdminScriptsOnActivation: this.buildAdminScriptsOnActivation,
70
+ updateAdminAssetsDistOnActivation: this.updateAdminAssetsDistOnActivation,
71
+ emitEvent: this.emitEvent,
72
+ editPath: this.editPath,
73
+ savePath: this.savePath,
74
+ deletePath: this.deletePath,
75
+ fetchUploadProperties: this.fetchUploadProperties.bind(this),
76
+ fetchTranslation: this.fetchTranslation.bind(this),
77
+ fetchEntityIdPropertyKey: this.fetchEntityIdPropertyKey.bind(this)
78
+ });
79
+ this.router = new Router({
80
+ app: this.app,
81
+ applicationFramework: this.applicationFramework,
82
+ bodyParser: this.bodyParser,
83
+ session: this.session,
84
+ secret: this.secret,
85
+ rootPath: this.rootPath,
86
+ adminRoleId: this.adminRoleId,
87
+ authenticationCallback: this.authenticationCallback,
88
+ uploaderFactory: this.uploaderFactory,
89
+ buckets: this.buckets,
90
+ blackList: this.blackList,
91
+ loginPath: this.loginPath,
92
+ logoutPath: this.logoutPath,
93
+ viewPath: this.viewPath,
94
+ editPath: this.editPath,
95
+ savePath: this.savePath,
96
+ deletePath: this.deletePath,
97
+ resources: () => this.resources,
98
+ emitEvent: this.emitEvent,
99
+ fetchUploadProperties: this.fetchUploadProperties.bind(this),
100
+ adminContents: () => this.contentsBuilder.adminContents,
101
+ generateListRouteContent: (...args) => this.routerContents.generateListRouteContent(...args),
102
+ generateViewRouteContent: (...args) => this.routerContents.generateViewRouteContent(...args),
103
+ generateEditRouteContent: (...args) => this.routerContents.generateEditRouteContent(...args),
104
+ processDeleteEntities: (...args) => this.routerContents.processDeleteEntities(...args),
105
+ processSaveEntity: (...args) => this.routerContents.processSaveEntity(...args)
106
+ });
107
+ this.routerContents = new RouterContents({
108
+ dataServer: this.dataServer,
109
+ translations: this.translations,
110
+ rootPath: this.rootPath,
111
+ relations: () => this.relations,
112
+ resourcesByReference: () => this.resourcesByReference,
113
+ adminFilesContents: this.adminFilesContents,
114
+ autoSyncDistCallback: this.autoSyncDistCallback,
115
+ viewPath: this.viewPath,
116
+ editPath: this.editPath,
117
+ deletePath: this.deletePath,
118
+ emitEvent: this.emitEvent,
119
+ adminContentsRender: (...args) => this.contentsBuilder.render(...args),
120
+ adminContentsRenderRoute: (...args) => this.contentsBuilder.renderRoute(...args),
121
+ adminContentsEntities: () => this.contentsBuilder.adminContents.entities,
122
+ adminContentsSideBar: () => this.contentsBuilder.adminContents.sideBar,
123
+ fetchTranslation: this.fetchTranslation.bind(this),
124
+ fetchEntityIdPropertyKey: this.fetchEntityIdPropertyKey.bind(this),
125
+ fetchUploadProperties: this.fetchUploadProperties.bind(this)
126
+ });
127
+ this.cacheRoutesHandler = new CacheRoutesHandler({
128
+ router: this.router,
129
+ rootPath: this.rootPath,
130
+ dataServer: this.dataServer,
131
+ cacheManager: this.cacheManager
132
+ });
133
+ this.addCacheButtonSubscriber = new AddCacheButtonSubscriber({
134
+ events: this.events,
135
+ cacheManager: this.cacheManager,
136
+ renderCallback: this.renderCallback,
137
+ cacheCleanButton: this.adminFilesContents.cacheCleanButton,
138
+ clearAllCacheButton: this.adminFilesContents.clearAllCacheButton,
139
+ translations: this.translations,
140
+ cacheCleanRoute: this.cacheRoutesHandler.cacheCleanRoute,
141
+ clearAllCacheRoute: this.cacheRoutesHandler.clearAllCacheRoute
142
+ });
53
143
  }
54
144
 
55
145
  async setupAdmin()
@@ -60,260 +150,17 @@ class AdminManager
60
150
  this.resourcesByReference = {};
61
151
  this.resources = this.prepareResources(this.entities);
62
152
  this.relations = this.prepareRelations(this.entities);
63
- await this.buildAdminContents();
64
- await this.buildAdminScripts();
65
- await this.buildAdminCss();
66
- await this.updateAdminAssets();
67
- this.setupAdminRouter();
153
+ await this.contentsBuilder.buildAdminContents();
154
+ await this.contentsBuilder.buildAdminScripts();
155
+ await this.contentsBuilder.buildAdminCss();
156
+ await this.contentsBuilder.updateAdminAssets();
68
157
  await this.events.emit('reldens.setupAdminRouter', {adminManager: this});
69
- this.setupAdminRoutes();
158
+ this.router.setupAdminRoutes();
70
159
  await this.events.emit('reldens.setupAdminRoutes', {adminManager: this});
71
- await this.setupEntitiesRoutes();
160
+ await this.router.setupEntitiesRoutes();
72
161
  await this.events.emit('reldens.setupAdminManagers', {adminManager: this});
73
162
  }
74
163
 
75
- async buildAdminContents()
76
- {
77
- this.adminContents.layout = await this.buildLayout();
78
- this.adminContents.sideBar = await this.buildSideBar();
79
- this.adminContents.login = await this.buildLogin();
80
- this.adminContents.dashboard = await this.buildDashboard();
81
- this.adminContents.entities = await this.buildEntitiesContents();
82
- await this.events.emit('reldens.buildAdminContentsAfter', {adminManager: this});
83
- }
84
-
85
- async buildLayout()
86
- {
87
- return await this.render(
88
- this.adminFilesContents.layout,
89
- {
90
- sideBar: '{{&sideBar}}',
91
- pageContent: '{{&pageContent}}',
92
- stylesFilePath: this.stylesFilePath,
93
- scriptsFilePath: this.scriptsFilePath,
94
- rootPath: this.rootPath,
95
- brandingCompanyName: this.branding.companyName,
96
- copyRight: this.branding.copyRight
97
- }
98
- );
99
- }
100
-
101
- async buildSideBar()
102
- {
103
- let navigationContents = {};
104
- let eventBuildSideBarBefore = {navigationContents, adminManager: this};
105
- await this.events.emit('reldens.eventBuildSideBarBefore', eventBuildSideBarBefore);
106
- navigationContents = eventBuildSideBarBefore.navigationContents;
107
- for(let driverResource of this.resources){
108
- let navigation = driverResource.options?.navigation;
109
- let name = this.translations.labels[driverResource.id()] || this.translations.labels[driverResource.entityKey];
110
- let path = this.rootPath+'/'+(driverResource.id().replace(/_/g, '-'));
111
- if(navigation?.name){
112
- if(!navigationContents[navigation.name]){
113
- navigationContents[navigation.name] = {};
114
- }
115
- navigationContents[navigation.name][driverResource.id()] = await this.render(
116
- this.adminFilesContents.sideBarItem,
117
- {name, path}
118
- );
119
- continue;
120
- }
121
- navigationContents[driverResource.id()] = await this.render(
122
- this.adminFilesContents.sideBarItem,
123
- {name, path}
124
- );
125
- }
126
- let eventAdminSideBarBeforeSubItems = {navigationContents, adminManager: this};
127
- await this.events.emit('reldens.adminSideBarBeforeSubItems', eventAdminSideBarBeforeSubItems);
128
- let navigationView = '';
129
- for(let id of Object.keys(navigationContents)){
130
- if(sc.isObject(navigationContents[id])){
131
- let subItems = '';
132
- for(let subId of Object.keys(navigationContents[id])){
133
- subItems += navigationContents[id][subId];
134
- }
135
- navigationView += await this.render(
136
- this.adminFilesContents.sideBarHeader,
137
- {name: id, subItems}
138
- );
139
- continue;
140
- }
141
- navigationView += navigationContents[id];
142
- }
143
- let eventAdminSideBarBeforeRender = {navigationContents, navigationView, adminManager: this};
144
- await this.events.emit('reldens.adminSideBarBeforeRender', eventAdminSideBarBeforeRender);
145
- return await this.render(
146
- this.adminFilesContents.sideBar,
147
- {
148
- rootPath: this.rootPath,
149
- navigationView: eventAdminSideBarBeforeRender.navigationView
150
- }
151
- );
152
- }
153
-
154
- async buildLogin()
155
- {
156
- return await this.renderRoute(this.adminFilesContents.login, '');
157
- }
158
-
159
- async buildDashboard()
160
- {
161
- return await this.renderRoute(this.adminFilesContents.dashboard, this.adminContents.sideBar);
162
- }
163
-
164
- async buildEntitiesContents()
165
- {
166
- let entitiesContents = {};
167
- for(let driverResource of this.resources){
168
- let templateTitle = this.translations.labels[driverResource.id()];
169
- let entityName = (driverResource.id().replace(/_/g, '-'));
170
- let entityListRoute = this.rootPath+'/'+entityName;
171
- let entityEditRoute = entityListRoute+this.editPath;
172
- let entitySaveRoute = entityListRoute+this.savePath;
173
- let entityDeleteRoute = entityListRoute+this.deletePath;
174
- let uploadProperties = this.fetchUploadProperties(driverResource);
175
- let multipartFormData = 0 < Object.keys(uploadProperties).length ? ' enctype="multipart/form-data"' : '';
176
- let idProperty = this.fetchEntityIdPropertyKey(driverResource);
177
- let editProperties = Object.keys(driverResource.options.properties);
178
- editProperties.splice(editProperties.indexOf(idProperty), 1);
179
- let filters = driverResource.options.filterProperties.map((property) => {
180
- return {
181
- propertyKey: property,
182
- name: this.fetchTranslation(property),
183
- value: '{{&'+property+'}}'
184
- };
185
- });
186
- let fields = driverResource.options.showProperties.map((property) => {
187
- return {
188
- name: this.fetchTranslation(property),
189
- value: '{{&'+property+'}}'
190
- };
191
- });
192
- let editFields = editProperties.map((property) => {
193
- return {
194
- name: this.fetchTranslation(property),
195
- value: '{{&'+property+'}}'
196
- };
197
- });
198
- let sectionsContents = this.adminFilesContents?.sections;
199
- let extraContentForList = sc.get(sectionsContents?.list, driverResource.entityPath, '');
200
- let extraContentForView = await this.render(
201
- sc.get(sectionsContents?.view, driverResource.entityPath, ''),
202
- {
203
- id: '{{&id}}',
204
- entitySerializedData: '{{&entitySerializedData}}'
205
- }
206
- );
207
- let extraFormContentForView = sc.get(sectionsContents?.viewForm, driverResource.entityPath, '');
208
- let extraContentForEdit = sc.get(sectionsContents?.edit, driverResource.entityPath, '');
209
- let extraFormContentForEdit = sc.get(sectionsContents?.editForm, driverResource.entityPath, '');
210
- entitiesContents[entityName] = {
211
- list: await this.render(
212
- this.adminFilesContents.list,
213
- {
214
- entityName,
215
- templateTitle,
216
- entityListRoute,
217
- entityEditRoute,
218
- filters,
219
- list: '{{&list}}',
220
- pagination: '{{&pagination}}',
221
- extraContent: extraContentForList,
222
- }
223
- ),
224
- view: await this.render(
225
- this.adminFilesContents.view,
226
- {
227
- entityName,
228
- templateTitle,
229
- entityDeleteRoute,
230
- entityListRoute,
231
- fields,
232
- id: '{{&id}}',
233
- entityEditRoute: '{{&entityEditRoute}}',
234
- entityNewRoute: '{{&entityNewRoute}}',
235
- extraContent: extraContentForView,
236
- extraFormContent: extraFormContentForView
237
- }
238
- ),
239
- edit: await this.render(
240
- this.adminFilesContents.edit,
241
- {
242
- entityName,
243
- entitySaveRoute,
244
- multipartFormData,
245
- editFields,
246
- idValue: '{{&idValue}}',
247
- idProperty: '{{&idProperty}}',
248
- templateTitle: '{{&templateTitle}}',
249
- entityViewRoute: '{{&entityViewRoute}}',
250
- extraContent: extraContentForEdit,
251
- extraFormContent: extraFormContentForEdit
252
- }
253
- )
254
- };
255
- }
256
- return entitiesContents;
257
- }
258
-
259
- fetchUploadProperties(driverResource)
260
- {
261
- if(!driverResource.options.uploadProperties){
262
- driverResource.options.uploadProperties = {};
263
- for(let propertyKey of Object.keys(driverResource.options.properties)){
264
- let property = driverResource.options.properties[propertyKey];
265
- if(property.isUpload){
266
- driverResource.options.uploadProperties[propertyKey] = property;
267
- }
268
- }
269
- }
270
- return driverResource.options.uploadProperties;
271
- }
272
-
273
- async render(content, params)
274
- {
275
- return await this.renderCallback(content, params);
276
- }
277
-
278
- async renderRoute(pageContent, sideBar)
279
- {
280
- return await this.render(
281
- this.adminContents.layout,
282
- {
283
- stylesFilePath: this.stylesFilePath,
284
- scriptsFilePath: this.scriptsFilePath,
285
- brandingCompanyName: this.branding.companyName,
286
- copyRight: this.branding.copyRight,
287
- pageContent,
288
- sideBar
289
- }
290
- );
291
- }
292
-
293
- async buildAdminScripts()
294
- {
295
- if(!sc.isFunction(this.buildAdminScriptsOnActivation)){
296
- return false;
297
- }
298
- return this.buildAdminScriptsOnActivation();
299
- }
300
-
301
- async updateAdminAssets()
302
- {
303
- if(!sc.isFunction(this.updateAdminAssetsDistOnActivation)){
304
- return false;
305
- }
306
- return this.updateAdminAssetsDistOnActivation();
307
- }
308
-
309
- async buildAdminCss()
310
- {
311
- if(!sc.isFunction(this.buildAdminCssOnActivation)){
312
- return false;
313
- }
314
- return this.buildAdminCssOnActivation();
315
- }
316
-
317
164
  prepareResources(rawResources)
318
165
  {
319
166
  let rawResourcesKeys = Object.keys(rawResources);
@@ -324,7 +171,6 @@ class AdminManager
324
171
  for(let i of rawResourcesKeys){
325
172
  let rawResource = rawResources[i];
326
173
  let tableName = rawResource.rawEntity.tableName();
327
- // @TODO - BETA - Refactor to add the ID property and composed labels (id + label), in the resource.
328
174
  let driverResource = {
329
175
  id: () => {
330
176
  return tableName;
@@ -355,7 +201,6 @@ class AdminManager
355
201
 
356
202
  prepareRelations()
357
203
  {
358
- // @TODO - BETA - Refactor, include in resources generation at once.
359
204
  let registeredRelations = {};
360
205
  for(let resource of this.resources){
361
206
  for(let propertyKey of Object.keys(resource.options.properties)){
@@ -380,680 +225,18 @@ class AdminManager
380
225
  return registeredRelations;
381
226
  }
382
227
 
383
- setupAdminRouter()
384
- {
385
- this.adminRouter = this.applicationFramework.Router();
386
- // apply session middleware only to /admin routes:
387
- if(this.session){
388
- if(!this.secret){
389
- Logger.warning('Admin Manager "secret" key was not provided.');
390
- }
391
- this.adminRouter.use(this.session({secret: this.secret, resave: false, saveUninitialized: true}));
392
- }
393
- this.adminRouter.use(this.bodyParser.json());
394
- }
395
-
396
- setupAdminRoutes()
397
- {
398
- this.adminRouter.get(this.loginPath, async (req, res) => {
399
- return res.send(this.adminContents.login);
400
- });
401
- // route for handling login:
402
- this.adminRouter.post(this.loginPath, async (req, res) => {
403
- let { email, password } = req.body;
404
- let loginResult = await this.authenticationCallback(email, password, this.adminRoleId);
405
- if(loginResult){
406
- req.session.user = loginResult;
407
- return res.redirect(this.rootPath);
408
- }
409
- return res.redirect(this.rootPath+this.loginPath+'?login-error=true');
410
- });
411
- // route for the admin panel dashboard:
412
- this.adminRouter.get('/', this.isAuthenticated.bind(this), async (req, res) => {
413
- return res.send(this.adminContents.dashboard);
414
- });
415
- // route for logout:
416
- this.adminRouter.get(this.logoutPath, (req, res) => {
417
- req.session.destroy();
418
- res.redirect(this.rootPath+this.loginPath);
419
- });
420
- this.app.use(this.rootPath, this.adminRouter);
421
- }
422
-
423
- async setupEntitiesRoutes()
424
- {
425
- if(!this.resources || 0 === this.resources.length){
426
- return;
427
- }
428
- for(let driverResource of this.resources){
429
- let entityPath = driverResource.entityPath;
430
- let entityRoute = '/'+entityPath;
431
- this.adminRouter.get(entityRoute, this.isAuthenticated.bind(this), async (req, res) => {
432
- let routeContents = await this.generateListRouteContent(req, driverResource, entityPath);
433
- return res.send(routeContents);
434
- });
435
- this.adminRouter.post(entityRoute, this.isAuthenticated.bind(this), async (req, res) => {
436
- let routeContents = await this.generateListRouteContent(req, driverResource, entityPath);
437
- return res.send(routeContents);
438
- });
439
- this.adminRouter.get(entityRoute+this.viewPath, this.isAuthenticated.bind(this), async (req, res) => {
440
- let routeContents = await this.generateViewRouteContent(req, driverResource, entityPath);
441
- if('' === routeContents){
442
- return res.redirect(this.rootPath+'/'+entityPath+'?result=errorView');
443
- }
444
- return res.send(routeContents);
445
- });
446
- this.adminRouter.get(entityRoute+this.editPath, this.isAuthenticated.bind(this), async (req, res) => {
447
- let adminBeforeEntityEditEvent = {
448
- adminManager: this,
449
- req,
450
- res,
451
- driverResource,
452
- entityPath
453
- };
454
- await this.events.emit('reldens.adminBeforeEntityEdit', adminBeforeEntityEditEvent);
455
- let routeContents = await this.generateEditRouteContent(req, driverResource, entityPath);
456
- if('' === routeContents){
457
- return res.redirect(this.rootPath+'/'+entityPath+'?result=errorEdit');
458
- }
459
- return res.send(routeContents);
460
- });
461
- this.setupSavePath(entityRoute, driverResource, entityPath);
462
- this.adminRouter.post(entityRoute+this.deletePath, this.isAuthenticated.bind(this), async (req, res) => {
463
- let redirectResult = await this.processDeleteEntities(req, res, driverResource, entityPath);
464
- return res.redirect(redirectResult);
465
- });
466
- await this.events.emit('reldens.setupEntitiesRoutes', {
467
- adminManager: this,
468
- entityPath,
469
- entityRoute,
470
- driverResource
471
- });
472
- }
473
- }
474
-
475
- setupSavePath(entityRoute, driverResource, entityPath)
476
- {
477
- let uploadProperties = this.fetchUploadProperties(driverResource);
478
- let uploadPropertiesKeys = Object.keys(uploadProperties || {});
479
- if(0 === uploadPropertiesKeys.length){
480
- this.adminRouter.post(
481
- entityRoute+this.savePath,
482
- this.isAuthenticated.bind(this),
483
- async (req, res) => {
484
- await this.events.emit('reldens.adminBeforeEntitySave', {
485
- adminManager: this,
486
- req,
487
- res,
488
- driverResource,
489
- entityPath
490
- });
491
- let redirectResult = await this.processSaveEntity(req, res, driverResource, entityPath);
492
- return res.redirect(redirectResult);
493
- }
494
- );
495
- return;
496
- }
497
- let fields = [];
498
- let allowedFileTypes = {};
499
- for(let uploadPropertyKey of uploadPropertiesKeys){
500
- let property = uploadProperties[uploadPropertyKey];
501
- allowedFileTypes[uploadPropertyKey] = property.allowedTypes || false;
502
- let field = {name: uploadPropertyKey};
503
- if(!property.isArray){
504
- field.maxCount = 1;
505
- }
506
- fields.push(field);
507
- this.buckets[uploadPropertyKey] = property.bucket;
508
- }
509
- this.adminRouter.post(
510
- entityRoute + this.savePath,
511
- this.isAuthenticated.bind(this),
512
- this.uploaderFactory.createUploader(fields, this.buckets, allowedFileTypes),
513
- async (req, res) => {
514
- await this.events.emit('reldens.adminBeforeEntitySave', {
515
- adminManager: this,
516
- req,
517
- res,
518
- driverResource,
519
- entityPath
520
- });
521
- let redirectResult = await this.processSaveEntity(req, res, driverResource, entityPath);
522
- return res.redirect(redirectResult);
523
- }
524
- );
525
- }
526
-
527
- async processDeleteEntities(req, res, driverResource, entityPath)
528
- {
529
- let ids = req?.body?.ids;
530
- if('string' === typeof ids){
531
- ids = ids.split(',');
532
- }
533
- let redirectPath = this.rootPath+'/'+entityPath+'?result=';
534
- let resultString = 'errorMissingId';
535
- if(!ids || 0 === ids.length){
536
- return redirectPath + resultString;
537
- }
538
- try {
539
- let entityRepository = this.dataServer.getEntity(driverResource.entityKey);
540
- let idProperty = this.fetchEntityIdPropertyKey(driverResource);
541
- let idsFilter = {[idProperty]: {operator: 'IN', value: ids}};
542
- let loadedEntities = await entityRepository.load(idsFilter);
543
- await this.deleteEntitiesRelatedFiles(driverResource, loadedEntities);
544
- let deleteResult = await entityRepository.delete(idsFilter);
545
- resultString = deleteResult ? 'success' : 'errorStorageFailure';
546
- } catch (error) {
547
- resultString = 'errorDeleteFailure';
548
- }
549
- return redirectPath + resultString;
550
- }
551
-
552
- async deleteEntitiesRelatedFiles(driverResource, entities)
553
- {
554
- let resourcePropertiesKeys = Object.keys(driverResource.options.properties);
555
- for(let propertyKey of resourcePropertiesKeys){
556
- let property = driverResource.options.properties[propertyKey];
557
- if(!property.isUpload){
558
- continue;
559
- }
560
- for(let entity of entities){
561
- if(!property.isArray){
562
- FileHandler.remove([(property.bucket || ''), entity[propertyKey]]);
563
- continue;
564
- }
565
- let entityFiles = entity[propertyKey].split(property.isArray);
566
- for(let entityFile of entityFiles){
567
- FileHandler.remove([(property.bucket || ''), entityFile]);
568
- }
569
- }
570
- }
571
- }
572
-
573
- async processSaveEntity(req, res, driverResource, entityPath)
574
- {
575
- let idProperty = this.fetchEntityIdPropertyKey(driverResource);
576
- let id = (req?.body[idProperty] || '').toString();
577
- let entityRepository = this.dataServer.getEntity(driverResource.entityKey);
578
- let resourceProperties = driverResource.options.properties;
579
- let entityDataPatch = this.preparePatchData(driverResource, idProperty, req, resourceProperties, id);
580
- if(!entityDataPatch){
581
- Logger.error('Bad patch data.', entityDataPatch);
582
- return this.rootPath+'/'+entityPath+'?result=saveBadPatchData';
583
- }
584
- let editRoute = this.generateEntityRoute('editPath', driverResource, idProperty, null, id);
585
- try {
586
- let saveResult = await this.saveEntity(id, entityRepository, entityDataPatch);
587
- if(!saveResult){
588
- Logger.error('Save result error.', saveResult, entityDataPatch);
589
- return editRoute+'?result=saveEntityStorageError';
590
- }
591
- await this.events.emit('reldens.adminAfterEntitySave', {
592
- adminManager: this,
593
- req,
594
- res,
595
- driverResource,
596
- entityPath,
597
- entityData: saveResult
598
- });
599
- if(sc.isFunction(this.autoSyncDistCallback)){
600
- let uploadProperties = this.fetchUploadProperties(driverResource);
601
- if(0 < Object.keys(uploadProperties).length){
602
- for(let uploadPropertyKey of Object.keys(uploadProperties)){
603
- let property = uploadProperties[uploadPropertyKey];
604
- await this.autoSyncDistCallback(
605
- property.bucket,
606
- saveResult[uploadPropertyKey],
607
- property.distFolder
608
- );
609
- }
610
- }
611
- }
612
- let saveAction = sc.get(req.body, 'saveAction', 'save');
613
- if('saveAndContinue' === saveAction){
614
- return this.generateEntityRoute('editPath', driverResource, idProperty, saveResult) +'&result=success';
615
- }
616
- return this.generateEntityRoute('viewPath', driverResource, idProperty, saveResult) +'&result=success';
617
- } catch (error) {
618
- Logger.error('Save entity error.', error);
619
- return this.rootPath+'/'+entityPath+'?result=saveEntityError';
620
- }
621
- }
622
-
623
- async saveEntity(id, entityRepository, entityDataPatch)
624
- {
625
- if('' === id){
626
- return entityRepository.create(entityDataPatch);
627
- }
628
- return entityRepository.updateById(id, entityDataPatch);
629
- }
630
-
631
- preparePatchData(driverResource, idProperty, req, resourceProperties, id)
632
- {
633
- let entityDataPatch = {};
634
- for(let i of driverResource.options.editProperties){
635
- if(i === idProperty){
636
- continue;
637
- }
638
- let propertyUpdateValue = sc.get(req.body, i, null);
639
- let property = resourceProperties[i];
640
- let isNullValue = null === propertyUpdateValue;
641
- let propertyType = property.type || 'string';
642
- if(property.isUpload){
643
- propertyType = 'upload';
644
- propertyUpdateValue = this.prepareUploadPatchData(req, i, propertyUpdateValue, property);
645
- }
646
- if('number' === propertyType && !isNullValue){
647
- propertyUpdateValue = Number(propertyUpdateValue);
648
- }
649
- if('string' === propertyType && !isNullValue){
650
- propertyUpdateValue = String(propertyUpdateValue);
651
- }
652
- if('boolean' === propertyType){
653
- propertyUpdateValue = Boolean(propertyUpdateValue);
654
- }
655
- let isUploadCreate = property.isUpload && !id;
656
- if(property.isRequired && null === propertyUpdateValue && (!property.isUpload || isUploadCreate)){
657
- // missing required fields would break the update:
658
- Logger.critical('Bad patch data on update.', propertyUpdateValue, property);
659
- return false;
660
- }
661
- if(!property.isUpload || (property.isUpload && null !== propertyUpdateValue)){
662
- entityDataPatch[i] = propertyUpdateValue;
663
- }
664
- }
665
- return entityDataPatch;
666
- }
667
-
668
- prepareUploadPatchData(req, i, propertyUpdateValue, property)
669
- {
670
- let filesData = sc.get(req.files, i, null);
671
- if(null === filesData){
672
- return null;
673
- }
674
- let fileNames = [];
675
- for(let file of filesData){
676
- fileNames.push(file.filename);
677
- }
678
- return fileNames.join(property.isArray);
679
- }
680
-
681
- async generateEditRouteContent(req, driverResource, entityPath)
682
- {
683
- let idProperty = this.fetchEntityIdPropertyKey(driverResource);
684
- let idValue = String(sc.get(req?.query, idProperty, ''));
685
- let templateTitle = (!idValue ? 'Create' : 'Edit')+' '+this.translations.labels[driverResource.id()];
686
- let loadedEntity = !idValue ? null : await this.loadEntityById(driverResource, idValue);
687
- let entityViewRoute = !idValue
688
- ? this.rootPath+'/'+driverResource.entityPath
689
- : this.generateEntityRoute('viewPath', driverResource, idProperty, loadedEntity);
690
- let renderedEditProperties = {
691
- idValue,
692
- idProperty,
693
- idPropertyLabel: this.fetchTranslation(idProperty),
694
- templateTitle,
695
- entityViewRoute
696
- };
697
- let editPropertiesEvent = {
698
- adminManager: this,
699
- req,
700
- driverResource,
701
- renderedEditProperties,
702
- loadedEntity
703
- };
704
- await this.events.emit('reldens.adminEditPropertiesPopulation', editPropertiesEvent);
705
- let propertiesKeys = Object.keys(driverResource.options.properties);
706
- for(let propertyKey of propertiesKeys){
707
- let property = driverResource.options.properties[propertyKey];
708
- let fieldDisabled = -1 === driverResource.options.editProperties.indexOf(propertyKey);
709
- renderedEditProperties[propertyKey] = await this.render(
710
- this.adminFilesContents.fields.edit[this.propertyType(property, 'edit')],
711
- {
712
- fieldName: propertyKey,
713
- fieldValue: await this.generatePropertyEditRenderedValue(
714
- loadedEntity,
715
- propertyKey,
716
- property,
717
- fieldDisabled
718
- ),
719
- fieldDisabled: fieldDisabled ? ' disabled="disabled"' : '',
720
- required: (!property.isUpload || !loadedEntity) && property.isRequired ? ' required="required"' : '',
721
- multiple: property.isArray ? ' multiple="multiple"' : '',
722
- inputType: this.getInputType(property, fieldDisabled)
723
- }
724
- );
725
- }
726
- return await this.renderRoute(
727
- await this.render(this.adminContents.entities[entityPath].edit, renderedEditProperties),
728
- this.adminContents.sideBar
729
- );
730
- }
731
-
732
- getInputType(resourceProperty, fieldDisabled)
733
- {
734
- if('datetime' === resourceProperty.type && !fieldDisabled){
735
- return 'datetime-local';
736
- }
737
- if('number' === resourceProperty.type){
738
- return 'number';
739
- }
740
- return 'text';
741
- }
742
-
743
- async loadEntityById(driverResource, id)
744
- {
745
- let entityRepository = this.dataServer.getEntity(driverResource.entityKey);
746
- if(!entityRepository){
747
- return false;
748
- }
749
- await this.events.emit('reldens.adminBeforeEntityLoad', {
750
- adminManager: this,
751
- driverResource,
752
- entityId: id
753
- });
754
- return await entityRepository.loadByIdWithRelations(id);
755
- }
756
-
757
- async generateViewRouteContent(req, driverResource, entityPath)
758
- {
759
- let idProperty = this.fetchEntityIdPropertyKey(driverResource);
760
- let id = (sc.get(req.query, idProperty, '')).toString();
761
- if('' === id){
762
- Logger.error('Missing ID on view route.', entityPath, id, idProperty);
763
- return '';
764
- }
765
- let loadedEntity = await this.loadEntityById(driverResource, id);
766
- let renderedViewProperties = {
767
- entityEditRoute: this.generateEntityRoute('editPath', driverResource, idProperty, loadedEntity),
768
- entityNewRoute: this.generateEntityRoute('editPath', driverResource, idProperty),
769
- id
770
- };
771
- let entitySerializedData = {};
772
- for(let propertyKey of driverResource.options.showProperties){
773
- let property = driverResource.options.properties[propertyKey];
774
- let {fieldValue, fieldName} = this.generatePropertyRenderedValueWithLabel(
775
- loadedEntity,
776
- propertyKey,
777
- property
778
- );
779
- entitySerializedData[fieldName] = fieldValue;
780
- renderedViewProperties[propertyKey] = await this.render(
781
- this.adminFilesContents.fields.view[this.propertyType(property)],
782
- {
783
- fieldName: propertyKey,
784
- fieldValue: await this.generatePropertyRenderedValue(
785
- fieldValue,
786
- fieldName,
787
- property,
788
- 'view'
789
- ),
790
- fieldOriginalValue: fieldValue,
791
- target: ' target="_blank"'
792
- }
793
- );
794
- }
795
- let extraDataEvent = {entitySerializedData, entityId: driverResource.id(), entity: loadedEntity};
796
- await this.events.emit('adminEntityExtraData', extraDataEvent);
797
- entitySerializedData = extraDataEvent.entitySerializedData;
798
- renderedViewProperties.entitySerializedData = JSON.stringify(entitySerializedData).replace(/"/g, '&quot;');
799
- let viewPropertiesEvent = {
800
- adminManager: this,
801
- idProperty,
802
- req,
803
- driverResource,
804
- loadedEntity,
805
- renderedViewProperties
806
- };
807
- await this.events.emit('reldens.adminViewPropertiesPopulation', viewPropertiesEvent);
808
- return await this.renderRoute(
809
- await this.render(this.adminContents.entities[entityPath].view, renderedViewProperties),
810
- this.adminContents.sideBar
811
- );
812
- }
813
-
814
- propertyType(resourceProperty, templateType)
815
- {
816
- let propertyType = sc.get(resourceProperty, 'type', 'text');
817
- if('reference' === propertyType && 'edit' === templateType){
818
- return 'select';
819
- }
820
- if(resourceProperty.isUpload){
821
- if('edit' === templateType){
822
- return 'file';
823
- }
824
- if('view' === templateType){
825
- let multiple = resourceProperty.isArray ? 's' : '';
826
- if('image' === resourceProperty.allowedTypes){
827
- return resourceProperty.allowedTypes + multiple;
828
- }
829
- if('text' === resourceProperty.allowedTypes){
830
- return 'link'+multiple
831
- }
832
- return 'text';
833
- }
834
- }
835
- if('textarea' === propertyType){
836
- return 'textarea';
837
- }
838
- if(-1 !== ['reference', 'number', 'datetime'].indexOf(propertyType)){
839
- propertyType = 'text';
840
- }
841
- return propertyType;
842
- }
843
-
844
- async generateListRouteContent(req, driverResource, entityPath)
845
- {
846
- let page = Number(req?.query?.page || 1);
847
- let pageSize = Number(req?.query?.pageSize || 25);
848
- let filtersFromParams = req?.body?.filters || {};
849
- let filters = this.prepareFilters(filtersFromParams, driverResource);
850
- let mappedFiltersValues = driverResource.options.filterProperties.map((property) => {
851
- let filterValue = (filtersFromParams[property] || '').toString();
852
- return {[property]: '' === filterValue ? '' : 'value="'+filterValue+'"'};
853
- });
854
- let entitiesRows = await this.loadEntitiesForList(driverResource, pageSize, page, req, filters);
855
- let listRawContent = this.adminContents.entities[entityPath].list.toString();
856
- let totalEntities = await this.countTotalEntities(driverResource, filters);
857
- let totalPages = totalEntities <= pageSize ? 1 : Math.ceil(totalEntities / pageSize);
858
- let pages = PageRangeProvider.fetch(page, totalPages);
859
- let renderedPagination = '';
860
- for(let page of pages){
861
- renderedPagination += await this.render(
862
- this.adminFilesContents.fields.view['link'],
863
- {
864
- fieldName: page.label,
865
- fieldValue: this.rootPath+'/'+driverResource.entityPath+'?page='+ page.value,
866
- fieldOriginalValue: page.value,
867
- }
868
- );
869
- }
870
- let listVars = {
871
- deletePath: this.rootPath + '/' + driverResource.entityPath + this.deletePath,
872
- fieldsHeaders: driverResource.options.listProperties.map((property) => {
873
- let propertyTitle = this.fetchTranslation(property, driverResource.id());
874
- let alias = this.fetchTranslation(
875
- driverResource.options.properties[property]?.alias || '',
876
- driverResource.id()
877
- );
878
- let title = '' !== alias ? alias + ' ('+propertyTitle+')' : propertyTitle;
879
- return {name: property, value: title};
880
- }),
881
- rows: entitiesRows
882
- };
883
- let list = await this.render(this.adminFilesContents.listContent, listVars);
884
- let entitiesListView = await this.render(
885
- listRawContent,
886
- Object.assign({list, pagination: renderedPagination}, ...mappedFiltersValues)
887
- );
888
- return await this.renderRoute(entitiesListView, this.adminContents.sideBar);
889
- }
890
-
891
- fetchTranslation(snippet, group)
892
- {
893
- if('' === snippet){
894
- return snippet;
895
- }
896
- let translationGroup = sc.get(this.translations, group);
897
- if(translationGroup){
898
- let translationByGroup = sc.get(translationGroup, snippet, '');
899
- if('' !== translationByGroup){
900
- return translationByGroup;
901
- }
902
- }
903
- return sc.get(this.translations, snippet, snippet);
904
- }
905
-
906
- async countTotalEntities(driverResource, filters)
907
- {
908
- /** @type {BaseDriver|ObjectionJsDriver} entityRepository **/
909
- let entityRepository = this.dataServer.getEntity(driverResource.entityKey);
910
- if(!entityRepository){
911
- return false;
912
- }
913
- return await entityRepository.count(filters);
914
- }
915
-
916
- async loadEntitiesForList(driverResource, pageSize, page, req, filters)
917
- {
918
- let entityRepository = this.dataServer.getEntity(driverResource.entityKey);
919
- entityRepository.limit = pageSize;
920
- if(1 < page){
921
- entityRepository.offset = (page - 1) * pageSize;
922
- }
923
- entityRepository.sortBy = req?.body?.sortBy || false;
924
- entityRepository.sortDirection = req?.body?.sortDirection || false;
925
- let loadedEntities = await entityRepository.loadWithRelations(filters, []);
926
- entityRepository.limit = 0;
927
- entityRepository.offset = 0;
928
- entityRepository.sortBy = false;
929
- entityRepository.sortDirection = false;
930
- let entityRows = [];
931
- let deleteLink = this.rootPath + '/' + driverResource.entityPath + this.deletePath;
932
- for(let entity of loadedEntities){
933
- let entityRow = {fields: []};
934
- let resourceProperties = driverResource.options?.properties;
935
- let idProperty = this.fetchEntityIdPropertyKey(driverResource);
936
- let viewLink = '';
937
- let editLink = '';
938
- if('' !== idProperty){
939
- viewLink = this.generateEntityRoute('viewPath', driverResource, idProperty, entity);
940
- editLink = this.generateEntityRoute('editPath', driverResource, idProperty, entity);
941
- }
942
- for(let property of driverResource.options.listProperties){
943
- let {fieldValue, fieldName} = this.generatePropertyRenderedValueWithLabel(
944
- entity,
945
- property,
946
- resourceProperties[property]
947
- );
948
- let value = await this.generatePropertyRenderedValue(
949
- fieldValue,
950
- fieldName,
951
- resourceProperties[property]
952
- );
953
- entityRow.fields.push({
954
- name: property,
955
- value,
956
- viewLink
957
- });
958
- }
959
- entityRow.editLink = editLink;
960
- entityRow.deleteLink = deleteLink;
961
- entityRow.id = entity[idProperty];
962
- entityRows.push(entityRow);
963
- }
964
- return entityRows;
965
- }
966
-
967
- async generatePropertyRenderedValue(fieldValue, fieldName, resourceProperty, templateType)
968
- {
969
- let fieldOriginalValue = fieldValue;
970
- if('view' === templateType){
971
- if(resourceProperty.isArray){
972
- fieldValue = fieldValue.split(resourceProperty.isArray).map((value) => {
973
- let target = resourceProperty.isUpload ? ' target="_blank"' : '';
974
- let fieldValuePart = resourceProperty.isUpload && resourceProperty.bucketPath
975
- ? resourceProperty.bucketPath+value
976
- : value;
977
- return {fieldValuePart, fieldOriginalValuePart: value, target};
978
- });
979
- }
980
- if(!resourceProperty.isArray && resourceProperty.isUpload){
981
- fieldValue = resourceProperty.bucketPath+fieldValue;
982
- }
983
- }
984
- return await this.render(
985
- this.adminFilesContents.fields.view[this.propertyType(resourceProperty, templateType)],
986
- {fieldName, fieldValue, fieldOriginalValue, target: ' target="_blank"'}
987
- );
988
- }
989
-
990
- generatePropertyRenderedValueWithLabel(entity, propertyKey, resourceProperty)
228
+ fetchUploadProperties(driverResource)
991
229
  {
992
- let fieldValue = (0 === entity[propertyKey] ? '0' : entity[propertyKey] || '').toString();
993
- let fieldName = propertyKey;
994
- if('boolean' === resourceProperty.type){
995
- fieldValue = '1' === fieldValue || 'true' === fieldValue ? 'Yes' : 'No';
996
- }
997
- if('datetime' === resourceProperty.type){
998
- fieldValue = '' !== fieldValue ? sc.formatDate(new Date(fieldValue)) : '';
999
- }
1000
- if('reference' === resourceProperty.type){
1001
- let relationKey = resourceProperty.alias || resourceProperty.reference;
1002
- let relationEntity = entity[relationKey];
1003
- if(relationEntity){
1004
- let relation = this.relations[resourceProperty.reference];
1005
- if(relation){
1006
- let relationTitleProperty = relation[relationKey];
1007
- if(relationTitleProperty && '' !== String(relationEntity[relationTitleProperty] || '')){
1008
- fieldName = relationTitleProperty;
1009
- fieldValue = relationEntity[relationTitleProperty]+(' ('+fieldValue+')');
1010
- }
230
+ if(!driverResource.options.uploadProperties){
231
+ driverResource.options.uploadProperties = {};
232
+ for(let propertyKey of Object.keys(driverResource.options.properties)){
233
+ let property = driverResource.options.properties[propertyKey];
234
+ if(property.isUpload){
235
+ driverResource.options.uploadProperties[propertyKey] = property;
1011
236
  }
1012
237
  }
1013
238
  }
1014
- if(resourceProperty.availableValues){
1015
- let optionData = resourceProperty.availableValues.filter((availableValue) => {
1016
- return String(availableValue.value) === String(fieldValue);
1017
- }).shift();
1018
- if(optionData){
1019
- fieldValue = optionData.label + ' (' + fieldValue + ')';
1020
- }
1021
- }
1022
- return {fieldValue, fieldName};
1023
- }
1024
-
1025
- async generatePropertyEditRenderedValue(entity, propertyKey, resourceProperty, isFieldDisabled)
1026
- {
1027
- let entityPropertyValue = sc.get(entity, propertyKey, null);
1028
- let fieldValue = (0 === entityPropertyValue ? '0' : entityPropertyValue || '').toString();
1029
- if('boolean' === resourceProperty.type){
1030
- fieldValue = '1' === fieldValue || 'true' === fieldValue ? ' checked="checked"' : '';
1031
- }
1032
- if('datetime' === resourceProperty.type){
1033
- fieldValue = !entityPropertyValue || '' === entityPropertyValue
1034
- ? ''
1035
- : sc.formatDate(new Date(entityPropertyValue), 'Y-m-d H:i:s');
1036
- }
1037
- if('reference' === resourceProperty.type){
1038
- let relationDriverResource = this.resourcesByReference[resourceProperty.reference];
1039
- let relation = this.relations[resourceProperty.reference];
1040
- let relationKey = resourceProperty.alias || resourceProperty.reference;
1041
- let idProperty = this.fetchEntityIdPropertyKey(relationDriverResource);
1042
- let relationTitleProperty = relation ? relation[relationKey] : idProperty;
1043
- let relationOptions = await this.fetchRelationOptions(relationDriverResource);
1044
- return relationOptions.map((option) => {
1045
- let value = option[idProperty];
1046
- let selected = entity && entity[propertyKey] === value ? ' selected="selected"' : '';
1047
- return {label: option[relationTitleProperty]+' (ID: '+value+')', value, selected}
1048
- });
1049
- }
1050
- return fieldValue;
1051
- }
1052
-
1053
- async fetchRelationOptions(relationDriverResource)
1054
- {
1055
- let relationEntityRepository = this.dataServer.getEntity(relationDriverResource.entityKey);
1056
- return await relationEntityRepository.loadAll();
239
+ return driverResource.options.uploadProperties;
1057
240
  }
1058
241
 
1059
242
  fetchEntityIdPropertyKey(driverResource)
@@ -1076,76 +259,19 @@ class AdminManager
1076
259
  return idProperty;
1077
260
  }
1078
261
 
1079
- generateEntityRoute(routeType, driverResource, idProperty, entity, entityId)
1080
- {
1081
- if(!idProperty || (!entity && !entityId)){
1082
- return this.rootPath + '/' + driverResource.entityPath;
1083
- }
1084
- let idParam = '?' + idProperty + '=';
1085
- if(entity){
1086
- idParam = idParam + entity[idProperty];
1087
- }
1088
- if(entityId){
1089
- idParam = idParam + entityId;
1090
- }
1091
- return this.rootPath + '/' + driverResource.entityPath + this[routeType] + idParam;
1092
- }
1093
-
1094
- isAuthenticated(req, res, next)
1095
- {
1096
- let allowContinue = {result: true, callback: null};
1097
- let event = {adminManager: this, req, res, next, allowContinue};
1098
- this.events.emit('reldens.adminIsAuthenticated', event);
1099
- let returnPath = this.rootPath+this.loginPath;
1100
- if(false === allowContinue.result){
1101
- return res.redirect(returnPath);
1102
- }
1103
- if(null !== allowContinue.callback){
1104
- return allowContinue.callback(event);
1105
- }
1106
- let user = req.session?.user;
1107
- if(!user){
1108
- return res.redirect(returnPath);
1109
- }
1110
- let userBlackList = this.blackList[user.role_id] || [];
1111
- if(-1 !== userBlackList.indexOf(req.path)){
1112
- let referrer = String(req.headers?.referer || '');
1113
- return res.redirect('' !== referrer ? referrer : returnPath);
1114
- }
1115
- return next();
1116
- }
1117
-
1118
- prepareFilters(filtersList, driverResource)
262
+ fetchTranslation(snippet, group)
1119
263
  {
1120
- let filtersKeys = Object.keys(filtersList);
1121
- if(0 === filtersKeys.length){
1122
- return {};
264
+ if('' === snippet){
265
+ return snippet;
1123
266
  }
1124
- let filters = {};
1125
- for(let i of filtersKeys){
1126
- let filter = filtersList[i];
1127
- if('' === filter){
1128
- continue;
1129
- }
1130
- let rawConfigFilterProperties = driverResource.options.properties[i];
1131
- if(!rawConfigFilterProperties){
1132
- Logger.critical('Could not found property by key.', i);
1133
- continue;
1134
- }
1135
- if(rawConfigFilterProperties.isUpload){
1136
- continue;
1137
- }
1138
- if('reference' === rawConfigFilterProperties.type){
1139
- filters[i] = filter;
1140
- continue;
1141
- }
1142
- if('boolean' === rawConfigFilterProperties.type){
1143
- filters[i] = ('true' === filter);
1144
- continue;
267
+ let translationGroup = sc.get(this.translations, group);
268
+ if(translationGroup){
269
+ let translationByGroup = sc.get(translationGroup, snippet, '');
270
+ if('' !== translationByGroup){
271
+ return translationByGroup;
1145
272
  }
1146
- filters[i] = {operator: 'like', value: '%'+filter+'%'};
1147
273
  }
1148
- return filters;
274
+ return sc.get(this.translations, snippet, snippet);
1149
275
  }
1150
276
 
1151
277
  }