Passed
Pull Request — 2.x (#1042)
by Antonio Carlos
06:10
created

TwillServiceProvider::check2FA()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
nc 3
nop 0
dl 0
loc 11
ccs 0
cts 0
cp 0
crap 12
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace A17\Twill;
4
5
use Exception;
6
use A17\Twill\Commands\BlockMake;
7
use A17\Twill\Commands\Build;
8
use A17\Twill\Commands\CapsuleInstall;
9
use A17\Twill\Commands\CreateSuperAdmin;
10
use A17\Twill\Commands\Dev;
11
use A17\Twill\Commands\GenerateBlocks;
12
use A17\Twill\Commands\Install;
13
use A17\Twill\Commands\ListBlocks;
14
use A17\Twill\Commands\ListIcons;
15
use A17\Twill\Commands\MakeCapsule;
16
use A17\Twill\Commands\ModuleMake;
17
use A17\Twill\Commands\ModuleMakeDeprecated;
18
use A17\Twill\Commands\RefreshLQIP;
19
use A17\Twill\Commands\SyncLang;
20
use A17\Twill\Commands\Update;
21
use A17\Twill\Http\ViewComposers\ActiveNavigation;
22
use A17\Twill\Http\ViewComposers\CurrentUser;
23
use A17\Twill\Http\ViewComposers\FilesUploaderConfig;
24
use A17\Twill\Http\ViewComposers\Localization;
25
use A17\Twill\Http\ViewComposers\MediasUploaderConfig;
26
use A17\Twill\Models\Block;
27
use A17\Twill\Models\File;
28
use A17\Twill\Models\Media;
29
use A17\Twill\Models\User;
30
use A17\Twill\Services\Capsules\HasCapsules;
31
use A17\Twill\Services\FileLibrary\FileService;
32
use A17\Twill\Services\MediaLibrary\ImageService;
33
use Astrotomic\Translatable\TranslatableServiceProvider;
34
use Cartalyst\Tags\TagsServiceProvider;
35
use Illuminate\Database\Eloquent\Relations\Relation;
36
use Illuminate\Foundation\AliasLoader;
37
use Illuminate\Support\Facades\View;
38
use Illuminate\Support\ServiceProvider;
39
use Illuminate\Support\Str;
40
use Spatie\Activitylog\ActivitylogServiceProvider;
41
42
class TwillServiceProvider extends ServiceProvider
43
{
44
    use HasCapsules;
0 ignored issues
show
Bug introduced by
The trait A17\Twill\Services\Capsules\HasCapsules requires the property $command which is not provided by A17\Twill\TwillServiceProvider.
Loading history...
45
46
    /**
47
     * The Twill version.
48
     *
49
     * @var string
50
     */
51
    const VERSION = '2.4.0';
52
53
    /**
54
     * Service providers to be registered.
55
     *
56
     * @var string[]
57
     */
58
    protected $providers = [
59
        RouteServiceProvider::class,
60
        AuthServiceProvider::class,
61
        ValidationServiceProvider::class,
62
        TranslatableServiceProvider::class,
63
        TagsServiceProvider::class,
64
        ActivitylogServiceProvider::class,
65
        CapsulesServiceProvider::class,
66
    ];
67
68
    private $migrationsCounter = 0;
0 ignored issues
show
introduced by
The private property $migrationsCounter is not used, and could be removed.
Loading history...
69 73
70
    /**
71 73
     * Bootstraps the package services.
72
     *
73 73
     * @return void
74 73
     */
75 73
    public function boot()
76
    {
77 73
        $this->requireHelpers();
78
79 73
        $this->publishConfigs();
80 73
        $this->publishMigrations();
81
        $this->publishAssets();
82 73
83 73
        $this->registerCommands();
84 73
85
        $this->registerAndPublishViews();
86
        $this->registerAndPublishTranslations();
87
88
        $this->extendBlade();
89 73
        $this->addViewComposers();
90
91 73
        $this->check2FA();
92 73
    }
93 73
94 73
    /**
95 73
     * @return void
96 73
     */
97 73
    private function requireHelpers()
98
    {
99
        require_once __DIR__ . '/Helpers/routes_helpers.php';
100
        require_once __DIR__ . '/Helpers/i18n_helpers.php';
101
        require_once __DIR__ . '/Helpers/media_library_helpers.php';
102
        require_once __DIR__ . '/Helpers/frontend_helpers.php';
103
        require_once __DIR__ . '/Helpers/migrations_helpers.php';
104 73
        require_once __DIR__ . '/Helpers/helpers.php';
105
    }
106 73
107
    /**
108 73
     * Registers the package services.
109 73
     *
110
     * @return void
111 73
     */
112 73
    public function register()
113
    {
114
        $this->mergeConfigs();
115
116
        $this->registerProviders();
117
        $this->registerAliases();
118 73
119 73
        Relation::morphMap([
120
            'users' => User::class,
121
            'media' => Media::class,
122
            'files' => File::class,
123
            'blocks' => Block::class,
124
        ]);
125
126 73
        config(['twill.version' => $this->version()]);
127
    }
128 73
129 73
    /**
130
     * Registers the package service providers.
131
     *
132 73
     * @return void
133 73
     */
134 8
    private function registerProviders()
135 73
    {
136
        foreach ($this->providers as $provider) {
137
            $this->app->register($provider);
138 73
        }
139 73
140 3
        if (config('twill.enabled.media-library')) {
141 73
            $this->app->singleton('imageService', function () {
142
                return $this->app->make(config('twill.media_library.image_service'));
143 73
            });
144
        }
145
146
        if (config('twill.enabled.file-library')) {
147
            $this->app->singleton('fileService', function () {
148
                return $this->app->make(config('twill.file_library.file_service'));
149
            });
150 73
        }
151
    }
152 73
153
    /**
154 73
     * Registers the package facade aliases.
155 73
     *
156
     * @return void
157
     */
158 73
    private function registerAliases()
159 73
    {
160
        $loader = AliasLoader::getInstance();
161
162 73
        if (config('twill.enabled.media-library')) {
163
            $loader->alias('ImageService', ImageService::class);
164
        }
165
166
        if (config('twill.enabled.file-library')) {
167
            $loader->alias('FileService', FileService::class);
168
        }
169 73
170
    }
171 73
172 73
    /**
173 73
     * Defines the package configuration files for publishing.
174
     *
175
     * @return void
176
     */
177 73
    private function publishConfigs()
178 73
    {
179
        if (config('twill.enabled.users-management')) {
180
            config(['auth.providers.twill_users' => [
181
                'driver' => 'eloquent',
182 73
                'model' => User::class,
183 73
            ]]);
184 73
185 73
            config(['auth.guards.twill_users' => [
186
                'driver' => 'session',
187
                'provider' => 'twill_users',
188
            ]]);
189 73
190 73
            config(['auth.passwords.twill_users' => [
191
                'provider' => 'twill_users',
192 73
                'table' => config('twill.password_resets_table', 'twill_password_resets'),
193
                'expire' => 60,
194 73
            ]]);
195 73
        }
196 73
197 73
        config(['activitylog.enabled' => config('twill.enabled.dashboard') ? true : config('twill.enabled.activitylog')]);
198
        config(['activitylog.subject_returns_soft_deleted_models' => true]);
199
200
        config(['analytics.service_account_credentials_json' => config('twill.dashboard.analytics.service_account_credentials_json', storage_path('app/analytics/service-account-credentials.json'))]);
201
202
        $this->publishes([__DIR__ . '/../config/twill-publish.php' => config_path('twill.php')], 'config');
203
        $this->publishes([__DIR__ . '/../config/twill-navigation.php' => config_path('twill-navigation.php')], 'config');
204 73
        $this->publishes([__DIR__ . '/../config/translatable.php' => config_path('translatable.php')], 'config');
205
    }
206 73
207 73
    /**
208 73
     * Merges the package configuration files into the given configuration namespaces.
209 73
     *
210 73
     * @return void
211 73
     */
212 73
    private function mergeConfigs()
213 73
    {
214 73
        $this->mergeConfigFrom(__DIR__ . '/../config/twill.php', 'twill');
215 73
        $this->mergeConfigFrom(__DIR__ . '/../config/frontend.php', 'twill.frontend');
216 73
        $this->mergeConfigFrom(__DIR__ . '/../config/debug.php', 'twill.debug');
217 73
        $this->mergeConfigFrom(__DIR__ . '/../config/seo.php', 'twill.seo');
218 73
        $this->mergeConfigFrom(__DIR__ . '/../config/blocks.php', 'twill.block_editor');
219
        $this->mergeConfigFrom(__DIR__ . '/../config/enabled.php', 'twill.enabled');
220 73
        $this->mergeConfigFrom(__DIR__ . '/../config/file-library.php', 'twill.file_library');
221 73
        $this->mergeConfigFrom(__DIR__ . '/../config/media-library.php', 'twill.media_library');
222 73
        $this->mergeConfigFrom(__DIR__ . '/../config/imgix.php', 'twill.imgix');
223
        $this->mergeConfigFrom(__DIR__ . '/../config/glide.php', 'twill.glide');
224
        $this->mergeConfigFrom(__DIR__ . '/../config/dashboard.php', 'twill.dashboard');
225 73
        $this->mergeConfigFrom(__DIR__ . '/../config/oauth.php', 'twill.oauth');
226 73
        $this->mergeConfigFrom(__DIR__ . '/../config/disks.php', 'filesystems.disks');
227 73
228
        if (config('twill.media_library.endpoint_type') === 'local'
229
            && config('twill.media_library.disk') === 'twill_media_library') {
230 73
            $this->setLocalDiskUrl('media');
231 73
        }
232
233 73
        if (config('twill.file_library.endpoint_type') === 'local'
234
            && config('twill.file_library.disk') === 'twill_file_library') {
235 73
            $this->setLocalDiskUrl('file');
236 73
        }
237 73
238 73
        $this->mergeConfigFrom(__DIR__ . '/../config/services.php', 'services');
239 73
    }
240 73
241
    private function setLocalDiskUrl($type)
242 73
    {
243
        config([
244 73
            'filesystems.disks.twill_' . $type . '_library.url' => request()->getScheme()
245
            . '://'
246 73
            . str_replace(['http://', 'https://'], '', config('app.url'))
247 73
            . '/storage/'
248
            . trim(config('twill.' . $type . '_library.local_path'), '/ '),
249
        ]);
250 73
    }
251 73
252 73
    private function publishMigrations()
253
    {
254 73
        if (config('twill.load_default_migrations', true)) {
255 73
            $this->loadMigrationsFrom(__DIR__ . '/../migrations/default');
256 73
        }
257
258 73
        $this->publishes([
259
            __DIR__ . '/../migrations/default' => database_path('migrations'),
260 73
        ], 'migrations');
261 69
262
        $this->publishOptionalMigration('users-2fa');
263 69
        $this->publishOptionalMigration('users-oauth');
264 69
    }
265 69
266
    private function publishOptionalMigration($feature)
267 73
    {
268
        if (config('twill.enabled.' . $feature, false)) {
269
            $this->loadMigrationsFrom(__DIR__ . '/../migrations/optional/' . $feature);
270
271
            $this->publishes([
272 73
                __DIR__ . '/../migrations/optional/' . $feature => database_path('migrations'),
273
            ], 'migrations');
274 73
        }
275 73
    }
276 73
277 73
    /**
278
     * @return void
279
     */
280
    private function publishAssets()
281
    {
282 73
        $this->publishes([
283
            __DIR__ . '/../dist' => public_path(),
284 73
        ], 'assets');
285
    }
286 73
287 73
    /**
288 73
     * @return void
289
     */
290
    private function registerAndPublishViews()
291
    {
292
        $viewPath = __DIR__ . '/../views';
293 73
294
        $this->loadViewsFrom($viewPath, 'twill');
295 73
        $this->publishes([$viewPath => resource_path('views/vendor/twill')], 'views');
296 73
    }
297
298
    /**
299
     * @return void
300
     */
301
    private function registerCommands()
302
    {
303
        $this->commands([
304
            Install::class,
305
            ModuleMake::class,
306
            MakeCapsule::class,
307
            ModuleMakeDeprecated::class,
308
            BlockMake::class,
309
            ListIcons::class,
310 73
            ListBlocks::class,
311
            CreateSuperAdmin::class,
312
            RefreshLQIP::class,
313
            GenerateBlocks::class,
314
            Build::class,
315
            Update::class,
316
            Dev::class,
317 5
            SyncLang::class,
318
            CapsuleInstall::class,
319 5
        ]);
320
    }
321 5
322
    /**
323 5
     * @param string $view
324
     * @param string $expression
325 5
     * @return string
326 5
     */
327 5
    private function includeView($view, $expression)
328 5
    {
329 4
        [$name] = str_getcsv($expression, ',', '\'');
330
331
        $partialNamespace = view()->exists('admin.' . $view . $name) ? 'admin.' : 'twill::';
332 5
333
        $view = $partialNamespace . $view . $name;
334
335
        $expression = explode(',', $expression);
336
        array_shift($expression);
337
        $expression = "(" . implode(',', $expression) . ")";
338
        if ($expression === "()") {
339
            $expression = '([])';
340 73
        }
341
342 73
        return "<?php echo \$__env->make('{$view}', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render(); ?>";
343
    }
344 73
345
    /**
346 73
     * Defines the package additional Blade Directives.
347
     *
348 73
     * @return void
349
     */
350
    private function extendBlade()
351 73
    {
352
        $blade = $this->app['view']->getEngineResolver()->resolve('blade')->getCompiler();
353 73
354 5
        $blade->directive('dd', function ($param) {
355 73
            return "<?php dd({$param}); ?>";
356
        });
357 73
358
        $blade->directive('dumpData', function ($data) {
359 3
            return sprintf("<?php (new Symfony\Component\VarDumper\VarDumper)->dump(%s); exit; ?>",
360
                null != $data ? $data : "get_defined_vars()");
361 3
        });
362 3
363
        $blade->directive('formField', function ($expression) {
364 3
            return $this->includeView('partials.form._', $expression);
365 3
        });
366 3
367 3
        $blade->directive('partialView', function ($expression) {
368
369 3
            $expressionAsArray = str_getcsv($expression, ',', '\'');
370
371
            [$moduleName, $viewName] = $expressionAsArray;
372
            $partialNamespace = 'twill::partials';
373 3
374 3
            $viewModule = "twillViewName($moduleName, '{$viewName}')";
375 3
            $viewApplication = "'admin.partials.{$viewName}'";
376 3
            $viewModuleTwill = "'twill::'.$moduleName.'.{$viewName}'";
377 2
            $view = $partialNamespace . "." . $viewName;
378
379
            if (!isset($moduleName) || is_null($moduleName)) {
380 3
                $viewModule = $viewApplication;
381 3
            }
382 3
383 3
            $expression = explode(',', $expression);
384 3
            $expression = array_slice($expression, 2);
385 3
            $expression = "(" . implode(',', $expression) . ")";
386 3
            if ($expression === "()") {
387 3
                $expression = '([])';
388 3
            }
389
390
            return "<?php
391 73
            if( view()->exists($viewModule)) {
392
                echo \$__env->make($viewModule, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render();
393 73
            } elseif( view()->exists($viewApplication)) {
394 1
                echo \$__env->make($viewApplication, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render();
395 1
            } elseif( view()->exists($viewModuleTwill)) {
396 1
                echo \$__env->make($viewModuleTwill, \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render();
397 73
            } elseif( view()->exists('$view')) {
398
                echo \$__env->make('$view', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->with{$expression}->render();
399 73
            }
400 1
            ?>";
401 73
        });
402
403 73
        $blade->directive('pushonce', function ($expression) {
404 73
            [$pushName, $pushSub] = explode(':', trim(substr($expression, 1, -1)));
405 73
            $key = '__pushonce_' . $pushName . '_' . str_replace('-', '_', $pushSub);
406 73
            return "<?php if(! isset(\$__env->{$key})): \$__env->{$key} = 1; \$__env->startPush('{$pushName}'); ?>";
407 73
        });
408
409 73
        $blade->directive('endpushonce', function () {
410 73
            return '<?php $__env->stopPush(); endif; ?>';
411 73
        });
412 73
413 73
        $blade->component('twill::partials.form.utils._fieldset', 'formFieldset');
414 73
        $blade->component('twill::partials.form.utils._columns', 'formColumns');
415
        $blade->component('twill::partials.form.utils._collapsed_fields', 'formCollapsedFields');
416
        $blade->component('twill::partials.form.utils._connected_fields', 'formConnectedFields');
417 73
        $blade->component('twill::partials.form.utils._inline_checkboxes', 'formInlineCheckboxes');
418
419
        if (method_exists($blade, 'aliasComponent')) {
420
            $blade->aliasComponent('twill::partials.form.utils._fieldset', 'formFieldset');
421
            $blade->aliasComponent('twill::partials.form.utils._columns', 'formColumns');
422
            $blade->aliasComponent('twill::partials.form.utils._collapsed_fields', 'formCollapsedFields');
423
            $blade->aliasComponent('twill::partials.form.utils._connected_fields', 'formConnectedFields');
424 73
            $blade->aliasComponent('twill::partials.form.utils._inline_checkboxes', 'formInlineCheckboxes');
425
        }
426 73
427 73
    }
428
429
    /**
430 73
     * Registers the package additional View Composers.
431 73
     *
432
     * @return void
433
     */
434 73
    private function addViewComposers()
435 73
    {
436
        if (config('twill.enabled.users-management')) {
437
            View::composer(['admin.*', 'twill::*'], CurrentUser::class);
438 73
        }
439
440 73
        if (config('twill.enabled.media-library')) {
441 52
            View::composer('twill::layouts.main', MediasUploaderConfig::class);
442 52
        }
443
444 52
        if (config('twill.enabled.file-library')) {
445
            View::composer('twill::layouts.main', FilesUploaderConfig::class);
446 52
        }
447 73
448
        View::composer('twill::partials.navigation.*', ActiveNavigation::class);
449 73
450 73
        View::composer(['admin.*', 'templates.*', 'twill::*'], function ($view) {
451
            $with = array_merge([
452
                'renderForBlocks' => false,
453
                'renderForModal' => false,
454
            ], $view->getData());
455
456
            return $view->with($with);
457 73
        });
458
459 73
        View::composer(['admin.*', 'twill::*'], Localization::class);
460
    }
461 73
462 73
    /**
463 73
     * Registers and publishes the package additional translations.
464
     *
465
     * @return void
466
     */
467
    private function registerAndPublishTranslations()
468
    {
469
        $translationPath = __DIR__ . '/../lang';
470 73
471
        $this->loadTranslationsFrom($translationPath, 'twill');
472 73
        $this->publishes([$translationPath => resource_path('lang/vendor/twill')], 'translations');
473
    }
474
475
    /**
476
     * Get the version number of Twill.
477
     *
478
     * @return string
479
     */
480
    public function version()
481
    {
482
        return static::VERSION;
483
    }
484
485
    /**
486
     * In case 2FA is enabled, we need to check if a QRCode compatible package is
487
     * installed.
488
     */
489
    public function check2FA()
490
    {
491
        if (!config('twill.enabled.users-2fa')) {
492
            return;
493
        }
494
495
        try {
496
            (new User())->get2faQrCode();
497
        } catch (Exception $e) {
498
            throw new Exception(
499
                "Twill ERROR: As you have 2FA enabled, you also need to install a QRCode service package, please check https://github.com/antonioribeiro/google2fa-qrcode#built-in-qrcode-rendering-services"
500
            );
501
        }
502
    }
503
}
504