@reldens/cms 0.5.0 → 0.7.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 +1 -1
- package/admin/assets/admin/filters.png +0 -0
- package/admin/assets/admin/list.png +0 -0
- package/admin/reldens-admin-client.css +830 -0
- package/admin/reldens-admin-client.js +272 -0
- package/admin/templates/dashboard.html +1 -0
- package/admin/templates/default-copyright.html +5 -0
- package/admin/templates/edit.html +25 -0
- package/admin/templates/fields/edit/button.html +3 -0
- package/admin/templates/fields/edit/checkbox.html +1 -0
- package/admin/templates/fields/edit/file.html +2 -0
- package/admin/templates/fields/edit/radio.html +1 -0
- package/admin/templates/fields/edit/select.html +5 -0
- package/admin/templates/fields/edit/text.html +1 -0
- package/admin/templates/fields/edit/textarea.html +1 -0
- package/admin/templates/fields/view/boolean.html +1 -0
- package/admin/templates/fields/view/image.html +4 -0
- package/admin/templates/fields/view/images.html +7 -0
- package/admin/templates/fields/view/link.html +1 -0
- package/admin/templates/fields/view/links.html +6 -0
- package/admin/templates/fields/view/text.html +1 -0
- package/admin/templates/layout.html +37 -0
- package/admin/templates/list-content.html +70 -0
- package/admin/templates/list.html +35 -0
- package/admin/templates/login.html +19 -0
- package/admin/templates/management.html +22 -0
- package/admin/templates/pagination-link.html +1 -0
- package/admin/templates/sidebar-header.html +4 -0
- package/admin/templates/sidebar-item.html +3 -0
- package/admin/templates/sidebar.html +11 -0
- package/admin/templates/view.html +23 -0
- package/bin/reldens-cms.js +20 -8
- package/index.js +2 -2
- package/install/index.html +0 -7
- package/install/success.html +30 -0
- package/lib/admin-manager.js +1 -1
- package/lib/admin-templates-loader.js +37 -0
- package/lib/admin-translations.js +4 -218
- package/lib/allowed-extensions.js +11 -0
- package/lib/entities-loader.js +42 -0
- package/lib/{storefront.js → frontend.js} +14 -19
- package/lib/installer.js +137 -52
- package/lib/loaded-entities-processor.js +30 -0
- package/lib/manager.js +135 -37
- package/lib/mime-types.js +35 -0
- package/lib/templates-list.js +0 -9
- package/lib/templates-to-path-mapper.js +28 -0
- package/migrations/default-user.sql +2 -1
- package/package.json +2 -2
- package/templates/.env.dist +11 -11
- package/templates/assets/web/loading.gif +0 -0
- package/templates/assets/web/reldens-your-logo-mage.png +0 -0
- package/templates/css/styles.css +1 -1
- package/templates/index.js.dist +32 -0
- package/templates/js/scripts.js +1 -1
package/lib/installer.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
const { FileHandler, Encryptor } = require('@reldens/server-utils');
|
|
8
8
|
const { DriversMap, EntitiesGenerator, PrismaSchemaGenerator } = require('@reldens/storage');
|
|
9
|
+
const { EntitiesLoader } = require('./entities-loader');
|
|
10
|
+
const { AdminEntitiesGenerator } = require('./admin-entities-generator');
|
|
9
11
|
const { Logger, sc } = require('@reldens/utils');
|
|
10
12
|
const mustache = require('mustache');
|
|
11
13
|
|
|
@@ -15,15 +17,26 @@ class Installer
|
|
|
15
17
|
constructor(props)
|
|
16
18
|
{
|
|
17
19
|
this.app = sc.get(props, 'app', false);
|
|
20
|
+
this.appServer = sc.get(props, 'appServer', false);
|
|
18
21
|
this.appServerFactory = sc.get(props, 'appServerFactory', false);
|
|
19
22
|
this.projectRoot = sc.get(props, 'projectRoot', './');
|
|
20
|
-
this.
|
|
23
|
+
this.projectTemplatesPath = FileHandler.joinPaths(this.projectRoot, 'templates');
|
|
24
|
+
this.projectPublicPath = FileHandler.joinPaths(this.projectRoot, 'public');
|
|
25
|
+
this.projectPublicAssetsPath = FileHandler.joinPaths(this.projectPublicPath, 'assets');
|
|
26
|
+
this.projectCssPath = FileHandler.joinPaths(this.projectPublicPath, 'css');
|
|
27
|
+
this.projectJsPath = FileHandler.joinPaths(this.projectPublicPath, 'js');
|
|
21
28
|
this.installLockPath = FileHandler.joinPaths(this.projectRoot, 'install.lock');
|
|
22
29
|
this.envFilePath = FileHandler.joinPaths(this.projectRoot, '.env');
|
|
23
30
|
this.modulePath = FileHandler.joinPaths(__dirname, '..');
|
|
24
31
|
this.installerPath = FileHandler.joinPaths(this.modulePath, 'install');
|
|
25
32
|
this.migrationsPath = FileHandler.joinPaths(this.modulePath, 'migrations');
|
|
26
33
|
this.defaultTemplatesPath = FileHandler.joinPaths(this.modulePath, 'templates');
|
|
34
|
+
this.moduleAdminPath = FileHandler.joinPaths(this.modulePath, 'admin');
|
|
35
|
+
this.moduleAdminAssetsPath = FileHandler.joinPaths(this.moduleAdminPath, 'assets');
|
|
36
|
+
this.moduleAdminTemplatesPath = FileHandler.joinPaths(this.moduleAdminPath, 'templates')
|
|
37
|
+
this.indexTemplatePath = FileHandler.joinPaths(this.defaultTemplatesPath, 'index.js.dist');
|
|
38
|
+
this.postInstallCallback = sc.get(props, 'postInstallCallback', false);
|
|
39
|
+
this.entitiesLoader = new EntitiesLoader({projectRoot: this.projectRoot});
|
|
27
40
|
}
|
|
28
41
|
|
|
29
42
|
isInstalled()
|
|
@@ -31,7 +44,7 @@ class Installer
|
|
|
31
44
|
return FileHandler.exists(this.installLockPath);
|
|
32
45
|
}
|
|
33
46
|
|
|
34
|
-
async prepareSetup(app, appServerFactory)
|
|
47
|
+
async prepareSetup(app, appServer, appServerFactory)
|
|
35
48
|
{
|
|
36
49
|
if(!app){
|
|
37
50
|
Logger.error('Missing app on prepareSetup for Installer.');
|
|
@@ -43,6 +56,7 @@ class Installer
|
|
|
43
56
|
}
|
|
44
57
|
this.app = app;
|
|
45
58
|
this.appServerFactory = appServerFactory;
|
|
59
|
+
this.appServer = appServer;
|
|
46
60
|
app.use('/install-assets', appServerFactory.applicationFramework.static(this.installerPath, {index: false}));
|
|
47
61
|
app.use(appServerFactory.session({
|
|
48
62
|
secret: Encryptor.generateSecretKey(),
|
|
@@ -63,18 +77,44 @@ class Installer
|
|
|
63
77
|
if(this.isInstalled()){
|
|
64
78
|
return next();
|
|
65
79
|
}
|
|
66
|
-
|
|
80
|
+
let urlPath = req._parsedUrl.pathname;
|
|
81
|
+
if('' === urlPath || '/' === urlPath){
|
|
67
82
|
let installerIndexPath = FileHandler.joinPaths(this.installerPath, 'index.html');
|
|
68
83
|
if(!FileHandler.exists(installerIndexPath)){
|
|
69
84
|
return res.status(500).send('Installer template not found.');
|
|
70
85
|
}
|
|
71
86
|
let content = FileHandler.readFile(installerIndexPath);
|
|
72
87
|
let contentParams = req.session?.templateVariables || this.fetchDefaults();
|
|
88
|
+
let errorParam = req.query?.error;
|
|
89
|
+
if(errorParam){
|
|
90
|
+
contentParams.errorMessage = this.getErrorMessage(errorParam);
|
|
91
|
+
}
|
|
73
92
|
return res.send(mustache.render(content, contentParams));
|
|
74
93
|
}
|
|
94
|
+
if('/install' !== urlPath){
|
|
95
|
+
return res.redirect('/');
|
|
96
|
+
}
|
|
75
97
|
next();
|
|
76
98
|
}
|
|
77
99
|
|
|
100
|
+
getErrorMessage(errorCode)
|
|
101
|
+
{
|
|
102
|
+
let errorMessages = {
|
|
103
|
+
'invalid-driver': 'Invalid storage driver selected.',
|
|
104
|
+
'connection-failed': 'Database connection failed. Please check your credentials.',
|
|
105
|
+
'raw-query-not-found': 'Query method not found in driver.',
|
|
106
|
+
'sql-file-not-found': 'SQL installation file not found.',
|
|
107
|
+
'sql-tables-creation-failed': 'Failed to create database tables.',
|
|
108
|
+
'sql-default-user-error': 'Failed to create default user.',
|
|
109
|
+
'installation-entities-generation-failed': 'Failed to generate entities.',
|
|
110
|
+
'installation-process-failed': 'Installation process failed.',
|
|
111
|
+
'installation-entities-callback-failed': 'Failed to process entities for callback.',
|
|
112
|
+
'configuration-error': 'Configuration error while completing installation.',
|
|
113
|
+
'already-installed': 'The application is already installed.'
|
|
114
|
+
};
|
|
115
|
+
return errorMessages[errorCode] || 'An unknown error occurred during installation.';
|
|
116
|
+
}
|
|
117
|
+
|
|
78
118
|
async executeInstallProcess(req, res)
|
|
79
119
|
{
|
|
80
120
|
if(this.isInstalled()){
|
|
@@ -101,7 +141,11 @@ class Installer
|
|
|
101
141
|
debug: false
|
|
102
142
|
};
|
|
103
143
|
if('prisma' === selectedDriver){
|
|
104
|
-
await this.generatePrismaSchema(dbConfig);
|
|
144
|
+
let generatedPrismaSchema = await this.generatePrismaSchema(dbConfig);
|
|
145
|
+
if(!generatedPrismaSchema){
|
|
146
|
+
Logger.error('Could not generated Prisma schema.');
|
|
147
|
+
return res.redirect('/?error=prisma-schema-generation-error');
|
|
148
|
+
}
|
|
105
149
|
Logger.info('Generated Prisma schema.');
|
|
106
150
|
}
|
|
107
151
|
let dbDriver = new driverClass(dbConfig);
|
|
@@ -129,7 +173,7 @@ class Installer
|
|
|
129
173
|
if(FileHandler.exists(defaultUserSqlPath)){
|
|
130
174
|
let queryUserResult = await this.executeQueryFile(dbDriver, defaultUserSqlPath);
|
|
131
175
|
if(!queryUserResult){
|
|
132
|
-
Logger.error('Default user creation failed.');
|
|
176
|
+
Logger.error('Default user creation failed.', queryUserResult);
|
|
133
177
|
return res.redirect('/?error=sql-default-user-error');
|
|
134
178
|
}
|
|
135
179
|
Logger.info('Created default user.');
|
|
@@ -144,19 +188,29 @@ class Installer
|
|
|
144
188
|
Logger.error('Installation error: '+error.message);
|
|
145
189
|
return res.redirect('/?error=installation-process-failed');
|
|
146
190
|
}
|
|
147
|
-
if('' === templateVariables['app-admin-path']){
|
|
148
|
-
templateVariables['app-admin-path'] = '/reldens-admin';
|
|
149
|
-
}
|
|
150
191
|
try {
|
|
151
192
|
await this.createEnvFile(templateVariables);
|
|
152
|
-
await this.createLockFile();
|
|
153
193
|
await this.prepareProjectDirectories();
|
|
194
|
+
await this.copyAdminDirectory();
|
|
195
|
+
await this.createIndexJsFile(templateVariables);
|
|
196
|
+
if(sc.isFunction(this.postInstallCallback)){
|
|
197
|
+
if(this.appServer && sc.isFunction(this.appServer.close)){
|
|
198
|
+
await this.appServer.close();
|
|
199
|
+
}
|
|
200
|
+
Logger.debug('Running postInstallCallback.');
|
|
201
|
+
await this.postInstallCallback(this.entitiesLoader.loadEntities(selectedDriver));
|
|
202
|
+
}
|
|
203
|
+
await this.createLockFile();
|
|
154
204
|
Logger.info('Installation successful!');
|
|
155
|
-
let
|
|
156
|
-
|
|
205
|
+
let successContent = 'Installation successful! Run "node ." to start your CMS.';
|
|
206
|
+
let successFileContent = FileHandler.readFile(FileHandler.joinPaths(this.installerPath, 'success.html'));
|
|
207
|
+
if(successFileContent){
|
|
208
|
+
successContent = mustache.render(successFileContent, {adminPath: templateVariables['app-admin-path']});
|
|
209
|
+
}
|
|
210
|
+
return res.send(successContent);
|
|
157
211
|
} catch (error) {
|
|
158
|
-
Logger.
|
|
159
|
-
return res.redirect('/?error=
|
|
212
|
+
Logger.critical('Configuration error: '+error.message);
|
|
213
|
+
return res.redirect('/?error=installation-error');
|
|
160
214
|
}
|
|
161
215
|
}
|
|
162
216
|
|
|
@@ -213,56 +267,87 @@ class Installer
|
|
|
213
267
|
dbDriver: templateVariables['db-storage-driver'],
|
|
214
268
|
adminPath: templateVariables['app-admin-path'],
|
|
215
269
|
adminSecret: Encryptor.generateSecretKey(),
|
|
216
|
-
host: templateVariables['app-host']
|
|
217
|
-
port: templateVariables['app-port']
|
|
270
|
+
host: templateVariables['app-host'],
|
|
271
|
+
port: templateVariables['app-port']
|
|
218
272
|
});
|
|
219
273
|
return FileHandler.writeFile(this.envFilePath, envContent);
|
|
220
274
|
}
|
|
221
275
|
|
|
276
|
+
async createIndexJsFile(templateVariables)
|
|
277
|
+
{
|
|
278
|
+
if(!FileHandler.exists(this.indexTemplatePath)){
|
|
279
|
+
Logger.error('Index.js template not found: '+this.indexTemplatePath);
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
let indexTemplate = FileHandler.readFile(this.indexTemplatePath);
|
|
283
|
+
let driverKey = templateVariables['db-storage-driver'];
|
|
284
|
+
let indexContent = mustache.render(indexTemplate, {driverKey});
|
|
285
|
+
let indexFilePath = FileHandler.joinPaths(this.projectRoot, 'index.js');
|
|
286
|
+
if(FileHandler.exists(indexFilePath)){
|
|
287
|
+
Logger.info('Index.js file already exists, the CMS installer will not override the existent one.');
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
return FileHandler.writeFile(indexFilePath, indexContent);
|
|
291
|
+
}
|
|
292
|
+
|
|
222
293
|
async createLockFile()
|
|
223
294
|
{
|
|
224
|
-
return FileHandler.writeFile(this.installLockPath,
|
|
225
|
-
'Installation completed on '+new Date().toISOString());
|
|
295
|
+
return FileHandler.writeFile(this.installLockPath, 'Installation completed on '+new Date().toISOString());
|
|
226
296
|
}
|
|
227
297
|
|
|
228
|
-
async
|
|
298
|
+
async copyAdminDirectory()
|
|
229
299
|
{
|
|
230
|
-
let
|
|
231
|
-
if(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
let projectPublicPath = FileHandler.joinPaths(this.projectRoot, 'public');
|
|
235
|
-
if(!FileHandler.exists(projectPublicPath)){
|
|
236
|
-
FileHandler.createFolder(projectPublicPath);
|
|
237
|
-
}
|
|
238
|
-
let projectCssPath = FileHandler.joinPaths(projectPublicPath, 'css');
|
|
239
|
-
if(!FileHandler.exists(projectCssPath)){
|
|
240
|
-
FileHandler.createFolder(projectCssPath);
|
|
241
|
-
}
|
|
242
|
-
let projectJsPath = FileHandler.joinPaths(projectPublicPath, 'js');
|
|
243
|
-
if(!FileHandler.exists(projectJsPath)){
|
|
244
|
-
FileHandler.createFolder(projectJsPath);
|
|
245
|
-
}
|
|
246
|
-
let defaultPagePath = FileHandler.joinPaths(this.defaultTemplatesPath, 'page.html');
|
|
247
|
-
let defaultNotFoundPath = FileHandler.joinPaths(this.defaultTemplatesPath, '404.html');
|
|
248
|
-
let defaultLayoutPath = FileHandler.joinPaths(this.defaultTemplatesPath, 'layout.html');
|
|
249
|
-
if(FileHandler.exists(defaultPagePath)){
|
|
250
|
-
FileHandler.copyFile(defaultPagePath, FileHandler.joinPaths(projectTemplatesPath, 'page.html'));
|
|
251
|
-
}
|
|
252
|
-
if(FileHandler.exists(defaultNotFoundPath)){
|
|
253
|
-
FileHandler.copyFile(defaultNotFoundPath, FileHandler.joinPaths(projectTemplatesPath, '404.html'));
|
|
300
|
+
let projectAdminPath = FileHandler.joinPaths(this.projectRoot, 'admin');
|
|
301
|
+
if(FileHandler.exists(projectAdminPath)){
|
|
302
|
+
Logger.info('Admin folder already exists in project root.');
|
|
303
|
+
return true;
|
|
254
304
|
}
|
|
255
|
-
if(FileHandler.exists(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
let defaultCssPath = FileHandler.joinPaths(this.defaultTemplatesPath, 'css', 'styles.css');
|
|
259
|
-
let defaultJsPath = FileHandler.joinPaths(this.defaultTemplatesPath, 'js', 'scripts.js');
|
|
260
|
-
if(FileHandler.exists(defaultCssPath)){
|
|
261
|
-
FileHandler.copyFile(defaultCssPath, FileHandler.joinPaths(projectCssPath, 'styles.css'));
|
|
262
|
-
}
|
|
263
|
-
if(FileHandler.exists(defaultJsPath)){
|
|
264
|
-
FileHandler.copyFile(defaultJsPath, FileHandler.joinPaths(projectJsPath, 'scripts.js'));
|
|
305
|
+
if(!FileHandler.exists(this.moduleAdminPath)){
|
|
306
|
+
Logger.error('Admin folder not found in module path: '+this.moduleAdminPath);
|
|
307
|
+
return false;
|
|
265
308
|
}
|
|
309
|
+
let projectAdminTemplates = FileHandler.joinPaths(projectAdminPath, 'templates');
|
|
310
|
+
FileHandler.copyFolderSync(this.moduleAdminTemplatesPath, projectAdminTemplates);
|
|
311
|
+
FileHandler.copyFolderSync(this.moduleAdminAssetsPath, this.projectPublicAssetsPath);
|
|
312
|
+
FileHandler.copyFile(
|
|
313
|
+
FileHandler.joinPaths(this.moduleAdminPath, 'reldens-admin-client.css'),
|
|
314
|
+
FileHandler.joinPaths(this.projectCssPath, 'reldens-admin-client.css'),
|
|
315
|
+
);
|
|
316
|
+
FileHandler.copyFile(
|
|
317
|
+
FileHandler.joinPaths(this.moduleAdminPath, 'reldens-admin-client.js'),
|
|
318
|
+
FileHandler.joinPaths(this.projectJsPath, 'reldens-admin-client.js'),
|
|
319
|
+
);
|
|
320
|
+
Logger.info('Admin folder copied to project root.');
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async prepareProjectDirectories()
|
|
325
|
+
{
|
|
326
|
+
FileHandler.createFolder(this.projectTemplatesPath);
|
|
327
|
+
FileHandler.createFolder(this.projectPublicPath);
|
|
328
|
+
FileHandler.createFolder(this.projectPublicAssetsPath);
|
|
329
|
+
FileHandler.createFolder(this.projectCssPath);
|
|
330
|
+
FileHandler.createFolder(this.projectJsPath);
|
|
331
|
+
FileHandler.copyFile(
|
|
332
|
+
FileHandler.joinPaths(this.defaultTemplatesPath, 'page.html'),
|
|
333
|
+
FileHandler.joinPaths(this.projectTemplatesPath, 'page.html')
|
|
334
|
+
);
|
|
335
|
+
FileHandler.copyFile(
|
|
336
|
+
FileHandler.joinPaths(this.defaultTemplatesPath, '404.html'),
|
|
337
|
+
FileHandler.joinPaths(this.projectTemplatesPath, '404.html')
|
|
338
|
+
);
|
|
339
|
+
FileHandler.copyFile(
|
|
340
|
+
FileHandler.joinPaths(this.defaultTemplatesPath, 'layout.html'),
|
|
341
|
+
FileHandler.joinPaths(this.projectTemplatesPath, 'layout.html')
|
|
342
|
+
);
|
|
343
|
+
FileHandler.copyFile(
|
|
344
|
+
FileHandler.joinPaths(this.defaultTemplatesPath, 'css', 'styles.css'),
|
|
345
|
+
FileHandler.joinPaths(this.projectCssPath, 'styles.css')
|
|
346
|
+
);
|
|
347
|
+
FileHandler.copyFile(
|
|
348
|
+
FileHandler.joinPaths(this.defaultTemplatesPath, 'js', 'scripts.js'),
|
|
349
|
+
FileHandler.joinPaths(this.projectJsPath, 'scripts.js')
|
|
350
|
+
);
|
|
266
351
|
return true;
|
|
267
352
|
}
|
|
268
353
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - LoadedEntitiesProcessor
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { sc } = require('@reldens/utils');
|
|
8
|
+
|
|
9
|
+
class LoadedEntitiesProcessor
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
process(rawRegisteredEntities, entitiesTranslations, entitiesConfig)
|
|
13
|
+
{
|
|
14
|
+
let exportedEntitiesList = Object.keys(rawRegisteredEntities);
|
|
15
|
+
if(0 === exportedEntitiesList.length){
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
let entities = {};
|
|
19
|
+
for (let i of exportedEntitiesList) {
|
|
20
|
+
entities[i] = {
|
|
21
|
+
rawEntity: rawRegisteredEntities[i],
|
|
22
|
+
config: sc.isFunction(entitiesConfig) ? entitiesConfig(props)[i] : entitiesConfig[i]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {entities, entitiesRaw: rawRegisteredEntities, translations: entitiesTranslations};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports.LoadedEntitiesProcessor = new LoadedEntitiesProcessor();
|
package/lib/manager.js
CHANGED
|
@@ -4,17 +4,27 @@
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const {
|
|
8
|
-
const {
|
|
7
|
+
const { TemplatesList } = require('./templates-list');
|
|
8
|
+
const { AdminTranslations } = require('./admin-translations');
|
|
9
|
+
const { AdminTemplatesLoader } = require('./admin-templates-loader');
|
|
10
|
+
const { AdminManagerValidator } = require('./admin-manager-validator');
|
|
11
|
+
const { MimeTypes } = require('./mime-types');
|
|
12
|
+
const { AllowedExtensions } = require('./allowed-extensions');
|
|
13
|
+
const { TemplatesToPathMapper } = require('./templates-to-path-mapper');
|
|
14
|
+
const { AdminEntitiesGenerator } = require('./admin-entities-generator');
|
|
15
|
+
const { LoadedEntitiesProcessor } = require('./loaded-entities-processor');
|
|
9
16
|
const { AdminManager } = require('./admin-manager');
|
|
10
17
|
const { Installer } = require('./installer');
|
|
11
|
-
const {
|
|
12
|
-
const { Logger, sc } = require('@reldens/utils');
|
|
18
|
+
const { Frontend } = require('./frontend');
|
|
19
|
+
const { EventsManagerSingleton, Logger, sc } = require('@reldens/utils');
|
|
20
|
+
const { DriversMap } = require('@reldens/storage');
|
|
21
|
+
const { AppServerFactory, FileHandler, Encryptor } = require('@reldens/server-utils');
|
|
13
22
|
const dotenv = require('dotenv');
|
|
14
23
|
const mustache = require('mustache');
|
|
15
24
|
|
|
16
25
|
class Manager
|
|
17
26
|
{
|
|
27
|
+
|
|
18
28
|
constructor(props = {})
|
|
19
29
|
{
|
|
20
30
|
this.projectRoot = sc.get(props, 'projectRoot', './');
|
|
@@ -22,35 +32,54 @@ class Manager
|
|
|
22
32
|
this.installLockPath = FileHandler.joinPaths(this.projectRoot, 'install.lock');
|
|
23
33
|
dotenv.config({path: this.envFilePath});
|
|
24
34
|
this.config = this.loadConfigFromEnv();
|
|
25
|
-
this.
|
|
35
|
+
this.adminEntities = sc.get(props, 'adminEntities', {});
|
|
36
|
+
this.rawRegisteredEntities = sc.get(props, 'rawRegisteredEntities', {});
|
|
37
|
+
this.entitiesTranslations = sc.get(props, 'entitiesTranslations', {});
|
|
38
|
+
this.entitiesConfig = sc.get(props, 'entitiesConfig', {});
|
|
39
|
+
this.processedEntities = sc.get(props, 'processedEntities', {});
|
|
26
40
|
this.authenticationMethod = sc.get(props, 'authenticationMethod', 'db-users');
|
|
27
41
|
this.authenticationCallback = sc.get(props, 'authenticationCallback', false);
|
|
42
|
+
this.events = sc.get(props, 'events', EventsManagerSingleton);
|
|
43
|
+
this.adminTemplatesList = sc.get(props, 'adminTemplatesList', TemplatesList);
|
|
44
|
+
this.projectAdminPath = FileHandler.joinPaths(this.projectRoot, 'admin');
|
|
45
|
+
this.projectAdminTemplatesPath = FileHandler.joinPaths(this.projectAdminPath, 'templates');
|
|
46
|
+
this.mimeTypes = sc.get(props, 'mimeTypes', MimeTypes);
|
|
47
|
+
this.allowedExtensions = sc.get(props, 'allowedExtensions', AllowedExtensions)
|
|
48
|
+
this.adminRoleId = sc.get(props, 'adminRoleId', 99);
|
|
49
|
+
this.stylesFilePath = sc.get(props, 'stylesFilePath', '/css/reldens-admin-client.css');
|
|
50
|
+
this.scriptsFilePath = sc.get(props, 'scriptsFilePath', '/js/reldens-admin-client.js');
|
|
51
|
+
this.companyName = sc.get(props, 'companyName', 'Reldens - CMS');
|
|
52
|
+
this.logo = sc.get(props, 'logo', '/assets/web/reldens-your-logo-mage.png');
|
|
53
|
+
this.favicon = sc.get(props, 'favicon', '/assets/web/favicon.ico');
|
|
28
54
|
this.appServerFactory = new AppServerFactory();
|
|
55
|
+
this.adminEntitiesGenerator = new AdminEntitiesGenerator();
|
|
29
56
|
this.installer = new Installer({
|
|
30
|
-
projectRoot: this.projectRoot
|
|
57
|
+
projectRoot: this.projectRoot,
|
|
58
|
+
postInstallCallback: this.initializeCmsAfterInstall.bind(this)
|
|
31
59
|
});
|
|
32
60
|
this.dataServer = false;
|
|
33
61
|
this.app = false;
|
|
34
62
|
this.appServer = false;
|
|
35
63
|
this.adminManager = false;
|
|
36
|
-
this.
|
|
64
|
+
this.frontend = false;
|
|
37
65
|
}
|
|
38
66
|
|
|
39
67
|
loadConfigFromEnv()
|
|
40
68
|
{
|
|
69
|
+
let envVars = process.env;
|
|
41
70
|
return {
|
|
42
|
-
host:
|
|
43
|
-
port: Number(
|
|
44
|
-
adminPath:
|
|
45
|
-
adminSecret:
|
|
71
|
+
host: sc.get(envVars, 'RELDENS_CMS_HOST', 'http://localhost'),
|
|
72
|
+
port: Number(sc.get(envVars, 'RELDENS_CMS_PORT', 8000)),
|
|
73
|
+
adminPath: sc.get(envVars, 'RELDENS_CMS_ADMIN_PATH', '/reldens-admin'),
|
|
74
|
+
adminSecret: sc.get(envVars, 'RELDENS_CMS_ADMIN_SECRET', ''),
|
|
46
75
|
database: {
|
|
47
|
-
client:
|
|
48
|
-
host:
|
|
49
|
-
port: Number(
|
|
50
|
-
name:
|
|
51
|
-
user:
|
|
52
|
-
password:
|
|
53
|
-
driver:
|
|
76
|
+
client: sc.get(envVars, 'RELDENS_CMS_DB_CLIENT', 'mysql'),
|
|
77
|
+
host: sc.get(envVars, 'RELDENS_CMS_DB_HOST', 'localhost'),
|
|
78
|
+
port: Number(sc.get(envVars, 'RELDENS_CMS_DB_PORT', 3306)),
|
|
79
|
+
name: sc.get(envVars, 'RELDENS_CMS_DB_NAME', 'reldens_cms'),
|
|
80
|
+
user: sc.get(envVars, 'RELDENS_CMS_DB_USER', ''),
|
|
81
|
+
password: sc.get(envVars, 'RELDENS_CMS_DB_PASSWORD', ''),
|
|
82
|
+
driver: sc.get(envVars, 'RELDENS_CMS_DB_DRIVER', 'prisma')
|
|
54
83
|
}
|
|
55
84
|
};
|
|
56
85
|
}
|
|
@@ -71,24 +100,64 @@ class Manager
|
|
|
71
100
|
this.appServer = createdAppServer.appServer;
|
|
72
101
|
if(!this.isInstalled()){
|
|
73
102
|
Logger.info('CMS not installed, preparing setup');
|
|
74
|
-
await this.installer.prepareSetup(this.app, this.appServerFactory);
|
|
103
|
+
await this.installer.prepareSetup(this.app, this.appServer, this.appServerFactory);
|
|
75
104
|
await this.appServer.listen(this.config.port);
|
|
76
105
|
Logger.info('Installer running on '+this.config.host+':'+this.config.port);
|
|
77
106
|
return true;
|
|
78
107
|
}
|
|
79
108
|
try {
|
|
80
|
-
await this.
|
|
81
|
-
await this.initializeAdminManager();
|
|
82
|
-
await this.initializeStorefront();
|
|
83
|
-
await this.appServer.listen(this.config.port);
|
|
109
|
+
await this.initializeServices();
|
|
84
110
|
Logger.info('CMS running on '+this.config.host+':'+this.config.port);
|
|
85
111
|
return true;
|
|
86
112
|
} catch (error) {
|
|
87
|
-
Logger.
|
|
113
|
+
Logger.critical('Failed to start CMS: '+error.message);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async initializeCmsAfterInstall(loadEntities)
|
|
119
|
+
{
|
|
120
|
+
try {
|
|
121
|
+
this.rawRegisteredEntities = loadEntities.rawRegisteredEntities;
|
|
122
|
+
this.entitiesTranslations = loadEntities.entitiesTranslations;
|
|
123
|
+
this.entitiesConfig = loadEntities.entitiesConfig;
|
|
124
|
+
this.dataServer.rawEntities = loadEntities.rawRegisteredEntities;
|
|
125
|
+
this.config = this.loadConfigFromEnv();
|
|
126
|
+
await this.initializeServices();
|
|
127
|
+
Logger.info('CMS initialized after installation on '+this.config.host+':'+this.config.port);
|
|
128
|
+
return true;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
Logger.critical('Failed to initialize CMS after installation: '+error.message);
|
|
88
131
|
return false;
|
|
89
132
|
}
|
|
90
133
|
}
|
|
91
134
|
|
|
135
|
+
async initializeServices()
|
|
136
|
+
{
|
|
137
|
+
await this.initializeDataServer();
|
|
138
|
+
if (0 === Object.keys(this.adminEntities).length){
|
|
139
|
+
if(0 === Object.keys(this.processedEntities).length){
|
|
140
|
+
this.processedEntities = LoadedEntitiesProcessor.process(
|
|
141
|
+
this.rawRegisteredEntities,
|
|
142
|
+
this.entitiesTranslations,
|
|
143
|
+
this.entitiesConfig
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
if(!this.processedEntities.entities){
|
|
147
|
+
Logger.critical('Processed entities undefined.');
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
await this.dataServer.generateEntities();
|
|
151
|
+
this.adminEntities = this.adminEntitiesGenerator.generate(
|
|
152
|
+
this.processedEntities.entities,
|
|
153
|
+
this.dataServer.entityManager.entities
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
await this.initializeAdminManager();
|
|
157
|
+
await this.initializeFrontend();
|
|
158
|
+
await this.appServer.listen(this.config.port);
|
|
159
|
+
}
|
|
160
|
+
|
|
92
161
|
async initializeDataServer()
|
|
93
162
|
{
|
|
94
163
|
let dbConfig = {
|
|
@@ -99,15 +168,18 @@ class Manager
|
|
|
99
168
|
database: this.config.database.name,
|
|
100
169
|
user: this.config.database.user,
|
|
101
170
|
password: this.config.database.password
|
|
102
|
-
}
|
|
171
|
+
},
|
|
172
|
+
rawEntities: this.rawRegisteredEntities
|
|
103
173
|
};
|
|
104
174
|
let DriverClass = DriversMap[this.config.database.driver];
|
|
105
175
|
if(!DriverClass){
|
|
106
|
-
|
|
176
|
+
Logger.critical('Invalid database driver: '+this.config.database.driver);
|
|
177
|
+
return false;
|
|
107
178
|
}
|
|
108
179
|
this.dataServer = new DriverClass(dbConfig);
|
|
109
180
|
if(!await this.dataServer.connect()){
|
|
110
|
-
|
|
181
|
+
Logger.critical('Failed to connect to database.');
|
|
182
|
+
return false;
|
|
111
183
|
}
|
|
112
184
|
await this.dataServer.generateEntities();
|
|
113
185
|
return true;
|
|
@@ -116,33 +188,58 @@ class Manager
|
|
|
116
188
|
async initializeAdminManager()
|
|
117
189
|
{
|
|
118
190
|
let authenticationCallback = this.authenticationCallback;
|
|
119
|
-
if('db-users' === this.authenticationMethod){
|
|
191
|
+
if('db-users' === this.authenticationMethod && !authenticationCallback){
|
|
120
192
|
authenticationCallback = async (email, password, roleId) => {
|
|
193
|
+
Logger.debug('Running default "db-users" authentication.');
|
|
121
194
|
let usersEntity = this.dataServer.getEntity('users');
|
|
122
195
|
if(!usersEntity){
|
|
196
|
+
Logger.critical('No users entity found.');
|
|
123
197
|
return false;
|
|
124
198
|
}
|
|
125
199
|
let user = await usersEntity.loadOneBy('email', email);
|
|
126
200
|
if(!user){
|
|
201
|
+
Logger.debug('User not found by email: '+email+'.', user);
|
|
127
202
|
return false;
|
|
128
203
|
}
|
|
129
204
|
if(Number(user.role_id) !== Number(roleId)){
|
|
205
|
+
Logger.debug('Invalid user role ID: '+roleId+' / '+user.role_id+'.');
|
|
130
206
|
return false;
|
|
131
207
|
}
|
|
132
|
-
|
|
208
|
+
let passwordResult = Encryptor.validatePassword(password, user.password) ? user : false;
|
|
209
|
+
if(!passwordResult){
|
|
210
|
+
Logger.debug('Invalid user password for: '+email+'.');
|
|
211
|
+
}
|
|
212
|
+
return passwordResult;
|
|
133
213
|
};
|
|
134
214
|
}
|
|
135
215
|
let adminConfig = {
|
|
136
|
-
events:
|
|
137
|
-
renderCallback: this.renderCallback.bind(this),
|
|
216
|
+
events: this.events,
|
|
138
217
|
dataServer: this.dataServer,
|
|
139
218
|
authenticationCallback,
|
|
140
219
|
app: this.app,
|
|
141
220
|
appServerFactory: this.appServerFactory,
|
|
221
|
+
entities: this.adminEntities,
|
|
222
|
+
validator: new AdminManagerValidator(),
|
|
223
|
+
renderCallback: this.renderCallback.bind(this),
|
|
142
224
|
secret: this.config.adminSecret,
|
|
143
225
|
rootPath: this.config.adminPath,
|
|
144
|
-
|
|
145
|
-
|
|
226
|
+
translations: AdminTranslations.appendTranslations(this.entitiesTranslations || {}),
|
|
227
|
+
adminFilesContents: await AdminTemplatesLoader.fetchAdminFilesContents(
|
|
228
|
+
TemplatesToPathMapper.map(this.adminTemplatesList, this.projectAdminTemplatesPath)
|
|
229
|
+
),
|
|
230
|
+
mimeTypes: this.mimeTypes,
|
|
231
|
+
allowedExtensions: this.allowedExtensions,
|
|
232
|
+
adminRoleId: this.adminRoleId,
|
|
233
|
+
stylesFilePath: this.stylesFilePath,
|
|
234
|
+
scriptsFilePath: this.scriptsFilePath,
|
|
235
|
+
branding: {
|
|
236
|
+
companyName: this.companyName,
|
|
237
|
+
logo: this.logo,
|
|
238
|
+
favicon: this.favicon,
|
|
239
|
+
copyRight: await FileHandler.fetchFileContents(
|
|
240
|
+
FileHandler.joinPaths(this.projectAdminTemplatesPath, this.adminTemplatesList.defaultCopyRight)
|
|
241
|
+
)
|
|
242
|
+
}
|
|
146
243
|
};
|
|
147
244
|
this.adminManager = new AdminManager(adminConfig);
|
|
148
245
|
await this.adminManager.setupAdmin();
|
|
@@ -157,14 +254,15 @@ class Manager
|
|
|
157
254
|
return mustache.render(template, params);
|
|
158
255
|
}
|
|
159
256
|
|
|
160
|
-
async
|
|
257
|
+
async initializeFrontend()
|
|
161
258
|
{
|
|
162
|
-
this.
|
|
259
|
+
this.frontend = new Frontend({
|
|
163
260
|
app: this.app,
|
|
164
261
|
dataServer: this.dataServer,
|
|
165
|
-
projectRoot: this.projectRoot
|
|
262
|
+
projectRoot: this.projectRoot,
|
|
263
|
+
appServerFactory: this.appServerFactory
|
|
166
264
|
});
|
|
167
|
-
return await this.
|
|
265
|
+
return await this.frontend.initialize();
|
|
168
266
|
}
|
|
169
267
|
}
|
|
170
268
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - MimeTypes
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
module.exports.MimeTypes = {
|
|
8
|
+
audio: [
|
|
9
|
+
'audio/aac',
|
|
10
|
+
'audio/midi',
|
|
11
|
+
'audio/x-midi',
|
|
12
|
+
'audio/mpeg',
|
|
13
|
+
'audio/ogg',
|
|
14
|
+
'application/ogg',
|
|
15
|
+
'audio/opus',
|
|
16
|
+
'audio/wav',
|
|
17
|
+
'audio/webm',
|
|
18
|
+
'audio/3gpp2'
|
|
19
|
+
],
|
|
20
|
+
image: [
|
|
21
|
+
'image/bmp',
|
|
22
|
+
'image/gif',
|
|
23
|
+
'image/jpeg',
|
|
24
|
+
'image/png',
|
|
25
|
+
'image/svg+xml',
|
|
26
|
+
'image/vnd.microsoft.icon',
|
|
27
|
+
'image/tiff',
|
|
28
|
+
'image/webp'
|
|
29
|
+
],
|
|
30
|
+
text: [
|
|
31
|
+
'application/json',
|
|
32
|
+
'application/ld+json',
|
|
33
|
+
'text/plain',
|
|
34
|
+
]
|
|
35
|
+
};
|
package/lib/templates-list.js
CHANGED
|
@@ -8,10 +8,6 @@ module.exports.TemplatesList = {
|
|
|
8
8
|
login: 'login.html',
|
|
9
9
|
dashboard: 'dashboard.html',
|
|
10
10
|
management: 'management.html',
|
|
11
|
-
mapsWizard: 'maps-wizard.html',
|
|
12
|
-
mapsWizardMapsSelection: 'maps-wizard-maps-selection.html',
|
|
13
|
-
objectsImport: 'objects-import.html',
|
|
14
|
-
skillsImport: 'skills-import.html',
|
|
15
11
|
list: 'list.html',
|
|
16
12
|
listContent: 'list-content.html',
|
|
17
13
|
view: 'view.html',
|
|
@@ -41,10 +37,5 @@ module.exports.TemplatesList = {
|
|
|
41
37
|
button: 'button.html',
|
|
42
38
|
file: 'file.html'
|
|
43
39
|
}
|
|
44
|
-
},
|
|
45
|
-
sections: {
|
|
46
|
-
view: {
|
|
47
|
-
rooms: 'rooms.html'
|
|
48
|
-
}
|
|
49
40
|
}
|
|
50
41
|
};
|