feat: add app and database modules
This commit is contained in:
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
*
|
||||
* @project biiproject
|
||||
*
|
||||
* @author Andika Debi Putra
|
||||
*
|
||||
* @email andikadebiputra@gmail.com
|
||||
*
|
||||
* @website https://biiproject.com
|
||||
*
|
||||
* @copyright Copyright (c) 2026 Andika Debi Putra
|
||||
* @license Proprietary - All Rights Reserved
|
||||
*
|
||||
* @version 1.0.0
|
||||
*
|
||||
* @created 2026-05-01
|
||||
* ============================================================
|
||||
*
|
||||
* Unauthorized copying, modification, distribution, or use
|
||||
* of this file is strictly prohibited without prior written
|
||||
* permission from the author.
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Events\ActivityLogCreated;
|
||||
use App\Listeners\AnalyzeSystemError;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use App\Observers\PermissionObserver;
|
||||
use App\Observers\RoleObserver;
|
||||
use App\Observers\UserObserver;
|
||||
use App\Services\Monitoring\SystemMonitoringService;
|
||||
use App\Services\SystemConfig\SystemConfigService;
|
||||
use Google\Client;
|
||||
use Google\Service\Drive;
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Filesystem\FilesystemAdapter;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Log\Events\MessageLogged;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use League\Flysystem\Filesystem;
|
||||
use Masbug\Flysystem\GoogleDriveAdapter;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
// 🔒 Configure Rate Limiters
|
||||
$this->configureRateLimiting();
|
||||
|
||||
// Super Admin Gate (Developer has full power)
|
||||
Gate::before(function ($user, $capability) {
|
||||
// Monitoring dynamic gates
|
||||
$monitoringKeys = [
|
||||
'view pulse' => 'engine_pulse_enabled',
|
||||
'view telescope' => 'engine_telescope_enabled',
|
||||
'view api docs' => 'engine_swagger_enabled',
|
||||
'viewHorizon' => 'engine_horizon_enabled',
|
||||
];
|
||||
|
||||
if (isset($monitoringKeys[$capability])) {
|
||||
if (!get_setting($monitoringKeys[$capability], true)) {
|
||||
return false; // Force deny if disabled at engine level
|
||||
}
|
||||
}
|
||||
|
||||
return $user->hasRole('Developer') ? true : null;
|
||||
});
|
||||
|
||||
// Force HTTPS in production
|
||||
if ($this->app->environment('production')) {
|
||||
URL::forceScheme('https');
|
||||
}
|
||||
|
||||
// Global Password Reset Expiry Override
|
||||
if ($this->app->bound(SystemConfigService::class)) {
|
||||
$expiry = get_setting('password_reset_link_expiry', 60);
|
||||
config(['auth.passwords.users.expire' => $expiry]);
|
||||
}
|
||||
|
||||
// User Observer
|
||||
User::observe(UserObserver::class);
|
||||
|
||||
// Role Observer
|
||||
Role::observe(RoleObserver::class);
|
||||
|
||||
// Permission Observer
|
||||
Permission::observe(PermissionObserver::class);
|
||||
|
||||
// Windows Backup Compatibility Layer
|
||||
$this->ensureWindowsBackupCompatibility();
|
||||
|
||||
// Google Drive Filesystem Adapter
|
||||
$this->registerGoogleDriveAdapter();
|
||||
|
||||
// S3 Dynamic Config
|
||||
$this->injectS3DynamicConfig();
|
||||
|
||||
// Backup Dynamic Config
|
||||
$this->injectBackupDynamicConfig();
|
||||
|
||||
// Monitoring Dynamic Config
|
||||
$this->injectMonitoringDynamicConfig();
|
||||
|
||||
// Dashboard View Composer
|
||||
$this->registerDashboardComposer();
|
||||
|
||||
// Tab-permission Blade directives
|
||||
$this->registerTabPermissionDirectives();
|
||||
|
||||
// 📡 Real-time Activity Log Broadcasting
|
||||
Activity::created(function ($activity) {
|
||||
try {
|
||||
broadcast(new ActivityLogCreated($activity))->toOthers();
|
||||
} catch (\Throwable $e) {
|
||||
// Silently fail if Reverb is not running
|
||||
}
|
||||
});
|
||||
|
||||
// 🔍 Register AI error analysis listener (not auto-discovered for MessageLogged)
|
||||
Event::listen(
|
||||
MessageLogged::class,
|
||||
AnalyzeSystemError::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the rate limiters for the application.
|
||||
*/
|
||||
protected function configureRateLimiting(): void
|
||||
{
|
||||
// Rate limiting for API
|
||||
RateLimiter::for('api', function (Request $request) {
|
||||
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
|
||||
});
|
||||
|
||||
// Rate limiting for Login attempts
|
||||
RateLimiter::for('login', function (Request $request) {
|
||||
return Limit::perMinute(5)->by($request->ip())->response(function (Request $request, array $headers) {
|
||||
return response()->json([
|
||||
'message' => 'Too many login attempts. Please try again in 1 minute.',
|
||||
'status' => 'error',
|
||||
], 429, $headers);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject Monitoring configuration from database.
|
||||
*/
|
||||
protected function injectMonitoringDynamicConfig(): void
|
||||
{
|
||||
if (!$this->app->bound(SystemConfigService::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
config(['pulse.enabled' => get_setting('engine_pulse_enabled', true)]);
|
||||
config(['telescope.enabled' => get_setting('engine_telescope_enabled', true)]);
|
||||
|
||||
if (!get_setting('engine_swagger_enabled', true)) {
|
||||
config(['l5-swagger.documentations.default.routes.api' => null]);
|
||||
config(['l5-swagger.defaults.routes.docs' => null]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a view composer for the dashboard.
|
||||
*/
|
||||
protected function registerDashboardComposer(): void
|
||||
{
|
||||
view()->composer('pages.dashboard', function ($view) {
|
||||
$stats = Cache::remember('dashboard_stats', now()->addMinutes(5), function () {
|
||||
return [
|
||||
'total_users' => User::count(),
|
||||
'active_sessions' => app(SystemMonitoringService::class)->getActiveUsers(),
|
||||
'today_actions' => Activity::whereDate('created_at', now()->today())->count(),
|
||||
'failed_jobs' => DB::table('failed_jobs')->count(),
|
||||
'recent_activities' => Activity::with('causer')->latest()->take(5)->get(),
|
||||
];
|
||||
});
|
||||
|
||||
$view->with('dashboardStats', $stats);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Google Drive filesystem adapter.
|
||||
*/
|
||||
protected function registerGoogleDriveAdapter(): void
|
||||
{
|
||||
Storage::extend('google', function ($app, $config) {
|
||||
$clientId = get_setting('gdrive_client_id', $config['clientId'] ?? '');
|
||||
$clientSecret = get_setting('gdrive_client_secret', $config['clientSecret'] ?? '');
|
||||
$refreshToken = get_setting('gdrive_refresh_token', $config['refreshToken'] ?? '');
|
||||
$folder = get_setting('gdrive_folder', $config['folder'] ?? 'LaravelBackups');
|
||||
|
||||
$client = new Client;
|
||||
$client->setClientId($clientId);
|
||||
$client->setClientSecret($clientSecret);
|
||||
|
||||
if ($refreshToken) {
|
||||
$token = $client->refreshToken($refreshToken);
|
||||
if (!isset($token['error'])) {
|
||||
$client->setAccessToken($token);
|
||||
}
|
||||
}
|
||||
|
||||
$service = new Drive($client);
|
||||
$adapter = new GoogleDriveAdapter($service, $folder, []);
|
||||
$driver = new Filesystem($adapter);
|
||||
|
||||
return new FilesystemAdapter($driver, $adapter, $config);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject S3 credentials from database if set.
|
||||
*/
|
||||
protected function injectS3DynamicConfig(): void
|
||||
{
|
||||
if (get_setting('backup_db_driver') === 's3') {
|
||||
config([
|
||||
'filesystems.disks.s3.key' => get_setting('s3_key', config('filesystems.disks.s3.key')),
|
||||
'filesystems.disks.s3.secret' => get_setting('s3_secret', config('filesystems.disks.s3.secret')),
|
||||
'filesystems.disks.s3.region' => get_setting('s3_region', config('filesystems.disks.s3.region')),
|
||||
'filesystems.disks.s3.bucket' => get_setting('s3_bucket', config('filesystems.disks.s3.bucket')),
|
||||
'filesystems.disks.s3.endpoint' => get_setting('s3_endpoint', config('filesystems.disks.s3.endpoint')),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures Windows backup compatibility.
|
||||
*/
|
||||
protected function ensureWindowsBackupCompatibility(): void
|
||||
{
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
|
||||
return;
|
||||
}
|
||||
|
||||
$dbDriver = config('database.default');
|
||||
if (config("database.connections.{$dbDriver}.dump.dump_binary_path")) {
|
||||
return;
|
||||
}
|
||||
|
||||
$isPg = $dbDriver === 'pgsql';
|
||||
$binary = $isPg ? 'pg_dump.exe' : 'mysqldump.exe';
|
||||
$paths = $isPg ? ['C:\laragon\bin\postgresql\*\bin', 'C:\Program Files\PostgreSQL\*\bin'] : ['C:\laragon\bin\mysql\*\bin', 'C:\xampp\mysql\bin'];
|
||||
|
||||
foreach ($paths as $path) {
|
||||
$matchedPaths = glob($path, GLOB_ONLYDIR);
|
||||
if (!$matchedPaths) {
|
||||
continue;
|
||||
}
|
||||
$foundPath = $matchedPaths[count($matchedPaths) - 1];
|
||||
if (file_exists($foundPath . DIRECTORY_SEPARATOR . $binary)) {
|
||||
config(["database.connections.{$dbDriver}.dump.dump_binary_path" => $foundPath]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Register Blade if/unless directives for tab-level permission checks.
|
||||
*
|
||||
* Usage in Blade:
|
||||
* @cantab('global settings', 'login-security') ... @endcantab
|
||||
* @managetab('mobile settings', 'branding') ... @endmanagetab
|
||||
*/
|
||||
protected function registerTabPermissionDirectives(): void
|
||||
{
|
||||
Blade::if('cantab', fn (string $menu, string $tab) => can_view_tab($menu, $tab));
|
||||
Blade::if('managetab', fn (string $menu, string $tab) => can_manage_tab($menu, $tab));
|
||||
Blade::if('canviewanytab', fn (string $menu) => can_view_any_tab($menu));
|
||||
Blade::if('canmanageanytab', fn (string $menu) => can_manage_any_tab($menu));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject Backup configuration from database.
|
||||
*/
|
||||
protected function injectBackupDynamicConfig(): void
|
||||
{
|
||||
if (!$this->app->bound(SystemConfigService::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$driver = get_setting('backup_db_driver', 'local');
|
||||
config(['backup.backup.destination.disks' => [$driver]]);
|
||||
config(['backup.monitor_backups.0.disks' => [$driver]]);
|
||||
|
||||
if ($driver === 'gdrive') {
|
||||
config([
|
||||
'filesystems.disks.gdrive.clientId' => get_setting('gdrive_client_id'),
|
||||
'filesystems.disks.gdrive.clientSecret' => get_setting('gdrive_client_secret'),
|
||||
'filesystems.disks.gdrive.refreshToken' => get_setting('gdrive_refresh_token'),
|
||||
'filesystems.disks.gdrive.folder' => get_setting('gdrive_folder', 'LaravelBackups'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers\Filament;
|
||||
|
||||
use Filament\Http\Middleware\Authenticate;
|
||||
use Filament\Http\Middleware\AuthenticateSession;
|
||||
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||
use Filament\Pages\Dashboard;
|
||||
use Filament\Panel;
|
||||
use Filament\PanelProvider;
|
||||
use Filament\Support\Colors\Color;
|
||||
use Filament\Widgets\AccountWidget;
|
||||
use Filament\Widgets\FilamentInfoWidget;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Illuminate\Session\Middleware\StartSession;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
|
||||
class AdminPanelProvider extends PanelProvider
|
||||
{
|
||||
public function panel(Panel $panel): Panel
|
||||
{
|
||||
$panel
|
||||
->default()
|
||||
->id('admin')
|
||||
->path('admin')
|
||||
->login()
|
||||
->colors([
|
||||
'primary' => Color::Indigo,
|
||||
])
|
||||
->discoverResources(in: app_path('Filament/Resources'), for: 'App\Filament\Resources')
|
||||
->discoverPages(in: app_path('Filament/Pages'), for: 'App\Filament\Pages')
|
||||
->pages([
|
||||
Dashboard::class,
|
||||
])
|
||||
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets')
|
||||
->widgets([
|
||||
AccountWidget::class,
|
||||
FilamentInfoWidget::class,
|
||||
])
|
||||
->middleware([
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartSession::class,
|
||||
AuthenticateSession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
PreventRequestForgery::class,
|
||||
SubstituteBindings::class,
|
||||
DisableBladeIconComponents::class,
|
||||
DispatchServingFilamentEvent::class,
|
||||
])
|
||||
->authMiddleware([
|
||||
Authenticate::class,
|
||||
]);
|
||||
|
||||
return $panel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Laravel\Horizon\Horizon;
|
||||
use Laravel\Horizon\HorizonApplicationServiceProvider;
|
||||
|
||||
class HorizonServiceProvider extends HorizonApplicationServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
// Horizon::routeSmsNotificationsTo('15556667777');
|
||||
// Horizon::routeMailNotificationsTo('example@example.com');
|
||||
// Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Horizon gate.
|
||||
*
|
||||
* This gate determines who can access Horizon in non-local environments.
|
||||
*/
|
||||
protected function gate(): void
|
||||
{
|
||||
Gate::define('viewHorizon', function ($user = null) {
|
||||
return optional($user)->hasRole('Administrator');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Services\MobileConfig\MobileConfigService;
|
||||
use App\Services\SystemConfig\SystemConfigService;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class SystemConfigServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->singleton(SystemConfigService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
// 1. Ensure settings helper is loaded
|
||||
$helper = app_path('Helpers/SettingsHelper.php');
|
||||
if (file_exists($helper)) {
|
||||
require_once $helper;
|
||||
}
|
||||
|
||||
/** @var SystemConfigService $systemConfig */
|
||||
$systemConfig = $this->app->make(SystemConfigService::class);
|
||||
|
||||
// 2. Localization
|
||||
$locale = $systemConfig->get('default_locale', 'en');
|
||||
app()->setLocale($locale);
|
||||
|
||||
// Sync app.name globally so mail sender name, document title etc. use DB value
|
||||
config(['app.name' => $systemConfig->get('app_name', config('app.name'))]);
|
||||
|
||||
// 3. Performance: Only run config overrides if not in console (optional, but speeds up Artisan)
|
||||
// or prioritize based on current context
|
||||
|
||||
// Apply timezone globally from settings
|
||||
$timezone = $systemConfig->get('regional_timezone', 'Asia/Jakarta');
|
||||
config(['app.timezone' => $timezone]);
|
||||
date_default_timezone_set($timezone);
|
||||
|
||||
// HTTPS Enforcement
|
||||
if ($systemConfig->get('force_https', false)) {
|
||||
URL::forceScheme('https');
|
||||
}
|
||||
|
||||
// CORS Dynamic Configuration
|
||||
config([
|
||||
'cors.allowed_origins' => array_filter(array_map('trim', explode(',', $systemConfig->get('cors_origins', '*')))),
|
||||
'cors.allowed_methods' => array_filter(array_map('trim', explode(',', $systemConfig->get('cors_methods', '*')))),
|
||||
'cors.allowed_headers' => array_filter(array_map('trim', explode(',', $systemConfig->get('cors_headers', '*')))),
|
||||
]);
|
||||
|
||||
// Apply Captcha Config
|
||||
config([
|
||||
'captcha.sitekey' => $systemConfig->get('captcha_site_key'),
|
||||
'captcha.secret' => $systemConfig->get('captcha_secret_key'),
|
||||
'captcha.options' => [
|
||||
'timeout' => 30,
|
||||
],
|
||||
]);
|
||||
|
||||
// Unified Social Login Callback Base
|
||||
$callbackUrl = $systemConfig->get('social_login_callback_url', '/auth/callback');
|
||||
|
||||
// Apply Socialite Config
|
||||
config([
|
||||
'services.google' => [
|
||||
'client_id' => $systemConfig->get('google_client_id'),
|
||||
'client_secret' => $systemConfig->get('google_client_secret'),
|
||||
'redirect' => url($callbackUrl),
|
||||
],
|
||||
'services.facebook' => [
|
||||
'client_id' => $systemConfig->get('facebook_app_id'),
|
||||
'client_secret' => $systemConfig->get('facebook_app_secret'),
|
||||
'redirect' => url($callbackUrl),
|
||||
],
|
||||
'services.github' => [
|
||||
'client_id' => $systemConfig->get('github_client_id'),
|
||||
'client_secret' => $systemConfig->get('github_client_secret'),
|
||||
'redirect' => url($callbackUrl),
|
||||
],
|
||||
]);
|
||||
|
||||
// Apply Session Configuration
|
||||
config([
|
||||
'session.driver' => $systemConfig->get('session_driver', 'file'),
|
||||
'session.lifetime' => $systemConfig->get('session_lifetime', 120),
|
||||
'session.secure' => $systemConfig->get('session_secure_cookie', false),
|
||||
'session.encrypt' => $systemConfig->get('session_encrypt', false),
|
||||
'session.remember' => $systemConfig->get('session_remember_me_duration', 30) * 1440, // Days to Minutes
|
||||
]);
|
||||
|
||||
config(['auth.passwords.users.expire' => $systemConfig->get('password_reset_link_expiry', 60)]);
|
||||
|
||||
// 7. DYNAMIC MAIL CONFIGURATION
|
||||
if ($systemConfig->get('mail_host')) {
|
||||
config([
|
||||
'mail.default' => $systemConfig->get('mail_driver', 'smtp'),
|
||||
'mail.mailers.smtp.host' => $systemConfig->get('mail_host'),
|
||||
'mail.mailers.smtp.port' => $systemConfig->get('mail_port', 587),
|
||||
'mail.mailers.smtp.encryption' => $systemConfig->get('mail_encryption', 'tls'),
|
||||
'mail.mailers.smtp.username' => $systemConfig->get('mail_username'),
|
||||
'mail.mailers.smtp.password' => $systemConfig->get('mail_password'),
|
||||
'mail.from.address' => $systemConfig->get('mail_from_address', 'noreply@example.com'),
|
||||
'mail.from.name' => $systemConfig->get('mail_from_name', config('app.name')),
|
||||
]);
|
||||
|
||||
// If using smtp transport specifically
|
||||
}
|
||||
|
||||
// 8. DYNAMIC BACKUP CONFIGURATION (Spatie Backup)
|
||||
if ($systemConfig->get('backup_db_enabled')) {
|
||||
$driver = $systemConfig->get('backup_db_driver', 'local');
|
||||
config([
|
||||
'backup.backup.destination.disks' => [$driver],
|
||||
'backup.monitor_backups.0.disks' => [$driver],
|
||||
'backup.cleanup.default_strategy.keep_all_backups_for_days' => (int) $systemConfig->get('backup_db_retention', 7),
|
||||
]);
|
||||
|
||||
// Encryption
|
||||
if ($systemConfig->get('backup_db_encrypt') && $systemConfig->get('backup_db_encrypt_key')) {
|
||||
config([
|
||||
'backup.backup.password' => $systemConfig->get('backup_db_encrypt_key'),
|
||||
'backup.backup.encryption' => 'aes256',
|
||||
]);
|
||||
} else {
|
||||
config([
|
||||
'backup.backup.password' => null,
|
||||
'backup.backup.encryption' => 'none',
|
||||
]);
|
||||
}
|
||||
|
||||
// Exclude Tables (Injected via database config dump key)
|
||||
if ($excludeTables = $systemConfig->get('backup_db_exclude')) {
|
||||
$tables = array_map('trim', explode(',', $excludeTables));
|
||||
$dbDriver = config('database.default');
|
||||
config(["database.connections.{$dbDriver}.dump.exclude_tables" => $tables]);
|
||||
}
|
||||
|
||||
// Notifications
|
||||
$notifyTo = $systemConfig->get('backup_db_notify_to');
|
||||
if ($notifyTo) {
|
||||
if (filter_var($notifyTo, FILTER_VALIDATE_EMAIL)) {
|
||||
config(['backup.notifications.mail.to' => $notifyTo]);
|
||||
} elseif (str_starts_with($notifyTo, 'http')) {
|
||||
config(['backup.notifications.notifications.webhook.url' => $notifyTo]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 9. DYNAMIC MOBILE AUTH CONFIGURATION
|
||||
$mobileConfig = $this->app->make(MobileConfigService::class);
|
||||
$allMobile = $mobileConfig->all();
|
||||
if ($ttl = ($allMobile['security_auth']['token_ttl_minutes'] ?? null)) {
|
||||
config(['sanctum.expiration' => (int) $ttl]);
|
||||
}
|
||||
|
||||
// 3. View Sharing (Cached for request duration)
|
||||
view()->share($systemConfig->getPublicSettings());
|
||||
|
||||
// 4. Pulse Access Gate
|
||||
Gate::define('viewPulse', function ($user) {
|
||||
return $user->can('view pulse');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Laravel\Telescope\IncomingEntry;
|
||||
use Laravel\Telescope\Telescope;
|
||||
use Laravel\Telescope\TelescopeApplicationServiceProvider;
|
||||
|
||||
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
// Telescope::night();
|
||||
|
||||
$this->hideSensitiveRequestDetails();
|
||||
|
||||
$isLocal = $this->app->environment('local');
|
||||
|
||||
Telescope::filter(function (IncomingEntry $entry) use ($isLocal) {
|
||||
return $isLocal ||
|
||||
$entry->isReportableException() ||
|
||||
$entry->isFailedRequest() ||
|
||||
$entry->isFailedJob() ||
|
||||
$entry->isScheduledTask() ||
|
||||
$entry->hasMonitoredTag();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent sensitive request details from being logged by Telescope.
|
||||
*/
|
||||
protected function hideSensitiveRequestDetails(): void
|
||||
{
|
||||
if ($this->app->environment('local')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Telescope::hideRequestParameters(['_token']);
|
||||
|
||||
Telescope::hideRequestHeaders([
|
||||
'cookie',
|
||||
'x-csrf-token',
|
||||
'x-xsrf-token',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Telescope gate.
|
||||
*
|
||||
* This gate determines who can access Telescope in non-local environments.
|
||||
*/
|
||||
protected function gate(): void
|
||||
{
|
||||
Gate::define('viewTelescope', function (User $user) {
|
||||
return $user->can('view telescope');
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user