@reldens/cms 0.16.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.
@@ -0,0 +1,101 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - AddCacheButtonSubscriber
4
+ *
5
+ */
6
+
7
+ const { Logger, sc } = require('@reldens/utils');
8
+
9
+ class AddCacheButtonSubscriber
10
+ {
11
+
12
+ constructor(props = {})
13
+ {
14
+ this.events = sc.get(props, 'events', false);
15
+ this.cacheManager = sc.get(props, 'cacheManager', false);
16
+ this.renderCallback = sc.get(props, 'renderCallback', false);
17
+ this.cacheCleanButton = sc.get(props, 'cacheCleanButton', '');
18
+ this.translations = sc.get(props, 'translations', {});
19
+ this.cacheCleanRoute = sc.get(props, 'cacheCleanRoute', '');
20
+ this.setupEvents();
21
+ }
22
+
23
+ setupEvents()
24
+ {
25
+ if(!this.cacheManager){
26
+ Logger.error('Cache Manager not found on AddCacheButtonSubscriber.');
27
+ return false;
28
+ }
29
+ if(!this.cacheManager.isEnabled()){
30
+ Logger.debug('Cache Manager not enabled.');
31
+ return false;
32
+ }
33
+ if(!this.events){
34
+ Logger.error('Events Manager not found on AddCacheButtonSubscriber.');
35
+ return false;
36
+ }
37
+ //Logger.debug('Listening events PropertiesPopulation.');
38
+ this.events.on('reldens.adminViewPropertiesPopulation', this.populateViewFields.bind(this));
39
+ this.events.on('reldens.adminEditPropertiesPopulation', this.populateEditFields.bind(this));
40
+
41
+ }
42
+
43
+ async populateViewFields(event)
44
+ {
45
+ let cacheButton = await this.generateCacheCleanButton(event);
46
+ if(!cacheButton){
47
+ Logger.warning('Missing cache button contents on AddCacheButtonSubscriber.');
48
+ return false;
49
+ }
50
+ if(!event.renderedViewProperties.extraContentForView){
51
+ event.renderedViewProperties.extraContentForView = '';
52
+ }
53
+ event.renderedViewProperties.extraContentForView += cacheButton;
54
+ //Logger.debug('Clean cache button ready on view.');
55
+ return true;
56
+ }
57
+
58
+ async populateEditFields(event)
59
+ {
60
+ let cacheButton = await this.generateCacheCleanButton(event);
61
+ if(!cacheButton){
62
+ Logger.warning('Missing cache button contents on AddCacheButtonSubscriber.');
63
+ return false;
64
+ }
65
+ if(!event.renderedEditProperties.extraContentForEdit){
66
+ event.renderedEditProperties.extraContentForEdit = '';
67
+ }
68
+ event.renderedEditProperties.extraContentForEdit += cacheButton;
69
+ //Logger.debug('Clean cache button ready on edit.');
70
+ return true;
71
+ }
72
+
73
+ async generateCacheCleanButton(event)
74
+ {
75
+ if('routes' !== event.driverResource.id()){
76
+ return false;
77
+ }
78
+ if(!event.loadedEntity || !event.loadedEntity.id){
79
+ return false;
80
+ }
81
+ if(!this.cacheCleanButton){
82
+ Logger.error('Cache clean button template content not found');
83
+ return '';
84
+ }
85
+ if(!this.renderCallback){
86
+ Logger.error('Render callback not available for cache button');
87
+ return '';
88
+ }
89
+ return await this.renderCallback(
90
+ this.cacheCleanButton,
91
+ {
92
+ cacheCleanRoute: this.cacheCleanRoute,
93
+ routeId: event.loadedEntity.id,
94
+ buttonText: sc.get(this.translations, 'cleanCache', 'Clean Cache')
95
+ }
96
+ );
97
+ }
98
+
99
+ }
100
+
101
+ module.exports.AddCacheButtonSubscriber = AddCacheButtonSubscriber;
@@ -0,0 +1,129 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - CacheManager
4
+ *
5
+ */
6
+
7
+ const { FileHandler } = require('@reldens/server-utils');
8
+ const { Logger, sc } = require('@reldens/utils');
9
+
10
+ class CacheManager
11
+ {
12
+
13
+ constructor(props = {})
14
+ {
15
+ this.projectRoot = sc.get(props, 'projectRoot', './');
16
+ this.cacheBasePath = FileHandler.joinPaths(this.projectRoot, '.reldens_cms_cache');
17
+ this.enabled = sc.get(props, 'enabled', true);
18
+ }
19
+
20
+ generateCacheKey(domain, path)
21
+ {
22
+ let domainFolder = domain || 'default';
23
+ let pathSegments = path.split('/').filter(segment => '' !== segment);
24
+ if(0 === pathSegments.length){
25
+ pathSegments = ['index'];
26
+ }
27
+ let fileName = pathSegments.pop() + '.html';
28
+ let folderPath = FileHandler.joinPaths(this.cacheBasePath, domainFolder, ...pathSegments);
29
+ return {
30
+ folderPath,
31
+ fileName,
32
+ fullPath: FileHandler.joinPaths(folderPath, fileName)
33
+ };
34
+ }
35
+
36
+ async get(domain, path)
37
+ {
38
+ if(!this.enabled){
39
+ return false;
40
+ }
41
+ let cacheInfo = this.generateCacheKey(domain, path);
42
+ if(!FileHandler.exists(cacheInfo.fullPath)){
43
+ return false;
44
+ }
45
+ let cachedContent = FileHandler.readFile(cacheInfo.fullPath);
46
+ if(!cachedContent){
47
+ Logger.debug('Failed to read cached file: '+cacheInfo.fullPath);
48
+ return false;
49
+ }
50
+ return cachedContent;
51
+ }
52
+
53
+ async set(domain, path, content)
54
+ {
55
+ if(!this.enabled){
56
+ return false;
57
+ }
58
+ let cacheInfo = this.generateCacheKey(domain, path);
59
+ if(!FileHandler.createFolder(cacheInfo.folderPath)){
60
+ Logger.error('Failed to create cache folder: '+cacheInfo.folderPath);
61
+ return false;
62
+ }
63
+ if(!FileHandler.writeFile(cacheInfo.fullPath, content)){
64
+ Logger.error('Failed to write cache file: '+cacheInfo.fullPath);
65
+ return false;
66
+ }
67
+ return true;
68
+ }
69
+
70
+ async delete(domain, path)
71
+ {
72
+ let cacheByDomains = this.fetchCachePathsByDomain(domain, path);
73
+ for(let cacheInfo of cacheByDomains){
74
+ if(!FileHandler.exists(cacheInfo.fullPath)){
75
+ Logger.debug('File does not exist: '+cacheInfo.fullPath);
76
+ return true;
77
+ }
78
+ if(!FileHandler.remove(cacheInfo.fullPath)){
79
+ Logger.error('Failed to delete cache file: '+cacheInfo.fullPath);
80
+ return false;
81
+ }
82
+ }
83
+ return true;
84
+ }
85
+
86
+ fetchCachePathsByDomain(domain, path)
87
+ {
88
+ let cacheByDomains = [];
89
+ if(domain && 'default' !== domain){
90
+ cacheByDomains.push(this.generateCacheKey(domain, path));
91
+ return cacheByDomains;
92
+ }
93
+ let cachedDomainFolders = FileHandler.readFolder(this.cacheBasePath);
94
+ for(let cachedDomainFolder of cachedDomainFolders) {
95
+ cacheByDomains.push(this.generateCacheKey(cachedDomainFolder, path));
96
+ }
97
+ return cacheByDomains;
98
+ }
99
+
100
+ async clear()
101
+ {
102
+ if(!FileHandler.exists(this.cacheBasePath)){
103
+ return true;
104
+ }
105
+ if(!FileHandler.remove(this.cacheBasePath)){
106
+ Logger.error('Failed to clear cache folder: '+this.cacheBasePath);
107
+ return false;
108
+ }
109
+ return true;
110
+ }
111
+
112
+ isEnabled()
113
+ {
114
+ return this.enabled;
115
+ }
116
+
117
+ enable()
118
+ {
119
+ this.enabled = true;
120
+ }
121
+
122
+ disable()
123
+ {
124
+ this.enabled = false;
125
+ }
126
+
127
+ }
128
+
129
+ module.exports.CacheManager = CacheManager;
@@ -0,0 +1,76 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - CacheRoutesHandler
4
+ *
5
+ */
6
+
7
+ const { Logger, sc } = require('@reldens/utils');
8
+
9
+ class CacheRoutesHandler
10
+ {
11
+
12
+ constructor(props)
13
+ {
14
+ this.router = sc.get(props, 'router', false);
15
+ this.dataServer = sc.get(props, 'dataServer', false);
16
+ /** @type {CacheManager} **/
17
+ this.cacheManager = sc.get(props, 'cacheManager', false);
18
+ this.rootPath = sc.get(props, 'rootPath', '');
19
+ this.cacheCleanPath = '/cache-clean';
20
+ this.cacheCleanRoute = this.rootPath+this.cacheCleanPath;
21
+ this.setupRoutes();
22
+ }
23
+
24
+ setupRoutes()
25
+ {
26
+ if(!this.cacheManager){
27
+ Logger.error('Cache Manager not found on CacheRoutesHandler.');
28
+ return false;
29
+ }
30
+ if(!this.cacheManager.isEnabled()){
31
+ Logger.debug('Cache Manager not enabled.');
32
+ return false;
33
+ }
34
+ if(!this.router){
35
+ Logger.error('Router not found on CacheRoutesHandler.');
36
+ return false;
37
+ }
38
+ this.router.adminRouter.post(
39
+ this.cacheCleanPath,
40
+ this.router.isAuthenticated.bind(this.router),
41
+ async (req, res) => {
42
+ return await this.processCacheClean(req, res);
43
+ }
44
+ );
45
+ return true;
46
+ }
47
+
48
+ async processCacheClean(req, res)
49
+ {
50
+ if(!this.cacheManager){
51
+ return res.json({error: 'Cache manager not available'});
52
+ }
53
+ let routeId = sc.get(req.body, 'routeId', '');
54
+ if(!routeId){
55
+ return res.json({error: 'Route ID is required'});
56
+ }
57
+ let routesEntity = this.dataServer.getEntity('routes');
58
+ if(!routesEntity){
59
+ return res.json({error: 'Routes entity not found'});
60
+ }
61
+ let route = await routesEntity.loadById(routeId);
62
+ if(!route){
63
+ return res.json({error: 'Route not found'});
64
+ }
65
+ let domain = sc.get(route, 'domain', '');
66
+ let path = route.path;
67
+ let cleanResult = await this.cacheManager.delete(domain, path);
68
+ if(!cleanResult){
69
+ return res.json({error: 'Failed to clean cache'});
70
+ }
71
+ return res.redirect(this.rootPath+'/routes/view'+'?id='+routeId+'&result=success');
72
+ }
73
+
74
+ }
75
+
76
+ module.exports.CacheRoutesHandler = CacheRoutesHandler;
@@ -26,17 +26,19 @@ class CmsPagesRouteManager
26
26
  async populateViewFields(event)
27
27
  {
28
28
  if('cms_pages' !== event.driverResource.id()){
29
- return;
29
+ return false;
30
+ }
31
+ if(!event.loadedEntity || !event.loadedEntity.route_id){
32
+ event.renderedViewProperties.routePath = '';
33
+ event.renderedViewProperties.routeDomain = '';
34
+ return true;
30
35
  }
31
36
  let routesRepository = this.dataServer.getEntity('routes');
32
37
  if(!routesRepository){
33
38
  Logger.error('Routes repository not found.');
34
39
  return false;
35
40
  }
36
- let existingRoute = await routesRepository.loadOne({
37
- router: 'cmsPages',
38
- cms_page_id: Number(event.renderedViewProperties.id)
39
- });
41
+ let existingRoute = await routesRepository.loadById(event.loadedEntity.route_id);
40
42
  event.renderedViewProperties.routePath = sc.get(existingRoute, 'path', '');
41
43
  event.renderedViewProperties.routeDomain = sc.get(existingRoute, 'domain', '');
42
44
  return true;
@@ -45,17 +47,19 @@ class CmsPagesRouteManager
45
47
  async populateEditFields(event)
46
48
  {
47
49
  if('cms_pages' !== event.driverResource.id()){
48
- return;
50
+ return false;
51
+ }
52
+ if(!event.loadedEntity || !event.loadedEntity.route_id){
53
+ event.renderedEditProperties.routePath = '';
54
+ event.renderedEditProperties.routeDomain = '';
55
+ return true;
49
56
  }
50
57
  let routesRepository = this.dataServer.getEntity('routes');
51
58
  if(!routesRepository){
52
59
  Logger.error('Routes repository not found.');
53
60
  return false;
54
61
  }
55
- let existingRoute = await routesRepository.loadOne({
56
- router: 'cmsPages',
57
- cms_page_id: Number(event.renderedEditProperties.idValue)
58
- });
62
+ let existingRoute = await routesRepository.loadById(event.loadedEntity.route_id);
59
63
  event.renderedEditProperties.routePath = sc.get(existingRoute, 'path', '');
60
64
  event.renderedEditProperties.routeDomain = sc.get(existingRoute, 'domain', '');
61
65
  return true;
@@ -73,22 +77,30 @@ class CmsPagesRouteManager
73
77
  return;
74
78
  }
75
79
  let cmsPageId = Number(entityData.id);
76
- let existingRoute = await routesRepository.loadOne({router: 'cmsPages', cms_page_id: cmsPageId});
77
- let patchData = {
80
+ let routePatchData = {
78
81
  path: sc.get(req.body, 'routePath', this.generateDefaultRoutePath(entityData)),
79
82
  router: sc.get(req.body, 'routeRouter', 'cmsPages'),
80
- cms_page_id: cmsPageId,
81
83
  cache_ttl_seconds: Number(sc.get(req.body, 'routeCacheTtl', 3600)),
82
84
  enabled: Number(sc.get(req.body, 'routeEnabled', 1)),
83
85
  domain: sc.get(req.body, 'routeDomain', null)
84
86
  };
85
- let result = existingRoute
86
- ? await routesRepository.updateById(existingRoute.id, patchData)
87
- : await routesRepository.create(patchData);
88
- if (!result){
89
- Logger.error('Route could not be saved.', patchData, existingRoute);
87
+ let routeResult = false;
88
+ if(entityData.route_id){
89
+ routeResult = await routesRepository.updateById(entityData.route_id, routePatchData);
90
+ }
91
+ if(!routeResult){
92
+ routeResult = await routesRepository.create(routePatchData);
93
+ if(routeResult){
94
+ let pagesRepository = this.dataServer.getEntity('cms_pages');
95
+ if(pagesRepository){
96
+ await pagesRepository.updateById(cmsPageId, {route_id: routeResult.id});
97
+ }
98
+ }
99
+ }
100
+ if(!routeResult){
101
+ Logger.error('Route could not be saved.', routePatchData);
90
102
  }
91
- return result;
103
+ return routeResult;
92
104
  }
93
105
 
94
106
  generateDefaultRoutePath(pageData)