applyLdapSettingsOverride(); $this->applyMailSettingsOverride(); $this->applySessionSettingsOverride(); $this->applyTimezoneSettingsOverride(); $this->configureApiRateLimiting(); $this->broadcastBellNotifications(); // 'user' backs the polymorphic notifiable_type column on the // database-notifications table (in-app notification bell). Relation::enforceMorphMap(['api_client' => ApiClient::class, 'user' => User::class]); } /** * A single choke point for realtime bell delivery — hooks Laravel's own * post-send event instead of threading a broadcast dispatch into every * TicketService call site that creates a "database" notification * (client leg, staff fan-out, and eventually the Trigger engine's * send_notification action). $event->response is the DatabaseChannel's * return value: the DatabaseNotification row that was just created, * whose id is the same one the bell already reads. */ protected function broadcastBellNotifications(): void { Event::listen(NotificationSent::class, function (NotificationSent $event) { if ($event->channel !== 'database' || ! $event->notification instanceof TicketNotification) { return; } $data = $event->notification->toDatabase($event->notifiable); NotificationCreated::dispatch($event->notifiable->id, $event->response->id, $data['message'], $data['url']); }); } /** * API keys get a generous per-key budget; unauthenticated requests (which * only ever hit the guard before rejecting with 401) get a much smaller * per-IP one so a single misconfigured client can't exhaust it for everyone. */ protected function configureApiRateLimiting(): void { RateLimiter::for('api', function (Request $request) { $clientId = $request->user()?->id; return $clientId ? Limit::perMinute(120)->by('api-client:'.$clientId) : Limit::perMinute(30)->by('ip:'.$request->ip()); }); } /** * Avoid touching the DB during artisan commands that run before the * `settings` table exists (e.g. `migrate` itself), or before it can be * queried at all — shared by every settings-driven config override below. */ protected function settingsTableUsable(): bool { if ($this->app->runningInConsole() && ! $this->app->runningUnitTests()) { return false; } try { return Schema::hasTable('settings'); } catch (\Throwable) { return false; } } /** * Let the Admin -> Konfiguracja -> LDAP/AD screen override the .env-based * LDAP connection at runtime, so changes take effect without a redeploy. */ protected function applyLdapSettingsOverride(): void { if (! $this->settingsTableUsable()) { return; } $host = Settings::get('ldap_host'); if (! $host) { return; } $config = Config::get('ldap.connections.default', []); $config['hosts'] = [$host]; $config['port'] = (int) Settings::get('ldap_port', $config['port'] ?? 389); $config['base_dn'] = Settings::get('ldap_base_dn', $config['base_dn'] ?? ''); $config['username'] = Settings::get('ldap_bind_dn', $config['username'] ?? ''); $config['password'] = Settings::get('ldap_bind_password') ?? $config['password'] ?? ''; $config['use_tls'] = Settings::bool('ldap_use_ssl'); Config::set('ldap.connections.default', $config); Container::addConnection(new Connection($config), 'default'); } /** * Let the Admin -> Konfiguracja -> E-mail (SMTP) screen override the * .env-based mail transport/sender at runtime. Sender address/name and * footer apply regardless; the SMTP transport itself only when the admin * has explicitly enabled it (otherwise the .env `MAIL_MAILER` stands). */ protected function applyMailSettingsOverride(): void { if (! $this->settingsTableUsable()) { return; } if (Settings::bool('mail_smtp_enabled') && Settings::get('mail_smtp_host')) { Config::set('mail.default', 'smtp'); Config::set('mail.mailers.smtp.host', Settings::get('mail_smtp_host')); Config::set('mail.mailers.smtp.port', (int) Settings::get('mail_smtp_port', '587')); Config::set('mail.mailers.smtp.username', Settings::get('mail_smtp_username') ?: null); Config::set('mail.mailers.smtp.password', Settings::get('mail_smtp_password')); Config::set('mail.mailers.smtp.scheme', match (Settings::get('mail_smtp_encryption')) { 'ssl' => 'smtps', 'tls' => 'smtp', default => null, }); } if ($address = Settings::get('mail_from_address')) { Config::set('mail.from.address', $address); Config::set('mail.from.name', Settings::get('mail_from_name') ?: Settings::get('company_name')); } } /** * Let the Admin -> Konfiguracja -> "Czas wygaśnięcia sesji" field override * the .env-based session lifetime. Only affects sessions created/renewed * after the change — already-active sessions keep their existing expiry. */ protected function applySessionSettingsOverride(): void { if (! $this->settingsTableUsable()) { return; } $minutes = Settings::get('session_lifetime_minutes'); if ($minutes) { Config::set('session.lifetime', (int) $minutes); } } /** * Let the Admin -> Konfiguracja -> "Strefa czasowa" field override the * .env-based app timezone at runtime, so every date shown or stored * (ticket timestamps, SLA deadlines, "x minutes ago" labels, ...) * reflects the admin's chosen zone instead of the container's UTC default. */ protected function applyTimezoneSettingsOverride(): void { if (! $this->settingsTableUsable()) { return; } $timezone = Settings::timezone(); Config::set('app.timezone', $timezone); date_default_timezone_set($timezone); } }