@reldens/cms 0.15.0 → 0.18.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 +150 -34
  2. package/admin/reldens-admin-client.css +39 -23
  3. package/admin/reldens-admin-client.js +7 -0
  4. package/admin/templates/cache-clean-button.html +4 -0
  5. package/admin/templates/edit.html +3 -1
  6. package/admin/templates/fields/view/textarea.html +1 -0
  7. package/admin/templates/sections/editForm/cms-pages.html +15 -0
  8. package/admin/templates/sections/viewForm/cms-pages.html +15 -0
  9. package/admin/templates/view.html +1 -0
  10. package/bin/reldens-cms-generate-entities.js +116 -5
  11. package/bin/reldens-cms.js +26 -8
  12. package/install/js/installer.js +5 -0
  13. package/install/success.html +1 -1
  14. package/lib/admin-manager/contents-builder.js +256 -0
  15. package/lib/admin-manager/router-contents.js +576 -0
  16. package/lib/admin-manager/router.js +208 -0
  17. package/lib/admin-manager.js +114 -944
  18. package/lib/cache/add-cache-button-subscriber.js +101 -0
  19. package/lib/cache/cache-manager.js +129 -0
  20. package/lib/cache/cache-routes-handler.js +76 -0
  21. package/lib/cms-pages-route-manager.js +117 -0
  22. package/lib/frontend.js +207 -64
  23. package/lib/installer.js +44 -20
  24. package/lib/json-fields-parser.js +74 -0
  25. package/lib/manager.js +55 -10
  26. package/lib/template-engine.js +361 -41
  27. package/lib/templates-list.js +10 -0
  28. package/migrations/default-blocks.sql +1 -1
  29. package/migrations/default-entity-access.sql +2 -2
  30. package/migrations/default-homepage.sql +27 -7
  31. package/migrations/install.sql +33 -36
  32. package/package.json +3 -3
  33. package/templates/index.js.dist +3 -3
  34. package/templates/js/scripts.js +5 -0
  35. package/templates/layouts/default.html +4 -4
  36. package/templates/page.html +14 -10
  37. package/templates/partials/footer.html +2 -23
  38. package/templates/partials/header.html +2 -35
package/lib/frontend.js CHANGED
@@ -28,7 +28,9 @@ class Frontend
28
28
  this.domainPartialsCache = new Map();
29
29
  this.domainTemplatesMap = new Map();
30
30
  this.entityAccessCache = new Map();
31
+ this.entitiesConfig = sc.get(props, 'entitiesConfig', {});
31
32
  this.templateEngine = false;
33
+ this.cacheManager = sc.get(props, 'cacheManager', false);
32
34
  }
33
35
 
34
36
  async initialize()
@@ -55,7 +57,9 @@ class Frontend
55
57
  }
56
58
  this.templateEngine = new TemplateEngine({
57
59
  renderEngine: this.renderEngine,
58
- dataServer: this.dataServer
60
+ dataServer: this.dataServer,
61
+ getPartials: this.getPartialsForDomain.bind(this),
62
+ entitiesConfig: this.entitiesConfig
59
63
  });
60
64
  await this.loadPartials();
61
65
  await this.setupDomainTemplates();
@@ -69,9 +73,9 @@ class Frontend
69
73
 
70
74
  async loadEntityAccessRules()
71
75
  {
72
- let accessEntity = this.dataServer.getEntity('cmsEntityAccess');
76
+ let accessEntity = this.dataServer.getEntity('entitiesAccess');
73
77
  if(!accessEntity){
74
- Logger.warning('CMS Entity Access not found.');
78
+ Logger.warning('Entities Access not found.');
75
79
  return;
76
80
  }
77
81
  let accessRules = await accessEntity.loadAll();
@@ -250,17 +254,24 @@ class Frontend
250
254
  try {
251
255
  let path = req.path;
252
256
  let domain = this.getDomainFromRequest(req);
253
- let route = await this.findRouteByPath(path);
257
+ this.templateEngine.setCurrentDomain(domain);
258
+ if(this.cacheManager && this.cacheManager.isEnabled()){
259
+ let cachedContent = await this.cacheManager.get(domain, path);
260
+ if(cachedContent){
261
+ return res.send(cachedContent);
262
+ }
263
+ }
264
+ let route = await this.findRouteByPath(path, domain);
254
265
  if(route){
255
- return await this.renderRoute(route, domain, res);
266
+ return await this.renderRouteWithCache(route, domain, res, path);
256
267
  }
257
268
  let entityResult = await this.findEntityByPath(path);
258
269
  if(entityResult){
259
- return await this.renderEntity(entityResult, domain, res);
270
+ return await this.renderEntityWithCache(entityResult, domain, res, path);
260
271
  }
261
272
  let templatePath = this.findTemplateByPath(path, domain);
262
273
  if(templatePath){
263
- return await this.renderTemplate(templatePath, domain, res);
274
+ return await this.renderTemplateWithCache(templatePath, domain, res, path);
264
275
  }
265
276
  return await this.renderNotFound(domain, res);
266
277
  } catch (error) {
@@ -269,21 +280,31 @@ class Frontend
269
280
  }
270
281
  }
271
282
 
272
- async findRouteByPath(path)
283
+ async findRouteByPath(path, domain)
273
284
  {
274
285
  let routesEntity = this.dataServer.getEntity('routes');
275
286
  if(!routesEntity){
276
- Logger.error('Routes entity not found in dataServer');
287
+ Logger.error('Routes entity not found in dataServer.');
277
288
  return false;
278
289
  }
279
- let route = await routesEntity.loadOneBy('path', path);
280
- if(route){
281
- return route;
290
+ let domainFilter = domain || null;
291
+ let routeFilters = {path, enabled: 1};
292
+ let routes = await routesEntity.load(routeFilters);
293
+ let matchingRoute = false;
294
+ let nullDomain = false;
295
+ for(let route of routes){
296
+ if(route.domain === domainFilter){
297
+ matchingRoute = route;
298
+ break;
299
+ }
300
+ if(!route.domain){
301
+ nullDomain = route;
302
+ }
282
303
  }
283
- if('/' === path){
284
- return await routesEntity.loadOneBy('path', '/home');
304
+ if(matchingRoute){
305
+ return matchingRoute;
285
306
  }
286
- return false;
307
+ return nullDomain;
287
308
  }
288
309
 
289
310
  async isEntityAccessible(entityName)
@@ -329,47 +350,163 @@ class Frontend
329
350
  return this.findTemplatePath(templatePath, domain);
330
351
  }
331
352
 
353
+ async renderRouteWithCache(route, domain, res, path)
354
+ {
355
+ let renderedContent = await this.generateRouteContent(route, domain);
356
+ if(!renderedContent){
357
+ return await this.renderNotFound(domain, res);
358
+ }
359
+ if(this.cacheManager && this.cacheManager.isEnabled()){
360
+ await this.cacheManager.set(domain, path, renderedContent);
361
+ }
362
+ return res.send(renderedContent);
363
+ }
364
+
365
+ async renderEntityWithCache(entityResult, domain, res, path)
366
+ {
367
+ let renderedContent = await this.generateEntityContent(entityResult, domain);
368
+ if(!renderedContent){
369
+ return await this.renderNotFound(domain, res);
370
+ }
371
+ if(this.cacheManager && this.cacheManager.isEnabled()){
372
+ await this.cacheManager.set(domain, path, renderedContent);
373
+ }
374
+ return res.send(renderedContent);
375
+ }
376
+
377
+ async renderTemplateWithCache(templatePath, domain, res, path)
378
+ {
379
+ let renderedContent = await this.generateTemplateContent(templatePath, domain);
380
+ if(!renderedContent){
381
+ return res.status(500).send('Template error: '+templatePath);
382
+ }
383
+ if(this.cacheManager && this.cacheManager.isEnabled()){
384
+ await this.cacheManager.set(domain, path, renderedContent);
385
+ }
386
+ let layoutContent = await this.processContentWithLayout({content: renderedContent}, {}, 'default', domain);
387
+ let pagePath = this.findTemplatePath('page', domain);
388
+ if(!pagePath){
389
+ return res.send(layoutContent);
390
+ }
391
+ let pageTemplate = FileHandler.readFile(pagePath);
392
+ if(!pageTemplate){
393
+ return res.send(layoutContent);
394
+ }
395
+ let finalContent = await this.templateEngine.render(
396
+ pageTemplate,
397
+ Object.assign({}, {}, {content: layoutContent, siteHandle: this.resolveDomainToSiteKey(domain)}),
398
+ this.getPartialsForDomain(domain)
399
+ );
400
+ return res.send(finalContent);
401
+ }
402
+
403
+ async generateRouteContent(route, domain)
404
+ {
405
+ if(!route.router){
406
+ return false;
407
+ }
408
+ let entity = this.dataServer.getEntity(route.router);
409
+ if(!entity){
410
+ return false;
411
+ }
412
+ let content = await entity.loadOne({route_id: route.id});
413
+ if(!content){
414
+ return false;
415
+ }
416
+ return await this.renderWithTemplateContent(content, Object.assign({}, route, content), domain);
417
+ }
418
+
419
+ async generateEntityContent(entityResult, domain)
420
+ {
421
+ return await this.renderWithTemplateContent(entityResult.entity, entityResult.entity, domain);
422
+ }
423
+
424
+ async generateTemplateContent(templatePath, domain)
425
+ {
426
+ let template = FileHandler.readFile(templatePath);
427
+ if(!template){
428
+ Logger.error('Failed to read template: ' + templatePath);
429
+ return false;
430
+ }
431
+ return await this.templateEngine.render(template, {}, this.getPartialsForDomain(domain));
432
+ }
433
+
332
434
  async renderRoute(route, domain, res)
333
435
  {
334
- if(!route.router || !route.content_id){
436
+ if(!route.router){
335
437
  return await this.renderNotFound(domain, res);
336
438
  }
337
439
  let entity = this.dataServer.getEntity(route.router);
338
440
  if(!entity){
339
441
  return await this.renderNotFound(domain, res);
340
442
  }
341
- let content = await entity.loadById(route.content_id);
443
+ let content = await entity.loadOne({route_id: route.id});
342
444
  if(!content){
343
445
  return await this.renderNotFound(domain, res);
344
446
  }
345
- return await this.renderWithLayout(
346
- content,
347
- Object.assign({}, route, content, {currentYear: new Date().getFullYear()}),
348
- sc.get(content, 'layout', 'default'),
349
- domain,
350
- res
351
- );
447
+ return await this.renderWithTemplate(content, Object.assign({}, route, content), domain, res);
352
448
  }
353
449
 
354
450
  async renderEntity(entityResult, domain, res)
355
451
  {
356
- return await this.renderWithLayout(
357
- entityResult.entity,
358
- Object.assign({}, entityResult.entity, {currentYear: new Date().getFullYear()}),
359
- sc.get(entityResult.entity, 'layout', 'default'),
360
- domain,
361
- res
452
+ return await this.renderWithTemplate(entityResult.entity, entityResult.entity, domain, res);
453
+ }
454
+
455
+ async renderWithTemplate(content, data, domain, res)
456
+ {
457
+ let templateName = sc.get(content, 'template', '');
458
+ let layoutName = sc.get(content, 'layout', 'default');
459
+ let layoutContent = await this.processContentWithLayout(content, data, layoutName, domain);
460
+ if(!templateName){
461
+ templateName = 'page';
462
+ }
463
+ let templatePath = this.findTemplatePath(templateName, domain);
464
+ if(!templatePath){
465
+ return res.send(layoutContent);
466
+ }
467
+ let pageTemplate = FileHandler.readFile(templatePath);
468
+ if(!pageTemplate){
469
+ return res.send(layoutContent);
470
+ }
471
+ return res.send(
472
+ await this.templateEngine.render(
473
+ pageTemplate,
474
+ Object.assign({}, data, {content: layoutContent, siteHandle: this.resolveDomainToSiteKey(domain)}),
475
+ this.getPartialsForDomain(domain)
476
+ )
477
+ );
478
+ }
479
+
480
+ async renderWithTemplateContent(content, data, domain)
481
+ {
482
+ let templateName = sc.get(content, 'template', '');
483
+ let layoutName = sc.get(content, 'layout', 'default');
484
+ let layoutContent = await this.processContentWithLayout(content, data, layoutName, domain);
485
+ if(!templateName){
486
+ templateName = 'page';
487
+ }
488
+ let templatePath = this.findTemplatePath(templateName, domain);
489
+ if(!templatePath){
490
+ return layoutContent;
491
+ }
492
+ let pageTemplate = FileHandler.readFile(templatePath);
493
+ if(!pageTemplate){
494
+ return layoutContent;
495
+ }
496
+ return await this.templateEngine.render(
497
+ pageTemplate,
498
+ Object.assign({}, data, {content: layoutContent, siteHandle: this.resolveDomainToSiteKey(domain)}),
499
+ this.getPartialsForDomain(domain)
362
500
  );
363
501
  }
364
502
 
365
503
  async renderTemplate(templatePath, domain, res)
366
504
  {
367
- let data = { currentYear: new Date().getFullYear() };
368
- let content = await this.renderContentWithTemplate(templatePath, data, domain);
505
+ let content = await this.renderContentWithTemplate(templatePath, {}, domain);
369
506
  if(!content){
370
507
  return res.status(500).send('Template error: '+templatePath);
371
508
  }
372
- return await this.renderWithLayout({content}, data, 'default', domain, res);
509
+ return await this.renderWithLayout({content}, {}, 'default', domain, res);
373
510
  }
374
511
 
375
512
  async renderContentWithTemplate(templatePath, data, domain)
@@ -384,23 +521,7 @@ class Frontend
384
521
 
385
522
  async renderWithLayout(content, data, layoutName, domain, res)
386
523
  {
387
- let layoutPath = this.findLayoutPath(layoutName, domain);
388
- let layoutContent = '';
389
- if(layoutPath){
390
- let layoutTemplate = FileHandler.readFile(layoutPath);
391
- if(layoutTemplate){
392
- layoutContent = await this.templateEngine.render(
393
- layoutTemplate,
394
- Object.assign({}, data, {
395
- content: sc.get(content, 'content', '')
396
- }),
397
- this.getPartialsForDomain(domain)
398
- );
399
- }
400
- }
401
- if('' === layoutContent){
402
- layoutContent = sc.get(content, 'content', '');
403
- }
524
+ let layoutContent = await this.processContentWithLayout(content, data, layoutName, domain);
404
525
  let pagePath = this.findTemplatePath('page', domain);
405
526
  if(!pagePath){
406
527
  return res.send(layoutContent);
@@ -412,28 +533,50 @@ class Frontend
412
533
  return res.send(
413
534
  await this.templateEngine.render(
414
535
  pageTemplate,
415
- Object.assign({}, data, {
416
- content: layoutContent,
417
- siteHandle: this.resolveDomainToSiteKey(domain)
418
- }),
536
+ Object.assign({}, data, {content: layoutContent, siteHandle: this.resolveDomainToSiteKey(domain)}),
419
537
  this.getPartialsForDomain(domain)
420
538
  )
421
539
  );
422
540
  }
423
541
 
424
- async renderNotFound(domain, res)
542
+ async processContentWithLayout(content, data, layoutName, domain)
425
543
  {
426
- let templatePath = this.findTemplatePath('404', domain);
427
- if(!templatePath){
428
- return res.status(404).send('Page not found');
544
+ let processedContent = await this.processContent(content, data, domain);
545
+ let layoutPath = this.findLayoutPath(layoutName, domain);
546
+ if(!layoutPath){
547
+ return processedContent;
429
548
  }
430
- let data = {title: '404 - Page Not Found', currentYear: new Date().getFullYear()};
431
- let content = await this.renderContentWithTemplate(templatePath, data, domain);
432
- if(!content){
433
- return res.status(404).send('Page not found');
549
+ let layoutTemplate = FileHandler.readFile(layoutPath);
550
+ if(!layoutTemplate){
551
+ return processedContent;
552
+ }
553
+ return await this.templateEngine.render(
554
+ layoutTemplate,
555
+ Object.assign({}, data, {content: processedContent}),
556
+ this.getPartialsForDomain(domain)
557
+ );
558
+ }
559
+
560
+ async processContent(content, data, domain)
561
+ {
562
+ let contentText = sc.get(content, 'content', '');
563
+ if(!contentText){
564
+ return '';
565
+ }
566
+ return await this.templateEngine.render(contentText, data, this.getPartialsForDomain(domain));
567
+ }
568
+
569
+ async renderNotFound(domain, res)
570
+ {
571
+ let notFoundPath = this.findTemplatePath('404', domain);
572
+ if(notFoundPath){
573
+ let content = await this.renderContentWithTemplate(notFoundPath, {}, domain);
574
+ if(content){
575
+ res.status(404);
576
+ return await this.renderWithLayout({content}, {}, 'default', domain, res);
577
+ }
434
578
  }
435
- res.status(404);
436
- return await this.renderWithLayout({content}, data, 'default', domain, res);
579
+ return res.status(404).send('Page not found');
437
580
  }
438
581
 
439
582
  }
package/lib/installer.js CHANGED
@@ -35,6 +35,7 @@ class Installer
35
35
  this.moduleAdminTemplatesPath = FileHandler.joinPaths(this.moduleAdminPath, 'templates')
36
36
  this.indexTemplatePath = FileHandler.joinPaths(this.defaultTemplatesPath, 'index.js.dist');
37
37
  this.postInstallCallback = sc.get(props, 'postInstallCallback', false);
38
+ this.prismaClient = sc.get(props, 'prismaClient', false);
38
39
  this.entitiesLoader = new EntitiesLoader({projectRoot: this.projectRoot});
39
40
  }
40
41
 
@@ -49,17 +50,21 @@ class Installer
49
50
  Logger.error('Missing app on prepareSetup for Installer.');
50
51
  return false;
51
52
  }
53
+ if(!appServer){
54
+ Logger.error('Missing appServer on prepareSetup for Installer.');
55
+ return false;
56
+ }
52
57
  if(!appServerFactory){
53
58
  Logger.error('Missing appServerFactory on prepareSetup for Installer.');
54
59
  return false;
55
60
  }
56
61
  if(!renderEngine){
57
- Logger.error('Missing renderEngine for Installer.');
62
+ Logger.error('Missing renderEngine on prepareSetup for Installer.');
58
63
  return false;
59
64
  }
60
65
  this.app = app;
61
- this.appServerFactory = appServerFactory;
62
66
  this.appServer = appServer;
67
+ this.appServerFactory = appServerFactory;
63
68
  this.renderEngine = renderEngine;
64
69
  app.use('/install-assets', appServerFactory.applicationFramework.static(this.installerPath, {index: false}));
65
70
  app.use(appServerFactory.session({
@@ -117,7 +122,7 @@ class Installer
117
122
  'configuration-error': 'Configuration error while completing installation.',
118
123
  'already-installed': 'The application is already installed.'
119
124
  };
120
- return errorMessages[errorCode] || 'An unknown error occurred during installation.';
125
+ return sc.get(errorMessages, errorCode, 'An unknown error occurred during installation.');
121
126
  }
122
127
 
123
128
  async executeInstallProcess(req, res)
@@ -145,13 +150,8 @@ class Installer
145
150
  },
146
151
  debug: false
147
152
  };
148
- if('prisma' === selectedDriver){
149
- let generatedPrismaSchema = await this.generatePrismaSchema(dbConfig);
150
- if(!generatedPrismaSchema){
151
- Logger.error('Could not generated Prisma schema.');
152
- return res.redirect('/?error=prisma-schema-generation-error');
153
- }
154
- Logger.info('Generated Prisma schema.');
153
+ if('prisma' === selectedDriver && this.prismaClient){
154
+ dbConfig.prismaClient = this.prismaClient;
155
155
  }
156
156
  let dbDriver = new driverClass(dbConfig);
157
157
  if(!await dbDriver.connect()){
@@ -181,7 +181,7 @@ class Installer
181
181
  return res.redirect(redirectError);
182
182
  }
183
183
  }
184
- let entitiesGenerationResult = await this.generateEntities(dbDriver);
184
+ let entitiesGenerationResult = await this.generateEntities(dbDriver, false, true);
185
185
  if(!entitiesGenerationResult){
186
186
  Logger.error('Entities generation error.');
187
187
  return res.redirect('/?error=installation-entities-generation-failed');
@@ -214,7 +214,7 @@ class Installer
214
214
  if(successFileContent){
215
215
  successContent = this.renderEngine.render(
216
216
  successFileContent,
217
- {adminPath: templateVariables['app-admin-path'], currentYear: new Date().getFullYear()},
217
+ {adminPath: templateVariables['app-admin-path']},
218
218
  );
219
219
  }
220
220
  return res.send(successContent);
@@ -234,7 +234,8 @@ class Installer
234
234
  Logger.error('SQL file "'+fileName+'" not found.');
235
235
  return '/?error=sql-file-not-found&file-name='+fileName;
236
236
  }
237
- if(!await dbDriver.rawQuery(sqlFileContent)){
237
+ let queryExecutionResult = await dbDriver.rawQuery(sqlFileContent);
238
+ if(!queryExecutionResult){
238
239
  Logger.error('SQL file "'+fileName+'" raw execution failed.');
239
240
  return '/?error=sql-file-execution-error&file-name='+fileName;
240
241
  }
@@ -242,23 +243,35 @@ class Installer
242
243
  return '';
243
244
  }
244
245
 
245
- async generateEntities(server, isOverride = false)
246
+ async generateEntities(server, isOverride = false, isInstallationMode = false, isDryPrisma = false)
246
247
  {
247
248
  let driverType = sc.get(DriversClassMap, server.constructor.name, '');
248
249
  Logger.debug('Driver type detected: '+driverType+', Server constructor: '+server.constructor.name);
249
- if('prisma' === driverType){
250
+ if('prisma' === driverType && !isInstallationMode && !isDryPrisma){
251
+ Logger.info('Running prisma introspect "npx prisma db pull"...');
250
252
  let dbConfig = this.extractDbConfigFromServer(server);
251
253
  Logger.debug('Extracted DB config:', dbConfig);
252
254
  if(dbConfig){
253
255
  let generatedPrismaSchema = await this.generatePrismaSchema(dbConfig);
254
256
  if(!generatedPrismaSchema){
255
- Logger.error('Could not generate Prisma schema for entities generation.');
257
+ Logger.error('Prisma schema generation failed.');
256
258
  return false;
257
259
  }
258
260
  Logger.info('Generated Prisma schema for entities generation.');
259
261
  }
260
262
  }
261
- let generator = new EntitiesGenerator({server, projectPath: this.projectRoot, isOverride});
263
+ if('prisma' === driverType && isDryPrisma){
264
+ Logger.info('Skipping Prisma schema generation due to --dry-prisma flag.');
265
+ }
266
+ let generatorConfig = {
267
+ server,
268
+ projectPath: this.projectRoot,
269
+ isOverride
270
+ };
271
+ if('prisma' === driverType && this.prismaClient){
272
+ generatorConfig.prismaClient = this.prismaClient;
273
+ }
274
+ let generator = new EntitiesGenerator(generatorConfig);
262
275
  let success = await generator.generate();
263
276
  if(!success){
264
277
  Logger.error('Entities generation failed.');
@@ -303,7 +316,8 @@ class Installer
303
316
  let generator = new PrismaSchemaGenerator({
304
317
  ...connectionData,
305
318
  dataProxy: useDataProxy,
306
- prismaSchemaPath: this.projectRoot+'/prisma'
319
+ clientOutputPath: FileHandler.joinPaths(this.projectRoot, 'prisma', 'client'),
320
+ prismaSchemaPath: FileHandler.joinPaths(this.projectRoot, 'prisma')
307
321
  });
308
322
  let success = await generator.generate();
309
323
  if(!success){
@@ -363,12 +377,22 @@ class Installer
363
377
  async createIndexJsFile(templateVariables)
364
378
  {
365
379
  if(!FileHandler.exists(this.indexTemplatePath)){
366
- Logger.error('Index.js template not found: '+this.indexTemplatePath);
380
+ Logger.error('Index.js template not found: ' + this.indexTemplatePath);
367
381
  return false;
368
382
  }
369
383
  let indexTemplate = FileHandler.readFile(this.indexTemplatePath);
370
384
  let driverKey = templateVariables['db-storage-driver'];
371
- let indexContent = this.renderEngine.render(indexTemplate, {driverKey});
385
+ let templateParams = {driverKey};
386
+ if('prisma' === driverKey){
387
+ let prismaClientPath = FileHandler.joinPaths(this.projectRoot, 'prisma', 'client');
388
+ templateParams.prismaClientImports = 'const { PrismaClient } = require(\'' + prismaClientPath + '\');';
389
+ templateParams.prismaClientParam = ',\n prismaClient: new PrismaClient()';
390
+ }
391
+ if('prisma' !== driverKey){
392
+ templateParams.prismaClientImports = '';
393
+ templateParams.prismaClientParam = '';
394
+ }
395
+ let indexContent = this.renderEngine.render(indexTemplate, templateParams);
372
396
  let indexFilePath = FileHandler.joinPaths(this.projectRoot, 'index.js');
373
397
  if(FileHandler.exists(indexFilePath)){
374
398
  Logger.info('Index.js file already exists, the CMS installer will not override the existent one.');
@@ -0,0 +1,74 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - JsonFieldsParser
4
+ *
5
+ */
6
+
7
+ const { Logger, sc } = require('@reldens/utils');
8
+
9
+ class JsonFieldsParser
10
+ {
11
+
12
+ constructor(props)
13
+ {
14
+ this.entitiesConfig = sc.get(props, 'entitiesConfig', {});
15
+ this.jsonFieldsCache = new Map();
16
+ }
17
+
18
+ getJsonFieldsForEntity(entityName)
19
+ {
20
+ if(this.jsonFieldsCache.has(entityName)){
21
+ return this.jsonFieldsCache.get(entityName);
22
+ }
23
+ let jsonFields = [];
24
+ let entityConfig = sc.get(this.entitiesConfig, entityName);
25
+ if(!entityConfig){
26
+ Logger.error('Entity not found in configuration: '+entityName);
27
+ return jsonFields;
28
+ }
29
+ if(!sc.hasOwn(entityConfig, 'properties')){
30
+ Logger.error('Missing properties on entity configuration: '+entityName);
31
+ return jsonFields;
32
+ }
33
+ for(let fieldName of Object.keys(entityConfig.properties)){
34
+ if('json' === sc.get(entityConfig.properties[fieldName], 'dbType', '')){
35
+ jsonFields.push(fieldName);
36
+ }
37
+ }
38
+ this.jsonFieldsCache.set(entityName, jsonFields);
39
+ return jsonFields;
40
+ }
41
+
42
+ parseJsonFields(data, jsonFields)
43
+ {
44
+ if(!sc.isArray(jsonFields) || 0 === jsonFields.length){
45
+ return data;
46
+ }
47
+ if(sc.isArray(data)){
48
+ for(let item of data){
49
+ this.parseEntityJsonFields(item, jsonFields);
50
+ }
51
+ return data;
52
+ }
53
+ if(sc.isObject(data)){
54
+ this.parseEntityJsonFields(data, jsonFields);
55
+ }
56
+ return data;
57
+ }
58
+
59
+ parseEntityJsonFields(entity, jsonFields)
60
+ {
61
+ for(let fieldName of jsonFields){
62
+ if(!sc.hasOwn(entity, fieldName) || !sc.isString(entity[fieldName])){
63
+ continue;
64
+ }
65
+ let parsed = sc.parseJson(entity[fieldName], false);
66
+ if(false !== parsed){
67
+ entity[fieldName] = parsed;
68
+ }
69
+ }
70
+ }
71
+
72
+ }
73
+
74
+ module.exports.JsonFieldsParser = JsonFieldsParser;