@reldens/cms 0.27.0 → 0.29.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,93 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - MySQLInstaller
4
+ *
5
+ */
6
+
7
+ const { execSync } = require('child_process');
8
+ const { FileHandler } = require('@reldens/server-utils');
9
+ const { Logger } = require('@reldens/utils');
10
+
11
+ class MySQLInstaller
12
+ {
13
+
14
+ static migrationFiles()
15
+ {
16
+ return {
17
+ 'install-cms-tables': 'install.sql',
18
+ 'install-user-auth': 'users-authentication.sql',
19
+ 'install-default-user': 'default-user.sql',
20
+ 'install-default-homepage': 'default-homepage.sql',
21
+ 'install-default-blocks': 'default-blocks.sql',
22
+ 'install-entity-access': 'default-entity-access.sql',
23
+ 'install-dynamic-forms': 'default-forms.sql'
24
+ };
25
+ }
26
+
27
+ static async executeQueryFile(isMarked, fileName, dbDriver, migrationsPath)
28
+ {
29
+ if('on' !== isMarked){
30
+ return '';
31
+ }
32
+ let sqlFileContent = FileHandler.readFile(FileHandler.joinPaths(migrationsPath, fileName));
33
+ if(!sqlFileContent){
34
+ Logger.error('SQL file "'+fileName+'" not found.');
35
+ return '/?error=sql-file-not-found&file-name='+fileName;
36
+ }
37
+ let queryExecutionResult = await dbDriver.rawQuery(sqlFileContent);
38
+ if(!queryExecutionResult){
39
+ Logger.error('SQL file "'+fileName+'" raw execution failed.');
40
+ return '/?error=sql-file-execution-error&file-name='+fileName;
41
+ }
42
+ Logger.info('SQL file "'+fileName+'" raw execution successfully.');
43
+ return '';
44
+ }
45
+
46
+ static async generateMinimalPrismaClient(dbConfig, projectRoot)
47
+ {
48
+ let prismaPath = FileHandler.joinPaths(projectRoot, 'prisma');
49
+ let schemaPath = FileHandler.joinPaths(prismaPath, 'schema.prisma');
50
+ FileHandler.createFolder(prismaPath);
51
+ let schemaContent = 'generator client {\n'
52
+ + ' provider = "prisma-client-js"\n'
53
+ + ' output = "./client"\n'
54
+ + '}\n'
55
+ + '\n'
56
+ + 'datasource db {\n'
57
+ + ' provider = "' + dbConfig.client + '"\n'
58
+ + ' url = "' + dbConfig.client + '://' + dbConfig.config.user + ':' + dbConfig.config.password + '@'
59
+ + dbConfig.config.host + ':' + dbConfig.config.port + '/' + dbConfig.config.database + '"\n'
60
+ + '}';
61
+ FileHandler.writeFile(schemaPath, schemaContent);
62
+ Logger.info('Running prisma generate...');
63
+ try {
64
+ execSync('npx prisma generate', { stdio: 'inherit', cwd: projectRoot });
65
+ let clientPath = FileHandler.joinPaths(projectRoot, 'prisma', 'client');
66
+ let { PrismaClient } = require(clientPath);
67
+ return new PrismaClient();
68
+ } catch(error) {
69
+ Logger.error('Prisma generate failed: '+error.message);
70
+ return false;
71
+ }
72
+ }
73
+
74
+ static async createPrismaClient(projectRoot)
75
+ {
76
+ try {
77
+ let clientPath = FileHandler.joinPaths(projectRoot, 'prisma', 'client');
78
+ if(!FileHandler.exists(clientPath)){
79
+ return false;
80
+ }
81
+ const { PrismaClient } = require(clientPath);
82
+ let client = new PrismaClient();
83
+ await client.$connect();
84
+ return client;
85
+ } catch(error){
86
+ Logger.error('Prisma client creation failed: '+error.message);
87
+ return false;
88
+ }
89
+ }
90
+
91
+ }
92
+
93
+ module.exports.MySQLInstaller = MySQLInstaller;
@@ -0,0 +1,97 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - PrismaSubprocessWorker
4
+ *
5
+ */
6
+
7
+ const { DriversMap } = require('@reldens/storage');
8
+ const { MySQLInstaller } = require('./mysql-installer');
9
+ const { Logger } = require('@reldens/utils');
10
+ const { sc } = require('@reldens/utils');
11
+
12
+ class PrismaSubprocessWorker
13
+ {
14
+
15
+ constructor()
16
+ {
17
+ this.setupProcessHandlers();
18
+ }
19
+
20
+ setupProcessHandlers()
21
+ {
22
+ process.on('message', async (message) => {
23
+ try {
24
+ await this.processIncomingMessage(message);
25
+ } catch(error) {
26
+ Logger.error('PrismaSubprocessWorker error: '+error.message);
27
+ this.sendErrorResponse(error.message);
28
+ setTimeout(() => process.exit(1), 100);
29
+ }
30
+ });
31
+ process.on('uncaughtException', (error) => {
32
+ Logger.error('PrismaSubprocessWorker uncaught exception: '+error.message);
33
+ this.sendErrorResponse(error.message);
34
+ setTimeout(() => process.exit(1), 100);
35
+ });
36
+ process.on('unhandledRejection', (error) => {
37
+ Logger.error('PrismaSubprocessWorker unhandled rejection: '+error.message);
38
+ this.sendErrorResponse(error.message);
39
+ setTimeout(() => process.exit(1), 100);
40
+ });
41
+ }
42
+
43
+ async processIncomingMessage(message)
44
+ {
45
+ let dbConfig = sc.get(message, 'dbConfig', {});
46
+ let templateVariables = sc.get(message, 'templateVariables', {});
47
+ let migrationsPath = sc.get(message, 'migrationsPath', './migrations');
48
+ let projectRoot = sc.get(message, 'projectRoot', './');
49
+ let generatedClient = await MySQLInstaller.generateMinimalPrismaClient(dbConfig, projectRoot);
50
+ if(!generatedClient){
51
+ this.sendErrorResponse('Failed to generate Prisma client.');
52
+ return;
53
+ }
54
+ dbConfig.prismaClient = generatedClient;
55
+ let driverClass = DriversMap['prisma'];
56
+ if(!driverClass){
57
+ this.sendErrorResponse('Prisma driver class not found.');
58
+ return;
59
+ }
60
+ let dbDriver = new driverClass(dbConfig);
61
+ if(!await dbDriver.connect()){
62
+ this.sendErrorResponse('Database connection failed.');
63
+ return;
64
+ }
65
+ let migrationFiles = MySQLInstaller.migrationFiles();
66
+ for(let checkboxName of Object.keys(migrationFiles)){
67
+ let fileName = migrationFiles[checkboxName];
68
+ let redirectError = await MySQLInstaller.executeQueryFile(
69
+ sc.get(templateVariables, checkboxName, 'off'),
70
+ fileName,
71
+ dbDriver,
72
+ migrationsPath
73
+ );
74
+ if('' !== redirectError){
75
+ this.sendErrorResponse('Migration failed: '+fileName);
76
+ return;
77
+ }
78
+ }
79
+ await generatedClient.$disconnect();
80
+ this.sendSuccessResponse('Subprocess installation completed.');
81
+ }
82
+
83
+ sendSuccessResponse(message)
84
+ {
85
+ process.send({success: true, message: message});
86
+ }
87
+
88
+ sendErrorResponse(errorMessage)
89
+ {
90
+ process.send({success: false, error: errorMessage});
91
+ }
92
+
93
+ }
94
+
95
+ module.exports.PrismaSubprocessWorker = PrismaSubprocessWorker;
96
+
97
+ new PrismaSubprocessWorker();
@@ -1,41 +1,43 @@
1
- /**
2
- *
3
- * Reldens - CMS - AssetTransformer
4
- *
5
- */
6
-
7
- const { sc } = require('@reldens/utils');
8
-
9
- class AssetTransformer
10
- {
11
-
12
- async transform(template, domain, req, systemVariables)
13
- {
14
- if(!template){
15
- return template;
16
- }
17
- let currentRequest = sc.get(systemVariables, 'currentRequest', {});
18
- let assetPattern = /\[asset\(([^)]+)\)\]/g;
19
- let matches = [...template.matchAll(assetPattern)];
20
- for(let i = matches.length - 1; i >= 0; i--){
21
- let match = matches[i];
22
- let assetPath = match[1].replace(/['"]/g, '');
23
- let absoluteUrl = this.buildAssetUrl(assetPath, currentRequest);
24
- template = template.substring(0, match.index) +
25
- absoluteUrl +
26
- template.substring(match.index + match[0].length);
27
- }
28
- return template;
29
- }
30
-
31
- buildAssetUrl(assetPath, currentRequest)
32
- {
33
- if(!assetPath || assetPath.startsWith('http')){
34
- return assetPath;
35
- }
36
- return sc.get(currentRequest, 'baseUrl', '')+'/assets'+(assetPath.startsWith('/') ? assetPath : '/'+assetPath);
37
- }
38
-
39
- }
40
-
41
- module.exports.AssetTransformer = AssetTransformer;
1
+ /**
2
+ *
3
+ * Reldens - CMS - AssetTransformer
4
+ *
5
+ */
6
+
7
+ const { sc } = require('@reldens/utils');
8
+
9
+ class AssetTransformer
10
+ {
11
+
12
+ async transform(template, domain, req, systemVariables)
13
+ {
14
+ if(!template){
15
+ return template;
16
+ }
17
+ let currentRequest = sc.get(systemVariables, 'currentRequest', {});
18
+ let assetPattern = /\[asset\(([^)]+)\)\]/g;
19
+ let matches = [...template.matchAll(assetPattern)];
20
+ for(let i = matches.length - 1; i >= 0; i--){
21
+ let match = matches[i];
22
+ let assetPath = match[1].replace(/['"]/g, '');
23
+ let absoluteUrl = this.buildAssetUrl(assetPath, currentRequest);
24
+ template = template.substring(0, match.index) +
25
+ absoluteUrl +
26
+ template.substring(match.index + match[0].length);
27
+ }
28
+ return template;
29
+ }
30
+
31
+ buildAssetUrl(assetPath, currentRequest)
32
+ {
33
+ if(!assetPath || assetPath.startsWith('http')){
34
+ return assetPath;
35
+ }
36
+ return sc.get(currentRequest, 'publicUrl', '')
37
+ +'/assets'
38
+ +(assetPath.startsWith('/') ? assetPath : '/'+assetPath);
39
+ }
40
+
41
+ }
42
+
43
+ module.exports.AssetTransformer = AssetTransformer;
@@ -38,12 +38,11 @@ class DateTransformer
38
38
  {
39
39
  let date;
40
40
  if(!dateValue || '' === dateValue || 'now' === dateValue.toLowerCase()){
41
+ return sc.formatDate(new Date(), format);
42
+ }
43
+ date = new Date(dateValue);
44
+ if(isNaN(date.getTime())){
41
45
  date = new Date();
42
- } else {
43
- date = new Date(dateValue);
44
- if(isNaN(date.getTime())){
45
- date = new Date();
46
- }
47
46
  }
48
47
  return sc.formatDate(date, format);
49
48
  }
@@ -1,108 +1,127 @@
1
- /**
2
- *
3
- * Reldens - CMS - SystemVariablesProvider
4
- *
5
- */
6
-
7
- const { sc } = require('@reldens/utils');
8
-
9
- class SystemVariablesProvider
10
- {
11
-
12
- constructor(props)
13
- {
14
- this.defaultDomain = sc.get(props, 'defaultDomain', 'default');
15
- this.projectRoot = sc.get(props, 'projectRoot', './');
16
- this.publicPath = sc.get(props, 'publicPath', './public');
17
- }
18
-
19
- buildSystemVariables(req, route, domain)
20
- {
21
- let currentRequest = this.buildCurrentRequestData(req, domain);
22
- let currentRoute = this.buildCurrentRouteData(route);
23
- let currentDomain = this.buildCurrentDomainData(domain);
24
- let systemInfo = this.buildSystemInfo();
25
- return {
26
- currentRequest,
27
- currentRoute,
28
- currentDomain,
29
- systemInfo
30
- };
31
- }
32
-
33
- buildCurrentRequestData(req, domain)
34
- {
35
- if(!req){
36
- return {};
37
- }
38
- let protocol = sc.get(req, 'protocol', 'http');
39
- let host = req.get('host') || 'localhost';
40
- let originalUrl = sc.get(req, 'originalUrl', sc.get(req, 'path', '/'));
41
- let fullUrl = protocol+'://'+host+originalUrl;
42
- return {
43
- method: sc.get(req, 'method', 'GET'),
44
- path: sc.get(req, 'path', '/'),
45
- originalUrl,
46
- fullUrl,
47
- protocol,
48
- host,
49
- domain: domain || host.split(':')[0],
50
- query: sc.get(req, 'query', {}),
51
- params: sc.get(req, 'params', {}),
52
- headers: sc.get(req, 'headers', {}),
53
- userAgent: req.get('user-agent') || '',
54
- ip: sc.get(req, 'ip', ''),
55
- baseUrl: protocol+'://'+host,
56
- timestamp: sc.getCurrentDate(),
57
- isSecure: 'https' === protocol
58
- };
59
- }
60
-
61
- buildCurrentRouteData(route)
62
- {
63
- if(!route){
64
- return null;
65
- }
66
- return {
67
- id: sc.get(route, 'id', null),
68
- path: sc.get(route, 'path', ''),
69
- router: sc.get(route, 'router', ''),
70
- domain: sc.get(route, 'domain', null),
71
- enabled: sc.get(route, 'enabled', false),
72
- title: sc.get(route, 'title', ''),
73
- template: sc.get(route, 'template', ''),
74
- layout: sc.get(route, 'layout', ''),
75
- meta_title: sc.get(route, 'meta_title', ''),
76
- meta_description: sc.get(route, 'meta_description', ''),
77
- sort_order: sc.get(route, 'sort_order', 0)
78
- };
79
- }
80
-
81
- buildCurrentDomainData(domain)
82
- {
83
- return {
84
- current: domain || this.defaultDomain,
85
- default: this.defaultDomain,
86
- resolved: domain || this.defaultDomain
87
- };
88
- }
89
-
90
- buildSystemInfo()
91
- {
92
- let date = new Date();
93
- return {
94
- projectRoot: this.projectRoot,
95
- publicPath: this.publicPath,
96
- nodeVersion: process.version,
97
- platform: process.platform,
98
- environment: process.env.NODE_ENV || 'development',
99
- timestamp: sc.getCurrentDate(),
100
- uptime: process.uptime(),
101
- currentDate: sc.formatDate(date),
102
- currentYear: sc.formatDate(date, 'Y')
103
- };
104
- }
105
-
106
- }
107
-
108
- module.exports.SystemVariablesProvider = SystemVariablesProvider;
1
+ /**
2
+ *
3
+ * Reldens - CMS - SystemVariablesProvider
4
+ *
5
+ */
6
+
7
+ const { sc } = require('@reldens/utils');
8
+
9
+ class SystemVariablesProvider
10
+ {
11
+
12
+ constructor(props)
13
+ {
14
+ this.defaultDomain = sc.get(props, 'defaultDomain', 'default');
15
+ this.projectRoot = sc.get(props, 'projectRoot', './');
16
+ this.publicPath = sc.get(props, 'publicPath', './public');
17
+ this.domainPublicUrlMapping = sc.get(props, 'domainPublicUrlMapping', {});
18
+ this.defaultPublicUrl = sc.get(props, 'defaultPublicUrl', '');
19
+ }
20
+
21
+ buildSystemVariables(req, route, domain)
22
+ {
23
+ let currentRequest = this.buildCurrentRequestData(req, domain);
24
+ let currentRoute = this.buildCurrentRouteData(route);
25
+ let currentDomain = this.buildCurrentDomainData(domain);
26
+ let systemInfo = this.buildSystemInfo();
27
+ return {
28
+ currentRequest,
29
+ currentRoute,
30
+ currentDomain,
31
+ systemInfo
32
+ };
33
+ }
34
+
35
+ buildCurrentRequestData(req, domain)
36
+ {
37
+ if(!req){
38
+ return {};
39
+ }
40
+ let protocol = sc.get(req, 'protocol', 'http');
41
+ let host = req.get('host') || 'localhost';
42
+ let originalUrl = sc.get(req, 'originalUrl', sc.get(req, 'path', '/'));
43
+ let baseUrl = protocol+'://'+host;
44
+ let publicUrl = baseUrl;
45
+ let customPublicUrl = req.get('x-public-url');
46
+ if(customPublicUrl){
47
+ publicUrl = customPublicUrl;
48
+ }
49
+ if(!customPublicUrl && domain && sc.hasOwn(this.domainPublicUrlMapping, domain)){
50
+ publicUrl = this.domainPublicUrlMapping[domain];
51
+ }
52
+ if(publicUrl === baseUrl && '' !== this.defaultPublicUrl){
53
+ publicUrl = this.defaultPublicUrl;
54
+ }
55
+ if('' === baseUrl && '' !== this.defaultPublicUrl){
56
+ baseUrl = this.defaultPublicUrl;
57
+ }
58
+ let fullUrl = protocol+'://'+host+originalUrl;
59
+ return {
60
+ method: sc.get(req, 'method', 'GET'),
61
+ path: sc.get(req, 'path', '/'),
62
+ originalUrl,
63
+ fullUrl,
64
+ protocol,
65
+ host,
66
+ domain: domain || host.split(':')[0],
67
+ query: sc.get(req, 'query', {}),
68
+ params: sc.get(req, 'params', {}),
69
+ headers: sc.get(req, 'headers', {}),
70
+ userAgent: req.get('user-agent') || '',
71
+ ip: sc.get(req, 'ip', ''),
72
+ baseUrl,
73
+ publicUrl,
74
+ defaultPublicUrl: this.defaultPublicUrl,
75
+ timestamp: sc.getCurrentDate(),
76
+ isSecure: 'https' === protocol
77
+ };
78
+ }
79
+
80
+ buildCurrentRouteData(route)
81
+ {
82
+ if(!route){
83
+ return null;
84
+ }
85
+ return {
86
+ id: sc.get(route, 'id', null),
87
+ path: sc.get(route, 'path', ''),
88
+ router: sc.get(route, 'router', ''),
89
+ domain: sc.get(route, 'domain', null),
90
+ enabled: sc.get(route, 'enabled', false),
91
+ title: sc.get(route, 'title', ''),
92
+ template: sc.get(route, 'template', ''),
93
+ layout: sc.get(route, 'layout', ''),
94
+ meta_title: sc.get(route, 'meta_title', ''),
95
+ meta_description: sc.get(route, 'meta_description', ''),
96
+ sort_order: sc.get(route, 'sort_order', 0)
97
+ };
98
+ }
99
+
100
+ buildCurrentDomainData(domain)
101
+ {
102
+ return {
103
+ current: domain || this.defaultDomain,
104
+ default: this.defaultDomain,
105
+ resolved: domain || this.defaultDomain
106
+ };
107
+ }
108
+
109
+ buildSystemInfo()
110
+ {
111
+ let date = new Date();
112
+ return {
113
+ projectRoot: this.projectRoot,
114
+ publicPath: this.publicPath,
115
+ nodeVersion: process.version,
116
+ platform: process.platform,
117
+ environment: process.env.NODE_ENV || 'development',
118
+ timestamp: sc.getCurrentDate(),
119
+ uptime: process.uptime(),
120
+ currentDate: sc.formatDate(date),
121
+ currentYear: sc.formatDate(date, 'Y')
122
+ };
123
+ }
124
+
125
+ }
126
+
127
+ module.exports.SystemVariablesProvider = SystemVariablesProvider;
@@ -1,41 +1,41 @@
1
- /**
2
- *
3
- * Reldens - CMS - UrlTransformer
4
- *
5
- */
6
-
7
- const { sc } = require('@reldens/utils');
8
-
9
- class UrlTransformer
10
- {
11
-
12
- async transform(template, domain, req, systemVariables)
13
- {
14
- if(!template){
15
- return template;
16
- }
17
- let currentRequest = sc.get(systemVariables, 'currentRequest', {});
18
- let urlPattern = /\[url\(([^)]+)\)\]/g;
19
- let matches = [...template.matchAll(urlPattern)];
20
- for(let i = matches.length - 1; i >= 0; i--){
21
- let match = matches[i];
22
- let urlPath = match[1].replace(/['"]/g, '');
23
- let absoluteUrl = this.buildAbsoluteUrl(urlPath, currentRequest);
24
- template = template.substring(0, match.index) +
25
- absoluteUrl +
26
- template.substring(match.index + match[0].length);
27
- }
28
- return template;
29
- }
30
-
31
- buildAbsoluteUrl(relativePath, currentRequest)
32
- {
33
- if(!relativePath || relativePath.startsWith('http')){
34
- return relativePath;
35
- }
36
- return sc.get(currentRequest, 'baseUrl', '') + relativePath;
37
- }
38
-
39
- }
40
-
41
- module.exports.UrlTransformer = UrlTransformer;
1
+ /**
2
+ *
3
+ * Reldens - CMS - UrlTransformer
4
+ *
5
+ */
6
+
7
+ const { sc } = require('@reldens/utils');
8
+
9
+ class UrlTransformer
10
+ {
11
+
12
+ async transform(template, domain, req, systemVariables)
13
+ {
14
+ if(!template){
15
+ return template;
16
+ }
17
+ let currentRequest = sc.get(systemVariables, 'currentRequest', {});
18
+ let urlPattern = /\[url\(([^)]+)\)\]/g;
19
+ let matches = [...template.matchAll(urlPattern)];
20
+ for(let i = matches.length - 1; i >= 0; i--){
21
+ let match = matches[i];
22
+ let urlPath = match[1].replace(/['"]/g, '');
23
+ let absoluteUrl = this.buildAbsoluteUrl(urlPath, currentRequest);
24
+ template = template.substring(0, match.index) +
25
+ absoluteUrl +
26
+ template.substring(match.index + match[0].length);
27
+ }
28
+ return template;
29
+ }
30
+
31
+ buildAbsoluteUrl(relativePath, currentRequest)
32
+ {
33
+ if(!relativePath || relativePath.startsWith('http')){
34
+ return relativePath;
35
+ }
36
+ return sc.get(currentRequest, 'publicUrl', '') + relativePath;
37
+ }
38
+
39
+ }
40
+
41
+ module.exports.UrlTransformer = UrlTransformer;