@reldens/cms 0.18.0 → 0.20.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 +260 -20
- package/admin/reldens-admin-client.css +127 -80
- package/admin/reldens-admin-client.js +24 -0
- package/admin/templates/clear-all-cache-button.html +18 -0
- package/lib/admin-manager/contents-builder.js +7 -6
- package/lib/admin-manager/router-contents.js +58 -16
- package/lib/admin-manager-validator.js +2 -1
- package/lib/admin-manager.js +4 -2
- package/lib/admin-translations.js +9 -1
- package/lib/cache/add-cache-button-subscriber.js +53 -5
- package/lib/cache/cache-manager.js +47 -8
- package/lib/cache/cache-routes-handler.js +23 -0
- package/lib/cms-pages-route-manager.js +16 -4
- package/lib/frontend.js +310 -119
- package/lib/manager.js +43 -3
- package/lib/pagination-handler.js +243 -0
- package/lib/search-renderer.js +116 -0
- package/lib/search.js +344 -0
- package/lib/template-engine/asset-transformer.js +41 -0
- package/lib/template-engine/collections-single-transformer.js +70 -0
- package/lib/template-engine/collections-transformer-base.js +84 -0
- package/lib/template-engine/collections-transformer.js +374 -0
- package/lib/template-engine/date-transformer.js +53 -0
- package/lib/template-engine/entities-transformer.js +67 -0
- package/lib/template-engine/partials-transformer.js +175 -0
- package/lib/template-engine/system-variables-provider.js +105 -0
- package/lib/template-engine/translate-transformer.js +98 -0
- package/lib/template-engine/translation-service.js +104 -0
- package/lib/template-engine/url-transformer.js +41 -0
- package/lib/template-engine.js +133 -438
- package/lib/templates-list.js +1 -0
- package/migrations/install.sql +18 -18
- package/package.json +4 -4
- package/templates/page.html +19 -2
- package/templates/partials/entriesListView.html +14 -0
- package/templates/partials/pagedCollection.html +33 -0
package/lib/search.js
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - CMS - Search
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { PaginationHandler } = require('./pagination-handler');
|
|
8
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
9
|
+
|
|
10
|
+
class Search
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
constructor(props)
|
|
14
|
+
{
|
|
15
|
+
this.dataServer = sc.get(props, 'dataServer', false);
|
|
16
|
+
this.jsonFieldsParser = sc.get(props, 'jsonFieldsParser', false);
|
|
17
|
+
this.paginationHandler = new PaginationHandler();
|
|
18
|
+
this.defaultSetKey = 'cmsPagesSearch';
|
|
19
|
+
this.searchSets = sc.get(props, 'searchSets', {
|
|
20
|
+
cmsPagesSearch: {
|
|
21
|
+
entities: [{
|
|
22
|
+
name: 'cmsPages',
|
|
23
|
+
fields: [
|
|
24
|
+
'title',
|
|
25
|
+
'content',
|
|
26
|
+
'json_data',
|
|
27
|
+
'meta_title',
|
|
28
|
+
'meta_description',
|
|
29
|
+
'meta_og_title',
|
|
30
|
+
'meta_og_description'
|
|
31
|
+
],
|
|
32
|
+
relations: 'routes'
|
|
33
|
+
}],
|
|
34
|
+
pagination: {active: true, limit: 20, sortBy: 'publish_date', sortDirection: 'desc'}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
this.defaultRenderConfig = {
|
|
38
|
+
page: 'page',
|
|
39
|
+
layout: 'search',
|
|
40
|
+
paginationContainer: 'pagedCollection',
|
|
41
|
+
partial: 'entriesListView'
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
parseSearchParameters(query)
|
|
46
|
+
{
|
|
47
|
+
let setKey = sc.get(query, 'set-key', this.defaultSetKey);
|
|
48
|
+
let config = sc.get(this.searchSets, setKey, false);
|
|
49
|
+
if(!config){
|
|
50
|
+
Logger.error('Search set not found: ' + setKey);
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
config = sc.deepJsonClone(config);
|
|
54
|
+
if(!sc.hasOwn(config, 'entities')){
|
|
55
|
+
config.entities = [];
|
|
56
|
+
}
|
|
57
|
+
if(!sc.hasOwn(config, 'pagination')){
|
|
58
|
+
config.pagination = {active: false};
|
|
59
|
+
}
|
|
60
|
+
config = this.parseEntityParameters(query, config);
|
|
61
|
+
config = this.parseSearchTerms(query, config);
|
|
62
|
+
config = this.parseRelationsParameters(query, config);
|
|
63
|
+
config = this.parsePaginationParameters(query, config);
|
|
64
|
+
config = this.parseRenderParameters(query, config);
|
|
65
|
+
return config;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
parseRelationsParameters(query, config)
|
|
69
|
+
{
|
|
70
|
+
for(let i = 0; i < config.entities.length; i++){
|
|
71
|
+
let entityConfig = config.entities[i];
|
|
72
|
+
let relationKey = 'relations[' + entityConfig.name + ']';
|
|
73
|
+
let relationsValue = sc.get(query, relationKey, '');
|
|
74
|
+
if(relationsValue){
|
|
75
|
+
entityConfig.relations = relationsValue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return config;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
parseEntityParameters(query, config)
|
|
82
|
+
{
|
|
83
|
+
for(let key of Object.keys(query)){
|
|
84
|
+
if(!key.startsWith('entity[')){
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
let entityMatch = key.match(/entity\[([^\]]+)\]/);
|
|
88
|
+
if(!entityMatch){
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
let entityName = entityMatch[1];
|
|
92
|
+
let fields = query[key];
|
|
93
|
+
if(sc.isString(fields)){
|
|
94
|
+
fields = fields.split(',').map(f => f.trim()).filter(f => '' !== f);
|
|
95
|
+
}
|
|
96
|
+
if(!sc.isArray(fields)){
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
let existingEntity = sc.fetchByProperty(config.entities, 'name', entityName);
|
|
100
|
+
if(existingEntity){
|
|
101
|
+
existingEntity.fields = fields;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
config.entities.push({name: entityName, fields});
|
|
105
|
+
}
|
|
106
|
+
return config;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
parseSearchTerms(query, config)
|
|
110
|
+
{
|
|
111
|
+
config.searchTerms = {};
|
|
112
|
+
let globalSearch = sc.get(query, 'search', '');
|
|
113
|
+
if(globalSearch && sc.isString(globalSearch)){
|
|
114
|
+
config.searchTerms.global = globalSearch;
|
|
115
|
+
return config;
|
|
116
|
+
}
|
|
117
|
+
for(let key of Object.keys(query)){
|
|
118
|
+
if(!key.startsWith('search[')){
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
let searchMatch = key.match(/search\[([^\]]+)\](?:\[([^\]]+)\])?/);
|
|
122
|
+
if(!searchMatch){
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
let entityName = searchMatch[1];
|
|
126
|
+
let fieldName = searchMatch[2];
|
|
127
|
+
let searchValue = query[key];
|
|
128
|
+
if(!sc.hasOwn(config.searchTerms, entityName)){
|
|
129
|
+
config.searchTerms[entityName] = {};
|
|
130
|
+
}
|
|
131
|
+
if(fieldName){
|
|
132
|
+
config.searchTerms[entityName][fieldName] = searchValue;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
config.searchTerms[entityName].global = searchValue;
|
|
136
|
+
}
|
|
137
|
+
return config;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
parsePaginationParameters(query, config)
|
|
141
|
+
{
|
|
142
|
+
let limit = sc.get(query, 'limit', '');
|
|
143
|
+
if(limit && sc.isValidInteger(Number(limit), 1)){
|
|
144
|
+
config.pagination.limit = Number(limit);
|
|
145
|
+
config.pagination.active = true;
|
|
146
|
+
}
|
|
147
|
+
let offset = sc.get(query, 'offset', '');
|
|
148
|
+
if(offset && sc.isValidInteger(Number(offset), 0)){
|
|
149
|
+
config.pagination.offset = Number(offset);
|
|
150
|
+
config.pagination.active = true;
|
|
151
|
+
}
|
|
152
|
+
let page = sc.get(query, 'pageNumber', '');
|
|
153
|
+
if(page && sc.isValidInteger(Number(page), 1)){
|
|
154
|
+
config.pagination.page = Number(page);
|
|
155
|
+
config.pagination.active = true;
|
|
156
|
+
}
|
|
157
|
+
let sortBy = sc.get(query, 'sortBy', '');
|
|
158
|
+
if(sortBy){
|
|
159
|
+
config.pagination.sortBy = sortBy;
|
|
160
|
+
}
|
|
161
|
+
let sortDirection = sc.get(query, 'sortDirection', '');
|
|
162
|
+
if(sortDirection && ('asc' === sortDirection || 'desc' === sortDirection)){
|
|
163
|
+
config.pagination.sortDirection = sortDirection;
|
|
164
|
+
}
|
|
165
|
+
return config;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
parseRenderParameters(query, config)
|
|
169
|
+
{
|
|
170
|
+
config.render = Object.assign({}, this.defaultRenderConfig);
|
|
171
|
+
let page = sc.get(query, 'renderPage', '');
|
|
172
|
+
if(page){
|
|
173
|
+
config.render.page = page;
|
|
174
|
+
}
|
|
175
|
+
let layout = sc.get(query, 'renderLayout', '');
|
|
176
|
+
if(layout){
|
|
177
|
+
config.render.layout = layout;
|
|
178
|
+
}
|
|
179
|
+
let paginationContainer = sc.get(query, 'renderPaginationContainer', '');
|
|
180
|
+
if(paginationContainer){
|
|
181
|
+
config.render.paginationContainer = paginationContainer;
|
|
182
|
+
}
|
|
183
|
+
let partial = sc.get(query, 'renderPartial', '');
|
|
184
|
+
if(partial){
|
|
185
|
+
config.render.partial = partial;
|
|
186
|
+
}
|
|
187
|
+
return config;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async executeSearch(config)
|
|
191
|
+
{
|
|
192
|
+
if(!config || !sc.isArray(config.entities) || 0 === config.entities.length){
|
|
193
|
+
Logger.error('Invalid search configuration');
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
let searchTerms = sc.get(config, 'searchTerms', {});
|
|
197
|
+
let hasSearchTerms = false;
|
|
198
|
+
if(sc.hasOwn(searchTerms, 'global') && '' !== searchTerms.global){
|
|
199
|
+
hasSearchTerms = true;
|
|
200
|
+
}
|
|
201
|
+
if(!hasSearchTerms){
|
|
202
|
+
for(let entityName of Object.keys(searchTerms)){
|
|
203
|
+
let entityTerms = searchTerms[entityName];
|
|
204
|
+
if(sc.isObject(entityTerms)){
|
|
205
|
+
for(let termKey of Object.keys(entityTerms)){
|
|
206
|
+
if('' !== entityTerms[termKey]){
|
|
207
|
+
hasSearchTerms = true;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if(hasSearchTerms){
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if(!hasSearchTerms){
|
|
218
|
+
let results = [];
|
|
219
|
+
for(let entityConfig of config.entities){
|
|
220
|
+
results.push({
|
|
221
|
+
entity: entityConfig.name,
|
|
222
|
+
results: [],
|
|
223
|
+
hasResults: false,
|
|
224
|
+
noResultsMessage: 'No search term provided.'
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return results;
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
230
|
+
let results = [];
|
|
231
|
+
for(let entityConfig of config.entities){
|
|
232
|
+
let entityResult = await this.searchEntity(entityConfig, config);
|
|
233
|
+
if(false === entityResult){
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
results.push(entityResult);
|
|
237
|
+
}
|
|
238
|
+
return results;
|
|
239
|
+
} catch(error) {
|
|
240
|
+
Logger.error('Search execution failed: ' + error.message);
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async searchEntity(entityConfig, config)
|
|
246
|
+
{
|
|
247
|
+
let entity = this.dataServer.getEntity(entityConfig.name);
|
|
248
|
+
if(!entity){
|
|
249
|
+
Logger.error('Entity not found: ' + entityConfig.name);
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
let searchFilters = this.buildSearchFilters(entityConfig, config);
|
|
253
|
+
if(!searchFilters){
|
|
254
|
+
Logger.error('No search filters built for entity: ' + entityConfig.name);
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
let results;
|
|
259
|
+
let paginationData = null;
|
|
260
|
+
let relationsString = sc.get(entityConfig, 'relations', '');
|
|
261
|
+
let originalState = entity.preserveEntityState();
|
|
262
|
+
if(config.pagination && config.pagination.active){
|
|
263
|
+
let totalRecords = await this.paginationHandler.getCollectionTotal(entity, searchFilters);
|
|
264
|
+
let currentPage = sc.get(config.pagination, 'page', 1);
|
|
265
|
+
let limit = sc.get(config.pagination, 'limit', 20);
|
|
266
|
+
let offset = (currentPage - 1) * limit;
|
|
267
|
+
let sortBy = sc.get(config.pagination, 'sortBy', 'id');
|
|
268
|
+
let sortDirection = sc.get(config.pagination, 'sortDirection', 'asc');
|
|
269
|
+
let queryOptions = {
|
|
270
|
+
limit,
|
|
271
|
+
offset,
|
|
272
|
+
sortBy,
|
|
273
|
+
sortDirection
|
|
274
|
+
};
|
|
275
|
+
results = await entity.loadEntityData(searchFilters, queryOptions, relationsString);
|
|
276
|
+
paginationData = this.paginationHandler.calculatePaginationData(
|
|
277
|
+
totalRecords,
|
|
278
|
+
currentPage,
|
|
279
|
+
limit,
|
|
280
|
+
'',
|
|
281
|
+
entityConfig.name,
|
|
282
|
+
config.pagination,
|
|
283
|
+
{}
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
if(!results){
|
|
287
|
+
results = await entity.loadEntityData(searchFilters, {}, relationsString);
|
|
288
|
+
}
|
|
289
|
+
entity.restoreEntityState(originalState);
|
|
290
|
+
if(this.jsonFieldsParser){
|
|
291
|
+
results = this.jsonFieldsParser.parseJsonFields(
|
|
292
|
+
results,
|
|
293
|
+
this.jsonFieldsParser.getJsonFieldsForEntity(entityConfig.name)
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
let entityResult = {
|
|
297
|
+
entity: entityConfig.name,
|
|
298
|
+
results: results || [],
|
|
299
|
+
hasResults: results && 0 < results.length,
|
|
300
|
+
noResultsMessage: 'No results found for your search.'
|
|
301
|
+
};
|
|
302
|
+
if(paginationData){
|
|
303
|
+
entityResult.pagination = paginationData;
|
|
304
|
+
}
|
|
305
|
+
return entityResult;
|
|
306
|
+
} catch(error) {
|
|
307
|
+
Logger.error('Search entity failed for ' + entityConfig.name + ': ' + error.message);
|
|
308
|
+
return {
|
|
309
|
+
entity: entityConfig.name,
|
|
310
|
+
results: [],
|
|
311
|
+
hasResults: false,
|
|
312
|
+
noResultsMessage: 'Search failed. Please try again.',
|
|
313
|
+
error: true
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
buildSearchFilters(entityConfig, config)
|
|
319
|
+
{
|
|
320
|
+
let searchTerms = sc.get(config, 'searchTerms', {});
|
|
321
|
+
let globalTerm = sc.get(searchTerms, 'global', '');
|
|
322
|
+
let entityTerms = sc.get(searchTerms, entityConfig.name, {});
|
|
323
|
+
let entityGlobalTerm = sc.get(entityTerms, 'global', '');
|
|
324
|
+
let searchTerm = entityGlobalTerm || globalTerm;
|
|
325
|
+
if(!searchTerm){
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
let entity = this.dataServer.getEntity(entityConfig.name);
|
|
329
|
+
if(!entity){
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
let searchableFields = entityConfig.fields;
|
|
333
|
+
let orConditions = [];
|
|
334
|
+
for(let field of searchableFields){
|
|
335
|
+
orConditions.push({
|
|
336
|
+
[field]: {operator: 'LIKE', value: '%' + searchTerm + '%'}
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
return {OR: orConditions};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
module.exports.Search = Search;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - CMS - AssetTransformer
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class AssetTransformer
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
async transform(template, domain, req, systemVariables)
|
|
13
|
+
{
|
|
14
|
+
if(!template){
|
|
15
|
+
return template;
|
|
16
|
+
}
|
|
17
|
+
let currentRequest = sc.get(systemVariables, 'currentRequest', {});
|
|
18
|
+
let assetPattern = /\[asset\(([^)]+)\)\]/g;
|
|
19
|
+
let matches = [...template.matchAll(assetPattern)];
|
|
20
|
+
for(let i = matches.length - 1; i >= 0; i--){
|
|
21
|
+
let match = matches[i];
|
|
22
|
+
let assetPath = match[1].replace(/['"]/g, '');
|
|
23
|
+
let absoluteUrl = this.buildAssetUrl(assetPath, currentRequest);
|
|
24
|
+
template = template.substring(0, match.index) +
|
|
25
|
+
absoluteUrl +
|
|
26
|
+
template.substring(match.index + match[0].length);
|
|
27
|
+
}
|
|
28
|
+
return template;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
buildAssetUrl(assetPath, currentRequest)
|
|
32
|
+
{
|
|
33
|
+
if(!assetPath || assetPath.startsWith('http')){
|
|
34
|
+
return assetPath;
|
|
35
|
+
}
|
|
36
|
+
return sc.get(currentRequest, 'baseUrl', '')+'/assets'+(assetPath.startsWith('/') ? assetPath : '/'+assetPath);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports.AssetTransformer = AssetTransformer;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - CMS - CollectionsSingleTransformer
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { CollectionsTransformerBase } = require('./collections-transformer-base');
|
|
8
|
+
const { sc } = require('@reldens/utils');
|
|
9
|
+
|
|
10
|
+
class CollectionsSingleTransformer extends CollectionsTransformerBase
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
constructor(props)
|
|
14
|
+
{
|
|
15
|
+
super(props);
|
|
16
|
+
this.renderEngine = sc.get(props, 'renderEngine', false);
|
|
17
|
+
this.getPartials = sc.get(props, 'getPartials', false);
|
|
18
|
+
this.findAllPartialTags = sc.get(props, 'findAllPartialTags', false);
|
|
19
|
+
this.loadPartialTemplate = sc.get(props, 'loadPartialTemplate', false);
|
|
20
|
+
this.processAllTemplateFunctions = sc.get(props, 'processAllTemplateFunctions', false);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getSingleFieldCollectionRegex()
|
|
24
|
+
{
|
|
25
|
+
return /<collection\s+([^>]+)\/>/g;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async transform(template, domain, req, systemVariables)
|
|
29
|
+
{
|
|
30
|
+
let processedTemplate = template;
|
|
31
|
+
for(let match of template.matchAll(this.getSingleFieldCollectionRegex())){
|
|
32
|
+
let tagContent = match[1];
|
|
33
|
+
if(!tagContent.includes('field=')){
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
let tableName = this.extractAttributeValue(tagContent, 'name');
|
|
37
|
+
let filtersJson = this.extractAttributeValue(tagContent, 'filters');
|
|
38
|
+
let queryOptionsJson = this.extractAttributeValue(tagContent, 'data');
|
|
39
|
+
let relationsString = this.extractAttributeValue(tagContent, 'relations');
|
|
40
|
+
let fieldName = this.extractAttributeValue(tagContent, 'field');
|
|
41
|
+
processedTemplate = processedTemplate.replace(
|
|
42
|
+
match[0],
|
|
43
|
+
await this.extractFieldValues(
|
|
44
|
+
await this.fetchCollectionForTemplate(tableName, filtersJson, queryOptionsJson, relationsString),
|
|
45
|
+
fieldName,
|
|
46
|
+
domain,
|
|
47
|
+
req,
|
|
48
|
+
systemVariables
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return processedTemplate;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async extractFieldValues(collectionData, fieldName, domain, req, systemVariables)
|
|
56
|
+
{
|
|
57
|
+
let fieldValues = '';
|
|
58
|
+
for(let row of collectionData){
|
|
59
|
+
let fieldValue = sc.get(row, fieldName, '');
|
|
60
|
+
if(fieldValue && this.processAllTemplateFunctions){
|
|
61
|
+
fieldValue = await this.processAllTemplateFunctions(fieldValue, domain, req, systemVariables);
|
|
62
|
+
}
|
|
63
|
+
fieldValues += fieldValue;
|
|
64
|
+
}
|
|
65
|
+
return fieldValues;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports.CollectionsSingleTransformer = CollectionsSingleTransformer;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - CMS - CollectionsTransformerBase
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class CollectionsTransformerBase
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
constructor(props)
|
|
13
|
+
{
|
|
14
|
+
this.dataServer = sc.get(props, 'dataServer', false);
|
|
15
|
+
this.jsonFieldsParser = sc.get(props, 'jsonFieldsParser', false);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
extractAttributeValue(tagContent, attributeName)
|
|
19
|
+
{
|
|
20
|
+
let doubleQuoteRegex = new RegExp(attributeName + '="([^"]*)"');
|
|
21
|
+
let singleQuoteRegex = new RegExp(attributeName + "='([^']*)'");
|
|
22
|
+
let doubleMatch = tagContent.match(doubleQuoteRegex);
|
|
23
|
+
if(doubleMatch){
|
|
24
|
+
return doubleMatch[1];
|
|
25
|
+
}
|
|
26
|
+
let singleMatch = tagContent.match(singleQuoteRegex);
|
|
27
|
+
if(singleMatch){
|
|
28
|
+
return singleMatch[1];
|
|
29
|
+
}
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
convertJsObjectToJson(jsObjectString)
|
|
34
|
+
{
|
|
35
|
+
if(!jsObjectString || '' === jsObjectString.trim()){
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
return jsObjectString
|
|
39
|
+
.replace(/([{,]\s*)([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/g, '$1"$2":')
|
|
40
|
+
.replace(/:\s*'([^']*)'/g, ': "$1"');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async fetchCollectionForTemplate(tableName, filtersJson, queryOptionsJson, relationsString)
|
|
44
|
+
{
|
|
45
|
+
let entity = this.dataServer.getEntity(tableName);
|
|
46
|
+
if(!entity){
|
|
47
|
+
Logger.warning('Entity not found in dataServer: '+tableName);
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
let filters = {};
|
|
51
|
+
if(filtersJson && '' !== filtersJson.trim()){
|
|
52
|
+
let convertedFiltersJson = this.convertJsObjectToJson(filtersJson);
|
|
53
|
+
let parsedFilters = sc.parseJson(convertedFiltersJson, false);
|
|
54
|
+
if(parsedFilters){
|
|
55
|
+
filters = parsedFilters;
|
|
56
|
+
}
|
|
57
|
+
if(!parsedFilters){
|
|
58
|
+
Logger.warning('Invalid filters JSON: '+filtersJson);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
let originalState = entity.preserveEntityState();
|
|
62
|
+
let queryOptions = {};
|
|
63
|
+
if(queryOptionsJson && '' !== queryOptionsJson.trim()){
|
|
64
|
+
let convertedOptionsJson = this.convertJsObjectToJson(queryOptionsJson);
|
|
65
|
+
queryOptions = sc.parseJson(convertedOptionsJson, {});
|
|
66
|
+
if(!queryOptions){
|
|
67
|
+
Logger.warning('Invalid query options JSON: '+queryOptionsJson);
|
|
68
|
+
queryOptions = {};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
let result = await entity.loadEntityData(filters, queryOptions, relationsString);
|
|
72
|
+
entity.restoreEntityState(originalState);
|
|
73
|
+
if(this.jsonFieldsParser){
|
|
74
|
+
result = this.jsonFieldsParser.parseJsonFields(
|
|
75
|
+
result,
|
|
76
|
+
this.jsonFieldsParser.getJsonFieldsForEntity(tableName)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports.CollectionsTransformerBase = CollectionsTransformerBase;
|