Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
74.19% |
23 / 31 |
|
50.00% |
1 / 2 |
CRAP | |
0.00% |
0 / 1 |
| AppServiceProvider | |
74.19% |
23 / 31 |
|
50.00% |
1 / 2 |
10.39 | |
0.00% |
0 / 1 |
| register | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
| boot | |
68.00% |
17 / 25 |
|
0.00% |
0 / 1 |
10.10 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace App\Providers; |
| 4 | |
| 5 | use App\Services\Builder\MenuService; |
| 6 | use App\Services\Builder\WidgetService; |
| 7 | use App\Services\Feature\FeatureService; |
| 8 | use App\Services\Permission\PermissionService; |
| 9 | use App\Services\Setting\SettingService; |
| 10 | use App\Services\Theme\ThemeService; |
| 11 | use Illuminate\Pagination\Paginator; |
| 12 | use Illuminate\Support\Facades\Blade; |
| 13 | use Illuminate\Support\Facades\Gate; |
| 14 | use Illuminate\Support\Facades\View; |
| 15 | use Illuminate\Support\ServiceProvider; |
| 16 | use Illuminate\Validation\Rules\Password; |
| 17 | |
| 18 | class AppServiceProvider extends ServiceProvider |
| 19 | { |
| 20 | public function register() |
| 21 | { |
| 22 | $this->app->singleton(SettingService::class); |
| 23 | $this->app->singleton(FeatureService::class); |
| 24 | $this->app->singleton(PermissionService::class); |
| 25 | $this->app->singleton(MenuService::class); |
| 26 | $this->app->singleton(WidgetService::class); |
| 27 | $this->app->singleton(ThemeService::class); |
| 28 | } |
| 29 | |
| 30 | public function boot() |
| 31 | { |
| 32 | // RBAC bypass: off, or the owner, sees everything. Otherwise fall |
| 33 | // through to spatie's normal permission check (Gate::before returns |
| 34 | // null to defer). |
| 35 | Gate::before(function ($user, string $ability) { |
| 36 | $svc = app(PermissionService::class); |
| 37 | if (! $svc->enforced()) { |
| 38 | return true; |
| 39 | } |
| 40 | if ((int) $user->id === 1 || $user->hasRole('Owner')) { |
| 41 | return true; |
| 42 | } |
| 43 | |
| 44 | return null; |
| 45 | }); |
| 46 | |
| 47 | // FIX: Laravel's default pagination view (`pagination::tailwind`) renders |
| 48 | // Tailwind utility classes, but this whole admin panel is built on |
| 49 | // Bootstrap 4 with no Tailwind loaded — so every `->links()` call |
| 50 | // rendered as unstyled/broken markup. Bootstrap 4 view matches the |
| 51 | // theme's own `.pagination`/`.page-item`/`.page-link` classes. |
| 52 | Paginator::useBootstrap(); |
| 53 | |
| 54 | // @feature('coupons') ... @else ... @endfeature |
| 55 | Blade::if('feature', fn (string $key) => feature($key)); |
| 56 | |
| 57 | // @allows('manage_products') — respects the rbac flag + owner bypass |
| 58 | Blade::if('allows', fn (string $ability) => permissions()->allows($ability)); |
| 59 | |
| 60 | // One password policy everywhere (staff, registration, reset): |
| 61 | // at least 8 characters with letters and numbers. |
| 62 | Password::defaults(fn () => Password::min(8)->letters()->numbers()); |
| 63 | |
| 64 | // Phase 11 Slice 4 — "Delete backups older than N days" from |
| 65 | // Settings → Backups drives spatie's cleanup. Set it here (not in |
| 66 | // config/backup.php) so it still applies when config is cached and |
| 67 | // so a DB read isn't done during config loading. Longer retention |
| 68 | // tiers are zeroed: the operator asked for one simple cutoff. |
| 69 | try { |
| 70 | $keepDays = (int) settings('backup.keep_days', 30); |
| 71 | if ($keepDays > 0) { |
| 72 | config([ |
| 73 | 'backup.cleanup.default_strategy.keep_all_backups_for_days' => $keepDays, |
| 74 | 'backup.cleanup.default_strategy.keep_daily_backups_for_days' => 0, |
| 75 | 'backup.cleanup.default_strategy.keep_weekly_backups_for_weeks' => 0, |
| 76 | 'backup.cleanup.default_strategy.keep_monthly_backups_for_months' => 0, |
| 77 | 'backup.cleanup.default_strategy.keep_yearly_backups_for_years' => 0, |
| 78 | ]); |
| 79 | } |
| 80 | } catch (\Throwable $e) { |
| 81 | // app_settings table not migrated yet (fresh install / CI bootstrap) |
| 82 | } |
| 83 | |
| 84 | // Theme files are namespaced instead of globally prepending their path. |
| 85 | // Shared page/page-builder views therefore cannot be replaced by a |
| 86 | // theme. Storefront templates opt in only at visual slots such as the |
| 87 | // header, footer, hero and product card via storefront_theme_view(). |
| 88 | try { |
| 89 | if ($path = app(ThemeService::class)->activePath()) { |
| 90 | View::addNamespace('theme', $path); |
| 91 | } |
| 92 | } catch (\Throwable $e) { |
| 93 | // themes table not migrated yet (fresh install / CI bootstrap) |
| 94 | } |
| 95 | } |
| 96 | } |