@reldens/cms 0.20.0 → 0.23.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/README.md +648 -12
- package/admin/reldens-admin-client.css +77 -141
- package/admin/reldens-admin-client.js +108 -133
- package/admin/templates/clear-all-cache-button.html +7 -7
- package/admin/templates/edit.html +7 -0
- package/admin/templates/fields/view/audio.html +7 -0
- package/admin/templates/fields/view/audios.html +8 -0
- package/admin/templates/layout.html +15 -9
- package/admin/templates/list-content.html +4 -2
- package/admin/templates/list.html +24 -8
- package/admin/templates/view.html +21 -0
- package/install/index.html +4 -0
- package/lib/admin-manager/admin-filters-manager.js +177 -0
- package/lib/admin-manager/contents-builder.js +1 -0
- package/lib/admin-manager/default-translations.js +38 -0
- package/lib/admin-manager/router-contents.js +64 -52
- package/lib/admin-manager/router.js +19 -0
- package/lib/dynamic-form-renderer.js +228 -0
- package/lib/dynamic-form-request-handler.js +135 -0
- package/lib/dynamic-form.js +310 -0
- package/lib/frontend/content-renderer.js +178 -0
- package/lib/frontend/entity-access-manager.js +63 -0
- package/lib/frontend/request-processor.js +128 -0
- package/lib/frontend/response-manager.js +54 -0
- package/lib/frontend/template-cache.js +102 -0
- package/lib/frontend/template-resolver.js +111 -0
- package/lib/frontend.js +122 -629
- package/lib/installer.js +2 -1
- package/lib/manager.js +25 -12
- package/lib/search-renderer.js +15 -7
- package/lib/search-request-handler.js +67 -0
- package/lib/search.js +13 -1
- package/lib/template-engine/collections-single-transformer.js +11 -5
- package/lib/template-engine/collections-transformer.js +47 -34
- package/lib/template-engine/entities-transformer.js +3 -2
- package/lib/template-engine/forms-transformer.js +187 -0
- package/lib/template-engine/partials-transformer.js +5 -6
- package/lib/template-engine/system-variables-provider.js +4 -1
- package/lib/template-engine.js +28 -5
- package/lib/template-reloader.js +307 -0
- package/lib/templates-list.js +2 -0
- package/migrations/default-forms.sql +22 -0
- package/package.json +5 -5
- package/templates/{browserconfig.xml → assets/favicons/default/browserconfig.xml} +1 -1
- package/templates/assets/favicons/default/favicon.ico +0 -0
- package/templates/{site.webmanifest → assets/favicons/default/site.webmanifest} +3 -3
- package/templates/cms_forms/field_email.html +14 -0
- package/templates/cms_forms/field_number.html +17 -0
- package/templates/cms_forms/field_select.html +15 -0
- package/templates/cms_forms/field_text.html +16 -0
- package/templates/cms_forms/field_textarea.html +13 -0
- package/templates/cms_forms/form.html +22 -0
- package/templates/css/styles.css +4 -0
- package/templates/js/functions.js +144 -0
- package/templates/js/scripts.js +5 -0
- package/templates/page.html +11 -5
- package/templates/partials/pagedCollection.html +1 -1
- package/lib/admin-translations.js +0 -56
- package/templates/favicon.ico +0 -0
- /package/templates/assets/favicons/{android-icon-144x144.png → default/android-icon-144x144.png} +0 -0
- /package/templates/assets/favicons/{android-icon-192x192.png → default/android-icon-192x192.png} +0 -0
- /package/templates/assets/favicons/{android-icon-512x512.png → default/android-icon-512x512.png} +0 -0
- /package/templates/assets/favicons/{apple-touch-icon.png → default/apple-touch-icon.png} +0 -0
- /package/templates/assets/favicons/{favicon-16x16.png → default/favicon-16x16.png} +0 -0
- /package/templates/assets/favicons/{favicon-32x32.png → default/favicon-32x32.png} +0 -0
- /package/templates/assets/favicons/{mstile-150x150.png → default/mstile-150x150.png} +0 -0
- /package/templates/assets/favicons/{safari-pinned-tab.svg → default/safari-pinned-tab.svg} +0 -0
package/lib/frontend.js
CHANGED
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
const { TemplateEngine } = require('./template-engine');
|
|
8
8
|
const { Search } = require('./search');
|
|
9
9
|
const { SearchRenderer } = require('./search-renderer');
|
|
10
|
+
const { SearchRequestHandler } = require('./search-request-handler');
|
|
11
|
+
const { DynamicForm } = require('./dynamic-form');
|
|
12
|
+
const { DynamicFormRenderer } = require('./dynamic-form-renderer');
|
|
13
|
+
const { DynamicFormRequestHandler } = require('./dynamic-form-request-handler');
|
|
14
|
+
const { TemplateResolver } = require('./frontend/template-resolver');
|
|
15
|
+
const { TemplateCache } = require('./frontend/template-cache');
|
|
16
|
+
const { RequestProcessor } = require('./frontend/request-processor');
|
|
17
|
+
const { EntityAccessManager } = require('./frontend/entity-access-manager');
|
|
18
|
+
const { ContentRenderer } = require('./frontend/content-renderer');
|
|
19
|
+
const { ResponseManager } = require('./frontend/response-manager');
|
|
10
20
|
const { FileHandler } = require('@reldens/server-utils');
|
|
11
21
|
const { Logger, sc } = require('@reldens/utils');
|
|
12
22
|
|
|
@@ -27,24 +37,28 @@ class Frontend
|
|
|
27
37
|
this.defaultDomain = sc.get(props, 'defaultDomain', 'default');
|
|
28
38
|
this.domainMapping = sc.get(props, 'domainMapping', {});
|
|
29
39
|
this.siteKeyMapping = sc.get(props, 'siteKeyMapping', {});
|
|
30
|
-
this.partialsCache = {};
|
|
31
|
-
this.domainPartialsCache = new Map();
|
|
32
|
-
this.domainTemplatesMap = new Map();
|
|
33
|
-
this.entityAccessCache = new Map();
|
|
34
40
|
this.entitiesConfig = sc.get(props, 'entitiesConfig', {});
|
|
35
41
|
this.templateEngine = false;
|
|
36
42
|
this.cacheManager = sc.get(props, 'cacheManager', false);
|
|
43
|
+
this.handleFrontendTemplateReload = sc.get(props, 'handleFrontendTemplateReload', false);
|
|
37
44
|
this.searchPath = sc.get(props, 'searchPath', '/search');
|
|
45
|
+
this.dynamicFormPath = sc.get(props, 'dynamicFormPath', '/dynamic-form');
|
|
46
|
+
this.dynamicFormDisplayPath = sc.get(props, 'dynamicFormDisplayPath', '/form');
|
|
38
47
|
this.searchSets = sc.get(props, 'searchSets', false);
|
|
39
48
|
this.searchConfig = {dataServer: this.dataServer};
|
|
40
49
|
if(this.searchSets){
|
|
41
50
|
this.searchConfig.searchSets = this.searchSets;
|
|
42
51
|
}
|
|
43
52
|
this.search = new Search(this.searchConfig);
|
|
44
|
-
this.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
this.dynamicFormConfig = {
|
|
54
|
+
dataServer: this.dataServer,
|
|
55
|
+
allowedOrigins: sc.get(props, 'allowedOrigins', []),
|
|
56
|
+
honeypotFieldName: sc.get(props, 'honeypotFieldName', 'website_url'),
|
|
57
|
+
rateLimitWindow: sc.get(props, 'rateLimitWindow', 300000),
|
|
58
|
+
rateLimitMax: sc.get(props, 'rateLimitMax', 5),
|
|
59
|
+
events: this.events
|
|
60
|
+
};
|
|
61
|
+
this.dynamicForm = new DynamicForm(this.dynamicFormConfig);
|
|
48
62
|
this.metaDefaults = sc.get(props, 'metaDefaults', {
|
|
49
63
|
locale: 'en',
|
|
50
64
|
viewport: 'width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes, viewport-fit=cover',
|
|
@@ -52,6 +66,32 @@ class Frontend
|
|
|
52
66
|
meta_theme_color: '#000000',
|
|
53
67
|
meta_twitter_card_type: 'summary'
|
|
54
68
|
});
|
|
69
|
+
this.templateResolver = new TemplateResolver(this);
|
|
70
|
+
this.templateCache = new TemplateCache(this);
|
|
71
|
+
this.requestProcessor = new RequestProcessor(this);
|
|
72
|
+
this.entityAccessManager = new EntityAccessManager(this);
|
|
73
|
+
this.contentRenderer = new ContentRenderer(this);
|
|
74
|
+
this.responseManager = new ResponseManager(this);
|
|
75
|
+
this.searchRenderer = new SearchRenderer({
|
|
76
|
+
renderEngine: this.renderEngine,
|
|
77
|
+
getPartials: this.templateCache.getPartialsForDomain.bind(this.templateCache)
|
|
78
|
+
});
|
|
79
|
+
this.dynamicFormRenderer = new DynamicFormRenderer({
|
|
80
|
+
renderEngine: this.renderEngine,
|
|
81
|
+
getPartials: this.templateCache.getPartialsForDomain.bind(this.templateCache),
|
|
82
|
+
projectRoot: this.projectRoot,
|
|
83
|
+
defaultDomain: this.defaultDomain,
|
|
84
|
+
events: this.events
|
|
85
|
+
});
|
|
86
|
+
this.searchRequestHandler = new SearchRequestHandler(this);
|
|
87
|
+
this.dynamicFormRequestHandler = new DynamicFormRequestHandler({
|
|
88
|
+
dynamicForm: this.dynamicForm,
|
|
89
|
+
contentRenderer: this.contentRenderer,
|
|
90
|
+
requestProcessor: this.requestProcessor,
|
|
91
|
+
cacheManager: this.cacheManager,
|
|
92
|
+
enableJsonResponse: sc.get(props, 'enableJsonResponse', false),
|
|
93
|
+
events: this.events
|
|
94
|
+
});
|
|
55
95
|
}
|
|
56
96
|
|
|
57
97
|
async initialize()
|
|
@@ -76,23 +116,30 @@ class Frontend
|
|
|
76
116
|
Logger.error('Public folder not found: '+this.publicPath);
|
|
77
117
|
return false;
|
|
78
118
|
}
|
|
119
|
+
this.templateResolver.domainTemplatesMap = this.templateCache.getDomainTemplatesMap();
|
|
79
120
|
this.templateEngine = new TemplateEngine({
|
|
80
121
|
renderEngine: this.renderEngine,
|
|
81
122
|
dataServer: this.dataServer,
|
|
82
|
-
getPartials: this.getPartialsForDomain.bind(this),
|
|
123
|
+
getPartials: this.templateCache.getPartialsForDomain.bind(this.templateCache),
|
|
83
124
|
entitiesConfig: this.entitiesConfig,
|
|
84
125
|
events: this.events,
|
|
85
126
|
defaultDomain: this.defaultDomain,
|
|
86
127
|
projectRoot: this.projectRoot,
|
|
87
|
-
publicPath: this.publicPath
|
|
128
|
+
publicPath: this.publicPath,
|
|
129
|
+
dynamicForm: this.dynamicForm,
|
|
130
|
+
dynamicFormRenderer: this.dynamicFormRenderer
|
|
88
131
|
});
|
|
132
|
+
this.contentRenderer.templateEngine = this.templateEngine;
|
|
89
133
|
this.searchConfig.jsonFieldsParser = this.templateEngine.jsonFieldsParser;
|
|
90
|
-
await this.loadPartials();
|
|
91
|
-
await this.setupDomainTemplates();
|
|
92
|
-
await this.loadEntityAccessRules();
|
|
134
|
+
await this.templateCache.loadPartials();
|
|
135
|
+
await this.templateCache.setupDomainTemplates();
|
|
136
|
+
await this.entityAccessManager.loadEntityAccessRules();
|
|
93
137
|
this.setupStaticAssets();
|
|
94
138
|
this.app.get(this.searchPath, async (req, res) => {
|
|
95
|
-
return await this.handleSearchRequest(req, res);
|
|
139
|
+
return await this.searchRequestHandler.handleSearchRequest(req, res);
|
|
140
|
+
});
|
|
141
|
+
this.app.post(this.dynamicFormPath, async (req, res) => {
|
|
142
|
+
return await this.dynamicFormRequestHandler.handleFormSubmission(req, res);
|
|
96
143
|
});
|
|
97
144
|
this.app.get('*', async (req, res) => {
|
|
98
145
|
return await this.handleRequest(req, res);
|
|
@@ -100,674 +147,120 @@ class Frontend
|
|
|
100
147
|
return true;
|
|
101
148
|
}
|
|
102
149
|
|
|
103
|
-
async loadEntityAccessRules()
|
|
104
|
-
{
|
|
105
|
-
let accessEntity = this.dataServer.getEntity('entitiesAccess');
|
|
106
|
-
if(!accessEntity){
|
|
107
|
-
Logger.warning('Entities Access not found.');
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
let accessRules = await accessEntity.loadAll();
|
|
111
|
-
for(let rule of accessRules){
|
|
112
|
-
this.entityAccessCache.set(rule.entity_name, rule.is_public);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async loadPartials()
|
|
117
|
-
{
|
|
118
|
-
let partialsPath = FileHandler.joinPaths(this.templatesPath, 'partials');
|
|
119
|
-
FileHandler.createFolder(partialsPath);
|
|
120
|
-
let partialFiles = FileHandler.getFilesInFolder(partialsPath, this.templateExtensions);
|
|
121
|
-
for(let file of partialFiles){
|
|
122
|
-
let partialName = this.extractTemplateName(file);
|
|
123
|
-
if(!partialName){
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
let partialPath = FileHandler.joinPaths(partialsPath, file);
|
|
127
|
-
let partialContent = FileHandler.readFile(partialPath);
|
|
128
|
-
if(!partialContent){
|
|
129
|
-
Logger.error('Failed to read partial: '+partialPath);
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
this.partialsCache[partialName] = partialContent;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async loadDomainPartials(domain, domainPath)
|
|
137
|
-
{
|
|
138
|
-
let domainPartialsPath = FileHandler.joinPaths(domainPath, 'partials');
|
|
139
|
-
if(!FileHandler.exists(domainPartialsPath)){
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
let domainPartials = {};
|
|
143
|
-
let partialFiles = FileHandler.getFilesInFolder(domainPartialsPath, this.templateExtensions);
|
|
144
|
-
for(let file of partialFiles){
|
|
145
|
-
let partialName = this.extractTemplateName(file);
|
|
146
|
-
if(!partialName){
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
let partialPath = FileHandler.joinPaths(domainPartialsPath, file);
|
|
150
|
-
let partialContent = FileHandler.readFile(partialPath);
|
|
151
|
-
if(!partialContent){
|
|
152
|
-
Logger.error('Failed to read domain partial: '+partialPath);
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
domainPartials[partialName] = partialContent;
|
|
156
|
-
}
|
|
157
|
-
this.domainPartialsCache.set(domain, domainPartials);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async setupDomainTemplates()
|
|
161
|
-
{
|
|
162
|
-
let domainsPath = FileHandler.joinPaths(this.templatesPath, 'domains');
|
|
163
|
-
if(!FileHandler.exists(domainsPath)){
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
let domainFolders = FileHandler.fetchSubFoldersList(domainsPath);
|
|
167
|
-
for(let domain of domainFolders){
|
|
168
|
-
let domainPath = FileHandler.joinPaths(domainsPath, domain);
|
|
169
|
-
this.domainTemplatesMap.set(domain, domainPath);
|
|
170
|
-
await this.loadDomainPartials(domain, domainPath);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
extractTemplateName(filename)
|
|
175
|
-
{
|
|
176
|
-
for(let extension of this.templateExtensions){
|
|
177
|
-
if(filename.endsWith(extension)){
|
|
178
|
-
return filename.replace(extension, '');
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
getDomainFromRequest(req)
|
|
185
|
-
{
|
|
186
|
-
let host = req.get('host');
|
|
187
|
-
if(!host){
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
return host.split(':')[0];
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
resolveDomainToFolder(domain)
|
|
194
|
-
{
|
|
195
|
-
if(!domain){
|
|
196
|
-
domain = this.defaultDomain;
|
|
197
|
-
}
|
|
198
|
-
return sc.get(this.domainMapping, domain, domain);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
resolveDomainToSiteKey(domain)
|
|
202
|
-
{
|
|
203
|
-
return sc.get(this.siteKeyMapping, this.resolveDomainToFolder(domain), 'default');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
getPartialsForDomain(domain)
|
|
207
|
-
{
|
|
208
|
-
let resolvedDomain = this.resolveDomainToFolder(domain);
|
|
209
|
-
let domainPartials = this.domainPartialsCache.get(resolvedDomain);
|
|
210
|
-
if(!domainPartials && this.defaultDomain && resolvedDomain !== this.defaultDomain){
|
|
211
|
-
domainPartials = this.domainPartialsCache.get(this.defaultDomain);
|
|
212
|
-
}
|
|
213
|
-
if(!domainPartials){
|
|
214
|
-
return this.partialsCache;
|
|
215
|
-
}
|
|
216
|
-
return Object.assign({}, this.partialsCache, domainPartials);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
findTemplatePath(templateName, domain)
|
|
220
|
-
{
|
|
221
|
-
let resolvedDomain = this.resolveDomainToFolder(domain);
|
|
222
|
-
if(resolvedDomain){
|
|
223
|
-
let domainPath = this.domainTemplatesMap.get(resolvedDomain);
|
|
224
|
-
if(domainPath){
|
|
225
|
-
let domainTemplatePath = this.findTemplateInPath(templateName, domainPath);
|
|
226
|
-
if(domainTemplatePath){
|
|
227
|
-
return domainTemplatePath;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
if(this.defaultDomain && resolvedDomain !== this.defaultDomain){
|
|
231
|
-
let defaultDomainPath = this.domainTemplatesMap.get(this.defaultDomain);
|
|
232
|
-
if(defaultDomainPath){
|
|
233
|
-
let defaultTemplatePath = this.findTemplateInPath(templateName, defaultDomainPath);
|
|
234
|
-
if(defaultTemplatePath){
|
|
235
|
-
return defaultTemplatePath;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
return this.findTemplateInPath(templateName, this.templatesPath);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
findTemplateInPath(templateName, basePath)
|
|
244
|
-
{
|
|
245
|
-
for(let extension of this.templateExtensions){
|
|
246
|
-
let templatePath = FileHandler.joinPaths(basePath, templateName + extension);
|
|
247
|
-
if(FileHandler.exists(templatePath)){
|
|
248
|
-
return templatePath;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
findLayoutPath(layoutName, domain)
|
|
255
|
-
{
|
|
256
|
-
let resolvedDomain = this.resolveDomainToFolder(domain);
|
|
257
|
-
if(resolvedDomain){
|
|
258
|
-
let domainPath = this.domainTemplatesMap.get(resolvedDomain);
|
|
259
|
-
if(domainPath){
|
|
260
|
-
let domainLayoutPath = this.findTemplateInPath('layouts/' + layoutName, domainPath);
|
|
261
|
-
if(domainLayoutPath){
|
|
262
|
-
return domainLayoutPath;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return this.findTemplateInPath('layouts/' + layoutName, this.templatesPath);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
setupStaticAssets()
|
|
270
|
-
{
|
|
271
|
-
if(!this.app || !this.appServerFactory || !this.publicPath){
|
|
272
|
-
return false;
|
|
273
|
-
}
|
|
274
|
-
if(this.appServerFactory && this.appServerFactory.applicationFramework){
|
|
275
|
-
this.app.use(this.appServerFactory.applicationFramework.static(this.publicPath));
|
|
276
|
-
return true;
|
|
277
|
-
}
|
|
278
|
-
return false;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
fetchMetaFields(data)
|
|
282
|
-
{
|
|
283
|
-
if(!sc.isObject(data) || 0 === Object.keys(data).length){
|
|
284
|
-
return this.metaDefaults;
|
|
285
|
-
}
|
|
286
|
-
let result = Object.assign({}, this.metaDefaults);
|
|
287
|
-
for(let key of Object.keys(data)){
|
|
288
|
-
let value = data[key];
|
|
289
|
-
if(null !== value && '' !== value && 'undefined' !== typeof value){
|
|
290
|
-
result[key] = value;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
let titleValue = sc.get(result, 'title', '');
|
|
294
|
-
let metaTitleValue = sc.get(result, 'meta_title', titleValue);
|
|
295
|
-
if(metaTitleValue && '' !== metaTitleValue){
|
|
296
|
-
result.meta_title = metaTitleValue;
|
|
297
|
-
}
|
|
298
|
-
let metaOgTitleValue = sc.get(result, 'meta_og_title', metaTitleValue);
|
|
299
|
-
if(metaOgTitleValue && '' !== metaOgTitleValue){
|
|
300
|
-
result.meta_og_title = metaOgTitleValue;
|
|
301
|
-
}
|
|
302
|
-
let metaDescValue = sc.get(result, 'meta_description', '');
|
|
303
|
-
let metaOgDescValue = sc.get(result, 'meta_og_description', metaDescValue);
|
|
304
|
-
if(metaOgDescValue && '' !== metaOgDescValue){
|
|
305
|
-
result.meta_og_description = metaOgDescValue;
|
|
306
|
-
}
|
|
307
|
-
let jsonData = sc.get(result, 'json_data', null);
|
|
308
|
-
if(sc.isString(jsonData)){
|
|
309
|
-
jsonData = sc.toJson(jsonData, {});
|
|
310
|
-
}
|
|
311
|
-
if(!sc.isObject(jsonData)){
|
|
312
|
-
jsonData = {};
|
|
313
|
-
}
|
|
314
|
-
let viewportValue = sc.get(jsonData, 'viewport', this.metaDefaults.viewport);
|
|
315
|
-
if(viewportValue && '' !== viewportValue){
|
|
316
|
-
jsonData.viewport = viewportValue;
|
|
317
|
-
}
|
|
318
|
-
result.json_data = jsonData;
|
|
319
|
-
return result;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
async handleSearchRequest(req, res)
|
|
323
|
-
{
|
|
324
|
-
try {
|
|
325
|
-
let domain = this.getDomainFromRequest(req);
|
|
326
|
-
let config = this.search.parseSearchParameters(req.query);
|
|
327
|
-
if(!config){
|
|
328
|
-
return res.redirect('/?error-message=searchInvalidParameters');
|
|
329
|
-
}
|
|
330
|
-
let cacheKey = this.buildCacheKey(req.path, req);
|
|
331
|
-
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
332
|
-
let cachedContent = await this.cacheManager.get(domain, cacheKey);
|
|
333
|
-
if(cachedContent){
|
|
334
|
-
return res.send(cachedContent);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
let searchResults = await this.search.executeSearch(config);
|
|
338
|
-
if(false === searchResults){
|
|
339
|
-
return res.redirect('/?error-message=searchExecutionFailed');
|
|
340
|
-
}
|
|
341
|
-
let content = await this.renderWithTemplateContent(
|
|
342
|
-
{
|
|
343
|
-
template: config.render.page,
|
|
344
|
-
layout: config.render.layout,
|
|
345
|
-
content: await this.searchRenderer.renderSearchResults(searchResults, config, domain, req)
|
|
346
|
-
},
|
|
347
|
-
Object.assign({}, {
|
|
348
|
-
search_query: sc.get(req.query, 'search', ''),
|
|
349
|
-
searchConfig: config,
|
|
350
|
-
query: req.query
|
|
351
|
-
}),
|
|
352
|
-
domain,
|
|
353
|
-
req,
|
|
354
|
-
null
|
|
355
|
-
);
|
|
356
|
-
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
357
|
-
await this.cacheManager.set(domain, cacheKey, content);
|
|
358
|
-
}
|
|
359
|
-
return res.send(content);
|
|
360
|
-
} catch (error) {
|
|
361
|
-
Logger.error('Search request handling error: ' + error.message);
|
|
362
|
-
return res.redirect('/?error-message=searchError');
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
normalizePathForRouteSearch(path)
|
|
367
|
-
{
|
|
368
|
-
if(!path || '/' === path){
|
|
369
|
-
return '/';
|
|
370
|
-
}
|
|
371
|
-
return path.endsWith('/') ? path.slice(0, -1) : path;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
async handleRouteRedirect(route, res)
|
|
375
|
-
{
|
|
376
|
-
let redirectUrl = sc.get(route, 'redirect_url', null);
|
|
377
|
-
if(!redirectUrl){
|
|
378
|
-
return false;
|
|
379
|
-
}
|
|
380
|
-
let redirectType = sc.get(route, 'redirect_type', '301');
|
|
381
|
-
let statusCode = '301' === redirectType ? 301 : 302;
|
|
382
|
-
return res.redirect(statusCode, redirectUrl);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
150
|
async handleRequest(req, res)
|
|
386
151
|
{
|
|
387
152
|
try {
|
|
153
|
+
if(this.handleFrontendTemplateReload){
|
|
154
|
+
await this.handleFrontendTemplateReload(this.templateCache, this.templateResolver);
|
|
155
|
+
}
|
|
388
156
|
let originalPath = req.path;
|
|
389
|
-
let domain = this.getDomainFromRequest(req);
|
|
157
|
+
let domain = this.requestProcessor.getDomainFromRequest(req);
|
|
390
158
|
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
391
159
|
let cachedContent = await this.cacheManager.get(domain, originalPath);
|
|
392
160
|
if(cachedContent){
|
|
393
161
|
return res.send(cachedContent);
|
|
394
162
|
}
|
|
395
163
|
}
|
|
396
|
-
let route = await this.findRouteByPath(originalPath, domain);
|
|
164
|
+
let route = await this.requestProcessor.findRouteByPath(originalPath, domain);
|
|
397
165
|
if(route){
|
|
398
|
-
let redirectResult = await this.handleRouteRedirect(route, res);
|
|
166
|
+
let redirectResult = await this.requestProcessor.handleRouteRedirect(route, res);
|
|
399
167
|
if(redirectResult){
|
|
400
168
|
return redirectResult;
|
|
401
169
|
}
|
|
402
|
-
let normalizedPath = this.normalizePathForRouteSearch(originalPath);
|
|
170
|
+
let normalizedPath = this.requestProcessor.normalizePathForRouteSearch(originalPath);
|
|
403
171
|
let routeFoundWithSlash = originalPath !== normalizedPath && route.path === normalizedPath + '/';
|
|
404
172
|
if(!originalPath.endsWith('/') && routeFoundWithSlash){
|
|
405
173
|
return res.redirect(301, originalPath + '/');
|
|
406
174
|
}
|
|
407
|
-
return await this.
|
|
175
|
+
return await this.responseManager.renderWithCacheHandler(
|
|
176
|
+
async () => await this.contentRenderer.generateRouteContent(route, domain, req),
|
|
177
|
+
async () => await this.responseManager.renderNotFound(domain, res, req),
|
|
178
|
+
async (content) => res.send(content),
|
|
179
|
+
domain,
|
|
180
|
+
res,
|
|
181
|
+
originalPath,
|
|
182
|
+
req
|
|
183
|
+
);
|
|
408
184
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
let redirectResult = await this.handleRouteRedirect(alternativeRoute, res);
|
|
185
|
+
if(!originalPath.endsWith('/') && '/' !== originalPath){
|
|
186
|
+
let routeWithSlash = await this.requestProcessor.findRouteByPath(originalPath + '/', domain);
|
|
187
|
+
if(routeWithSlash){
|
|
188
|
+
let redirectResult = await this.requestProcessor.handleRouteRedirect(routeWithSlash, res);
|
|
414
189
|
if(redirectResult){
|
|
415
190
|
return redirectResult;
|
|
416
191
|
}
|
|
417
|
-
|
|
418
|
-
return res.redirect(301, originalPath + '/');
|
|
419
|
-
}
|
|
420
|
-
return await this.renderRouteWithCache(alternativeRoute, domain, res, originalPath, req);
|
|
192
|
+
return res.redirect(301, originalPath + '/');
|
|
421
193
|
}
|
|
422
194
|
}
|
|
423
|
-
|
|
424
|
-
return res.redirect(301, originalPath + '/');
|
|
425
|
-
}
|
|
426
|
-
let entityResult = await this.findEntityByPath(originalPath);
|
|
195
|
+
let entityResult = await this.entityAccessManager.findEntityByPath(originalPath);
|
|
427
196
|
if(entityResult){
|
|
428
|
-
return await this.
|
|
197
|
+
return await this.responseManager.renderWithCacheHandler(
|
|
198
|
+
async () => await this.contentRenderer.renderWithTemplateContent(
|
|
199
|
+
entityResult.entity,
|
|
200
|
+
{},
|
|
201
|
+
domain,
|
|
202
|
+
req,
|
|
203
|
+
null
|
|
204
|
+
),
|
|
205
|
+
async () => await this.responseManager.renderNotFound(domain, res, req),
|
|
206
|
+
async (content) => res.send(content),
|
|
207
|
+
domain,
|
|
208
|
+
res,
|
|
209
|
+
originalPath,
|
|
210
|
+
req
|
|
211
|
+
);
|
|
429
212
|
}
|
|
430
|
-
let templatePath = this.findTemplateByPath(originalPath, domain);
|
|
213
|
+
let templatePath = this.templateResolver.findTemplateByPath(originalPath, domain);
|
|
431
214
|
if(templatePath){
|
|
432
|
-
return await this.
|
|
215
|
+
return await this.responseManager.renderWithCacheHandler(
|
|
216
|
+
async () => await this.contentRenderer.generateTemplateContent(templatePath, domain, req),
|
|
217
|
+
async () => res.status(500).send('Template error: '+templatePath),
|
|
218
|
+
async (content) => res.send(await this.contentRenderer.renderWithTemplateContent({content}, {}, domain, req, null)),
|
|
219
|
+
domain,
|
|
220
|
+
res,
|
|
221
|
+
originalPath,
|
|
222
|
+
req
|
|
223
|
+
);
|
|
433
224
|
}
|
|
434
|
-
return await this.renderNotFound(domain, res, req);
|
|
225
|
+
return await this.responseManager.renderNotFound(domain, res, req);
|
|
435
226
|
} catch (error) {
|
|
436
227
|
Logger.error('Request handling error: '+error.message);
|
|
437
228
|
return res.status(500).send('Internal server error');
|
|
438
229
|
}
|
|
439
230
|
}
|
|
440
231
|
|
|
441
|
-
async findRouteByPath(path, domain)
|
|
442
|
-
{
|
|
443
|
-
let routesEntity = this.dataServer.getEntity('routes');
|
|
444
|
-
if(!routesEntity){
|
|
445
|
-
Logger.error('Routes entity not found in dataServer.');
|
|
446
|
-
return false;
|
|
447
|
-
}
|
|
448
|
-
let normalizedPath = this.normalizePathForRouteSearch(path);
|
|
449
|
-
let domainFilter = domain || null;
|
|
450
|
-
let routeFilters = {path: normalizedPath, enabled: 1};
|
|
451
|
-
let routes = await routesEntity.load(routeFilters);
|
|
452
|
-
let matchingRoute = false;
|
|
453
|
-
let nullDomain = false;
|
|
454
|
-
for(let route of routes){
|
|
455
|
-
if(route.domain === domainFilter){
|
|
456
|
-
matchingRoute = route;
|
|
457
|
-
break;
|
|
458
|
-
}
|
|
459
|
-
if(!route.domain){
|
|
460
|
-
nullDomain = route;
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
if(matchingRoute){
|
|
464
|
-
return matchingRoute;
|
|
465
|
-
}
|
|
466
|
-
if(nullDomain){
|
|
467
|
-
return nullDomain;
|
|
468
|
-
}
|
|
469
|
-
if(normalizedPath !== path){
|
|
470
|
-
let routeFiltersWithSlash = {path: path, enabled: 1};
|
|
471
|
-
let routesWithSlash = await routesEntity.load(routeFiltersWithSlash);
|
|
472
|
-
for(let route of routesWithSlash){
|
|
473
|
-
if(route.domain === domainFilter){
|
|
474
|
-
return route;
|
|
475
|
-
}
|
|
476
|
-
if(!route.domain){
|
|
477
|
-
nullDomain = route;
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
if(nullDomain){
|
|
481
|
-
return nullDomain;
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
return false;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
async isEntityAccessible(entityName)
|
|
488
|
-
{
|
|
489
|
-
if(this.entityAccessCache.has(entityName)){
|
|
490
|
-
return this.entityAccessCache.get(entityName);
|
|
491
|
-
}
|
|
492
|
-
return false;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
async findEntityByPath(path)
|
|
496
|
-
{
|
|
497
|
-
let pathSegments = path.split('/').filter(segment => '' !== segment);
|
|
498
|
-
if(2 > pathSegments.length){
|
|
499
|
-
return false;
|
|
500
|
-
}
|
|
501
|
-
let entityName = pathSegments[0];
|
|
502
|
-
if(!await this.isEntityAccessible(entityName)){
|
|
503
|
-
return false;
|
|
504
|
-
}
|
|
505
|
-
let entityId = pathSegments[1];
|
|
506
|
-
let entity = this.dataServer.getEntity(entityName);
|
|
507
|
-
if(!entity){
|
|
508
|
-
return false;
|
|
509
|
-
}
|
|
510
|
-
let loadedEntity = await entity.loadById(entityId);
|
|
511
|
-
if(!loadedEntity){
|
|
512
|
-
return false;
|
|
513
|
-
}
|
|
514
|
-
return {entity: loadedEntity, entityName};
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
findTemplateByPath(path, domain)
|
|
518
|
-
{
|
|
519
|
-
if('/' === path){
|
|
520
|
-
path = '/index';
|
|
521
|
-
}
|
|
522
|
-
let templatePath = path.endsWith('/') ? path.slice(0, -1) : path;
|
|
523
|
-
templatePath = templatePath.startsWith('/') ? templatePath.substring(1) : templatePath;
|
|
524
|
-
if('page' === templatePath){
|
|
525
|
-
return false;
|
|
526
|
-
}
|
|
527
|
-
return this.findTemplatePath(templatePath, domain);
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
async renderRouteWithCache(route, domain, res, path, req)
|
|
531
|
-
{
|
|
532
|
-
let renderedContent = await this.generateRouteContent(route, domain, req);
|
|
533
|
-
if(!renderedContent){
|
|
534
|
-
return await this.renderNotFound(domain, res, req);
|
|
535
|
-
}
|
|
536
|
-
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
537
|
-
let cacheKey = this.buildCacheKey(path, req);
|
|
538
|
-
await this.cacheManager.set(domain, cacheKey, renderedContent);
|
|
539
|
-
}
|
|
540
|
-
return res.send(renderedContent);
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
async renderEntityWithCache(entityResult, domain, res, path, req)
|
|
544
|
-
{
|
|
545
|
-
let renderedContent = await this.generateEntityContent(entityResult, domain, req);
|
|
546
|
-
if(!renderedContent){
|
|
547
|
-
return await this.renderNotFound(domain, res, req);
|
|
548
|
-
}
|
|
549
|
-
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
550
|
-
let cacheKey = this.buildCacheKey(path, req);
|
|
551
|
-
await this.cacheManager.set(domain, cacheKey, renderedContent);
|
|
552
|
-
}
|
|
553
|
-
return res.send(renderedContent);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
async renderTemplateWithCache(templatePath, domain, res, path, req)
|
|
557
|
-
{
|
|
558
|
-
let renderedContent = await this.generateTemplateContent(templatePath, domain, req);
|
|
559
|
-
if(!renderedContent){
|
|
560
|
-
return res.status(500).send('Template error: '+templatePath);
|
|
561
|
-
}
|
|
562
|
-
if(this.cacheManager && this.cacheManager.isEnabled()){
|
|
563
|
-
let cacheKey = this.buildCacheKey(path, req);
|
|
564
|
-
await this.cacheManager.set(domain, cacheKey, renderedContent);
|
|
565
|
-
}
|
|
566
|
-
return await this.renderWithLayout({content: renderedContent}, {}, 'default', domain, res, req);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
async generateRouteContent(route, domain, req)
|
|
570
|
-
{
|
|
571
|
-
if(!route.router){
|
|
572
|
-
return false;
|
|
573
|
-
}
|
|
574
|
-
let entity = this.dataServer.getEntity(route.router);
|
|
575
|
-
if(!entity){
|
|
576
|
-
return false;
|
|
577
|
-
}
|
|
578
|
-
let content = await entity.loadOne({route_id: route.id});
|
|
579
|
-
if(!content){
|
|
580
|
-
return false;
|
|
581
|
-
}
|
|
582
|
-
return await this.renderWithTemplateContent(content, Object.assign({}, route, content), domain, req, route);
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
async generateEntityContent(entityResult, domain, req)
|
|
586
|
-
{
|
|
587
|
-
return await this.renderWithTemplateContent(entityResult.entity, entityResult.entity, domain, req, null);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
async generateTemplateContent(templatePath, domain, req)
|
|
591
|
-
{
|
|
592
|
-
let template = FileHandler.readFile(templatePath);
|
|
593
|
-
if(!template){
|
|
594
|
-
Logger.error('Failed to read template: ' + templatePath);
|
|
595
|
-
return false;
|
|
596
|
-
}
|
|
597
|
-
return await this.templateEngine.render(
|
|
598
|
-
template,
|
|
599
|
-
{},
|
|
600
|
-
this.getPartialsForDomain(domain),
|
|
601
|
-
domain,
|
|
602
|
-
req,
|
|
603
|
-
null,
|
|
604
|
-
null
|
|
605
|
-
);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
232
|
async renderRoute(route, domain, res, req)
|
|
609
233
|
{
|
|
610
234
|
if(!route.router){
|
|
611
|
-
return await this.renderNotFound(domain, res, req);
|
|
235
|
+
return await this.responseManager.renderNotFound(domain, res, req);
|
|
612
236
|
}
|
|
613
237
|
let entity = this.dataServer.getEntity(route.router);
|
|
614
238
|
if(!entity){
|
|
615
|
-
return await this.renderNotFound(domain, res, req);
|
|
239
|
+
return await this.responseManager.renderNotFound(domain, res, req);
|
|
616
240
|
}
|
|
617
241
|
let content = await entity.loadOne({route_id: route.id});
|
|
618
242
|
if(!content){
|
|
619
|
-
return await this.renderNotFound(domain, res, req);
|
|
243
|
+
return await this.responseManager.renderNotFound(domain, res, req);
|
|
620
244
|
}
|
|
621
|
-
return await this.
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
async renderWithTemplate(content, data, domain, res, req)
|
|
625
|
-
{
|
|
626
|
-
return res.send(await this.renderWithTemplateContent(content, data, domain, req, null));
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
async renderWithTemplateContent(content, data, domain, req, route)
|
|
630
|
-
{
|
|
631
|
-
let templateName = sc.get(content, 'template', 'page');
|
|
632
|
-
if(!templateName){
|
|
633
|
-
templateName = 'page';
|
|
634
|
-
}
|
|
635
|
-
let layoutName = sc.get(content, 'layout', '');
|
|
636
|
-
if(!layoutName){
|
|
637
|
-
layoutName = 'default';
|
|
638
|
-
}
|
|
639
|
-
let currentEntityData = Object.assign({}, content, data);
|
|
640
|
-
let layoutContent = await this.processContentWithLayout(
|
|
245
|
+
return res.send(await this.contentRenderer.renderWithTemplateContent(
|
|
641
246
|
content,
|
|
642
|
-
|
|
643
|
-
layoutName,
|
|
644
|
-
domain,
|
|
645
|
-
req,
|
|
646
|
-
route,
|
|
647
|
-
currentEntityData
|
|
648
|
-
);
|
|
649
|
-
let templatePath = this.findTemplatePath(templateName, domain);
|
|
650
|
-
if(!templatePath){
|
|
651
|
-
return layoutContent;
|
|
652
|
-
}
|
|
653
|
-
let pageTemplate = FileHandler.readFile(templatePath);
|
|
654
|
-
if(!pageTemplate){
|
|
655
|
-
return layoutContent;
|
|
656
|
-
}
|
|
657
|
-
return await this.templateEngine.render(
|
|
658
|
-
pageTemplate,
|
|
659
|
-
Object.assign(
|
|
660
|
-
{},
|
|
661
|
-
this.fetchMetaFields(data),
|
|
662
|
-
{
|
|
663
|
-
content: layoutContent,
|
|
664
|
-
siteHandle: this.resolveDomainToSiteKey(domain)
|
|
665
|
-
}
|
|
666
|
-
),
|
|
667
|
-
this.getPartialsForDomain(domain),
|
|
668
|
-
domain,
|
|
669
|
-
req,
|
|
670
|
-
route,
|
|
671
|
-
currentEntityData
|
|
672
|
-
);
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
async renderContentWithTemplate(templatePath, data, domain, req)
|
|
676
|
-
{
|
|
677
|
-
let template = FileHandler.readFile(templatePath);
|
|
678
|
-
if(!template){
|
|
679
|
-
Logger.error('Failed to read template: ' + templatePath);
|
|
680
|
-
return false;
|
|
681
|
-
}
|
|
682
|
-
return await this.templateEngine.render(
|
|
683
|
-
template,
|
|
684
|
-
data,
|
|
685
|
-
this.getPartialsForDomain(domain),
|
|
247
|
+
Object.assign({}, route, content),
|
|
686
248
|
domain,
|
|
687
249
|
req,
|
|
688
|
-
null,
|
|
689
250
|
null
|
|
690
|
-
);
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
async renderWithLayout(content, data, layoutName, domain, res, req)
|
|
694
|
-
{
|
|
695
|
-
return res.send(await this.renderWithTemplateContent(content, data, domain, req, null));
|
|
251
|
+
));
|
|
696
252
|
}
|
|
697
253
|
|
|
698
|
-
|
|
699
|
-
{
|
|
700
|
-
let processedContent = await this.processContent(content, data, domain, req, route, currentEntityData);
|
|
701
|
-
let layoutPath = this.findLayoutPath(layoutName, domain);
|
|
702
|
-
if(!layoutPath){
|
|
703
|
-
return processedContent;
|
|
704
|
-
}
|
|
705
|
-
let layoutTemplate = FileHandler.readFile(layoutPath);
|
|
706
|
-
if(!layoutTemplate){
|
|
707
|
-
return processedContent;
|
|
708
|
-
}
|
|
709
|
-
return await this.templateEngine.render(
|
|
710
|
-
layoutTemplate,
|
|
711
|
-
Object.assign({}, data, {content: processedContent}),
|
|
712
|
-
this.getPartialsForDomain(domain),
|
|
713
|
-
domain,
|
|
714
|
-
req,
|
|
715
|
-
route,
|
|
716
|
-
currentEntityData
|
|
717
|
-
);
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
async processContent(content, data, domain, req, route, currentEntityData)
|
|
721
|
-
{
|
|
722
|
-
let contentText = sc.get(content, 'content', '');
|
|
723
|
-
if(!contentText){
|
|
724
|
-
return '';
|
|
725
|
-
}
|
|
726
|
-
return await this.templateEngine.render(
|
|
727
|
-
contentText,
|
|
728
|
-
data,
|
|
729
|
-
this.getPartialsForDomain(domain),
|
|
730
|
-
domain,
|
|
731
|
-
req,
|
|
732
|
-
route,
|
|
733
|
-
currentEntityData
|
|
734
|
-
);
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
async renderNotFound(domain, res, req)
|
|
738
|
-
{
|
|
739
|
-
let notFoundPath = this.findTemplatePath('404', domain);
|
|
740
|
-
if(notFoundPath){
|
|
741
|
-
let content = await this.renderContentWithTemplate(notFoundPath, {}, domain, req);
|
|
742
|
-
if(content){
|
|
743
|
-
res.status(404);
|
|
744
|
-
return await this.renderWithLayout({content}, {}, 'default', domain, res, req);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
return res.status(404).send('Page not found');
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
buildCacheKey(path, req)
|
|
254
|
+
setupStaticAssets()
|
|
751
255
|
{
|
|
752
|
-
if(!
|
|
753
|
-
return
|
|
256
|
+
if(!this.app || !this.appServerFactory || !this.publicPath){
|
|
257
|
+
return false;
|
|
754
258
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
for(let qKey of Object.keys(req.query)){
|
|
759
|
-
queryString += (queryString ? '&' : '') + qKey + '=' + req.query[qKey];
|
|
760
|
-
}
|
|
761
|
-
let hash = 0;
|
|
762
|
-
for(let i = 0; i < queryString.length; i++){
|
|
763
|
-
let char = queryString.charCodeAt(i);
|
|
764
|
-
hash = ((hash << 5) - hash) + char;
|
|
765
|
-
hash = hash & hash;
|
|
766
|
-
}
|
|
767
|
-
return path + '_' + Math.abs(hash);
|
|
768
|
-
}
|
|
259
|
+
if(this.appServerFactory && this.appServerFactory.applicationFramework){
|
|
260
|
+
this.app.use(this.appServerFactory.applicationFramework.static(this.publicPath));
|
|
261
|
+
return true;
|
|
769
262
|
}
|
|
770
|
-
return
|
|
263
|
+
return false;
|
|
771
264
|
}
|
|
772
265
|
|
|
773
266
|
}
|