@reldens/cms 0.18.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.
@@ -67,17 +67,53 @@ class CacheManager
67
67
  return true;
68
68
  }
69
69
 
70
+ findAllCacheFilesForPath(domain, path)
71
+ {
72
+ let cacheInfo = this.generateCacheKey(domain, path);
73
+ if(!FileHandler.exists(cacheInfo.folderPath)){
74
+ return [];
75
+ }
76
+ let allFiles = FileHandler.readFolder(cacheInfo.folderPath);
77
+ if(0 === allFiles.length){
78
+ return [];
79
+ }
80
+ let baseFileName = cacheInfo.fileName.replace('.html', '');
81
+ let matchingFiles = [];
82
+ for(let file of allFiles){
83
+ if(file === cacheInfo.fileName){
84
+ matchingFiles.push(FileHandler.joinPaths(cacheInfo.folderPath, file));
85
+ continue;
86
+ }
87
+ if(file.startsWith(baseFileName + '_') && file.endsWith('.html')){
88
+ matchingFiles.push(FileHandler.joinPaths(cacheInfo.folderPath, file));
89
+ }
90
+ }
91
+ return matchingFiles;
92
+ }
93
+
70
94
  async delete(domain, path)
71
95
  {
72
96
  let cacheByDomains = this.fetchCachePathsByDomain(domain, path);
73
97
  for(let cacheInfo of cacheByDomains){
74
- if(!FileHandler.exists(cacheInfo.fullPath)){
75
- Logger.debug('File does not exist: '+cacheInfo.fullPath);
76
- return true;
98
+ let allCacheFiles = this.findAllCacheFilesForPath(cacheInfo.domain || domain, path);
99
+ if(0 === allCacheFiles.length){
100
+ let singleCacheInfo = this.generateCacheKey(cacheInfo.domain || domain, path);
101
+ if(!FileHandler.exists(singleCacheInfo.fullPath)){
102
+ Logger.debug('No cache files found for: '+path);
103
+ continue;
104
+ }
105
+ allCacheFiles = [singleCacheInfo.fullPath];
77
106
  }
78
- if(!FileHandler.remove(cacheInfo.fullPath)){
79
- Logger.error('Failed to delete cache file: '+cacheInfo.fullPath);
80
- return false;
107
+ for(let cacheFilePath of allCacheFiles){
108
+ if(!FileHandler.exists(cacheFilePath)){
109
+ Logger.debug('File does not exist: '+cacheFilePath);
110
+ continue;
111
+ }
112
+ if(!FileHandler.remove(cacheFilePath)){
113
+ Logger.error('Failed to delete cache file: '+cacheFilePath);
114
+ return false;
115
+ }
116
+ Logger.debug('Deleted cache file: '+cacheFilePath);
81
117
  }
82
118
  }
83
119
  return true;
@@ -87,12 +123,15 @@ class CacheManager
87
123
  {
88
124
  let cacheByDomains = [];
89
125
  if(domain && 'default' !== domain){
90
- cacheByDomains.push(this.generateCacheKey(domain, path));
126
+ cacheByDomains.push({domain: domain});
127
+ return cacheByDomains;
128
+ }
129
+ if(!FileHandler.exists(this.cacheBasePath)){
91
130
  return cacheByDomains;
92
131
  }
93
132
  let cachedDomainFolders = FileHandler.readFolder(this.cacheBasePath);
94
133
  for(let cachedDomainFolder of cachedDomainFolders) {
95
- cacheByDomains.push(this.generateCacheKey(cachedDomainFolder, path));
134
+ cacheByDomains.push({domain: cachedDomainFolder});
96
135
  }
97
136
  return cacheByDomains;
98
137
  }
@@ -18,6 +18,8 @@ class CacheRoutesHandler
18
18
  this.rootPath = sc.get(props, 'rootPath', '');
19
19
  this.cacheCleanPath = '/cache-clean';
20
20
  this.cacheCleanRoute = this.rootPath+this.cacheCleanPath;
21
+ this.clearAllCachePath = '/cache-clear-all';
22
+ this.clearAllCacheRoute = this.rootPath+this.clearAllCachePath;
21
23
  this.setupRoutes();
22
24
  }
23
25
 
@@ -42,6 +44,13 @@ class CacheRoutesHandler
42
44
  return await this.processCacheClean(req, res);
43
45
  }
44
46
  );
47
+ this.router.adminRouter.post(
48
+ this.clearAllCachePath,
49
+ this.router.isAuthenticated.bind(this.router),
50
+ async (req, res) => {
51
+ return await this.processClearAllCache(req, res);
52
+ }
53
+ );
45
54
  return true;
46
55
  }
47
56
 
@@ -71,6 +80,20 @@ class CacheRoutesHandler
71
80
  return res.redirect(this.rootPath+'/routes/view'+'?id='+routeId+'&result=success');
72
81
  }
73
82
 
83
+ async processClearAllCache(req, res)
84
+ {
85
+ if(!this.cacheManager){
86
+ return res.json({error: 'Cache manager not available'});
87
+ }
88
+ let clearResult = await this.cacheManager.clear();
89
+ if(!clearResult){
90
+ Logger.error('Failed to clear all cache');
91
+ return res.redirect(this.rootPath+'/routes?result=errorClearAllCache');
92
+ }
93
+ Logger.info('All cache cleared successfully');
94
+ return res.redirect(this.rootPath+'/routes?result=success');
95
+ }
96
+
74
97
  }
75
98
 
76
99
  module.exports.CacheRoutesHandler = CacheRoutesHandler;
@@ -76,9 +76,14 @@ class CmsPagesRouteManager
76
76
  Logger.error('Routes repository not found.');
77
77
  return;
78
78
  }
79
+ let path = sc.get(req.body, 'routePath', this.generateDefaultRoutePath(entityData));
80
+ if(!path || '' === path.trim()){
81
+ Logger.debug('No valid path available for CMS page route creation. Skipping route management.');
82
+ return;
83
+ }
79
84
  let cmsPageId = Number(entityData.id);
80
85
  let routePatchData = {
81
- path: sc.get(req.body, 'routePath', this.generateDefaultRoutePath(entityData)),
86
+ path,
82
87
  router: sc.get(req.body, 'routeRouter', 'cmsPages'),
83
88
  cache_ttl_seconds: Number(sc.get(req.body, 'routeCacheTtl', 3600)),
84
89
  enabled: Number(sc.get(req.body, 'routeEnabled', 1)),
@@ -91,9 +96,12 @@ class CmsPagesRouteManager
91
96
  if(!routeResult){
92
97
  routeResult = await routesRepository.create(routePatchData);
93
98
  if(routeResult){
94
- let pagesRepository = this.dataServer.getEntity('cms_pages');
99
+ let pagesRepository = this.dataServer.getEntity('cmsPages');
95
100
  if(pagesRepository){
96
- await pagesRepository.updateById(cmsPageId, {route_id: routeResult.id});
101
+ let pageResult = await pagesRepository.updateById(cmsPageId, {route_id: routeResult.id});
102
+ if(!pageResult){
103
+ Logger.error('Page could not be updated with route ID.', routeResult);
104
+ }
97
105
  }
98
106
  }
99
107
  }
@@ -105,7 +113,11 @@ class CmsPagesRouteManager
105
113
 
106
114
  generateDefaultRoutePath(pageData)
107
115
  {
108
- return '/' + sc.get(pageData, 'title', 'page').toLowerCase()
116
+ let title = sc.get(pageData, 'title', '');
117
+ if(!title || '' === title.trim()){
118
+ return '';
119
+ }
120
+ return '/' + title.toLowerCase()
109
121
  .replace(/[^a-z0-9\s-]/g, '')
110
122
  .replace(/\s+/g, '-')
111
123
  .replace(/-+/g, '-')
package/lib/frontend.js CHANGED
@@ -4,9 +4,11 @@
4
4
  *
5
5
  */
6
6
 
7
+ const { TemplateEngine } = require('./template-engine');
8
+ const { Search } = require('./search');
9
+ const { SearchRenderer } = require('./search-renderer');
7
10
  const { FileHandler } = require('@reldens/server-utils');
8
11
  const { Logger, sc } = require('@reldens/utils');
9
- const { TemplateEngine } = require('./template-engine');
10
12
 
11
13
  class Frontend
12
14
  {
@@ -31,6 +33,24 @@ class Frontend
31
33
  this.entitiesConfig = sc.get(props, 'entitiesConfig', {});
32
34
  this.templateEngine = false;
33
35
  this.cacheManager = sc.get(props, 'cacheManager', false);
36
+ this.searchPath = sc.get(props, 'searchPath', '/search');
37
+ this.searchSets = sc.get(props, 'searchSets', false);
38
+ this.searchConfig = {dataServer: this.dataServer};
39
+ if(this.searchSets){
40
+ this.searchConfig.searchSets = this.searchSets;
41
+ }
42
+ this.search = new Search(this.searchConfig);
43
+ this.searchRenderer = new SearchRenderer({
44
+ renderEngine: this.renderEngine,
45
+ getPartials: this.getPartialsForDomain.bind(this)
46
+ });
47
+ this.metaDefaults = sc.get(props, 'metaDefaults', {
48
+ locale: 'en',
49
+ viewport: 'width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes, viewport-fit=cover',
50
+ meta_robots: 'index,follow',
51
+ meta_theme_color: '#000000',
52
+ meta_twitter_card_type: 'summary'
53
+ });
34
54
  }
35
55
 
36
56
  async initialize()
@@ -61,10 +81,14 @@ class Frontend
61
81
  getPartials: this.getPartialsForDomain.bind(this),
62
82
  entitiesConfig: this.entitiesConfig
63
83
  });
84
+ this.searchConfig.jsonFieldsParser = this.templateEngine.jsonFieldsParser;
64
85
  await this.loadPartials();
65
86
  await this.setupDomainTemplates();
66
87
  await this.loadEntityAccessRules();
67
88
  this.setupStaticAssets();
89
+ this.app.get(this.searchPath, async (req, res) => {
90
+ return await this.handleSearchRequest(req, res);
91
+ });
68
92
  this.app.get('*', async (req, res) => {
69
93
  return await this.handleRequest(req, res);
70
94
  });
@@ -249,12 +273,95 @@ class Frontend
249
273
  return false;
250
274
  }
251
275
 
276
+ fetchMetaFields(data)
277
+ {
278
+ if(!sc.isObject(data) || 0 === Object.keys(data).length){
279
+ return this.metaDefaults;
280
+ }
281
+ let result = Object.assign({}, this.metaDefaults);
282
+ for(let key of Object.keys(data)){
283
+ let value = data[key];
284
+ if(null !== value && '' !== value && 'undefined' !== typeof value){
285
+ result[key] = value;
286
+ }
287
+ }
288
+ let titleValue = sc.get(result, 'title', '');
289
+ let metaTitleValue = sc.get(result, 'meta_title', titleValue);
290
+ if(metaTitleValue && '' !== metaTitleValue){
291
+ result.meta_title = metaTitleValue;
292
+ }
293
+ let metaOgTitleValue = sc.get(result, 'meta_og_title', metaTitleValue);
294
+ if(metaOgTitleValue && '' !== metaOgTitleValue){
295
+ result.meta_og_title = metaOgTitleValue;
296
+ }
297
+ let metaDescValue = sc.get(result, 'meta_description', '');
298
+ let metaOgDescValue = sc.get(result, 'meta_og_description', metaDescValue);
299
+ if(metaOgDescValue && '' !== metaOgDescValue){
300
+ result.meta_og_description = metaOgDescValue;
301
+ }
302
+ let jsonData = sc.get(result, 'json_data', null);
303
+ if(sc.isString(jsonData)){
304
+ jsonData = sc.toJson(jsonData, {});
305
+ }
306
+ if(!sc.isObject(jsonData)){
307
+ jsonData = {};
308
+ }
309
+ let viewportValue = sc.get(jsonData, 'viewport', this.metaDefaults.viewport);
310
+ if(viewportValue && '' !== viewportValue){
311
+ jsonData.viewport = viewportValue;
312
+ }
313
+ result.json_data = jsonData;
314
+ return result;
315
+ }
316
+
317
+ async handleSearchRequest(req, res)
318
+ {
319
+ try {
320
+ let domain = this.getDomainFromRequest(req);
321
+ let config = this.search.parseSearchParameters(req.query);
322
+ if(!config){
323
+ return res.redirect('/?error-message=searchInvalidParameters');
324
+ }
325
+ let cacheKey = this.buildCacheKey(req.path, req);
326
+ if(this.cacheManager && this.cacheManager.isEnabled()){
327
+ let cachedContent = await this.cacheManager.get(domain, cacheKey);
328
+ if(cachedContent){
329
+ return res.send(cachedContent);
330
+ }
331
+ }
332
+ let searchResults = await this.search.executeSearch(config);
333
+ if(false === searchResults){
334
+ return res.redirect('/?error-message=searchExecutionFailed');
335
+ }
336
+ let content = await this.renderWithTemplateContent(
337
+ {
338
+ template: config.render.page,
339
+ layout: config.render.layout,
340
+ content: await this.searchRenderer.renderSearchResults(searchResults, config, domain, req)
341
+ },
342
+ Object.assign({}, {
343
+ search_query: sc.get(req.query, 'search', ''),
344
+ searchConfig: config,
345
+ query: req.query
346
+ }),
347
+ domain,
348
+ req
349
+ );
350
+ if(this.cacheManager && this.cacheManager.isEnabled()){
351
+ await this.cacheManager.set(domain, cacheKey, content);
352
+ }
353
+ return res.send(content);
354
+ } catch (error) {
355
+ Logger.error('Search request handling error: ' + error.message);
356
+ return res.redirect('/?error-message=searchError');
357
+ }
358
+ }
359
+
252
360
  async handleRequest(req, res)
253
361
  {
254
362
  try {
255
363
  let path = req.path;
256
364
  let domain = this.getDomainFromRequest(req);
257
- this.templateEngine.setCurrentDomain(domain);
258
365
  if(this.cacheManager && this.cacheManager.isEnabled()){
259
366
  let cachedContent = await this.cacheManager.get(domain, path);
260
367
  if(cachedContent){
@@ -263,17 +370,17 @@ class Frontend
263
370
  }
264
371
  let route = await this.findRouteByPath(path, domain);
265
372
  if(route){
266
- return await this.renderRouteWithCache(route, domain, res, path);
373
+ return await this.renderRouteWithCache(route, domain, res, path, req);
267
374
  }
268
375
  let entityResult = await this.findEntityByPath(path);
269
376
  if(entityResult){
270
- return await this.renderEntityWithCache(entityResult, domain, res, path);
377
+ return await this.renderEntityWithCache(entityResult, domain, res, path, req);
271
378
  }
272
379
  let templatePath = this.findTemplateByPath(path, domain);
273
380
  if(templatePath){
274
- return await this.renderTemplateWithCache(templatePath, domain, res, path);
381
+ return await this.renderTemplateWithCache(templatePath, domain, res, path, req);
275
382
  }
276
- return await this.renderNotFound(domain, res);
383
+ return await this.renderNotFound(domain, res, req);
277
384
  } catch (error) {
278
385
  Logger.error('Request handling error: '+error.message);
279
386
  return res.status(500).send('Internal server error');
@@ -350,57 +457,46 @@ class Frontend
350
457
  return this.findTemplatePath(templatePath, domain);
351
458
  }
352
459
 
353
- async renderRouteWithCache(route, domain, res, path)
460
+ async renderRouteWithCache(route, domain, res, path, req)
354
461
  {
355
- let renderedContent = await this.generateRouteContent(route, domain);
462
+ let renderedContent = await this.generateRouteContent(route, domain, req);
356
463
  if(!renderedContent){
357
- return await this.renderNotFound(domain, res);
464
+ return await this.renderNotFound(domain, res, req);
358
465
  }
359
466
  if(this.cacheManager && this.cacheManager.isEnabled()){
360
- await this.cacheManager.set(domain, path, renderedContent);
467
+ let cacheKey = this.buildCacheKey(path, req);
468
+ await this.cacheManager.set(domain, cacheKey, renderedContent);
361
469
  }
362
470
  return res.send(renderedContent);
363
471
  }
364
472
 
365
- async renderEntityWithCache(entityResult, domain, res, path)
473
+ async renderEntityWithCache(entityResult, domain, res, path, req)
366
474
  {
367
- let renderedContent = await this.generateEntityContent(entityResult, domain);
475
+ let renderedContent = await this.generateEntityContent(entityResult, domain, req);
368
476
  if(!renderedContent){
369
- return await this.renderNotFound(domain, res);
477
+ return await this.renderNotFound(domain, res, req);
370
478
  }
371
479
  if(this.cacheManager && this.cacheManager.isEnabled()){
372
- await this.cacheManager.set(domain, path, renderedContent);
480
+ let cacheKey = this.buildCacheKey(path, req);
481
+ await this.cacheManager.set(domain, cacheKey, renderedContent);
373
482
  }
374
483
  return res.send(renderedContent);
375
484
  }
376
485
 
377
- async renderTemplateWithCache(templatePath, domain, res, path)
486
+ async renderTemplateWithCache(templatePath, domain, res, path, req)
378
487
  {
379
- let renderedContent = await this.generateTemplateContent(templatePath, domain);
488
+ let renderedContent = await this.generateTemplateContent(templatePath, domain, req);
380
489
  if(!renderedContent){
381
490
  return res.status(500).send('Template error: '+templatePath);
382
491
  }
383
492
  if(this.cacheManager && this.cacheManager.isEnabled()){
384
- await this.cacheManager.set(domain, path, renderedContent);
493
+ let cacheKey = this.buildCacheKey(path, req);
494
+ await this.cacheManager.set(domain, cacheKey, renderedContent);
385
495
  }
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);
496
+ return await this.renderWithLayout({content: renderedContent}, {}, 'default', domain, res, req);
401
497
  }
402
498
 
403
- async generateRouteContent(route, domain)
499
+ async generateRouteContent(route, domain, req)
404
500
  {
405
501
  if(!route.router){
406
502
  return false;
@@ -413,78 +509,56 @@ class Frontend
413
509
  if(!content){
414
510
  return false;
415
511
  }
416
- return await this.renderWithTemplateContent(content, Object.assign({}, route, content), domain);
512
+ return await this.renderWithTemplateContent(content, Object.assign({}, route, content), domain, req);
417
513
  }
418
514
 
419
- async generateEntityContent(entityResult, domain)
515
+ async generateEntityContent(entityResult, domain, req)
420
516
  {
421
- return await this.renderWithTemplateContent(entityResult.entity, entityResult.entity, domain);
517
+ return await this.renderWithTemplateContent(entityResult.entity, entityResult.entity, domain, req);
422
518
  }
423
519
 
424
- async generateTemplateContent(templatePath, domain)
520
+ async generateTemplateContent(templatePath, domain, req)
425
521
  {
426
522
  let template = FileHandler.readFile(templatePath);
427
523
  if(!template){
428
524
  Logger.error('Failed to read template: ' + templatePath);
429
525
  return false;
430
526
  }
431
- return await this.templateEngine.render(template, {}, this.getPartialsForDomain(domain));
527
+ return await this.templateEngine.render(template, {}, this.getPartialsForDomain(domain), domain, req);
432
528
  }
433
529
 
434
- async renderRoute(route, domain, res)
530
+ async renderRoute(route, domain, res, req)
435
531
  {
436
532
  if(!route.router){
437
- return await this.renderNotFound(domain, res);
533
+ return await this.renderNotFound(domain, res, req);
438
534
  }
439
535
  let entity = this.dataServer.getEntity(route.router);
440
536
  if(!entity){
441
- return await this.renderNotFound(domain, res);
537
+ return await this.renderNotFound(domain, res, req);
442
538
  }
443
539
  let content = await entity.loadOne({route_id: route.id});
444
540
  if(!content){
445
- return await this.renderNotFound(domain, res);
541
+ return await this.renderNotFound(domain, res, req);
446
542
  }
447
- return await this.renderWithTemplate(content, Object.assign({}, route, content), domain, res);
543
+ return await this.renderWithTemplate(content, Object.assign({}, route, content), domain, res, req);
448
544
  }
449
545
 
450
- async renderEntity(entityResult, domain, res)
546
+ async renderWithTemplate(content, data, domain, res, req)
451
547
  {
452
- return await this.renderWithTemplate(entityResult.entity, entityResult.entity, domain, res);
548
+ return res.send(await this.renderWithTemplateContent(content, data, domain, req));
453
549
  }
454
550
 
455
- async renderWithTemplate(content, data, domain, res)
551
+ async renderWithTemplateContent(content, data, domain, req)
456
552
  {
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);
553
+ let templateName = sc.get(content, 'template', 'page');
460
554
  if(!templateName){
461
555
  templateName = 'page';
462
556
  }
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';
557
+ let layoutName = sc.get(content, 'layout', '');
558
+ if(!layoutName){
559
+ layoutName = 'default';
487
560
  }
561
+ let layoutContent = await this.processContentWithLayout(content, data, layoutName, domain, req);
488
562
  let templatePath = this.findTemplatePath(templateName, domain);
489
563
  if(!templatePath){
490
564
  return layoutContent;
@@ -495,53 +569,31 @@ class Frontend
495
569
  }
496
570
  return await this.templateEngine.render(
497
571
  pageTemplate,
498
- Object.assign({}, data, {content: layoutContent, siteHandle: this.resolveDomainToSiteKey(domain)}),
499
- this.getPartialsForDomain(domain)
572
+ Object.assign({}, this.fetchMetaFields(data), {content: layoutContent, siteHandle: this.resolveDomainToSiteKey(domain)}),
573
+ this.getPartialsForDomain(domain),
574
+ domain,
575
+ req
500
576
  );
501
577
  }
502
578
 
503
- async renderTemplate(templatePath, domain, res)
504
- {
505
- let content = await this.renderContentWithTemplate(templatePath, {}, domain);
506
- if(!content){
507
- return res.status(500).send('Template error: '+templatePath);
508
- }
509
- return await this.renderWithLayout({content}, {}, 'default', domain, res);
510
- }
511
-
512
- async renderContentWithTemplate(templatePath, data, domain)
579
+ async renderContentWithTemplate(templatePath, data, domain, req)
513
580
  {
514
581
  let template = FileHandler.readFile(templatePath);
515
582
  if(!template){
516
583
  Logger.error('Failed to read template: ' + templatePath);
517
584
  return false;
518
585
  }
519
- return await this.templateEngine.render(template, data, this.getPartialsForDomain(domain));
586
+ return await this.templateEngine.render(template, data, this.getPartialsForDomain(domain), domain, req);
520
587
  }
521
588
 
522
- async renderWithLayout(content, data, layoutName, domain, res)
589
+ async renderWithLayout(content, data, layoutName, domain, res, req)
523
590
  {
524
- let layoutContent = await this.processContentWithLayout(content, data, layoutName, domain);
525
- let pagePath = this.findTemplatePath('page', domain);
526
- if(!pagePath){
527
- return res.send(layoutContent);
528
- }
529
- let pageTemplate = FileHandler.readFile(pagePath);
530
- if(!pageTemplate){
531
- return res.send(layoutContent);
532
- }
533
- return res.send(
534
- await this.templateEngine.render(
535
- pageTemplate,
536
- Object.assign({}, data, {content: layoutContent, siteHandle: this.resolveDomainToSiteKey(domain)}),
537
- this.getPartialsForDomain(domain)
538
- )
539
- );
591
+ return res.send(await this.renderWithTemplateContent(content, data, domain, req));
540
592
  }
541
593
 
542
- async processContentWithLayout(content, data, layoutName, domain)
594
+ async processContentWithLayout(content, data, layoutName, domain, req)
543
595
  {
544
- let processedContent = await this.processContent(content, data, domain);
596
+ let processedContent = await this.processContent(content, data, domain, req);
545
597
  let layoutPath = this.findLayoutPath(layoutName, domain);
546
598
  if(!layoutPath){
547
599
  return processedContent;
@@ -553,32 +605,57 @@ class Frontend
553
605
  return await this.templateEngine.render(
554
606
  layoutTemplate,
555
607
  Object.assign({}, data, {content: processedContent}),
556
- this.getPartialsForDomain(domain)
608
+ this.getPartialsForDomain(domain),
609
+ domain,
610
+ req
557
611
  );
558
612
  }
559
613
 
560
- async processContent(content, data, domain)
614
+ async processContent(content, data, domain, req)
561
615
  {
562
616
  let contentText = sc.get(content, 'content', '');
563
617
  if(!contentText){
564
618
  return '';
565
619
  }
566
- return await this.templateEngine.render(contentText, data, this.getPartialsForDomain(domain));
620
+ return await this.templateEngine.render(contentText, data, this.getPartialsForDomain(domain), domain, req);
567
621
  }
568
622
 
569
- async renderNotFound(domain, res)
623
+ async renderNotFound(domain, res, req)
570
624
  {
571
625
  let notFoundPath = this.findTemplatePath('404', domain);
572
626
  if(notFoundPath){
573
- let content = await this.renderContentWithTemplate(notFoundPath, {}, domain);
627
+ let content = await this.renderContentWithTemplate(notFoundPath, {}, domain, req);
574
628
  if(content){
575
629
  res.status(404);
576
- return await this.renderWithLayout({content}, {}, 'default', domain, res);
630
+ return await this.renderWithLayout({content}, {}, 'default', domain, res, req);
577
631
  }
578
632
  }
579
633
  return res.status(404).send('Page not found');
580
634
  }
581
635
 
636
+ buildCacheKey(path, req)
637
+ {
638
+ if(!req || !req.query){
639
+ return path;
640
+ }
641
+ for(let key of Object.keys(req.query)){
642
+ if(key.endsWith('-key')){
643
+ let queryString = '';
644
+ for(let qKey of Object.keys(req.query)){
645
+ queryString += (queryString ? '&' : '') + qKey + '=' + req.query[qKey];
646
+ }
647
+ let hash = 0;
648
+ for(let i = 0; i < queryString.length; i++){
649
+ let char = queryString.charCodeAt(i);
650
+ hash = ((hash << 5) - hash) + char;
651
+ hash = hash & hash;
652
+ }
653
+ return path + '_' + Math.abs(hash);
654
+ }
655
+ }
656
+ return path;
657
+ }
658
+
582
659
  }
583
660
 
584
661
  module.exports.Frontend = Frontend;