@reldens/cms 0.1.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/LICENSE +21 -0
- package/README.md +125 -0
- package/bin/reldens-cms.js +21 -0
- package/index.js +15 -0
- package/install/css/installer.css +117 -0
- package/install/index.html +100 -0
- package/install/js/installer.js +32 -0
- package/lib/admin-dist-helper.js +56 -0
- package/lib/admin-entities-generator.js +32 -0
- package/lib/admin-manager-validator.js +37 -0
- package/lib/admin-manager.js +1059 -0
- package/lib/admin-translations.js +262 -0
- package/lib/installer.js +283 -0
- package/lib/manager.js +171 -0
- package/lib/storefront.js +228 -0
- package/lib/templates-list.js +50 -0
- package/migrations/default-user.sql +11 -0
- package/migrations/install.sql +84 -0
- package/package.json +42 -0
- package/templates/.env.dist +16 -0
- package/templates/404.html +30 -0
- package/templates/css/styles.css +102 -0
- package/templates/js/scripts.js +12 -0
- package/templates/page.html +38 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - AdminTranslations
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class AdminTranslations
|
|
8
|
+
{
|
|
9
|
+
|
|
10
|
+
static appendTranslations(translations)
|
|
11
|
+
{
|
|
12
|
+
// @TODO - BETA - Fix translations, use snippets, include new snippets under the basic config script.
|
|
13
|
+
let adminTranslations = {
|
|
14
|
+
messages: {
|
|
15
|
+
loginWelcome: 'Administration Panel - Login',
|
|
16
|
+
reldensTitle: 'Reldens - Administration Panel',
|
|
17
|
+
reldensSlogan: 'You can do it',
|
|
18
|
+
reldensDiscordTitle: 'Join our Discord server!',
|
|
19
|
+
reldensDiscordText: 'Talk with the creators and other Reldens users',
|
|
20
|
+
reldensGithubTitle: 'Find us on GitHub!',
|
|
21
|
+
reldensGithubText: 'Need a new feature?'
|
|
22
|
+
+' Would you like to contribute with code?'
|
|
23
|
+
+' Find the source code or create an issue in GitHub',
|
|
24
|
+
reldensLoading: 'Loading...'
|
|
25
|
+
},
|
|
26
|
+
labels: {
|
|
27
|
+
navigation: 'Reldens - Administration Panel',
|
|
28
|
+
adminVersion: 'Admin: {{version}}',
|
|
29
|
+
loginWelcome: 'Reldens',
|
|
30
|
+
pages: 'Server Management',
|
|
31
|
+
management: 'Management',
|
|
32
|
+
mapsWizard: 'Maps Generation and Import',
|
|
33
|
+
objectsImport: 'Objects Import',
|
|
34
|
+
skillsImport: 'Skills Import',
|
|
35
|
+
shuttingDown: 'Server is shutting down in:',
|
|
36
|
+
submitShutdownLabel: 'Shutdown Server',
|
|
37
|
+
submitCancelLabel: 'Cancel Server Shutdown',
|
|
38
|
+
},
|
|
39
|
+
active_from: 'Active From',
|
|
40
|
+
active_to: 'Active To',
|
|
41
|
+
ads_id: 'Ads ID',
|
|
42
|
+
ads_type: 'Ads Type',
|
|
43
|
+
affectedProperty: 'Affected Property',
|
|
44
|
+
aimProperties: 'Aim Properties',
|
|
45
|
+
allowEffectBelowZero: 'Allow Effect Below Zero',
|
|
46
|
+
allowSelfTarget: 'Allow Self Target',
|
|
47
|
+
also_show_in_type: 'Also Show In Type',
|
|
48
|
+
animationData: 'Animation Data',
|
|
49
|
+
animationKey: 'Animation Key',
|
|
50
|
+
applyDirectDamage: 'Apply Direct Damage',
|
|
51
|
+
asset_file: 'Asset File',
|
|
52
|
+
asset_key: 'Asset Key',
|
|
53
|
+
asset_type: 'Asset Type',
|
|
54
|
+
attackProperties: 'Attack Properties',
|
|
55
|
+
audio_id: 'Audio ID',
|
|
56
|
+
audio_key: 'Audio Key',
|
|
57
|
+
autoFillExperienceMultiplier: 'Auto Fill Experience Multiplier',
|
|
58
|
+
autoFillRanges: 'Auto Fill Ranges',
|
|
59
|
+
autoValidation: 'Auto Validation',
|
|
60
|
+
auto_remove_requirement: 'Auto Remove Requirement',
|
|
61
|
+
banner_data: 'Banner Data',
|
|
62
|
+
base_value: 'Base Value',
|
|
63
|
+
bottom: 'Bottom',
|
|
64
|
+
castTime: 'Cast Time',
|
|
65
|
+
category_id: 'Category ID',
|
|
66
|
+
category_key: 'Category Key',
|
|
67
|
+
category_label: 'Category Label',
|
|
68
|
+
chat_player_id: 'Chat Player ID',
|
|
69
|
+
chat_private_player_id: 'Chat Private Player',
|
|
70
|
+
chat_room: 'Chat Room',
|
|
71
|
+
chat_type: 'Chat Type',
|
|
72
|
+
clan_id: 'Clan ID',
|
|
73
|
+
classKey: 'Class Key',
|
|
74
|
+
class_path: 'Class Path',
|
|
75
|
+
class_path_id: 'Class Path ID',
|
|
76
|
+
class_path_level: 'Level Key',
|
|
77
|
+
class_path_level_skill: 'Skill',
|
|
78
|
+
class_path_owner: 'Class Path Owner',
|
|
79
|
+
class_type: 'Class Type',
|
|
80
|
+
client_key: 'Client Key',
|
|
81
|
+
client_params: 'Client Params',
|
|
82
|
+
code: 'Code',
|
|
83
|
+
conditional: 'Conditional',
|
|
84
|
+
config: 'Config',
|
|
85
|
+
country_code: 'Country Code',
|
|
86
|
+
created_at: 'Created At',
|
|
87
|
+
criticalAffected: 'Critical Affected',
|
|
88
|
+
criticalChance: 'Critical Chance',
|
|
89
|
+
criticalFixedValue: 'Critical FixedValue',
|
|
90
|
+
criticalMultiplier: 'Critical Multiplier',
|
|
91
|
+
currentExp: 'Current Exp',
|
|
92
|
+
currentLevel: 'Current Level',
|
|
93
|
+
customData: 'Custom Data',
|
|
94
|
+
damageAffected: 'Damage Affected',
|
|
95
|
+
defenseProperties: 'Defense Properties',
|
|
96
|
+
description: 'Description',
|
|
97
|
+
dir: 'Dir',
|
|
98
|
+
direction: 'Direction',
|
|
99
|
+
drop_quantity: 'Drop Quantity',
|
|
100
|
+
drop_rate: 'Drop Rate',
|
|
101
|
+
dodgeFullEnabled: 'Dodge Full Enabled',
|
|
102
|
+
dodgeOverAimSuccess: 'Dodge Over Aim Success',
|
|
103
|
+
dodgeProperties: 'Dodge Properties',
|
|
104
|
+
duration: 'Duration',
|
|
105
|
+
email: 'Email',
|
|
106
|
+
enabled: 'Enabled',
|
|
107
|
+
ended_at: 'Ended At',
|
|
108
|
+
event_data: 'Event Data',
|
|
109
|
+
event_key: 'Event Key',
|
|
110
|
+
experience: 'Experience',
|
|
111
|
+
execTimeOut: 'Exec Time Out',
|
|
112
|
+
extra_params: 'Extra Params',
|
|
113
|
+
file: 'File',
|
|
114
|
+
files_name: 'Files Name',
|
|
115
|
+
from_room_id: 'From Room ID',
|
|
116
|
+
group_id: 'Group ID',
|
|
117
|
+
handler_key: 'Handler Key',
|
|
118
|
+
has_drop_body: 'Has Drop Body',
|
|
119
|
+
height: 'Height',
|
|
120
|
+
hitDamage: 'Hit Damage',
|
|
121
|
+
id: 'ID',
|
|
122
|
+
instances_limit: 'Instances Limit',
|
|
123
|
+
is_active: 'Is Active',
|
|
124
|
+
is_default: 'Is Default',
|
|
125
|
+
is_enabled: 'Is Enabled',
|
|
126
|
+
is_unique: 'Is Unique',
|
|
127
|
+
item_id: 'Item ID',
|
|
128
|
+
item_key: 'Item Key',
|
|
129
|
+
items_limit: 'Items Limit',
|
|
130
|
+
key: 'Key',
|
|
131
|
+
kill_npc_id: 'Kill NPC ID',
|
|
132
|
+
kill_player_id: 'Kill Player ID',
|
|
133
|
+
kill_time: 'Kill Time',
|
|
134
|
+
label: 'Label',
|
|
135
|
+
label_level: 'Label Level',
|
|
136
|
+
language_code: 'Language Code',
|
|
137
|
+
last_npc_kill_time: 'Last NPC Kill Time',
|
|
138
|
+
last_player_kill_time: 'Last Player Kill Time',
|
|
139
|
+
layer: 'Layer',
|
|
140
|
+
layer_name: 'Layer Name',
|
|
141
|
+
level: 'Level',
|
|
142
|
+
level_id: 'Level ID',
|
|
143
|
+
level_owner: 'Level Owner',
|
|
144
|
+
level_set: 'Level Set',
|
|
145
|
+
level_set_id: 'Level Set ID',
|
|
146
|
+
levels_set_id: 'Levels Set ID',
|
|
147
|
+
limit_per_item: 'Limit Per Item',
|
|
148
|
+
locale: 'Locale',
|
|
149
|
+
locale_id: 'Locale ID',
|
|
150
|
+
login_count: 'Login Count',
|
|
151
|
+
login_date: 'Login Date',
|
|
152
|
+
logout_date: 'Logout Date',
|
|
153
|
+
map_filename: 'Map Filename',
|
|
154
|
+
marker_key: 'Marker Key',
|
|
155
|
+
maxProperty: 'Max Property',
|
|
156
|
+
maxValue: 'Max Value',
|
|
157
|
+
message: 'Message',
|
|
158
|
+
message_time: 'Message Time',
|
|
159
|
+
message_type: 'Message Type',
|
|
160
|
+
magnitude: 'Magnitude',
|
|
161
|
+
minProperty: 'Min Property',
|
|
162
|
+
minValue: 'Min Value',
|
|
163
|
+
modifier_id: 'Modifier ID',
|
|
164
|
+
name: 'Name',
|
|
165
|
+
next_room_id: 'Next Room ID',
|
|
166
|
+
npcs_kills_count: 'NPCs Kills Count',
|
|
167
|
+
objectHeight: 'Object Height',
|
|
168
|
+
objectWidth: 'Object Width',
|
|
169
|
+
object_asset_id: 'Object Asset ID',
|
|
170
|
+
object_class_key: 'Object Class Key',
|
|
171
|
+
object_id: 'Object ID',
|
|
172
|
+
obtained_score: 'Obtained Score',
|
|
173
|
+
operation: 'Operation',
|
|
174
|
+
owner_id: 'Owner ID',
|
|
175
|
+
parent_group: 'Parent Group',
|
|
176
|
+
parent_skill: 'Parent Skill',
|
|
177
|
+
path: 'Path',
|
|
178
|
+
password: 'Password',
|
|
179
|
+
player_id: 'Player ID',
|
|
180
|
+
played_time: 'Played Time',
|
|
181
|
+
players_kill_count: 'Players Kills Count',
|
|
182
|
+
players_kills_count: 'Players Kills Count',
|
|
183
|
+
points: 'Points',
|
|
184
|
+
position: 'Position',
|
|
185
|
+
position_bottom: 'Position Bottom',
|
|
186
|
+
position_left: 'Position Left',
|
|
187
|
+
position_right: 'Position Right',
|
|
188
|
+
position_top: 'Position Top',
|
|
189
|
+
private_params: 'Private Params',
|
|
190
|
+
private_player_id: 'Private Player ID',
|
|
191
|
+
property_key: 'Property Key',
|
|
192
|
+
provider_id: 'Provider ID',
|
|
193
|
+
qty: 'Qty',
|
|
194
|
+
qty_limit: 'Qty Limit',
|
|
195
|
+
range: 'Range',
|
|
196
|
+
rangeAutomaticValidation: 'Range Automatic Validation',
|
|
197
|
+
rangePropertyX: 'Range Property X',
|
|
198
|
+
rangePropertyY: 'Range Property Y',
|
|
199
|
+
rangeTargetPropertyX: 'Range Target Property X',
|
|
200
|
+
rangeTargetPropertyY: 'Range Target Property Y',
|
|
201
|
+
remaining_uses: 'Remaining Uses',
|
|
202
|
+
required_experience: 'Required Experience',
|
|
203
|
+
required_item_key: 'Required Item Key',
|
|
204
|
+
required_quantity: 'Required Quantity',
|
|
205
|
+
respawn_time: 'Respawn Time',
|
|
206
|
+
replay: 'Replay',
|
|
207
|
+
reward_item_is_required: 'Reward Item Is Required',
|
|
208
|
+
reward_item_key: 'Reward Item Key',
|
|
209
|
+
reward_quantity: 'Reward Quantity',
|
|
210
|
+
rewards_events_id: 'Rewards Events ID',
|
|
211
|
+
role_id: 'Role ID',
|
|
212
|
+
room_class_key: 'Room Class Key',
|
|
213
|
+
room_id: 'Room ID',
|
|
214
|
+
scene_images: 'Scene Images',
|
|
215
|
+
scope: 'Scope',
|
|
216
|
+
server_url: 'Server URL',
|
|
217
|
+
show_in_general: 'Show In General',
|
|
218
|
+
show_tab: 'Show Tab',
|
|
219
|
+
single_audio: 'Single Audio',
|
|
220
|
+
skill: 'Skill',
|
|
221
|
+
skillDelay: 'Skill Delay',
|
|
222
|
+
skill_id: 'Skill ID',
|
|
223
|
+
sort: 'Sort',
|
|
224
|
+
start: 'Start',
|
|
225
|
+
started_at: 'Started At',
|
|
226
|
+
state: 'State',
|
|
227
|
+
stat_id: 'Stat ID',
|
|
228
|
+
status: 'Status',
|
|
229
|
+
target_id: 'Target ID',
|
|
230
|
+
target_key: 'Target Key',
|
|
231
|
+
target_label: 'Target Label',
|
|
232
|
+
tile_index: 'Tile Index',
|
|
233
|
+
title: 'Title',
|
|
234
|
+
top: 'Top',
|
|
235
|
+
total_score: 'Total Score',
|
|
236
|
+
type: 'Type',
|
|
237
|
+
type_id: 'Type ID',
|
|
238
|
+
updated_at: 'Updated At',
|
|
239
|
+
useTimeOut: 'Use Time Out',
|
|
240
|
+
user_id: 'User ID',
|
|
241
|
+
username: 'Username',
|
|
242
|
+
usesLimit: 'Uses Limit',
|
|
243
|
+
uses_limit: 'Uses Limit',
|
|
244
|
+
validateTargetOnHit: 'Validate Target On Hit',
|
|
245
|
+
value: 'Value',
|
|
246
|
+
was_given: 'Was Given',
|
|
247
|
+
width: 'Width',
|
|
248
|
+
x: 'X',
|
|
249
|
+
y: 'Y'
|
|
250
|
+
};
|
|
251
|
+
for(let i of Object.keys(translations)){
|
|
252
|
+
if(!adminTranslations[i]){
|
|
253
|
+
adminTranslations[i] = {};
|
|
254
|
+
}
|
|
255
|
+
Object.assign(adminTranslations[i], translations[i]);
|
|
256
|
+
}
|
|
257
|
+
return adminTranslations;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
module.exports.AdminTranslations = AdminTranslations;
|
package/lib/installer.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - CMS - Installer
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { FileHandler, Encryptor } = require('@reldens/server-utils');
|
|
8
|
+
const { DriversMap, EntitiesGenerator, PrismaSchemaGenerator } = require('@reldens/storage');
|
|
9
|
+
const { Logger, sc } = require('@reldens/utils');
|
|
10
|
+
const mustache = require('mustache');
|
|
11
|
+
|
|
12
|
+
class Installer
|
|
13
|
+
{
|
|
14
|
+
|
|
15
|
+
constructor(props)
|
|
16
|
+
{
|
|
17
|
+
this.app = sc.get(props, 'app', false);
|
|
18
|
+
this.appServerFactory = sc.get(props, 'appServerFactory', false);
|
|
19
|
+
this.projectRoot = sc.get(props, 'projectRoot', './');
|
|
20
|
+
this.encoding = sc.get(props, 'encoding', 'utf8');
|
|
21
|
+
this.installLockPath = FileHandler.joinPaths(this.projectRoot, 'install.lock');
|
|
22
|
+
this.envFilePath = FileHandler.joinPaths(this.projectRoot, '.env');
|
|
23
|
+
this.modulePath = FileHandler.joinPaths(__dirname, '..');
|
|
24
|
+
this.installerPath = FileHandler.joinPaths(this.modulePath, 'install');
|
|
25
|
+
this.migrationsPath = FileHandler.joinPaths(this.modulePath, 'migrations');
|
|
26
|
+
this.defaultTemplatesPath = FileHandler.joinPaths(this.modulePath, 'templates');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
isInstalled()
|
|
30
|
+
{
|
|
31
|
+
return FileHandler.exists(this.installLockPath);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async prepareSetup(app, appServerFactory)
|
|
35
|
+
{
|
|
36
|
+
if(!app){
|
|
37
|
+
Logger.error('Missing app on prepareSetup for Installer.');
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
if(!appServerFactory){
|
|
41
|
+
Logger.error('Missing appServerFactory on prepareSetup for Installer.');
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
this.app = app;
|
|
45
|
+
this.appServerFactory = appServerFactory;
|
|
46
|
+
app.use('/install-assets', appServerFactory.applicationFramework.static(this.installerPath, {index: false}));
|
|
47
|
+
app.use(appServerFactory.session({
|
|
48
|
+
secret: Encryptor.generateSecretKey(),
|
|
49
|
+
resave: true,
|
|
50
|
+
saveUninitialized: true
|
|
51
|
+
}));
|
|
52
|
+
app.use(async (req, res, next) => {
|
|
53
|
+
return await this.executeForEveryRequest(req, res, next);
|
|
54
|
+
});
|
|
55
|
+
app.post('/install', async (req, res) => {
|
|
56
|
+
return await this.executeInstallProcess(req, res);
|
|
57
|
+
});
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async executeForEveryRequest(req, res, next)
|
|
62
|
+
{
|
|
63
|
+
if(this.isInstalled()){
|
|
64
|
+
return next();
|
|
65
|
+
}
|
|
66
|
+
if('' === req._parsedUrl.pathname || '/' === req._parsedUrl.pathname){
|
|
67
|
+
let installerIndexPath = FileHandler.joinPaths(this.installerPath, 'index.html');
|
|
68
|
+
if(!FileHandler.exists(installerIndexPath)){
|
|
69
|
+
return res.status(500).send('Installer template not found');
|
|
70
|
+
}
|
|
71
|
+
let content = FileHandler.readFile(installerIndexPath, {
|
|
72
|
+
encoding: this.encoding
|
|
73
|
+
});
|
|
74
|
+
return res.send(mustache.render(content, req.session?.templateVariables || this.fetchDefaults()));
|
|
75
|
+
}
|
|
76
|
+
next();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async executeInstallProcess(req, res)
|
|
80
|
+
{
|
|
81
|
+
if(this.isInstalled()){
|
|
82
|
+
return res.redirect('/?redirect=already-installed');
|
|
83
|
+
}
|
|
84
|
+
let templateVariables = req.body;
|
|
85
|
+
req.session.templateVariables = templateVariables;
|
|
86
|
+
let selectedDriver = templateVariables['db-storage-driver'];
|
|
87
|
+
let driverClass = DriversMap[selectedDriver];
|
|
88
|
+
if(!driverClass){
|
|
89
|
+
Logger.error('Invalid storage driver: ' + selectedDriver);
|
|
90
|
+
return res.redirect('/?error=invalid-driver');
|
|
91
|
+
}
|
|
92
|
+
let dbConfig = {
|
|
93
|
+
client: templateVariables['db-client'],
|
|
94
|
+
config: {
|
|
95
|
+
host: templateVariables['db-host'],
|
|
96
|
+
port: Number(templateVariables['db-port']),
|
|
97
|
+
database: templateVariables['db-name'],
|
|
98
|
+
user: templateVariables['db-username'],
|
|
99
|
+
password: templateVariables['db-password'],
|
|
100
|
+
multipleStatements: true
|
|
101
|
+
},
|
|
102
|
+
debug: false
|
|
103
|
+
};
|
|
104
|
+
if('prisma' === selectedDriver){
|
|
105
|
+
await this.generatePrismaSchema(dbConfig);
|
|
106
|
+
Logger.info('Generated Prisma schema.');
|
|
107
|
+
}
|
|
108
|
+
let dbDriver = new driverClass(dbConfig);
|
|
109
|
+
if(!await dbDriver.connect()){
|
|
110
|
+
Logger.error('Connection failed');
|
|
111
|
+
return res.redirect('/?error=connection-failed');
|
|
112
|
+
}
|
|
113
|
+
if(!sc.isObjectFunction(dbDriver, 'rawQuery')){
|
|
114
|
+
Logger.error('Method "rawQuery" not found');
|
|
115
|
+
return res.redirect('/?error=raw-query-not-found');
|
|
116
|
+
}
|
|
117
|
+
let installSqlPath = FileHandler.joinPaths(this.migrationsPath, 'install.sql');
|
|
118
|
+
if(!FileHandler.exists(installSqlPath)){
|
|
119
|
+
Logger.error('SQL installation file not found');
|
|
120
|
+
return res.redirect('/?error=sql-file-not-found');
|
|
121
|
+
}
|
|
122
|
+
await this.executeQueryFile(dbDriver, installSqlPath);
|
|
123
|
+
Logger.info('Installed tables.');
|
|
124
|
+
let defaultUserSqlPath = FileHandler.joinPaths(this.migrationsPath, 'default-user.sql');
|
|
125
|
+
try {
|
|
126
|
+
if(FileHandler.exists(defaultUserSqlPath)){
|
|
127
|
+
await this.executeQueryFile(dbDriver, defaultUserSqlPath);
|
|
128
|
+
Logger.info('Created default user.');
|
|
129
|
+
}
|
|
130
|
+
let connectionData = {
|
|
131
|
+
client: dbConfig.client,
|
|
132
|
+
connection: dbConfig.config
|
|
133
|
+
};
|
|
134
|
+
await this.generateEntities(connectionData);
|
|
135
|
+
Logger.info('Generated entities.');
|
|
136
|
+
} catch (error) {
|
|
137
|
+
Logger.error('Installation error: '+error.message);
|
|
138
|
+
return res.redirect('/?error=installation-process-failed');
|
|
139
|
+
}
|
|
140
|
+
if('' === templateVariables['app-admin-path']){
|
|
141
|
+
templateVariables['app-admin-path'] = '/reldens-admin';
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
await this.createEnvFile(templateVariables);
|
|
145
|
+
await this.createLockFile();
|
|
146
|
+
await this.prepareProjectDirectories();
|
|
147
|
+
Logger.info('Installation successful!');
|
|
148
|
+
let adminPath = templateVariables['app-admin-path'];
|
|
149
|
+
return res.redirect(adminPath);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
Logger.error('Configuration error: '+error.message);
|
|
152
|
+
return res.redirect('/?error=configuration-error');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async executeQueryFile(dbDriver, filePath)
|
|
157
|
+
{
|
|
158
|
+
let sqlContent = FileHandler.readFile(filePath, {
|
|
159
|
+
encoding: this.encoding
|
|
160
|
+
});
|
|
161
|
+
if(!sqlContent){
|
|
162
|
+
throw new Error('Could not read SQL file: '+filePath);
|
|
163
|
+
}
|
|
164
|
+
return await dbDriver.rawQuery(sqlContent.toString());
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async generateEntities(connectionData)
|
|
168
|
+
{
|
|
169
|
+
let generator = new EntitiesGenerator({connectionData: connectionData, projectPath: this.projectRoot});
|
|
170
|
+
let success = await generator.generate();
|
|
171
|
+
if(!success){
|
|
172
|
+
Logger.error('Entities generation failed.');
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
Logger.info('Entities generation success.');
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async generatePrismaSchema(connectionData)
|
|
180
|
+
{
|
|
181
|
+
let generator = new PrismaSchemaGenerator({
|
|
182
|
+
...connectionData,
|
|
183
|
+
prismaSchemaPath: this.projectRoot+'/prisma'
|
|
184
|
+
});
|
|
185
|
+
let success = await generator.generate();
|
|
186
|
+
if(!success){
|
|
187
|
+
Logger.error('Prisma schema generation failed.');
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async createEnvFile(templateVariables)
|
|
194
|
+
{
|
|
195
|
+
let envTemplatePath = FileHandler.joinPaths(this.defaultTemplatesPath, '.env.dist');
|
|
196
|
+
if(!FileHandler.exists(envTemplatePath)){
|
|
197
|
+
Logger.error('ENV template not found: '+envTemplatePath);
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
let envTemplate = FileHandler.readFile(envTemplatePath, {
|
|
201
|
+
encoding: this.encoding
|
|
202
|
+
});
|
|
203
|
+
let envContent = mustache.render(envTemplate, {
|
|
204
|
+
dbClient: templateVariables['db-client'],
|
|
205
|
+
dbHost: templateVariables['db-host'],
|
|
206
|
+
dbPort: templateVariables['db-port'],
|
|
207
|
+
dbName: templateVariables['db-name'],
|
|
208
|
+
dbUser: templateVariables['db-username'],
|
|
209
|
+
dbPassword: templateVariables['db-password'],
|
|
210
|
+
dbDriver: templateVariables['db-storage-driver'],
|
|
211
|
+
adminPath: templateVariables['app-admin-path'],
|
|
212
|
+
adminSecret: Encryptor.generateSecretKey(),
|
|
213
|
+
host: templateVariables['app-host'] || 'http://localhost',
|
|
214
|
+
port: templateVariables['app-port'] || '3000'
|
|
215
|
+
});
|
|
216
|
+
return FileHandler.writeFile(this.envFilePath, envContent);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async createLockFile()
|
|
220
|
+
{
|
|
221
|
+
return FileHandler.writeFile(this.installLockPath,
|
|
222
|
+
'Installation completed on '+new Date().toISOString());
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async prepareProjectDirectories()
|
|
226
|
+
{
|
|
227
|
+
let projectTemplatesPath = FileHandler.joinPaths(this.projectRoot, 'templates');
|
|
228
|
+
if(!FileHandler.exists(projectTemplatesPath)){
|
|
229
|
+
FileHandler.createFolder(projectTemplatesPath);
|
|
230
|
+
}
|
|
231
|
+
let projectPublicPath = FileHandler.joinPaths(this.projectRoot, 'public');
|
|
232
|
+
if(!FileHandler.exists(projectPublicPath)){
|
|
233
|
+
FileHandler.createFolder(projectPublicPath);
|
|
234
|
+
}
|
|
235
|
+
let projectCssPath = FileHandler.joinPaths(projectPublicPath, 'css');
|
|
236
|
+
if(!FileHandler.exists(projectCssPath)){
|
|
237
|
+
FileHandler.createFolder(projectCssPath);
|
|
238
|
+
}
|
|
239
|
+
let projectJsPath = FileHandler.joinPaths(projectPublicPath, 'js');
|
|
240
|
+
if(!FileHandler.exists(projectJsPath)){
|
|
241
|
+
FileHandler.createFolder(projectJsPath);
|
|
242
|
+
}
|
|
243
|
+
let defaultPagePath = FileHandler.joinPaths(this.defaultTemplatesPath, 'page.html');
|
|
244
|
+
let defaultNotFoundPath = FileHandler.joinPaths(this.defaultTemplatesPath, '404.html');
|
|
245
|
+
let defaultLayoutPath = FileHandler.joinPaths(this.defaultTemplatesPath, 'layout.html');
|
|
246
|
+
if(FileHandler.exists(defaultPagePath)){
|
|
247
|
+
FileHandler.copyFile(defaultPagePath, FileHandler.joinPaths(projectTemplatesPath, 'page.html'));
|
|
248
|
+
}
|
|
249
|
+
if(FileHandler.exists(defaultNotFoundPath)){
|
|
250
|
+
FileHandler.copyFile(defaultNotFoundPath, FileHandler.joinPaths(projectTemplatesPath, '404.html'));
|
|
251
|
+
}
|
|
252
|
+
if(FileHandler.exists(defaultLayoutPath)){
|
|
253
|
+
FileHandler.copyFile(defaultLayoutPath, FileHandler.joinPaths(projectTemplatesPath, 'layout.html'));
|
|
254
|
+
}
|
|
255
|
+
let defaultCssPath = FileHandler.joinPaths(this.defaultTemplatesPath, 'css', 'styles.css');
|
|
256
|
+
let defaultJsPath = FileHandler.joinPaths(this.defaultTemplatesPath, 'js', 'scripts.js');
|
|
257
|
+
if(FileHandler.exists(defaultCssPath)){
|
|
258
|
+
FileHandler.copyFile(defaultCssPath, FileHandler.joinPaths(projectCssPath, 'styles.css'));
|
|
259
|
+
}
|
|
260
|
+
if(FileHandler.exists(defaultJsPath)){
|
|
261
|
+
FileHandler.copyFile(defaultJsPath, FileHandler.joinPaths(projectJsPath, 'scripts.js'));
|
|
262
|
+
}
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
fetchDefaults()
|
|
267
|
+
{
|
|
268
|
+
return {
|
|
269
|
+
'app-host': process.env.RELDENS_CMS_HOST || 'http://localhost',
|
|
270
|
+
'app-port': process.env.RELDENS_CMS_PORT || '3000',
|
|
271
|
+
'app-admin-path': process.env.RELDENS_CMS_ADMIN_PATH || '/reldens-admin',
|
|
272
|
+
'db-storage-driver': 'prisma',
|
|
273
|
+
'db-client': process.env.RELDENS_CMS_DB_CLIENT || 'mysql2',
|
|
274
|
+
'db-host': process.env.RELDENS_CMS_DB_HOST || 'localhost',
|
|
275
|
+
'db-port': process.env.RELDENS_CMS_DB_PORT || '3306',
|
|
276
|
+
'db-name': process.env.RELDENS_CMS_DB_NAME || 'reldens_cms',
|
|
277
|
+
'db-username': process.env.RELDENS_CMS_DB_USER || '',
|
|
278
|
+
'db-password': process.env.RELDENS_CMS_DB_PASSWORD || ''
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports.Installer = Installer;
|