@reldens/cms 0.8.0 → 0.9.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 (2) hide show
  1. package/lib/frontend.js +132 -25
  2. package/package.json +2 -2
package/lib/frontend.js CHANGED
@@ -19,6 +19,10 @@ class Frontend
19
19
  this.projectRoot = sc.get(props, 'projectRoot', './');
20
20
  this.templatesPath = FileHandler.joinPaths(this.projectRoot, 'templates');
21
21
  this.publicPath = FileHandler.joinPaths(this.projectRoot, 'public');
22
+ this.partialsExtensions = sc.get(props, 'partialsExtensions', ['.html', '.mustache', '.template']);
23
+ this.partialsCache = {};
24
+ this.domainPartialsCache = new Map();
25
+ this.domainTemplatesMap = new Map();
22
26
  this.error = false;
23
27
  }
24
28
 
@@ -36,6 +40,8 @@ class Frontend
36
40
  Logger.error('Public folder not found: '+this.publicPath);
37
41
  return false;
38
42
  }
43
+ await this.loadPartials();
44
+ await this.setupDomainTemplates();
39
45
  this.setupStaticAssets();
40
46
  this.app.get('*', async (req, res) => {
41
47
  return await this.handleRequest(req, res);
@@ -43,6 +49,101 @@ class Frontend
43
49
  return true;
44
50
  }
45
51
 
52
+ async loadPartials()
53
+ {
54
+ let partialsPath = FileHandler.joinPaths(this.templatesPath, 'partials');
55
+ FileHandler.createFolder(partialsPath);
56
+ let partialFiles = FileHandler.getFilesInFolder(partialsPath, this.partialsExtensions);
57
+ for(let file of partialFiles){
58
+ let partialName = '';
59
+ for(let extension of this.partialsExtensions){
60
+ if(file.endsWith(extension)){
61
+ partialName = file.replace(extension, '');
62
+ break;
63
+ }
64
+ }
65
+ let partialPath = FileHandler.joinPaths(partialsPath, file);
66
+ let partialContent = FileHandler.readFile(partialPath);
67
+ this.partialsCache[partialName] = partialContent.toString();
68
+ }
69
+ }
70
+
71
+ async loadDomainPartials(domain, domainPath)
72
+ {
73
+ let domainPartialsPath = FileHandler.joinPaths(domainPath, 'partials');
74
+ if(!FileHandler.exists(domainPartialsPath)){
75
+ return;
76
+ }
77
+ let domainPartials = {};
78
+ let partialFiles = FileHandler.getFilesInFolder(domainPartialsPath, this.partialsExtensions);
79
+ for(let file of partialFiles){
80
+ let partialName = '';
81
+ for(let extension of this.partialsExtensions){
82
+ if(file.endsWith(extension)){
83
+ partialName = file.replace(extension, '');
84
+ break;
85
+ }
86
+ }
87
+ let partialPath = FileHandler.joinPaths(domainPartialsPath, file);
88
+ let partialContent = FileHandler.readFile(partialPath);
89
+ domainPartials[partialName] = partialContent.toString();
90
+ }
91
+ this.domainPartialsCache.set(domain, domainPartials);
92
+ }
93
+
94
+ async setupDomainTemplates()
95
+ {
96
+ let domainsPath = FileHandler.joinPaths(this.templatesPath, 'domains');
97
+ if(!FileHandler.exists(domainsPath)){
98
+ return;
99
+ }
100
+ let domainFolders = FileHandler.fetchSubFoldersList(domainsPath);
101
+ for(let domain of domainFolders){
102
+ let domainPath = FileHandler.joinPaths(domainsPath, domain);
103
+ this.domainTemplatesMap.set(domain, domainPath);
104
+ await this.loadDomainPartials(domain, domainPath);
105
+ }
106
+ }
107
+
108
+ getDomainFromRequest(req)
109
+ {
110
+ let host = req.get('host');
111
+ if(!host){
112
+ return false;
113
+ }
114
+ return host.split(':')[0];
115
+ }
116
+
117
+ getPartialsForDomain(domain)
118
+ {
119
+ let domainPartials = this.domainPartialsCache.get(domain);
120
+ if(!domainPartials){
121
+ return this.partialsCache;
122
+ }
123
+ return Object.assign({}, this.partialsCache, domainPartials);
124
+ }
125
+
126
+ findTemplatePathForDomain(templateName, domain)
127
+ {
128
+ if(!domain){
129
+ return this.getDefaultTemplatePath(templateName);
130
+ }
131
+ let domainPath = this.domainTemplatesMap.get(domain);
132
+ if(!domainPath){
133
+ return this.getDefaultTemplatePath(templateName);
134
+ }
135
+ let domainTemplatePath = FileHandler.joinPaths(domainPath, templateName + '.html');
136
+ if(!FileHandler.exists(domainTemplatePath)){
137
+ return this.getDefaultTemplatePath(templateName);
138
+ }
139
+ return domainTemplatePath;
140
+ }
141
+
142
+ getDefaultTemplatePath(templateName)
143
+ {
144
+ return FileHandler.joinPaths(this.templatesPath, templateName + '.html');
145
+ }
146
+
46
147
  setupStaticAssets()
47
148
  {
48
149
  if(!this.app || !this.appServerFactory || !this.publicPath){
@@ -62,10 +163,11 @@ class Frontend
62
163
  return res.status(404).send('');
63
164
  }
64
165
  try {
166
+ let domain = this.getDomainFromRequest(req);
65
167
  let route = await this.findRouteByPath(path);
66
168
  if(route){
67
169
  Logger.debug('Found route for path: '+path, route);
68
- return await this.renderContentFromRoute(res, route);
170
+ return await this.renderContentFromRoute(res, route, domain);
69
171
  }
70
172
  let pathSegments = path.split('/').filter(segment => segment !== '');
71
173
  if(0 < pathSegments.length){
@@ -75,17 +177,18 @@ class Frontend
75
177
  return await this.renderContentFromEntity(
76
178
  res,
77
179
  entityResult.entity,
78
- entityResult.entityName
180
+ entityResult.entityName,
181
+ domain
79
182
  );
80
183
  }
81
184
  }
82
- let templatePath = this.findTemplateByPath(path);
185
+ let templatePath = this.findTemplateByPath(path, domain);
83
186
  if(templatePath){
84
187
  Logger.debug('Found template for path: '+path+' at: '+templatePath);
85
- return await this.renderTemplateOnly(res, templatePath);
188
+ return await this.renderTemplateOnly(res, templatePath, domain);
86
189
  }
87
190
  Logger.debug('No template found for path: '+path+', rendering 404');
88
- return await this.renderNotFoundPage(res);
191
+ return await this.renderNotFoundPage(res, domain);
89
192
  } catch (error) {
90
193
  Logger.error('Request handling error: '+error.message);
91
194
  return res.status(500).send('Internal server error');
@@ -137,7 +240,7 @@ class Frontend
137
240
  };
138
241
  }
139
242
 
140
- findTemplateByPath(path)
243
+ findTemplateByPath(path, domain)
141
244
  {
142
245
  if('/' === path){
143
246
  path = '/index';
@@ -148,36 +251,36 @@ class Frontend
148
251
  templatePath = templatePath.startsWith('/')
149
252
  ? templatePath.substring(1)
150
253
  : templatePath;
151
- let fullPath = FileHandler.joinPaths(this.templatesPath, templatePath + '.html');
254
+ let fullPath = this.findTemplatePathForDomain(templatePath, domain);
152
255
  if(FileHandler.exists(fullPath)){
153
256
  return fullPath;
154
257
  }
155
258
  return false;
156
259
  }
157
260
 
158
- async renderContentFromRoute(res, route)
261
+ async renderContentFromRoute(res, route, domain)
159
262
  {
160
263
  if(!route.router || !route.content_id){
161
264
  Logger.debug('Route missing router or content_id');
162
- return await this.renderNotFoundPage(res);
265
+ return await this.renderNotFoundPage(res, domain);
163
266
  }
164
267
  let entity = this.dataServer.getEntity(route.router);
165
268
  if(!entity){
166
269
  Logger.debug('Entity not found: '+route.router);
167
- return await this.renderNotFoundPage(res);
270
+ return await this.renderNotFoundPage(res, domain);
168
271
  }
169
272
  let content = await entity.loadById(route.content_id);
170
273
  if(!content){
171
274
  Logger.debug('Content not found for ID: '+route.content_id+' in entity: '+route.router);
172
- return await this.renderNotFoundPage(res);
275
+ return await this.renderNotFoundPage(res, domain);
173
276
  }
174
277
  let templateName = content.template || route.router;
175
- let templatePath = FileHandler.joinPaths(this.templatesPath, templateName + '.html');
278
+ let templatePath = this.findTemplatePathForDomain(templateName, domain);
176
279
  if(!FileHandler.exists(templatePath)){
177
- templatePath = FileHandler.joinPaths(this.templatesPath, 'page.html');
280
+ templatePath = this.findTemplatePathForDomain('page', domain);
178
281
  if(!FileHandler.exists(templatePath)){
179
282
  Logger.debug('Neither template found: '+templateName+'.html nor page.html');
180
- return await this.renderNotFoundPage(res);
283
+ return await this.renderNotFoundPage(res, domain);
181
284
  }
182
285
  }
183
286
  let template = FileHandler.readFile(templatePath).toString();
@@ -186,17 +289,18 @@ class Frontend
186
289
  ...content,
187
290
  current_year: new Date().getFullYear()
188
291
  };
189
- let rendered = mustache.render(template, data);
292
+ let partials = this.getPartialsForDomain(domain);
293
+ let rendered = mustache.render(template, data, partials);
190
294
  return res.send(rendered);
191
295
  }
192
296
 
193
- async renderContentFromEntity(res, entity, entityName)
297
+ async renderContentFromEntity(res, entity, entityName, domain)
194
298
  {
195
- let templatePath = FileHandler.joinPaths(this.templatesPath, entityName + '.html');
299
+ let templatePath = this.findTemplatePathForDomain(entityName, domain);
196
300
  if(!FileHandler.exists(templatePath)){
197
- templatePath = FileHandler.joinPaths(this.templatesPath, 'page.html');
301
+ templatePath = this.findTemplatePathForDomain('page', domain);
198
302
  if(!FileHandler.exists(templatePath)){
199
- return await this.renderNotFoundPage(res);
303
+ return await this.renderNotFoundPage(res, domain);
200
304
  }
201
305
  }
202
306
  let template = FileHandler.readFile(templatePath).toString();
@@ -205,24 +309,26 @@ class Frontend
205
309
  title: entity.title || entity.name || entityName,
206
310
  current_year: new Date().getFullYear()
207
311
  };
208
- let rendered = mustache.render(template, data);
312
+ let partials = this.getPartialsForDomain(domain);
313
+ let rendered = mustache.render(template, data, partials);
209
314
  return res.send(rendered);
210
315
  }
211
316
 
212
- async renderTemplateOnly(res, templatePath)
317
+ async renderTemplateOnly(res, templatePath, domain)
213
318
  {
214
319
  let template = FileHandler.readFile(templatePath).toString();
215
320
  let data = {
216
321
  title: 'Page Title',
217
322
  current_year: new Date().getFullYear()
218
323
  };
219
- let rendered = mustache.render(template, data);
324
+ let partials = this.getPartialsForDomain(domain);
325
+ let rendered = mustache.render(template, data, partials);
220
326
  return res.send(rendered);
221
327
  }
222
328
 
223
- async renderNotFoundPage(res)
329
+ async renderNotFoundPage(res, domain)
224
330
  {
225
- let templatePath = FileHandler.joinPaths(this.templatesPath, '404.html');
331
+ let templatePath = this.findTemplatePathForDomain('404', domain);
226
332
  if(!FileHandler.exists(templatePath)){
227
333
  return res.status(404).send('Page not found');
228
334
  }
@@ -231,7 +337,8 @@ class Frontend
231
337
  title: '404 - Page Not Found',
232
338
  current_year: new Date().getFullYear()
233
339
  };
234
- let rendered = mustache.render(template, data);
340
+ let partials = this.getPartialsForDomain(domain);
341
+ let rendered = mustache.render(template, data, partials);
235
342
  return res.status(404).send(rendered);
236
343
  }
237
344
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@reldens/cms",
3
3
  "scope": "@reldens",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "description": "Reldens - CMS",
6
6
  "author": "Damian A. Pastorini",
7
7
  "license": "MIT",
@@ -32,7 +32,7 @@
32
32
  "url": "https://github.com/damian-pastorini/reldens-cms/issues"
33
33
  },
34
34
  "dependencies": {
35
- "@reldens/server-utils": "^0.16.0",
35
+ "@reldens/server-utils": "^0.17.0",
36
36
  "@reldens/storage": "^0.45.0",
37
37
  "@reldens/utils": "^0.47.0",
38
38
  "dotenv": "^16.5.0",