1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Epesi\Core\System; |
4
|
|
|
|
5
|
|
|
use Epesi\Core\System\View\Form; |
6
|
|
|
use atk4\ui\Wizard; |
7
|
|
|
use Illuminate\Support\Facades\Artisan; |
8
|
|
|
use Epesi\Core\System\Modules\Concerns\HasAdminMode; |
9
|
|
|
use Illuminate\Support\Facades\App; |
10
|
|
|
use Epesi\Core\System\Modules\ModuleManager; |
11
|
|
|
use Epesi\Core\System\User\Database\Models\User; |
12
|
|
|
use Illuminate\Support\Facades\Hash; |
13
|
|
|
use atk4\ui\View; |
14
|
|
|
use atk4\ui\Message; |
15
|
|
|
|
16
|
|
|
class SystemInstallWizard extends Wizard |
17
|
|
|
{ |
18
|
|
|
use HasAdminMode; |
19
|
|
|
|
20
|
|
|
protected function init(): void |
21
|
|
|
{ |
22
|
|
|
parent::init(); |
23
|
|
|
|
24
|
|
|
$this->setAdminMode()->performInstallationSteps(); |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
public function performInstallationSteps() |
28
|
|
|
{ |
29
|
|
|
$this->addStep(__('Welcome'), [__CLASS__, 'stepWelcome']); |
30
|
|
|
|
31
|
|
|
$this->addStep([__('License'), 'icon'=>'id card', 'description'=>__('Accept license conditions')], [self::class, 'stepLicense']); |
32
|
|
|
|
33
|
|
|
$this->addStep([__('Database'), 'icon'=>'database', 'description'=>__('Database connection settings')], [self::class, 'stepDatabase']); |
34
|
|
|
|
35
|
|
|
$this->addStep([__('Environment'), 'icon'=>'configure', 'description'=>__('Check environment')], [self::class, 'stepEnvironment']); |
36
|
|
|
|
37
|
|
|
$this->addStep([__('Super Admin'), 'icon'=>'user', 'description'=>__('Create first user')], [self::class, 'stepUser']); |
38
|
|
|
|
39
|
|
|
$this->addStep([__('Complete'), 'icon'=>'check', 'description'=>__('Complete installation')], [self::class, 'stepInstallationCompleted']); |
40
|
|
|
|
41
|
|
|
// below step is skipped because of redirecting to 'login' path once system installed |
42
|
|
|
// see \Epesi\Core\Controller::install |
43
|
|
|
$this->addFinish(\Closure::fromCallable([self::class, 'stepInstallationCompleted'])); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
public function addRequiredNote() |
47
|
|
|
{ |
48
|
|
|
View::addTo($this, [__('denotes required field'), 'class' => ['required-note']])->setStyle(['float' => 'right']); |
49
|
|
|
|
50
|
|
|
$this->getApp()->addStyle(' |
51
|
|
|
.required-note::before { |
52
|
|
|
margin: 0 .2em 0 0; |
53
|
|
|
content: \'*\'; |
54
|
|
|
color: #db2828; |
55
|
|
|
} |
56
|
|
|
'); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
public function setForm($form) |
60
|
|
|
{ |
61
|
|
|
$this->buttonNext->on('click', $form->js()->submit()); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
public static function stepWelcome($wizard) |
65
|
|
|
{ |
66
|
|
|
$columns = \atk4\ui\Columns::addTo($wizard); |
67
|
|
|
|
68
|
|
|
$column = $columns->addColumn(); |
69
|
|
|
Message::addTo($column, [__('Thank you for downloading EPESI!')])->text |
70
|
|
|
->addParagraph(__('This wizard will guide you though the process of setting up your new CRM / ERP installation')) |
|
|
|
|
71
|
|
|
->addParagraph(__('Select the installation language and click NEXT button to proceed to next step')); |
72
|
|
|
|
73
|
|
|
$column = $columns->addColumn(); |
74
|
|
|
|
75
|
|
|
$systemLanguages = app()->make(\JoeDixon\Translation\Drivers\Translation::class)->allLanguages()->toArray(); |
76
|
|
|
|
77
|
|
|
$values = array_intersect_key(self::getDisplayLanguages(), $systemLanguages); |
78
|
|
|
|
79
|
|
|
$form = Form::addTo($column); |
80
|
|
|
|
81
|
|
|
$form->addControl('language', [\atk4\ui\Form\Control\Dropdown::class, 'values' => $values, 'caption' => __('Select Language'), 'iconLeft' => 'globe'], ['required'=>true])->set($wizard->recall('language', 'en')); |
82
|
|
|
|
83
|
|
|
$form->onSubmit(function ($form) use ($wizard) { |
84
|
|
|
$wizard->memorize('language', $form->model->get('language')); |
85
|
|
|
|
86
|
|
|
App::setLocale($form->model->get('language')); |
87
|
|
|
|
88
|
|
|
return $wizard->jsNext(); |
89
|
|
|
}); |
90
|
|
|
|
91
|
|
|
$wizard->setForm($form); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
public static function stepLicense($wizard) |
95
|
|
|
{ |
96
|
|
|
$columns = \atk4\ui\Columns::addTo($wizard); |
97
|
|
|
$column = $columns->addColumn(); |
98
|
|
|
|
99
|
|
|
$license = View::addTo($column, ['defaultTemplate' => 'license.html'])->setStyle(['max-height' => '500px', 'overflow' => 'auto', 'padding' => '5px']); |
100
|
|
|
|
101
|
|
|
$license->js(true)->niceScroll(); |
102
|
|
|
|
103
|
|
|
$license->template->setHTML('epesi', config('epesi.ui.title')); |
|
|
|
|
104
|
|
|
|
105
|
|
|
$license->template->setHTML('copyright', config('epesi.ui.copyright')); |
|
|
|
|
106
|
|
|
|
107
|
|
|
$column = $columns->addColumn(); |
108
|
|
|
|
109
|
|
|
$form = Form::addTo($column); |
110
|
|
|
$form->addControl('copyright', [\atk4\ui\Form\Control\Checkbox::class, 'caption' => __('I will not remove the Copyright notice as required by the MIT license.')], ['required'=>true]); |
111
|
|
|
$form->addControl('logo', [\atk4\ui\Form\Control\Checkbox::class, 'caption' => __('I will not remove ":epesi powered" logo and the link from the application login screen or the toolbar.', ['epesi' => config('epesi.ui.title')])], ['required'=>true]); |
112
|
|
|
$form->addControl('support', [\atk4\ui\Form\Control\Checkbox::class, 'caption' => __('I will not remove "Support -> About" credit page from the application menu.')], ['required'=>true]); |
113
|
|
|
$form->addControl('store', [\atk4\ui\Form\Control\Checkbox::class, 'caption' => __('I will not remove or rename ":epesi Store" links from the application.', ['epesi' => config('epesi.ui.title')])], ['required'=>true]); |
114
|
|
|
|
115
|
|
|
$form->onSubmit(function ($form) use ($wizard) { |
|
|
|
|
116
|
|
|
return $wizard->jsNext(); |
117
|
|
|
}); |
118
|
|
|
|
119
|
|
|
$wizard->setForm($form); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
public static function stepDatabase($wizard) |
123
|
|
|
{ |
124
|
|
|
$wizard->addRequiredNote(); |
125
|
|
|
|
126
|
|
|
$form = Form::addTo($wizard); |
127
|
|
|
|
128
|
|
|
$form->addControl('host', __('Database Host'), ['required'=>true])->placeholder = __('e.g. localhost'); |
129
|
|
|
$form->addControl('port', __('Database Port')); |
130
|
|
|
|
131
|
|
|
$form->addControl('driver', [\atk4\ui\Form\Control\Dropdown::class, 'values' => [ |
132
|
|
|
'mysql' => 'MySQL', |
133
|
|
|
'postgre' => 'PostgeSQL', |
134
|
|
|
], 'caption' => __('Database Engine')], ['required'=>true]); |
135
|
|
|
|
136
|
|
|
$form->addControl('database', __('Database Name')); |
137
|
|
|
$form->addControl('username', __('Database Server User'), ['required'=>true]); |
138
|
|
|
$form->addControl('password', [\atk4\ui\Form\Control\Password::class, 'caption' => __('Database Server Password')], ['required'=>true]); |
139
|
|
|
|
140
|
|
|
$form->addControl('create', [\atk4\ui\Form\Control\Checkbox::class, 'caption' => __('Create New Database')])->on('change', new \atk4\ui\JsExpression('if ($(event.target).is(":checked")) alert([])', [__('WARNING: Make sure you have CREATE access level to do this!')])); |
|
|
|
|
141
|
|
|
|
142
|
|
|
foreach ($wizard->recall('connection', []) as $name => $value) { |
143
|
|
|
if (! $field = $form->fields[$name]?? null) continue; |
|
|
|
|
144
|
|
|
|
145
|
|
|
$field->set($value); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
$form->onSubmit(function ($form) use ($wizard) { |
149
|
|
|
$connection = $form->model->get(); |
150
|
|
|
|
151
|
|
|
$wizard->memorize('connection', $connection); |
152
|
|
|
|
153
|
|
|
Artisan::call('epesi:database-connection', ['--connection' => $connection]); |
154
|
|
|
|
155
|
|
|
if ($connection['create']) { |
156
|
|
|
Artisan::call('epesi:database-create', ['name' => $connection['database'], '--connection' => $connection]); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
ModuleManager::clearCache(); |
160
|
|
|
|
161
|
|
|
Artisan::call('config:clear'); |
162
|
|
|
Artisan::call('cache:clear'); |
163
|
|
|
|
164
|
|
|
return $wizard->jsNext(); |
165
|
|
|
}); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
public static function stepEnvironment($wizard) |
169
|
|
|
{ |
170
|
|
|
$wizard->add(new SystemEnvironmentOverview()); |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
public static function stepUser($wizard) |
174
|
|
|
{ |
175
|
|
|
$wizard->addRequiredNote(); |
176
|
|
|
|
177
|
|
|
$form = Form::addTo($wizard, ['buttonSave' => [\atk4\ui\Button::class]]); |
178
|
|
|
|
179
|
|
|
$form->addControl('name', __('Name'), ['required'=>true])->placeholder = __('e.g. John Doe'); |
180
|
|
|
$form->addControl('email', __('Email'), ['required'=>true])->placeholder = __('e.g. [email protected]'); |
181
|
|
|
$form->addControl('password', [\atk4\ui\Form\Control\Password::class, 'caption' => __('Password')], ['required'=>true]); |
182
|
|
|
$form->addControl('password_verify', [\atk4\ui\Form\Control\Password::class, 'caption' => __('Verify Password')], ['required'=>true]); |
183
|
|
|
|
184
|
|
|
$form->addFieldRules('email', [[ |
|
|
|
|
185
|
|
|
'type' => 'email', |
186
|
|
|
'prompt' => __('Invalid email address') |
187
|
|
|
]]); |
188
|
|
|
|
189
|
|
|
$form->addFieldRules('password_verify', [[ |
190
|
|
|
'type' => 'match[password]', |
191
|
|
|
'prompt' => __('Password mismatch') |
192
|
|
|
]]); |
193
|
|
|
|
194
|
|
|
$form->model->setMulti($wizard->recall('user', [])); |
195
|
|
|
|
196
|
|
|
$form->validate(function ($form) use ($wizard) { |
197
|
|
|
$wizard->memorize('user', $form->model->get()); |
198
|
|
|
|
199
|
|
|
return $wizard->jsNext(); |
200
|
|
|
}); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
public static function stepInstallationCompleted($wizard) |
204
|
|
|
{ |
205
|
|
|
Artisan::call('migrate'); |
206
|
|
|
|
207
|
|
|
ob_start(); |
208
|
|
|
ModuleManager::install('system'); |
209
|
|
|
ob_end_clean(); |
210
|
|
|
|
211
|
|
|
// run boot routine for newly installed modules |
212
|
|
|
ModuleManager::call('boot'); |
213
|
|
|
|
214
|
|
|
$user = $wizard->recall('user'); |
215
|
|
|
|
216
|
|
|
User::create([ |
217
|
|
|
'name' => $user['name'], |
218
|
|
|
'email' => $user['email'], |
219
|
|
|
'password' => Hash::make($user['password']), |
220
|
|
|
])->assignRole('Super Admin'); |
221
|
|
|
|
222
|
|
|
\atk4\ui\Header::addTo($wizard, [__(':epesi was successfully installed!', ['epesi' => config('epesi.ui.title')]), 'huge centered']); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
public static function getDisplayLanguages() { |
226
|
|
|
return [ |
227
|
|
|
'aa' => __('Afar'), |
228
|
|
|
'ab' => __('Abkhazian'), |
229
|
|
|
'ae' => __('Avestan'), |
230
|
|
|
'af' => __('Afrikaans'), |
231
|
|
|
'ak' => __('Akan'), |
232
|
|
|
'am' => __('Amharic'), |
233
|
|
|
'an' => __('Aragonese'), |
234
|
|
|
'ar' => __('Arabic'), |
235
|
|
|
'as' => __('Assamese'), |
236
|
|
|
'av' => __('Avaric'), |
237
|
|
|
'ay' => __('Aymara'), |
238
|
|
|
'az' => __('Azerbaijani'), |
239
|
|
|
'ba' => __('Bashkir'), |
240
|
|
|
'be' => __('Belarusian'), |
241
|
|
|
'bg' => __('Bulgarian'), |
242
|
|
|
'bh' => __('Bihari'), |
243
|
|
|
'bi' => __('Bislama'), |
244
|
|
|
'bm' => __('Bambara'), |
245
|
|
|
'bn' => __('Bengali'), |
246
|
|
|
'bo' => __('Tibetan'), |
247
|
|
|
'br' => __('Breton'), |
248
|
|
|
'bs' => __('Bosnian'), |
249
|
|
|
'ca' => __('Catalan'), |
250
|
|
|
'ce' => __('Chechen'), |
251
|
|
|
'ch' => __('Chamorro'), |
252
|
|
|
'co' => __('Corsican'), |
253
|
|
|
'cr' => __('Cree'), |
254
|
|
|
'cs' => __('Czech'), |
255
|
|
|
'cu' => __('Church Slavic'), |
256
|
|
|
'cv' => __('Chuvash'), |
257
|
|
|
'cy' => __('Welsh'), |
258
|
|
|
'da' => __('Danish'), |
259
|
|
|
'de' => __('German'), |
260
|
|
|
'dv' => __('Divehi'), |
261
|
|
|
'dz' => __('Dzongkha'), |
262
|
|
|
'ee' => __('Ewe'), |
263
|
|
|
'el' => __('Greek'), |
264
|
|
|
'en' => __('English'), |
265
|
|
|
'eo' => __('Esperanto'), |
266
|
|
|
'es' => __('Spanish'), |
267
|
|
|
'et' => __('Estonian'), |
268
|
|
|
'eu' => __('Basque'), |
269
|
|
|
'fa' => __('Persian'), |
270
|
|
|
'ff' => __('Fulah'), |
271
|
|
|
'fi' => __('Finnish'), |
272
|
|
|
'fj' => __('Fijian'), |
273
|
|
|
'fo' => __('Faroese'), |
274
|
|
|
'fr' => __('French'), |
275
|
|
|
'fy' => __('Western Frisian'), |
276
|
|
|
'ga' => __('Irish'), |
277
|
|
|
'gd' => __('Scottish Gaelic'), |
278
|
|
|
'gl' => __('Galician'), |
279
|
|
|
'gn' => __('Guarani'), |
280
|
|
|
'gu' => __('Gujarati'), |
281
|
|
|
'gv' => __('Manx'), |
282
|
|
|
'ha' => __('Hausa'), |
283
|
|
|
'he' => __('Hebrew'), |
284
|
|
|
'hi' => __('Hindi'), |
285
|
|
|
'ho' => __('Hiri Motu'), |
286
|
|
|
'hr' => __('Croatian'), |
287
|
|
|
'ht' => __('Haitian'), |
288
|
|
|
'hu' => __('Hungarian'), |
289
|
|
|
'hy' => __('Armenian'), |
290
|
|
|
'hz' => __('Herero'), |
291
|
|
|
'ia' => __('Interlingua (International Auxiliary Language Association)'), |
292
|
|
|
'id' => __('Indonesian'), |
293
|
|
|
'ie' => __('Interlingue'), |
294
|
|
|
'ig' => __('Igbo'), |
295
|
|
|
'ii' => __('Sichuan Yi'), |
296
|
|
|
'ik' => __('Inupiaq'), |
297
|
|
|
'io' => __('Ido'), |
298
|
|
|
'is' => __('Icelandic'), |
299
|
|
|
'it' => __('Italian'), |
300
|
|
|
'iu' => __('Inuktitut'), |
301
|
|
|
'ja' => __('Japanese'), |
302
|
|
|
'jv' => __('Javanese'), |
303
|
|
|
'ka' => __('Georgian'), |
304
|
|
|
'kg' => __('Kongo'), |
305
|
|
|
'ki' => __('Kikuyu'), |
306
|
|
|
'kj' => __('Kwanyama'), |
307
|
|
|
'kk' => __('Kazakh'), |
308
|
|
|
'kl' => __('Kalaallisut'), |
309
|
|
|
'km' => __('Khmer'), |
310
|
|
|
'kn' => __('Kannada'), |
311
|
|
|
'ko' => __('Korean'), |
312
|
|
|
'kr' => __('Kanuri'), |
313
|
|
|
'ks' => __('Kashmiri'), |
314
|
|
|
'ku' => __('Kurdish'), |
315
|
|
|
'kv' => __('Komi'), |
316
|
|
|
'kw' => __('Cornish'), |
317
|
|
|
'ky' => __('Kirghiz'), |
318
|
|
|
'la' => __('Latin'), |
319
|
|
|
'lb' => __('Luxembourgish'), |
320
|
|
|
'lg' => __('Ganda'), |
321
|
|
|
'li' => __('Limburgish'), |
322
|
|
|
'ln' => __('Lingala'), |
323
|
|
|
'lo' => __('Lao'), |
324
|
|
|
'lt' => __('Lithuanian'), |
325
|
|
|
'lu' => __('Luba-Katanga'), |
326
|
|
|
'lv' => __('Latvian'), |
327
|
|
|
'mg' => __('Malagasy'), |
328
|
|
|
'mh' => __('Marshallese'), |
329
|
|
|
'mi' => __('Maori'), |
330
|
|
|
'mk' => __('Macedonian'), |
331
|
|
|
'ml' => __('Malayalam'), |
332
|
|
|
'mn' => __('Mongolian'), |
333
|
|
|
'mr' => __('Marathi'), |
334
|
|
|
'ms' => __('Malay'), |
335
|
|
|
'mt' => __('Maltese'), |
336
|
|
|
'my' => __('Burmese'), |
337
|
|
|
'na' => __('Nauru'), |
338
|
|
|
'nb' => __('Norwegian Bokmal'), |
339
|
|
|
'nd' => __('North Ndebele'), |
340
|
|
|
'ne' => __('Nepali'), |
341
|
|
|
'ng' => __('Ndonga'), |
342
|
|
|
'nl' => __('Dutch'), |
343
|
|
|
'nn' => __('Norwegian Nynorsk'), |
344
|
|
|
'no' => __('Norwegian'), |
345
|
|
|
'nr' => __('South Ndebele'), |
346
|
|
|
'nv' => __('Navajo'), |
347
|
|
|
'ny' => __('Chichewa'), |
348
|
|
|
'oc' => __('Occitan'), |
349
|
|
|
'oj' => __('Ojibwa'), |
350
|
|
|
'om' => __('Oromo'), |
351
|
|
|
'or' => __('Oriya'), |
352
|
|
|
'os' => __('Ossetian'), |
353
|
|
|
'pa' => __('Panjabi'), |
354
|
|
|
'pi' => __('Pali'), |
355
|
|
|
'pl' => __('Polish'), |
356
|
|
|
'ps' => __('Pashto'), |
357
|
|
|
'pt' => __('Portuguese'), |
358
|
|
|
'qu' => __('Quechua'), |
359
|
|
|
'rm' => __('Raeto-Romance'), |
360
|
|
|
'rn' => __('Kirundi'), |
361
|
|
|
'ro' => __('Romanian'), |
362
|
|
|
'ru' => __('Russian'), |
363
|
|
|
'rw' => __('Kinyarwanda'), |
364
|
|
|
'sa' => __('Sanskrit'), |
365
|
|
|
'sc' => __('Sardinian'), |
366
|
|
|
'sd' => __('Sindhi'), |
367
|
|
|
'se' => __('Northern Sami'), |
368
|
|
|
'sg' => __('Sango'), |
369
|
|
|
'si' => __('Sinhala'), |
370
|
|
|
'sk' => __('Slovak'), |
371
|
|
|
'sl' => __('Slovenian'), |
372
|
|
|
'sm' => __('Samoan'), |
373
|
|
|
'sn' => __('Shona'), |
374
|
|
|
'so' => __('Somali'), |
375
|
|
|
'sq' => __('Albanian'), |
376
|
|
|
'sr' => __('Serbian'), |
377
|
|
|
'ss' => __('Swati'), |
378
|
|
|
'st' => __('Southern Sotho'), |
379
|
|
|
'su' => __('Sundanese'), |
380
|
|
|
'sv' => __('Swedish'), |
381
|
|
|
'sw' => __('Swahili'), |
382
|
|
|
'ta' => __('Tamil'), |
383
|
|
|
'te' => __('Telugu'), |
384
|
|
|
'tg' => __('Tajik'), |
385
|
|
|
'th' => __('Thai'), |
386
|
|
|
'ti' => __('Tigrinya'), |
387
|
|
|
'tk' => __('Turkmen'), |
388
|
|
|
'tl' => __('Tagalog'), |
389
|
|
|
'tn' => __('Tswana'), |
390
|
|
|
'to' => __('Tonga'), |
391
|
|
|
'tr' => __('Turkish'), |
392
|
|
|
'ts' => __('Tsonga'), |
393
|
|
|
'tt' => __('Tatar'), |
394
|
|
|
'tw' => __('Twi'), |
395
|
|
|
'ty' => __('Tahitian'), |
396
|
|
|
'ug' => __('Uighur'), |
397
|
|
|
'uk' => __('Ukrainian'), |
398
|
|
|
'ur' => __('Urdu'), |
399
|
|
|
'uz' => __('Uzbek'), |
400
|
|
|
've' => __('Venda'), |
401
|
|
|
'vi' => __('Vietnamese'), |
402
|
|
|
'vo' => __('Volapuk'), |
403
|
|
|
'wa' => __('Walloon'), |
404
|
|
|
'wo' => __('Wolof'), |
405
|
|
|
'xh' => __('Xhosa'), |
406
|
|
|
'yi' => __('Yiddish'), |
407
|
|
|
'yo' => __('Yoruba'), |
408
|
|
|
'za' => __('Zhuang'), |
409
|
|
|
'zh' => __('Chinese'), |
410
|
|
|
'zu' => __('Zulu') |
411
|
|
|
]; |
412
|
|
|
} |
413
|
|
|
} |
414
|
|
|
|