@reldens/cms 0.15.0 → 0.16.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 +150 -34
- package/admin/reldens-admin-client.css +28 -23
- package/admin/reldens-admin-client.js +7 -0
- package/admin/templates/edit.html +3 -1
- package/admin/templates/fields/view/textarea.html +1 -0
- package/admin/templates/sections/editForm/cms-pages.html +15 -0
- package/admin/templates/sections/viewForm/cms-pages.html +15 -0
- package/admin/templates/view.html +1 -0
- package/bin/reldens-cms-generate-entities.js +47 -3
- package/bin/reldens-cms.js +26 -8
- package/install/js/installer.js +5 -0
- package/install/success.html +1 -1
- package/lib/admin-manager.js +80 -34
- package/lib/cms-pages-route-manager.js +105 -0
- package/lib/frontend.js +53 -50
- package/lib/installer.js +41 -20
- package/lib/manager.js +48 -9
- package/lib/template-engine.js +310 -42
- package/lib/templates-list.js +9 -0
- package/migrations/default-blocks.sql +1 -1
- package/migrations/default-entity-access.sql +2 -2
- package/migrations/default-homepage.sql +24 -4
- package/migrations/install.sql +31 -35
- package/package.json +3 -3
- package/templates/index.js.dist +3 -3
- package/templates/js/scripts.js +5 -0
- package/templates/layouts/default.html +4 -4
- package/templates/page.html +14 -10
- package/templates/partials/footer.html +2 -23
- package/templates/partials/header.html +2 -35
package/lib/installer.js
CHANGED
|
@@ -35,6 +35,7 @@ class Installer
|
|
|
35
35
|
this.moduleAdminTemplatesPath = FileHandler.joinPaths(this.moduleAdminPath, 'templates')
|
|
36
36
|
this.indexTemplatePath = FileHandler.joinPaths(this.defaultTemplatesPath, 'index.js.dist');
|
|
37
37
|
this.postInstallCallback = sc.get(props, 'postInstallCallback', false);
|
|
38
|
+
this.prismaClient = sc.get(props, 'prismaClient', false);
|
|
38
39
|
this.entitiesLoader = new EntitiesLoader({projectRoot: this.projectRoot});
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -49,17 +50,21 @@ class Installer
|
|
|
49
50
|
Logger.error('Missing app on prepareSetup for Installer.');
|
|
50
51
|
return false;
|
|
51
52
|
}
|
|
53
|
+
if(!appServer){
|
|
54
|
+
Logger.error('Missing appServer on prepareSetup for Installer.');
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
52
57
|
if(!appServerFactory){
|
|
53
58
|
Logger.error('Missing appServerFactory on prepareSetup for Installer.');
|
|
54
59
|
return false;
|
|
55
60
|
}
|
|
56
61
|
if(!renderEngine){
|
|
57
|
-
Logger.error('Missing renderEngine for Installer.');
|
|
62
|
+
Logger.error('Missing renderEngine on prepareSetup for Installer.');
|
|
58
63
|
return false;
|
|
59
64
|
}
|
|
60
65
|
this.app = app;
|
|
61
|
-
this.appServerFactory = appServerFactory;
|
|
62
66
|
this.appServer = appServer;
|
|
67
|
+
this.appServerFactory = appServerFactory;
|
|
63
68
|
this.renderEngine = renderEngine;
|
|
64
69
|
app.use('/install-assets', appServerFactory.applicationFramework.static(this.installerPath, {index: false}));
|
|
65
70
|
app.use(appServerFactory.session({
|
|
@@ -117,7 +122,7 @@ class Installer
|
|
|
117
122
|
'configuration-error': 'Configuration error while completing installation.',
|
|
118
123
|
'already-installed': 'The application is already installed.'
|
|
119
124
|
};
|
|
120
|
-
return errorMessages
|
|
125
|
+
return sc.get(errorMessages, errorCode, 'An unknown error occurred during installation.');
|
|
121
126
|
}
|
|
122
127
|
|
|
123
128
|
async executeInstallProcess(req, res)
|
|
@@ -145,13 +150,8 @@ class Installer
|
|
|
145
150
|
},
|
|
146
151
|
debug: false
|
|
147
152
|
};
|
|
148
|
-
if('prisma' === selectedDriver){
|
|
149
|
-
|
|
150
|
-
if(!generatedPrismaSchema){
|
|
151
|
-
Logger.error('Could not generated Prisma schema.');
|
|
152
|
-
return res.redirect('/?error=prisma-schema-generation-error');
|
|
153
|
-
}
|
|
154
|
-
Logger.info('Generated Prisma schema.');
|
|
153
|
+
if('prisma' === selectedDriver && this.prismaClient){
|
|
154
|
+
dbConfig.prismaClient = this.prismaClient;
|
|
155
155
|
}
|
|
156
156
|
let dbDriver = new driverClass(dbConfig);
|
|
157
157
|
if(!await dbDriver.connect()){
|
|
@@ -181,7 +181,7 @@ class Installer
|
|
|
181
181
|
return res.redirect(redirectError);
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
|
-
let entitiesGenerationResult = await this.generateEntities(dbDriver);
|
|
184
|
+
let entitiesGenerationResult = await this.generateEntities(dbDriver, false, true);
|
|
185
185
|
if(!entitiesGenerationResult){
|
|
186
186
|
Logger.error('Entities generation error.');
|
|
187
187
|
return res.redirect('/?error=installation-entities-generation-failed');
|
|
@@ -214,7 +214,7 @@ class Installer
|
|
|
214
214
|
if(successFileContent){
|
|
215
215
|
successContent = this.renderEngine.render(
|
|
216
216
|
successFileContent,
|
|
217
|
-
{adminPath: templateVariables['app-admin-path']
|
|
217
|
+
{adminPath: templateVariables['app-admin-path']},
|
|
218
218
|
);
|
|
219
219
|
}
|
|
220
220
|
return res.send(successContent);
|
|
@@ -234,7 +234,8 @@ class Installer
|
|
|
234
234
|
Logger.error('SQL file "'+fileName+'" not found.');
|
|
235
235
|
return '/?error=sql-file-not-found&file-name='+fileName;
|
|
236
236
|
}
|
|
237
|
-
|
|
237
|
+
let queryExecutionResult = await dbDriver.rawQuery(sqlFileContent);
|
|
238
|
+
if(!queryExecutionResult){
|
|
238
239
|
Logger.error('SQL file "'+fileName+'" raw execution failed.');
|
|
239
240
|
return '/?error=sql-file-execution-error&file-name='+fileName;
|
|
240
241
|
}
|
|
@@ -242,23 +243,32 @@ class Installer
|
|
|
242
243
|
return '';
|
|
243
244
|
}
|
|
244
245
|
|
|
245
|
-
async generateEntities(server, isOverride = false)
|
|
246
|
+
async generateEntities(server, isOverride = false, isInstallationMode = false)
|
|
246
247
|
{
|
|
247
248
|
let driverType = sc.get(DriversClassMap, server.constructor.name, '');
|
|
248
249
|
Logger.debug('Driver type detected: '+driverType+', Server constructor: '+server.constructor.name);
|
|
249
|
-
if('prisma' === driverType){
|
|
250
|
+
if('prisma' === driverType && !isInstallationMode){
|
|
251
|
+
Logger.info('Running prisma introspect "npx prisma db pull"...');
|
|
250
252
|
let dbConfig = this.extractDbConfigFromServer(server);
|
|
251
253
|
Logger.debug('Extracted DB config:', dbConfig);
|
|
252
254
|
if(dbConfig){
|
|
253
255
|
let generatedPrismaSchema = await this.generatePrismaSchema(dbConfig);
|
|
254
256
|
if(!generatedPrismaSchema){
|
|
255
|
-
Logger.error('
|
|
257
|
+
Logger.error('Prisma schema generation failed.');
|
|
256
258
|
return false;
|
|
257
259
|
}
|
|
258
260
|
Logger.info('Generated Prisma schema for entities generation.');
|
|
259
261
|
}
|
|
260
262
|
}
|
|
261
|
-
let
|
|
263
|
+
let generatorConfig = {
|
|
264
|
+
server,
|
|
265
|
+
projectPath: this.projectRoot,
|
|
266
|
+
isOverride
|
|
267
|
+
};
|
|
268
|
+
if('prisma' === driverType && this.prismaClient){
|
|
269
|
+
generatorConfig.prismaClient = this.prismaClient;
|
|
270
|
+
}
|
|
271
|
+
let generator = new EntitiesGenerator(generatorConfig);
|
|
262
272
|
let success = await generator.generate();
|
|
263
273
|
if(!success){
|
|
264
274
|
Logger.error('Entities generation failed.');
|
|
@@ -303,7 +313,8 @@ class Installer
|
|
|
303
313
|
let generator = new PrismaSchemaGenerator({
|
|
304
314
|
...connectionData,
|
|
305
315
|
dataProxy: useDataProxy,
|
|
306
|
-
|
|
316
|
+
clientOutputPath: FileHandler.joinPaths(this.projectRoot, 'prisma', 'client'),
|
|
317
|
+
prismaSchemaPath: FileHandler.joinPaths(this.projectRoot, 'prisma')
|
|
307
318
|
});
|
|
308
319
|
let success = await generator.generate();
|
|
309
320
|
if(!success){
|
|
@@ -363,12 +374,22 @@ class Installer
|
|
|
363
374
|
async createIndexJsFile(templateVariables)
|
|
364
375
|
{
|
|
365
376
|
if(!FileHandler.exists(this.indexTemplatePath)){
|
|
366
|
-
Logger.error('Index.js template not found: '+this.indexTemplatePath);
|
|
377
|
+
Logger.error('Index.js template not found: ' + this.indexTemplatePath);
|
|
367
378
|
return false;
|
|
368
379
|
}
|
|
369
380
|
let indexTemplate = FileHandler.readFile(this.indexTemplatePath);
|
|
370
381
|
let driverKey = templateVariables['db-storage-driver'];
|
|
371
|
-
let
|
|
382
|
+
let templateParams = {driverKey};
|
|
383
|
+
if('prisma' === driverKey){
|
|
384
|
+
let prismaClientPath = FileHandler.joinPaths(this.projectRoot, 'prisma', 'client');
|
|
385
|
+
templateParams.prismaClientImports = 'const { PrismaClient } = require(\'' + prismaClientPath + '\');';
|
|
386
|
+
templateParams.prismaClientParam = ',\n prismaClient: new PrismaClient()';
|
|
387
|
+
}
|
|
388
|
+
if('prisma' !== driverKey){
|
|
389
|
+
templateParams.prismaClientImports = '';
|
|
390
|
+
templateParams.prismaClientParam = '';
|
|
391
|
+
}
|
|
392
|
+
let indexContent = this.renderEngine.render(indexTemplate, templateParams);
|
|
372
393
|
let indexFilePath = FileHandler.joinPaths(this.projectRoot, 'index.js');
|
|
373
394
|
if(FileHandler.exists(indexFilePath)){
|
|
374
395
|
Logger.info('Index.js file already exists, the CMS installer will not override the existent one.');
|
package/lib/manager.js
CHANGED
|
@@ -14,6 +14,7 @@ const { TemplatesToPathMapper } = require('./templates-to-path-mapper');
|
|
|
14
14
|
const { AdminEntitiesGenerator } = require('./admin-entities-generator');
|
|
15
15
|
const { LoadedEntitiesProcessor } = require('./loaded-entities-processor');
|
|
16
16
|
const { AdminManager } = require('./admin-manager');
|
|
17
|
+
const { CmsPagesRouteManager } = require('./cms-pages-route-manager');
|
|
17
18
|
const { Installer } = require('./installer');
|
|
18
19
|
const { Frontend } = require('./frontend');
|
|
19
20
|
const { EventsManagerSingleton, Logger, sc } = require('@reldens/utils');
|
|
@@ -47,6 +48,7 @@ class Manager
|
|
|
47
48
|
this.mimeTypes = sc.get(props, 'mimeTypes', MimeTypes);
|
|
48
49
|
this.allowedExtensions = sc.get(props, 'allowedExtensions', AllowedExtensions)
|
|
49
50
|
this.adminRoleId = sc.get(props, 'adminRoleId', 99);
|
|
51
|
+
this.mappedAdminTemplates = TemplatesToPathMapper.map(this.adminTemplatesList, this.projectAdminTemplatesPath);
|
|
50
52
|
this.stylesFilePath = sc.get(props, 'stylesFilePath', '/css/reldens-admin-client.css');
|
|
51
53
|
this.scriptsFilePath = sc.get(props, 'scriptsFilePath', '/js/reldens-admin-client.js');
|
|
52
54
|
this.companyName = sc.get(props, 'companyName', 'Reldens - CMS');
|
|
@@ -62,16 +64,22 @@ class Manager
|
|
|
62
64
|
this.adminManager = sc.get(props, 'adminManager', false);
|
|
63
65
|
this.frontend = sc.get(props, 'frontend', false);
|
|
64
66
|
this.renderEngine = sc.get(props, 'renderEngine', mustache);
|
|
67
|
+
this.prismaClient = sc.get(props, 'prismaClient', false);
|
|
65
68
|
this.appServerFactory = new AppServerFactory();
|
|
66
69
|
this.adminEntitiesGenerator = new AdminEntitiesGenerator();
|
|
67
70
|
this.installer = new Installer({
|
|
68
71
|
projectRoot: this.projectRoot,
|
|
72
|
+
prismaClient: this.prismaClient,
|
|
69
73
|
postInstallCallback: this.initializeCmsAfterInstall.bind(this)
|
|
70
74
|
});
|
|
71
75
|
this.useProvidedServer = this.validateProvidedServer();
|
|
72
76
|
this.useProvidedDataServer = this.validateProvidedDataServer();
|
|
73
77
|
this.useProvidedAdminManager = this.validateProvidedAdminManager();
|
|
74
78
|
this.useProvidedFrontend = this.validateProvidedFrontend();
|
|
79
|
+
this.cmsPagesRouteManager = new CmsPagesRouteManager({
|
|
80
|
+
dataServer: this.dataServer,
|
|
81
|
+
events: this.events
|
|
82
|
+
});
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
validateProvidedServer()
|
|
@@ -206,8 +214,10 @@ class Manager
|
|
|
206
214
|
|
|
207
215
|
async initializeServices()
|
|
208
216
|
{
|
|
217
|
+
this.events.emit('reldens.cmsManagerInitializeServices', {manager: this});
|
|
209
218
|
if(!this.useProvidedDataServer){
|
|
210
219
|
if(!await this.initializeDataServer()){
|
|
220
|
+
Logger.debug('Initialize Data Server failed.');
|
|
211
221
|
return false;
|
|
212
222
|
}
|
|
213
223
|
}
|
|
@@ -215,32 +225,41 @@ class Manager
|
|
|
215
225
|
await this.setupEntityAccess();
|
|
216
226
|
}
|
|
217
227
|
if(!this.loadProcessedEntities()){
|
|
228
|
+
Logger.debug('Load Processed Entities for Entities failed.');
|
|
218
229
|
return false;
|
|
219
230
|
}
|
|
220
231
|
if(!await this.generateAdminEntities()){
|
|
232
|
+
Logger.debug('Generate Admin Entities for Entities failed.');
|
|
221
233
|
return false;
|
|
222
234
|
}
|
|
223
235
|
if(!this.useProvidedAdminManager){
|
|
224
236
|
if(!await this.initializeAdminManager()){
|
|
237
|
+
Logger.debug('Initialize Admin Manager failed.');
|
|
225
238
|
return false;
|
|
226
239
|
}
|
|
227
240
|
}
|
|
241
|
+
if(!await this.initializeCmsPagesRouteManager()){
|
|
242
|
+
Logger.debug('Initialize CMS Pages Route Manager failed.');
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
228
245
|
if(!this.useProvidedFrontend){
|
|
229
246
|
if(!await this.initializeFrontend()){
|
|
247
|
+
Logger.debug('Initialize Frontend failed.');
|
|
230
248
|
return false;
|
|
231
249
|
}
|
|
232
250
|
}
|
|
233
251
|
if(!this.useProvidedServer){
|
|
234
252
|
await this.appServer.listen(this.config.port);
|
|
235
253
|
}
|
|
254
|
+
Logger.debug('Initialize Services successfully.');
|
|
236
255
|
return true;
|
|
237
256
|
}
|
|
238
257
|
|
|
239
258
|
async setupEntityAccess()
|
|
240
259
|
{
|
|
241
|
-
let accessEntity = this.dataServer.getEntity('
|
|
260
|
+
let accessEntity = this.dataServer.getEntity('entitiesAccess');
|
|
242
261
|
if(!accessEntity){
|
|
243
|
-
Logger.warning('
|
|
262
|
+
Logger.warning('Entities Access not found.');
|
|
244
263
|
return;
|
|
245
264
|
}
|
|
246
265
|
for(let entityName of Object.keys(this.entityAccess)){
|
|
@@ -305,12 +324,15 @@ class Manager
|
|
|
305
324
|
},
|
|
306
325
|
rawEntities: this.rawRegisteredEntities
|
|
307
326
|
};
|
|
308
|
-
let
|
|
309
|
-
if(!
|
|
327
|
+
let driverClass = DriversMap[this.config.database.driver];
|
|
328
|
+
if(!driverClass){
|
|
310
329
|
Logger.critical('Invalid database driver: '+this.config.database.driver);
|
|
311
330
|
return false;
|
|
312
331
|
}
|
|
313
|
-
this.
|
|
332
|
+
if('prisma' === this.config.database.driver && this.prismaClient){
|
|
333
|
+
dbConfig.prismaClient = this.prismaClient;
|
|
334
|
+
}
|
|
335
|
+
this.dataServer = new driverClass(dbConfig);
|
|
314
336
|
if(!await this.dataServer.connect()){
|
|
315
337
|
Logger.critical('Failed to connect to database.');
|
|
316
338
|
return false;
|
|
@@ -347,6 +369,14 @@ class Manager
|
|
|
347
369
|
return passwordResult;
|
|
348
370
|
};
|
|
349
371
|
}
|
|
372
|
+
let adminFilesContents = await AdminTemplatesLoader.fetchAdminFilesContents(this.mappedAdminTemplates);
|
|
373
|
+
let translations = AdminTranslations.appendTranslations(this.entitiesTranslations || {});
|
|
374
|
+
this.events.emit('reldens.manager.initializeAdminManager', {
|
|
375
|
+
manager: this,
|
|
376
|
+
authenticationCallback,
|
|
377
|
+
adminFilesContents,
|
|
378
|
+
translations
|
|
379
|
+
});
|
|
350
380
|
let adminConfig = {
|
|
351
381
|
events: this.events,
|
|
352
382
|
dataServer: this.dataServer,
|
|
@@ -358,10 +388,8 @@ class Manager
|
|
|
358
388
|
renderCallback: this.renderCallback.bind(this),
|
|
359
389
|
secret: this.config.adminSecret,
|
|
360
390
|
rootPath: this.config.adminPath,
|
|
361
|
-
translations:
|
|
362
|
-
adminFilesContents
|
|
363
|
-
TemplatesToPathMapper.map(this.adminTemplatesList, this.projectAdminTemplatesPath)
|
|
364
|
-
),
|
|
391
|
+
translations: translations,
|
|
392
|
+
adminFilesContents,
|
|
365
393
|
mimeTypes: this.mimeTypes,
|
|
366
394
|
allowedExtensions: this.allowedExtensions,
|
|
367
395
|
adminRoleId: this.adminRoleId,
|
|
@@ -381,6 +409,17 @@ class Manager
|
|
|
381
409
|
return true;
|
|
382
410
|
}
|
|
383
411
|
|
|
412
|
+
async initializeCmsPagesRouteManager()
|
|
413
|
+
{
|
|
414
|
+
if(!this.dataServer){
|
|
415
|
+
Logger.warning('CmsPagesRouteManager initialization skipped - missing dataServer.');
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
this.cmsPagesRouteManager.dataServer = this.dataServer;
|
|
419
|
+
Logger.debug('CmsPagesRouteManager initialized successfully');
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
|
|
384
423
|
async renderCallback(template, params = {})
|
|
385
424
|
{
|
|
386
425
|
if(!template){
|