@reldens/cms 0.64.0 → 0.66.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.
@@ -0,0 +1,323 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - Manager Services Initializer
4
+ *
5
+ */
6
+
7
+ const { DefaultTranslations } = require('./admin-manager/default-translations');
8
+ const { AdminTemplatesLoader } = require('./admin-templates-loader');
9
+ const { AdminManagerValidator } = require('./admin-manager-validator');
10
+ const { LoadedEntitiesProcessor } = require('./loaded-entities-processor');
11
+ const { EntitiesConfigProcessor } = require('./entities-config-processor');
12
+ const { AdminManager } = require('./admin-manager');
13
+ const { Frontend } = require('./frontend');
14
+ const { SitemapLoader } = require('./sitemap-loader');
15
+ const { PasswordEncryptionHandler } = require('./password-encryption-handler');
16
+ const { Logger, sc } = require('@reldens/utils');
17
+ const { DriversMap, PrismaClientLoader } = require('@reldens/storage');
18
+ const { FileHandler, Encryptor } = require('@reldens/server-utils');
19
+
20
+ class ManagerServicesInitializer
21
+ {
22
+
23
+ constructor(manager)
24
+ {
25
+ this.manager = manager;
26
+ }
27
+
28
+ async initializeServices()
29
+ {
30
+ this.manager.events.emit('reldens.cmsManagerInitializeServices', {manager: this.manager});
31
+ if(!this.manager.useProvidedDataServer){
32
+ if(!await this.initializeDataServer()){
33
+ Logger.debug('Initialize Data Server failed.');
34
+ return false;
35
+ }
36
+ }
37
+ if(0 < Object.keys(this.manager.entityAccess).length){
38
+ await this.setupEntityAccess();
39
+ }
40
+ if(!this.loadProcessedEntities()){
41
+ Logger.debug('Load Processed Entities for Entities failed.');
42
+ return false;
43
+ }
44
+ if(!await this.generateAdminEntities()){
45
+ Logger.debug('Generate Admin Entities for Entities failed.');
46
+ return false;
47
+ }
48
+ if(!this.manager.useProvidedAdminManager){
49
+ if(!await this.initializeAdminManager()){
50
+ Logger.debug('Initialize Admin Manager failed.');
51
+ return false;
52
+ }
53
+ }
54
+ if(!await this.initializeCmsPagesRouteManager()){
55
+ Logger.debug('Initialize CMS Pages Route Manager failed.');
56
+ return false;
57
+ }
58
+ if(!this.manager.useProvidedFrontend){
59
+ if(!await this.initializeFrontend()){
60
+ Logger.debug('Initialize Frontend failed.');
61
+ return false;
62
+ }
63
+ }
64
+ this.manager.sitemapLoader = new SitemapLoader({
65
+ dataServer: this.manager.dataServer,
66
+ events: this.manager.events,
67
+ domainMapping: this.manager.domainMapping
68
+ });
69
+ if(!this.manager.useProvidedServer){
70
+ await this.manager.appServer.listen(this.manager.config.port);
71
+ }
72
+ Logger.debug('Initialize Services successfully.');
73
+ return true;
74
+ }
75
+
76
+ async setupEntityAccess()
77
+ {
78
+ let accessEntity = this.manager.dataServer.getEntity('entitiesAccess');
79
+ if(!accessEntity){
80
+ Logger.warning('Entities Access not found.');
81
+ return;
82
+ }
83
+ for(let entityName of Object.keys(this.manager.entityAccess)){
84
+ let accessConfig = this.manager.entityAccess[entityName];
85
+ if(!await accessEntity.loadOneBy('entity_name', entityName)){
86
+ await accessEntity.create({
87
+ entity_name: entityName,
88
+ is_public: sc.get(accessConfig, 'public', false),
89
+ allowed_operations: JSON.stringify(sc.get(accessConfig, 'operations', ['read']))
90
+ });
91
+ }
92
+ }
93
+ }
94
+
95
+ loadProcessedEntities()
96
+ {
97
+ if(0 === Object.keys(this.manager.processedEntities).length){
98
+ let mergedConfig = EntitiesConfigProcessor.applyOverrides(
99
+ this.manager.entitiesConfig,
100
+ this.manager.entitiesConfigOverride,
101
+ {projectRoot: this.manager.projectRoot}
102
+ );
103
+ this.manager.processedEntities = LoadedEntitiesProcessor.process(
104
+ this.manager.rawRegisteredEntities,
105
+ this.manager.entitiesTranslations,
106
+ mergedConfig
107
+ );
108
+ }
109
+ if(!this.manager.processedEntities?.entities){
110
+ Logger.critical('Processed entities undefined.');
111
+ return false;
112
+ }
113
+ return true;
114
+ }
115
+
116
+ async generateAdminEntities()
117
+ {
118
+ if(0 < Object.keys(this.manager.adminEntities).length){
119
+ return true;
120
+ }
121
+ if(!this.manager.dataServer.rawEntities && this.manager.rawRegisteredEntities){
122
+ this.manager.dataServer.rawEntities = this.manager.rawRegisteredEntities;
123
+ }
124
+ Logger.debug('Generate entities count: '+Object.keys(this.manager.rawRegisteredEntities).length);
125
+ await this.manager.dataServer.generateEntities();
126
+ this.manager.adminEntities = this.manager.adminEntitiesGenerator.generate(
127
+ this.manager.processedEntities.entities,
128
+ this.manager.dataServer.entityManager.entities
129
+ );
130
+ if(0 === Object.keys(this.manager.adminEntities).length){
131
+ Logger.critical('Admin entities generation failed - no entities available.');
132
+ Logger.critical('CMS cannot start without admin entities.');
133
+ return false;
134
+ }
135
+ return true;
136
+ }
137
+
138
+ async initializeDataServer()
139
+ {
140
+ let dbConfig = {
141
+ client: this.manager.config.database.client,
142
+ config: {
143
+ host: this.manager.config.database.host,
144
+ port: this.manager.config.database.port,
145
+ database: this.manager.config.database.name,
146
+ user: this.manager.config.database.user,
147
+ password: this.manager.config.database.password
148
+ },
149
+ rawEntities: this.manager.rawRegisteredEntities,
150
+ entitiesConfig: this.manager.entitiesConfig
151
+ };
152
+ let driverClass = DriversMap[this.manager.config.database.driver];
153
+ if(!driverClass){
154
+ Logger.critical('Invalid database driver: '+this.manager.config.database.driver);
155
+ return false;
156
+ }
157
+ if('prisma' === this.manager.config.database.driver){
158
+ if(!this.manager.prismaClient){
159
+ this.manager.prismaClient = PrismaClientLoader.load(this.manager.projectRoot, null, {
160
+ client: this.manager.config.database.client,
161
+ user: this.manager.config.database.user,
162
+ password: this.manager.config.database.password,
163
+ host: this.manager.config.database.host,
164
+ port: this.manager.config.database.port,
165
+ database: this.manager.config.database.name
166
+ });
167
+ if(!this.manager.prismaClient){
168
+ Logger.critical('Failed to create PrismaClient via PrismaClientLoader.');
169
+ return false;
170
+ }
171
+ }
172
+ dbConfig.prismaClient = this.manager.prismaClient;
173
+ }
174
+ this.manager.dataServer = new driverClass(dbConfig);
175
+ if(!await this.manager.dataServer.connect()){
176
+ Logger.critical('Failed to connect to database.');
177
+ return false;
178
+ }
179
+ Logger.debug('Entities count: '+Object.keys(this.manager.rawRegisteredEntities).length);
180
+ await this.manager.dataServer.generateEntities();
181
+ return true;
182
+ }
183
+
184
+ async initializeAdminManager()
185
+ {
186
+ let authenticationCallback = this.manager.authenticationCallback;
187
+ if('db-users' === this.manager.authenticationMethod && !authenticationCallback){
188
+ authenticationCallback = async (email, password, roleId) => {
189
+ Logger.debug('Running default "db-users" authentication.');
190
+ let usersEntity = this.manager.dataServer.getEntity('users');
191
+ if(!usersEntity){
192
+ Logger.critical('No users entity found.');
193
+ return false;
194
+ }
195
+ let user = await usersEntity.loadOneBy('email', email);
196
+ if(!user){
197
+ Logger.debug('User not found by email: '+email+'.', user);
198
+ return false;
199
+ }
200
+ if(Number(user.role_id) !== Number(roleId)){
201
+ Logger.debug('Invalid user role ID: '+roleId+' / '+user.role_id+'.');
202
+ return false;
203
+ }
204
+ let passwordResult = Encryptor.validatePassword(password, user.password) ? user : false;
205
+ if(!passwordResult){
206
+ Logger.debug('Invalid user password for: '+email+'.');
207
+ }
208
+ return passwordResult;
209
+ };
210
+ }
211
+ this.manager.templateReloader.trackTemplateFiles(this.manager.mappedAdminTemplates);
212
+ let adminFilesContents = await AdminTemplatesLoader.fetchAdminFilesContents(this.manager.mappedAdminTemplates);
213
+ let translations = sc.deepMergeProperties(
214
+ sc.deepMergeProperties({}, DefaultTranslations),
215
+ sc.deepMergeProperties(this.manager.entitiesTranslations, this.manager.adminTranslations)
216
+ );
217
+ this.manager.events.emit('reldens.manager.initializeAdminManager', {
218
+ manager: this.manager,
219
+ authenticationCallback,
220
+ adminFilesContents,
221
+ translations
222
+ });
223
+ this.initializePasswordEncryptionHandler();
224
+ let adminConfig = {
225
+ events: this.manager.events,
226
+ dataServer: this.manager.dataServer,
227
+ authenticationCallback,
228
+ app: this.manager.app,
229
+ appServerFactory: this.manager.appServerFactory,
230
+ entities: this.manager.adminEntities,
231
+ validator: new AdminManagerValidator(),
232
+ renderCallback: this.renderCallback.bind(this),
233
+ secret: this.manager.config.adminSecret,
234
+ rootPath: this.manager.config.adminPath,
235
+ translations,
236
+ adminFilesContents,
237
+ mimeTypes: this.manager.mimeTypes,
238
+ allowedExtensions: this.manager.allowedExtensions,
239
+ adminRoleId: this.manager.adminRoleId,
240
+ stylesFilePath: this.manager.stylesFilePath,
241
+ scriptsFilePath: this.manager.scriptsFilePath,
242
+ cacheManager: this.manager.cacheManager,
243
+ branding: {
244
+ companyName: this.manager.companyName,
245
+ logo: this.manager.logo,
246
+ favicon: this.manager.favicon,
247
+ copyRight: await FileHandler.fetchFileContents(
248
+ FileHandler.joinPaths(
249
+ this.manager.projectAdminTemplatesPath,
250
+ this.manager.adminTemplatesList.defaultCopyRight
251
+ )
252
+ )
253
+ }
254
+ };
255
+ this.manager.adminManager = new AdminManager(adminConfig);
256
+ this.manager.adminManager.router.checkAndReloadAdminTemplates = async () => {
257
+ return await this.manager.templateReloader.handleAdminTemplateReload(this.manager.adminManager);
258
+ };
259
+ await this.manager.adminManager.setupAdmin();
260
+ return true;
261
+ }
262
+
263
+ initializePasswordEncryptionHandler()
264
+ {
265
+ if(!this.manager.enablePasswordEncryption){
266
+ Logger.debug('Password encryption handler is disabled.');
267
+ return false;
268
+ }
269
+ this.manager.passwordEncryptionHandler = new PasswordEncryptionHandler({
270
+ events: this.manager.events,
271
+ enabled: this.manager.enablePasswordEncryption
272
+ });
273
+ this.manager.passwordEncryptionHandler.registerEventListeners();
274
+ Logger.debug('Password encryption handler initialized and registered.');
275
+ return true;
276
+ }
277
+
278
+ async initializeCmsPagesRouteManager()
279
+ {
280
+ if(!this.manager.dataServer){
281
+ Logger.warning('CmsPagesRouteManager initialization skipped - missing dataServer.');
282
+ return false;
283
+ }
284
+ this.manager.cmsPagesRouteManager.dataServer = this.manager.dataServer;
285
+ Logger.debug('CmsPagesRouteManager initialized successfully');
286
+ return true;
287
+ }
288
+
289
+ async renderCallback(template, params = {})
290
+ {
291
+ if(!template){
292
+ return '';
293
+ }
294
+ return this.manager.renderEngine.render(template, params);
295
+ }
296
+
297
+ async initializeFrontend()
298
+ {
299
+ this.manager.frontend = new Frontend({
300
+ app: this.manager.app,
301
+ dataServer: this.manager.dataServer,
302
+ events: this.manager.events,
303
+ renderEngine: this.manager.renderEngine,
304
+ projectRoot: this.manager.projectRoot,
305
+ appServerFactory: this.manager.appServerFactory,
306
+ defaultDomain: this.manager.defaultDomain,
307
+ domainMapping: this.manager.domainMapping,
308
+ siteKeyMapping: this.manager.siteKeyMapping,
309
+ domainPublicUrlMapping: this.manager.domainPublicUrlMapping,
310
+ domainCdnMapping: this.manager.domainCdnMapping,
311
+ defaultPublicUrl: this.manager.config.publicUrl,
312
+ templateExtensions: this.manager.templateExtensions,
313
+ entitiesConfig: this.manager.entitiesConfig,
314
+ cacheManager: this.manager.cacheManager,
315
+ handleFrontendTemplateReload: this.manager.templateReloader.handleFrontendTemplateReload.bind(
316
+ this.manager.templateReloader
317
+ )
318
+ });
319
+ return await this.manager.frontend.initialize();
320
+ }
321
+ }
322
+
323
+ module.exports.ManagerServicesInitializer = ManagerServicesInitializer;