@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.
- package/lib/frontend.js +132 -25
- 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 =
|
|
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 =
|
|
278
|
+
let templatePath = this.findTemplatePathForDomain(templateName, domain);
|
|
176
279
|
if(!FileHandler.exists(templatePath)){
|
|
177
|
-
templatePath =
|
|
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
|
|
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 =
|
|
299
|
+
let templatePath = this.findTemplatePathForDomain(entityName, domain);
|
|
196
300
|
if(!FileHandler.exists(templatePath)){
|
|
197
|
-
templatePath =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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.
|
|
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.
|
|
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",
|