@reldens/cms 0.6.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/lib/manager.js CHANGED
@@ -4,12 +4,21 @@
4
4
  *
5
5
  */
6
6
 
7
- const { AppServerFactory, FileHandler, Encryptor } = require('@reldens/server-utils');
8
- const { DriversMap } = require('@reldens/storage');
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
18
  const { Frontend } = require('./frontend');
12
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
 
@@ -23,14 +32,27 @@ class Manager
23
32
  this.installLockPath = FileHandler.joinPaths(this.projectRoot, 'install.lock');
24
33
  dotenv.config({path: this.envFilePath});
25
34
  this.config = this.loadConfigFromEnv();
26
- this.entities = sc.get(props, 'entities', {});
27
- this.rawEntities = sc.get(props, 'rawEntities', {});
28
- this.entitiesConfig = sc.get(props, 'entitiesConfig', {});
35
+ this.adminEntities = sc.get(props, 'adminEntities', {});
36
+ this.rawRegisteredEntities = sc.get(props, 'rawRegisteredEntities', {});
29
37
  this.entitiesTranslations = sc.get(props, 'entitiesTranslations', {});
38
+ this.entitiesConfig = sc.get(props, 'entitiesConfig', {});
39
+ this.processedEntities = sc.get(props, 'processedEntities', {});
30
40
  this.authenticationMethod = sc.get(props, 'authenticationMethod', 'db-users');
31
41
  this.authenticationCallback = sc.get(props, 'authenticationCallback', false);
32
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');
33
54
  this.appServerFactory = new AppServerFactory();
55
+ this.adminEntitiesGenerator = new AdminEntitiesGenerator();
34
56
  this.installer = new Installer({
35
57
  projectRoot: this.projectRoot,
36
58
  postInstallCallback: this.initializeCmsAfterInstall.bind(this)
@@ -84,36 +106,24 @@ class Manager
84
106
  return true;
85
107
  }
86
108
  try {
87
- await this.initializeDataServer();
88
- await this.initializeAdminManager();
89
- await this.initializeFrontend();
90
- await this.appServer.listen(this.config.port);
109
+ await this.initializeServices();
91
110
  Logger.info('CMS running on '+this.config.host+':'+this.config.port);
92
111
  return true;
93
112
  } catch (error) {
94
- Logger.error('Failed to start CMS: '+error.message);
113
+ Logger.critical('Failed to start CMS: '+error.message);
95
114
  return false;
96
115
  }
97
116
  }
98
117
 
99
- async initializeCmsAfterInstall(entitiesData)
118
+ async initializeCmsAfterInstall(loadEntities)
100
119
  {
101
120
  try {
102
- if(entitiesData){
103
- this.entities = sc.get(entitiesData, 'entities', this.entities);
104
- this.rawEntities = sc.get(entitiesData, 'rawEntities', this.rawEntities);
105
- this.entitiesConfig = sc.get(entitiesData, 'entitiesConfig', this.entitiesConfig);
106
- this.entitiesTranslations = sc.get(entitiesData, 'entitiesTranslations', this.entitiesTranslations);
107
- }
121
+ this.rawRegisteredEntities = loadEntities.rawRegisteredEntities;
122
+ this.entitiesTranslations = loadEntities.entitiesTranslations;
123
+ this.entitiesConfig = loadEntities.entitiesConfig;
124
+ this.dataServer.rawEntities = loadEntities.rawRegisteredEntities;
108
125
  this.config = this.loadConfigFromEnv();
109
- if(this.appServerFactory.error.message){
110
- Logger.critical('App server creation failed: '+this.appServerFactory.error.message);
111
- return false;
112
- }
113
- await this.initializeDataServer();
114
- await this.initializeAdminManager();
115
- await this.initializeFrontend();
116
- await this.appServer.listen(this.config.port);
126
+ await this.initializeServices();
117
127
  Logger.info('CMS initialized after installation on '+this.config.host+':'+this.config.port);
118
128
  return true;
119
129
  } catch (error) {
@@ -122,6 +132,32 @@ class Manager
122
132
  }
123
133
  }
124
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
+
125
161
  async initializeDataServer()
126
162
  {
127
163
  let dbConfig = {
@@ -133,7 +169,7 @@ class Manager
133
169
  user: this.config.database.user,
134
170
  password: this.config.database.password
135
171
  },
136
- rawEntities: this.rawEntities
172
+ rawEntities: this.rawRegisteredEntities
137
173
  };
138
174
  let DriverClass = DriversMap[this.config.database.driver];
139
175
  if(!DriverClass){
@@ -152,35 +188,58 @@ class Manager
152
188
  async initializeAdminManager()
153
189
  {
154
190
  let authenticationCallback = this.authenticationCallback;
155
- if('db-users' === this.authenticationMethod){
191
+ if('db-users' === this.authenticationMethod && !authenticationCallback){
156
192
  authenticationCallback = async (email, password, roleId) => {
193
+ Logger.debug('Running default "db-users" authentication.');
157
194
  let usersEntity = this.dataServer.getEntity('users');
158
195
  if(!usersEntity){
196
+ Logger.critical('No users entity found.');
159
197
  return false;
160
198
  }
161
199
  let user = await usersEntity.loadOneBy('email', email);
162
200
  if(!user){
201
+ Logger.debug('User not found by email: '+email+'.', user);
163
202
  return false;
164
203
  }
165
204
  if(Number(user.role_id) !== Number(roleId)){
205
+ Logger.debug('Invalid user role ID: '+roleId+' / '+user.role_id+'.');
166
206
  return false;
167
207
  }
168
- return Encryptor.validatePassword(password, user.password) ? user : false;
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;
169
213
  };
170
214
  }
171
215
  let adminConfig = {
172
216
  events: this.events,
173
- renderCallback: this.renderCallback.bind(this),
174
217
  dataServer: this.dataServer,
175
218
  authenticationCallback,
176
219
  app: this.app,
177
220
  appServerFactory: this.appServerFactory,
221
+ entities: this.adminEntities,
222
+ validator: new AdminManagerValidator(),
223
+ renderCallback: this.renderCallback.bind(this),
178
224
  secret: this.config.adminSecret,
179
225
  rootPath: this.config.adminPath,
180
- adminRoleId: 99,
181
- entities: this.entities,
182
- entitiesConfig: this.entitiesConfig,
183
- translations: this.entitiesTranslations
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
+ }
184
243
  };
185
244
  this.adminManager = new AdminManager(adminConfig);
186
245
  await this.adminManager.setupAdmin();
@@ -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
+ };
@@ -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
  };
@@ -0,0 +1,28 @@
1
+ /**
2
+ *
3
+ * Reldens - TemplatesToPathMapper
4
+ *
5
+ */
6
+
7
+ const { sc } = require('@reldens/utils');
8
+ const { FileHandler } = require('@reldens/server-utils');
9
+
10
+ class TemplatesToPathMapper
11
+ {
12
+
13
+ map(templateList, path)
14
+ {
15
+ let result = {};
16
+ for(let templateName of Object.keys(templateList)){
17
+ if(sc.isObject(templateList[templateName])){
18
+ result[templateName] = this.map(templateList[templateName], FileHandler.joinPaths(path, templateName));
19
+ continue;
20
+ }
21
+ result[templateName] = FileHandler.joinPaths(path, templateList[templateName]);
22
+ }
23
+ return result;
24
+ }
25
+
26
+ }
27
+
28
+ module.exports.TemplatesToPathMapper = new TemplatesToPathMapper();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@reldens/cms",
3
3
  "scope": "@reldens",
4
- "version": "0.6.0",
4
+ "version": "0.7.0",
5
5
  "description": "Reldens - CMS",
6
6
  "author": "Damian A. Pastorini",
7
7
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@reldens/server-utils": "^0.16.0",
36
- "@reldens/storage": "^0.43.0",
36
+ "@reldens/storage": "^0.44.0",
37
37
  "@reldens/utils": "^0.47.0",
38
38
  "dotenv": "^16.5.0",
39
39
  "mustache": "^4.2.0"
Binary file
@@ -13,7 +13,7 @@ let projectRoot = args[0] || process.cwd();
13
13
 
14
14
  let manager = new Manager({
15
15
  projectRoot,
16
- entities: rawRegisteredEntities,
16
+ rawRegisteredEntities,
17
17
  entitiesConfig,
18
18
  entitiesTranslations
19
19
  });
@@ -27,6 +27,6 @@ manager.start().then((result) => {
27
27
  Logger.info('Reldens CMS started by command.');
28
28
  return true;
29
29
  }).catch((error) => {
30
- Logger.error('Failed to start CMS: '+error.message);
30
+ Logger.critical('Failed to start CMS: '+error.message);
31
31
  process.exit();
32
32
  });
@@ -1,85 +0,0 @@
1
- <h2>Maps Wizard</h2>
2
- <div class="sub-content maps-wizard">
3
- <div class="sub-content-box">
4
- <form class="sub-content-form maps-wizard-form confirmation-required"
5
- name="maps-wizard-form"
6
- id="maps-wizard-form"
7
- action="{{&actionPath}}"
8
- method="post"
9
- enctype="multipart/form-data">
10
- <input type="hidden" name="mainAction" id="mainAction" value="import"/>
11
- <input type="hidden" name="generatedMapsHandler" id="generatedMapsHandler" value="{{&generatedMapsHandler}}"/>
12
- <input type="hidden" name="importAssociationsForChangePoints" id="importAssociationsForChangePoints" value="{{&importAssociationsForChangePoints}}"/>
13
- <input type="hidden" name="importAssociationsRecursively" id="importAssociationsRecursively" value="{{&importAssociationsRecursively}}"/>
14
- <input type="hidden" name="automaticallyExtrudeMaps" id="automaticallyExtrudeMaps" value="{{&automaticallyExtrudeMaps}}"/>
15
- <input type="hidden" name="verifyTilesetImage" id="verifyTilesetImage" value="{{&verifyTilesetImage}}"/>
16
- <input type="hidden" name="handlerParams" id="handlerParams" value="{{handlerParams}}"/>
17
- <div class="main-action-container maps-selection">
18
- <h3>Select the maps to be imported</h3>
19
- <p>Notes:<p>
20
- <p>
21
- - The Game Server requires a reboot in order to make the maps available on the game.<br/>
22
- - If you refresh the page you will get a new set of random maps generated.<br/>
23
- - Generated sub-maps will be automatically imported, if you don't want to import those you can download all the related maps (the main map and the sub-map) and edit change them to your needs.<br/>
24
- </p>
25
- <ul class="wizard-options-container">
26
- {{#maps}}
27
- <li class="wizard-map-option-container">
28
- <div class="selector-box">
29
- <input class="map-wizard-option" type="checkbox" name="selectedMaps[]" id="maps-wizard-map-option-{{&key}}" value="{{&key}}"/>
30
- <input type="hidden" name="map-title-{{&key}}" id="map-title-{{&key}}" value="{{&key}}"/>
31
- <label class="main-option" for="maps-wizard-map-option-{{&key}}">
32
- {{&key}}
33
- </label>
34
- <p>Downloads:</p>
35
- <p>
36
- - <a href="{{&mapJson}}" target="_blank">{{&mapJson}}</a><br/>
37
- - <a href="{{&mapImage}}" target="_blank">{{&mapImage}}</a>
38
- </p>
39
- </div>
40
- <canvas
41
- class="mapCanvas"
42
- data-toggle="modal"
43
- width="{{&mapWidth}}"
44
- height="{{&mapHeight}}"
45
- data-tile-width="{{&tileWidth}}"
46
- data-tile-height="{{&tileHeight}}"
47
- data-image-key="{{&mapImage}}"
48
- data-map-json="{{&mapJson}}">
49
- </canvas>
50
- {{#hasSubMaps}}
51
- <div class="sub-maps">
52
- <p class="sub-map-option-description clickable" data-expand-collapse=".sub-maps-container-{{&key}}">
53
- <img class="icon-sm" src="/assets/admin/filters.png" alt="Associated maps"/>
54
- <span>Associated maps generated</span>
55
- </p>
56
- <div class="sub-maps-container sub-maps-container-{{&key}} hidden">
57
- {{#subMaps}}
58
- <p>{{&key}}</p>
59
- <p>Downloads:</p>
60
- <p>
61
- - <a href="{{&mapJson}}" target="_blank">{{&mapJson}}</a><br/>
62
- - <a href="{{&mapImage}}" target="_blank">{{&mapImage}}</a>
63
- </p>
64
- <canvas
65
- class="mapCanvas"
66
- data-toggle="modal"
67
- width="{{&mapWidth}}"
68
- height="{{&mapHeight}}"
69
- data-tile-width="{{&tileWidth}}"
70
- data-tile-height="{{&tileHeight}}"
71
- data-image-key="{{&mapImage}}"
72
- data-map-json="{{&mapJson}}">
73
- </canvas>
74
- {{/subMaps}}
75
- </div>
76
- </div>
77
- {{/hasSubMaps}}
78
- </li>
79
- {{/maps}}
80
- </ul>
81
- </div>
82
- <input type="submit" class="button button-primary button-maps-wizard" value="Import Selected Maps"/>
83
- </form>
84
- </div>
85
- </div>