@reldens/cms 0.15.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.
Files changed (38) hide show
  1. package/README.md +150 -34
  2. package/admin/reldens-admin-client.css +39 -23
  3. package/admin/reldens-admin-client.js +7 -0
  4. package/admin/templates/cache-clean-button.html +4 -0
  5. package/admin/templates/edit.html +3 -1
  6. package/admin/templates/fields/view/textarea.html +1 -0
  7. package/admin/templates/sections/editForm/cms-pages.html +15 -0
  8. package/admin/templates/sections/viewForm/cms-pages.html +15 -0
  9. package/admin/templates/view.html +1 -0
  10. package/bin/reldens-cms-generate-entities.js +116 -5
  11. package/bin/reldens-cms.js +26 -8
  12. package/install/js/installer.js +5 -0
  13. package/install/success.html +1 -1
  14. package/lib/admin-manager/contents-builder.js +256 -0
  15. package/lib/admin-manager/router-contents.js +576 -0
  16. package/lib/admin-manager/router.js +208 -0
  17. package/lib/admin-manager.js +114 -944
  18. package/lib/cache/add-cache-button-subscriber.js +101 -0
  19. package/lib/cache/cache-manager.js +129 -0
  20. package/lib/cache/cache-routes-handler.js +76 -0
  21. package/lib/cms-pages-route-manager.js +117 -0
  22. package/lib/frontend.js +207 -64
  23. package/lib/installer.js +44 -20
  24. package/lib/json-fields-parser.js +74 -0
  25. package/lib/manager.js +55 -10
  26. package/lib/template-engine.js +361 -41
  27. package/lib/templates-list.js +10 -0
  28. package/migrations/default-blocks.sql +1 -1
  29. package/migrations/default-entity-access.sql +2 -2
  30. package/migrations/default-homepage.sql +27 -7
  31. package/migrations/install.sql +33 -36
  32. package/package.json +3 -3
  33. package/templates/index.js.dist +3 -3
  34. package/templates/js/scripts.js +5 -0
  35. package/templates/layouts/default.html +4 -4
  36. package/templates/page.html +14 -10
  37. package/templates/partials/footer.html +2 -23
  38. package/templates/partials/header.html +2 -35
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  const { Logger, sc } = require('@reldens/utils');
8
+ const { JsonFieldsParser } = require('./json-fields-parser');
8
9
 
9
10
  class TemplateEngine
10
11
  {
@@ -13,6 +14,27 @@ class TemplateEngine
13
14
  {
14
15
  this.renderEngine = sc.get(props, 'renderEngine', false);
15
16
  this.dataServer = sc.get(props, 'dataServer', false);
17
+ this.getPartials = sc.get(props, 'getPartials', false);
18
+ this.currentDomain = '';
19
+ this.jsonFieldsParser = new JsonFieldsParser({
20
+ entitiesConfig: sc.get(props, 'entitiesConfig', {})
21
+ });
22
+ }
23
+
24
+ setCurrentDomain(domain)
25
+ {
26
+ this.currentDomain = domain;
27
+ }
28
+
29
+ async processAllTemplateFunctions(template)
30
+ {
31
+ return await this.processCustomPartials(
32
+ await this.processLoopCollections(
33
+ await this.processSingleFieldCollections(
34
+ await this.processEntityFunctions(template)
35
+ )
36
+ )
37
+ );
16
38
  }
17
39
 
18
40
  async render(template, data, partials)
@@ -26,37 +48,50 @@ class TemplateEngine
26
48
  return '';
27
49
  }
28
50
  return this.renderEngine.render(
29
- await this.processLoopCollections(
30
- await this.processSingleFieldCollections(
31
- await this.processEntityFunctions(template)
32
- )
33
- ),
51
+ this.unescapeHtml(await this.processAllTemplateFunctions(template)),
34
52
  data,
35
53
  partials
36
54
  );
37
55
  }
38
56
 
57
+ unescapeHtml(text)
58
+ {
59
+ return text
60
+ .replace(/"/g, '"')
61
+ .replace(/'/g, "'")
62
+ .replace(/'/g, "'")
63
+ .replace(/=/g, '=')
64
+ .replace(///g, '/')
65
+ .replace(/&lt;/g, '<')
66
+ .replace(/&gt;/g, '>')
67
+ .replace(/&amp;/g, '&');
68
+ }
69
+
39
70
  getEntityRegex()
40
71
  {
41
- return /\{\{\s*entity\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"]\s*)?\)\s*\}\}/g;
72
+ return /<entity\s+name="([^"]+)"(?:\s+field="([^"]+)"\s+value="([^"]+)"|\s+id="([^"]+)")?\s*\/?>/g;
42
73
  }
43
74
 
44
75
  getSingleFieldCollectionRegex()
45
76
  {
46
- return /\{\{\s*collection\(\s*['"]([^'"]+)['"]\s*,\s*(\{[^}]*\})\s*,\s*['"]([^'"]+)['"]\s*\)\s*\}\}/g;
77
+ return /<collection\s+([^>]+)\/>/g;
47
78
  }
48
79
 
49
80
  getLoopCollectionStartRegex()
50
81
  {
51
- return /\{\{\s*#collection\(\s*['"]([^'"]+)['"]\s*,\s*(\{[^}]*\})\s*\)\s*\}\}/g;
82
+ return /<collection\s+([^>]+)>/g;
52
83
  }
53
84
 
54
- getLoopCollectionEndRegex(tableName)
85
+ getLoopCollectionEndRegex()
55
86
  {
56
- return new RegExp('\\{\\{\\s*\\/collection\\(\\s*[\'"]'
57
- +this.escapeRegex(tableName)
58
- +'[\'"]\\s*\\)\\s*\\}\\}'
59
- );
87
+ return new RegExp('<\\/collection>');
88
+ }
89
+
90
+ extractAttributeValue(tagContent, attributeName)
91
+ {
92
+ let regex = new RegExp(attributeName + '=([\'"])([^\'"]*)\\1');
93
+ let match = tagContent.match(regex);
94
+ return match ? match[2] : '';
60
95
  }
61
96
 
62
97
  async processEntityFunctions(template)
@@ -64,10 +99,18 @@ class TemplateEngine
64
99
  let processedTemplate = template;
65
100
  for(let match of template.matchAll(this.getEntityRegex())){
66
101
  let tableName = match[1];
67
- let identifier = match[2];
68
- let identifierField = match[3] || 'id';
69
- let entityData = await this.fetchEntityForTemplate(tableName, identifier, identifierField);
70
- processedTemplate = processedTemplate.replace(match[0], sc.get(entityData, 'content', ''));
102
+ let field = sc.get(match, '2', 'id');
103
+ let value = sc.get(match, '3', sc.get(match, '4', ''));
104
+ if(!value){
105
+ Logger.warning('Entity tag missing value: '+match[0]);
106
+ continue;
107
+ }
108
+ processedTemplate = processedTemplate.replace(
109
+ match[0],
110
+ await this.processAllTemplateFunctions(
111
+ sc.get(await this.fetchEntityForTemplate(tableName, value, field), 'content', '')
112
+ )
113
+ );
71
114
  }
72
115
  return processedTemplate;
73
116
  }
@@ -76,13 +119,19 @@ class TemplateEngine
76
119
  {
77
120
  let processedTemplate = template;
78
121
  for(let match of template.matchAll(this.getSingleFieldCollectionRegex())){
79
- let tableName = match[1];
80
- let filtersJson = match[2];
81
- let fieldName = match[3];
122
+ let tagContent = match[1];
123
+ if(!tagContent.includes('field=')){
124
+ continue;
125
+ }
126
+ let tableName = this.extractAttributeValue(tagContent, 'name');
127
+ let filtersJson = this.extractAttributeValue(tagContent, 'filters');
128
+ let queryOptionsJson = this.extractAttributeValue(tagContent, 'data');
129
+ let relationsString = this.extractAttributeValue(tagContent, 'relations');
130
+ let fieldName = this.extractAttributeValue(tagContent, 'field');
82
131
  processedTemplate = processedTemplate.replace(
83
132
  match[0],
84
133
  this.extractFieldValues(
85
- await this.fetchCollectionForTemplate(tableName, filtersJson),
134
+ await this.fetchCollectionForTemplate(tableName, filtersJson, queryOptionsJson, relationsString),
86
135
  fieldName
87
136
  )
88
137
  );
@@ -96,17 +145,181 @@ class TemplateEngine
96
145
  let matches = [...template.matchAll(this.getLoopCollectionStartRegex())];
97
146
  for(let i = matches.length - 1; i >= 0; i--){
98
147
  let startMatch = matches[i];
99
- let tableName = startMatch[1];
100
- let filtersJson = startMatch[2];
101
- let loopResult = await this.processLoopCollection(processedTemplate, startMatch, tableName, filtersJson);
102
- if(false !== loopResult){
148
+ let tagContent = startMatch[1];
149
+ if(tagContent.includes('field=')){
150
+ continue;
151
+ }
152
+ let tableName = this.extractAttributeValue(tagContent, 'name');
153
+ let filtersJson = this.extractAttributeValue(tagContent, 'filters');
154
+ let queryOptionsJson = this.extractAttributeValue(tagContent, 'data');
155
+ let relationsString = this.extractAttributeValue(tagContent, 'relations');
156
+ let loopResult = await this.processLoopCollection(
157
+ processedTemplate,
158
+ startMatch,
159
+ tableName,
160
+ filtersJson,
161
+ relationsString,
162
+ queryOptionsJson
163
+ );
164
+ if(loopResult){
103
165
  processedTemplate = loopResult;
104
166
  }
105
167
  }
106
168
  return processedTemplate;
107
169
  }
108
170
 
109
- async processLoopCollection(template, startMatch, tableName, filtersJson)
171
+ async processCustomPartials(template)
172
+ {
173
+ let processedTemplate = template;
174
+ let partialTags = this.findAllPartialTags(template);
175
+ for(let i = partialTags.length - 1; i >= 0; i--){
176
+ let tag = partialTags[i];
177
+ let partialContent = this.loadPartialTemplate(tag.name);
178
+ if(!partialContent){
179
+ Logger.warning('Partial template not found: ' + tag.name);
180
+ processedTemplate = processedTemplate.substring(0, tag.start)+''+processedTemplate.substring(tag.end);
181
+ continue;
182
+ }
183
+ let wrapperTemplate = '{{#vars}}{{> ' + tag.name + '}}{{/vars}}';
184
+ let renderData = { vars: tag.attributes };
185
+ let partials = {[tag.name]: partialContent};
186
+ processedTemplate = processedTemplate.substring(0, tag.start) +
187
+ this.renderEngine.render(wrapperTemplate, renderData, partials) +
188
+ processedTemplate.substring(tag.end);
189
+ }
190
+ return processedTemplate;
191
+ }
192
+
193
+ findAllPartialTags(template)
194
+ {
195
+ let partialTags = [];
196
+ let pos = 0;
197
+ let partial = '<partial';
198
+ for(let tagStart = template.indexOf(partial, pos); -1 !== tagStart; tagStart=template.indexOf(partial, pos)){
199
+ let tagEnd = this.findPartialTagEnd(template, tagStart);
200
+ if(-1 === tagEnd){
201
+ pos = tagStart + partial.length;
202
+ continue;
203
+ }
204
+ let fullTag = template.substring(tagStart, tagEnd);
205
+ let nameMatch = fullTag.match(/name=["']([^"']+)["']/);
206
+ if(!nameMatch){
207
+ pos = tagStart + partial.length;
208
+ continue;
209
+ }
210
+ let partialName = nameMatch[1];
211
+ let attributes = this.parsePartialAttributes(fullTag, partialName);
212
+ partialTags.push({
213
+ start: tagStart,
214
+ end: tagEnd,
215
+ name: partialName,
216
+ attributes: attributes,
217
+ fullTag: fullTag
218
+ });
219
+ pos = tagEnd;
220
+ }
221
+ return partialTags;
222
+ }
223
+
224
+ findPartialTagEnd(template, tagStart)
225
+ {
226
+ let inQuotes = false;
227
+ let quoteChar = '';
228
+ let selfCloseTag = '/>';
229
+ let openCloseTag = '</partial>';
230
+ for(let i = tagStart; i < template.length; i++){
231
+ let char = template[i];
232
+ if(!inQuotes && ('"' === char || "'" === char)){
233
+ inQuotes = true;
234
+ quoteChar = char;
235
+ continue;
236
+ }
237
+ if(inQuotes && char === quoteChar && '\\' !== template[i - 1]){
238
+ inQuotes = false;
239
+ quoteChar = '';
240
+ continue;
241
+ }
242
+ if(!inQuotes){
243
+ if(template.substring(i, i + selfCloseTag.length) === selfCloseTag){
244
+ return i + selfCloseTag.length;
245
+ }
246
+ if('>' === char){
247
+ let closeIndex = template.indexOf(openCloseTag, i);
248
+ if(-1 !== closeIndex){
249
+ return closeIndex + openCloseTag.length;
250
+ }
251
+ return i + 1;
252
+ }
253
+ }
254
+ }
255
+ return -1;
256
+ }
257
+
258
+ parsePartialAttributes(fullTag, partialName)
259
+ {
260
+ let namePattern = 'name=' + this.getQuotePattern(fullTag, partialName);
261
+ let nameIndex = fullTag.indexOf(namePattern);
262
+ if(-1 === nameIndex){
263
+ return {};
264
+ }
265
+ let attributesStart = nameIndex + namePattern.length;
266
+ let attributesEnd = fullTag.lastIndexOf('/>');
267
+ if(-1 === attributesEnd){
268
+ attributesEnd = fullTag.lastIndexOf('</partial>');
269
+ }
270
+ if(-1 === attributesEnd){
271
+ attributesEnd = fullTag.lastIndexOf('>');
272
+ }
273
+ if(-1 === attributesEnd || attributesEnd <= attributesStart){
274
+ return {};
275
+ }
276
+ let attributesString = fullTag.substring(attributesStart, attributesEnd).trim();
277
+ return this.extractAttributesObject(attributesString);
278
+ }
279
+
280
+ getQuotePattern(fullTag, partialName)
281
+ {
282
+ if(fullTag.includes('name="' + partialName + '"')){
283
+ return '"' + partialName + '"';
284
+ }
285
+ if(fullTag.includes("name='" + partialName + "'")){
286
+ return "'" + partialName + "'";
287
+ }
288
+ return '"' + partialName + '"';
289
+ }
290
+
291
+ extractAttributesObject(attributesString)
292
+ {
293
+ if(!attributesString){
294
+ return {};
295
+ }
296
+ let attributes = {};
297
+ let valueRegex = /(\w+)=(['"])((?:(?!\2)[^\\]|\\.)*)(\2)/g;
298
+ for(let match of attributesString.matchAll(valueRegex)){
299
+ attributes[match[1]] = match[3];
300
+ }
301
+ let booleanRegex = /\b(\w+)(?!\s*=)/g;
302
+ for(let match of attributesString.matchAll(booleanRegex)){
303
+ if(!sc.hasOwn(attributes, match[1])){
304
+ attributes[match[1]] = true;
305
+ }
306
+ }
307
+ return attributes;
308
+ }
309
+
310
+ loadPartialTemplate(partialName)
311
+ {
312
+ if(!this.getPartials){
313
+ return false;
314
+ }
315
+ let partials = this.getPartials(this.currentDomain);
316
+ if(sc.hasOwn(partials, partialName)){
317
+ return partials[partialName];
318
+ }
319
+ return false;
320
+ }
321
+
322
+ async processLoopCollection(template, startMatch, tableName, filtersJson, relationsString, queryOptionsJson)
110
323
  {
111
324
  let startPos = startMatch.index;
112
325
  let startEnd = startPos + startMatch[0].length;
@@ -116,10 +329,14 @@ class TemplateEngine
116
329
  return false;
117
330
  }
118
331
  let endPos = startEnd + endMatch.index;
119
- let renderedContent = await this.renderCollectionLoop(
120
- template.substring(startEnd, endPos),
121
- await this.fetchCollectionForTemplate(tableName, filtersJson)
332
+ let loopContent = template.substring(startEnd, endPos);
333
+ let collectionData = await this.fetchCollectionForTemplate(
334
+ tableName,
335
+ filtersJson,
336
+ queryOptionsJson,
337
+ relationsString
122
338
  );
339
+ let renderedContent = await this.renderCollectionLoop(loopContent, collectionData);
123
340
  return template.substring(0, startPos) + renderedContent + template.substring(endPos + endMatch[0].length);
124
341
  }
125
342
 
@@ -127,11 +344,39 @@ class TemplateEngine
127
344
  {
128
345
  let renderedContent = '';
129
346
  for(let row of collectionData){
130
- renderedContent += this.renderEngine.render(loopContent, {row}, {});
347
+ renderedContent += await this.processPartialsInLoop(loopContent, row);
131
348
  }
132
349
  return renderedContent;
133
350
  }
134
351
 
352
+ async processPartialsInLoop(content, rowData)
353
+ {
354
+ let processedContent = content;
355
+ let partialTags = this.findAllPartialTags(content);
356
+ for(let i = partialTags.length - 1; i >= 0; i--){
357
+ let tag = partialTags[i];
358
+ let partialContent = this.loadPartialTemplate(tag.name);
359
+ if(!partialContent){
360
+ Logger.warning('Partial template not found: ' + tag.name);
361
+ processedContent = processedContent.substring(0, tag.start)+''+processedContent.substring(tag.end);
362
+ continue;
363
+ }
364
+ if(sc.hasOwn(tag.attributes, 'row')){
365
+ processedContent = processedContent.substring(0, tag.start)
366
+ +this.renderEngine.render(partialContent, {row: rowData}, this.getPartials(this.currentDomain))
367
+ +processedContent.substring(tag.end);
368
+ continue;
369
+ }
370
+ let wrapperTemplate = '{{#vars}}{{> ' + tag.name + '}}{{/vars}}';
371
+ let renderData = { vars: tag.attributes };
372
+ let partials = {[tag.name]: partialContent};
373
+ processedContent = processedContent.substring(0, tag.start) +
374
+ this.renderEngine.render(wrapperTemplate, renderData, partials) +
375
+ processedContent.substring(tag.end);
376
+ }
377
+ return this.renderEngine.render(processedContent, {row: rowData}, this.getPartials(this.currentDomain));
378
+ }
379
+
135
380
  extractFieldValues(collectionData, fieldName)
136
381
  {
137
382
  let fieldValues = '';
@@ -141,11 +386,6 @@ class TemplateEngine
141
386
  return fieldValues;
142
387
  }
143
388
 
144
- escapeRegex(string)
145
- {
146
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
147
- }
148
-
149
389
  async fetchEntityForTemplate(tableName, identifier, identifierField)
150
390
  {
151
391
  let entity = this.dataServer.getEntity(tableName);
@@ -153,21 +393,101 @@ class TemplateEngine
153
393
  Logger.warning('Entity not found in dataServer: '+tableName);
154
394
  return false;
155
395
  }
156
- return await entity.loadOneBy(identifierField, identifier);
396
+ let result = await entity.loadOneBy(identifierField, identifier);
397
+ if(!result){
398
+ return false;
399
+ }
400
+ return this.jsonFieldsParser.parseJsonFields(
401
+ result,
402
+ this.jsonFieldsParser.getJsonFieldsForEntity(tableName)
403
+ );
404
+ }
405
+
406
+ convertJsObjectToJson(jsObjectString)
407
+ {
408
+ if(!jsObjectString || '' === jsObjectString.trim()){
409
+ return '';
410
+ }
411
+ return jsObjectString.replace(/([{,]\s*)([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/g, '$1"$2":');
412
+ }
413
+
414
+ parseRelationsString(relationsString)
415
+ {
416
+ if(!relationsString || '' === relationsString.trim()){
417
+ return [];
418
+ }
419
+ return relationsString.split(',').map(relation => relation.trim()).filter(relation => '' !== relation);
157
420
  }
158
421
 
159
- async fetchCollectionForTemplate(tableName, filtersJson)
422
+ async fetchCollectionForTemplate(tableName, filtersJson, queryOptionsJson, relationsString)
160
423
  {
161
424
  let entity = this.dataServer.getEntity(tableName);
162
425
  if(!entity){
163
426
  Logger.warning('Entity not found in dataServer: '+tableName);
164
427
  return [];
165
428
  }
166
- let filters = sc.toJson(filtersJson);
167
- if(!filters){
168
- return await entity.loadAll();
429
+ let filters = false;
430
+ if(filtersJson && '' !== filtersJson.trim()){
431
+ let convertedFiltersJson = this.convertJsObjectToJson(filtersJson);
432
+ filters = sc.parseJson(convertedFiltersJson, false);
433
+ if(!filters){
434
+ Logger.warning('Invalid filters JSON: '+filtersJson);
435
+ }
436
+ }
437
+ let originalState = this.preserveEntityState(entity);
438
+ let queryOptions = {};
439
+ if(queryOptionsJson && '' !== queryOptionsJson.trim()){
440
+ let convertedOptionsJson = this.convertJsObjectToJson(queryOptionsJson);
441
+ queryOptions = sc.parseJson(convertedOptionsJson, {});
442
+ if(!queryOptions){
443
+ Logger.warning('Invalid query options JSON: '+queryOptionsJson);
444
+ queryOptions = {};
445
+ }
446
+ }
447
+ this.applyQueryOptions(entity, queryOptions);
448
+ let relations = this.parseRelationsString(relationsString);
449
+ let result = 0 < relations.length
450
+ ? await entity.loadWithRelations(filters || {}, relations)
451
+ : filters ? await entity.load(filters) : await entity.loadAll();
452
+ this.restoreEntityState(entity, originalState);
453
+ return this.jsonFieldsParser.parseJsonFields(
454
+ result,
455
+ this.jsonFieldsParser.getJsonFieldsForEntity(tableName)
456
+ );
457
+ }
458
+
459
+ preserveEntityState(entity)
460
+ {
461
+ return {
462
+ limit: entity.limit,
463
+ offset: entity.offset,
464
+ sortBy: entity.sortBy,
465
+ sortDirection: entity.sortDirection
466
+ };
467
+ }
468
+
469
+ restoreEntityState(entity, originalState)
470
+ {
471
+ entity.limit = originalState.limit;
472
+ entity.offset = originalState.offset;
473
+ entity.sortBy = originalState.sortBy;
474
+ entity.sortDirection = originalState.sortDirection;
475
+ }
476
+
477
+ applyQueryOptions(entity, queryOptions)
478
+ {
479
+ if(sc.hasOwn(queryOptions, 'limit')){
480
+ entity.limit = queryOptions.limit;
481
+ }
482
+ if(sc.hasOwn(queryOptions, 'offset')){
483
+ entity.offset = queryOptions.offset;
484
+ }
485
+ if(sc.hasOwn(queryOptions, 'sortBy')){
486
+ entity.sortBy = queryOptions.sortBy;
487
+ }
488
+ if(sc.hasOwn(queryOptions, 'sortDirection')){
489
+ entity.sortDirection = queryOptions.sortDirection;
169
490
  }
170
- return await entity.load(filters);
171
491
  }
172
492
 
173
493
  }
@@ -18,9 +18,11 @@ module.exports.TemplatesList = {
18
18
  sideBarItem: 'sidebar-item.html',
19
19
  paginationLink: 'pagination-link.html',
20
20
  defaultCopyRight: 'default-copyright.html',
21
+ cacheCleanButton: 'cache-clean-button.html',
21
22
  fields: {
22
23
  view: {
23
24
  text: 'text.html',
25
+ textarea: 'textarea.html',
24
26
  image: 'image.html',
25
27
  images: 'images.html',
26
28
  link: 'link.html',
@@ -37,5 +39,13 @@ module.exports.TemplatesList = {
37
39
  button: 'button.html',
38
40
  file: 'file.html'
39
41
  }
42
+ },
43
+ sections: {
44
+ viewForm: {
45
+ 'cms-pages': 'cms-pages.html',
46
+ },
47
+ editForm: {
48
+ 'cms-pages': 'cms-pages.html',
49
+ }
40
50
  }
41
51
  };
@@ -1,7 +1,7 @@
1
1
 
2
2
  -- Default CMS blocks:
3
3
 
4
- REPLACE INTO `cms_blocks` (`name`, `title`, `content`, `is_active`) VALUES
4
+ REPLACE INTO `cms_blocks` (`name`, `title`, `content`, `enabled`) VALUES
5
5
  ('header-main', 'Main Header', '{{>header}}', 1),
6
6
  ('sidebar-left', 'Left Sidebar', '<aside class="sidebar-left">{{>sidebar}}</aside>', 1),
7
7
  ('sidebar-right', 'Right Sidebar', '<aside class="sidebar-right">{{>sidebar}}</aside>', 1),
@@ -1,9 +1,9 @@
1
1
 
2
2
  -- Default entity access rules:
3
3
 
4
- REPLACE INTO `cms_entity_access` (`entity_name`, `is_public`, `allowed_operations`) VALUES
4
+ REPLACE INTO `entities_access` (`entity_name`, `is_public`, `allowed_operations`) VALUES
5
5
  ('cms_pages', TRUE, '["read"]'),
6
6
  ('routes', FALSE, '[]'),
7
7
  ('users', FALSE, '[]'),
8
8
  ('cms_blocks', FALSE, '[]'),
9
- ('cms_entity_access', FALSE, '[]');
9
+ ('entities_access', FALSE, '[]');
@@ -1,10 +1,30 @@
1
-
2
1
  -- Default homepage:
3
2
 
4
- -- Create a default homepage route if not exists
5
- REPLACE INTO `cms_pages` (`id`, `title`, `content`, `template`, `created_at`) VALUES
6
- (1, 'Home', '<h1>Welcome to Reldens CMS</h1><p>This is your homepage. Edit this content in the admin panel.</p>', NULL, NOW());
3
+ -- Create a default route first
4
+ REPLACE INTO `routes` (`id`, `path`, `router`, `cache_ttl_seconds`, `enabled`, `created_at`) VALUES (1, '/home', 'cmsPages', 3600, 1, NOW());
7
5
 
8
- -- Create a default route to the homepage
9
- REPLACE INTO `routes` (`id`, `path`, `router`, `content_id`, `title`, `meta_description`, `status`, `created_at`) VALUES
10
- (1, '/home', 'cmsPages', 1, 'Home', 'Welcome to Reldens CMS', 'published', NOW());
6
+ -- Create a default homepage with route_id reference
7
+ REPLACE INTO `cms_pages` (
8
+ `id`, `title`, `content`, `template`, `route_id`, `meta_title`, `meta_description`,
9
+ `canonical_url`, `meta_robots`, `meta_og_title`, `meta_og_description`,
10
+ `meta_og_image`, `meta_twitter_card_type`, `status`, `locale`, `publish_date`, `expire_date`, `created_at`
11
+ ) VALUES (
12
+ 1,
13
+ 'Home',
14
+ '<h1>Welcome to Reldens CMS</h1><p>This is your homepage. Edit this content in the admin panel.</p>',
15
+ NULL,
16
+ 1,
17
+ 'Home - Reldens CMS',
18
+ 'Welcome to Reldens CMS',
19
+ NULL,
20
+ 'index,follow',
21
+ 'Home - Reldens CMS',
22
+ 'Welcome to the Reldens CMS homepage',
23
+ NULL,
24
+ 'summary',
25
+ 'published',
26
+ 'en',
27
+ NOW(),
28
+ NULL,
29
+ NOW()
30
+ );