diff --git a/app/Filament/Pages/MailSettings.php b/app/Filament/Pages/MailSettings.php new file mode 100644 index 0000000..5555d96 --- /dev/null +++ b/app/Filament/Pages/MailSettings.php @@ -0,0 +1,162 @@ + | null + */ + public ?array $data = []; + + protected static ?string $title = 'Mail'; + + protected static string | BackedEnum | null $navigationIcon = 'heroicon-o-envelope-open'; // Uncomment if you want to set a custom navigation icon + + // protected ?string $subheading = ''; // Uncomment if you want to set a custom subheading + + // protected static ?string $slug = 'mail-settings'; // Uncomment if you want to set a custom slug + + protected string $view = 'filament.pages.mail-settings'; + + protected function settingName(): string + { + return 'mail'; + } + + /** + * Provide default values. + * + * @return array + */ + public function getDefaultData(): array + { + return [ + 'mail_driver' => 'smtp', + 'mail_encryption' => 'tls', + ]; + } + + public function getHeaderActions(): array + { + return [ + Action::make('test_connection') + ->label('Test Connection') + ->color('gray') + ->icon('heroicon-o-paper-airplane') + ->action(fn() => $this->testSMTPConnection()), + + ...parent::getHeaderActions(), + ]; + } + + public function form(Schema $schema): Schema + { + return $schema + ->components([ + Components\Section::make('Mail Settings')->schema([ + TextInput::make('mail_driver') + ->label('Mail Driver') + ->placeholder('smtp') + ->required(), + TextInput::make('mail_host') + ->label('Mail Host') + ->placeholder('mail.example.com') + ->required(), + TextInput::make('mail_port') + ->label('Mail Port') + ->integer() + ->minValue(1) + ->maxValue(65535) + ->placeholder('587') + ->required(), + TextInput::make('mail_username') + ->label('Mail Username') + ->placeholder('username') + ->required(), + TextInput::make('mail_password') + ->label('Mail Password') + ->placeholder('password') + ->required(), + Select::make('mail_encryption') + ->label('Mail Encryption') + ->options([ + 'tls' => 'TLS', + 'ssl' => 'SSL' + ]) + ->native(false) + ->required(), + + TextInput::make('mail_from_name') + ->label('Mail From Name') + ->placeholder('John Doe') + ->required(), + TextInput::make('mail_from_address') + ->label('Mail From Address') + ->placeholder('john@example.com') + ->required(), + ]), + ]) + ->statePath('data'); + } + + private function testSMTPConnection(): void + { + $settings = $this->data; + + // Required keys for testing connection + $requiredFields = [ + 'mail_host', + 'mail_port', + 'mail_username', + 'mail_password', + 'mail_encryption', + ]; + + // Check for missing or empty required fields + $missingFields = collect($requiredFields)->filter(function ($field) use ($settings) { + return empty($settings[$field]); + }); + + if ($missingFields->isNotEmpty()) { + Notification::make() + ->title('Missing required mail settings: ' . $missingFields->implode(', ')) + ->danger() + ->send(); + return; + } + + try { + $transport = new \Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport( + $settings['mail_host'], + (int) $settings['mail_port'], + strtolower($settings['mail_encryption']) === 'ssl' + ); + + $transport->setUsername($settings['mail_username']); + $transport->setPassword($settings['mail_password']); + + $transport->start(); // Attempt connection + + Notification::make() + ->title('SMTP connection successful!') + ->success() + ->send(); + } catch (\Exception $e) { + Notification::make() + ->title('SMTP connection failed: ' . $e->getMessage()) + ->danger() + ->send(); + } + } +} diff --git a/app/Providers/DynamicMailConfigServiceProvider.php b/app/Providers/DynamicMailConfigServiceProvider.php new file mode 100644 index 0000000..c556262 --- /dev/null +++ b/app/Providers/DynamicMailConfigServiceProvider.php @@ -0,0 +1,93 @@ +loadConfiguration(); + + Config::set('mail.default', $this->mailDriver ?? config('mail.default')); + + Config::set('mail.mailers.smtp', [ + 'transport' => $this->mailDriver, + 'scheme' => $this->mailScheme, + 'host' => $this->mailHost, + 'port' => $this->mailPort, + 'username' => $this->mailUsername, + 'password' => $this->mailPassword, + 'timeout' => $this->mailTimeout, + 'local_domain' => $this->mailEHLO, + ]); + + Config::set('mail.from', [ + 'address' => $this->mailFromAddress, + 'name' => $this->mailFromName, + ]); + + } + + private function loadConfiguration(): void + { + try { + $this->mailConfig = DbConfig::getGroup('mail') ?: []; + $this->mailConfig['app_url'] = db_config('website.site_url') ?? env('APP_URL', 'http://localhost'); + } catch (\Throwable $e) { + Log::warning('Database mail configuration unavailable; falling back to env values.'); + $this->mailConfig = ['app_url' => env('APP_URL', 'http://localhost')]; + } + + // Load mail configuration + $this->appUrl = $this->getConfig('app_url'); + $this->mailDriver = $this->getConfig('mail_driver', 'smtp'); + $this->mailScheme = $this->getConfig('mail_scheme', env('MAIL_SCHEME')); + $this->mailHost = $this->getConfig('mail_host', env('MAIL_HOST', '127.0.0.1')); + $this->mailPort = $this->getConfig('mail_port', env('MAIL_PORT', 2525)); + $this->mailUsername = $this->getConfig('mail_username', env('MAIL_USERNAME', 'username')); + $this->mailPassword = $this->getConfig('mail_password', env('MAIL_PASSWORD', 'password')); + $this->mailFromName = $this->getConfig('mail_from_name', env('MAIL_FROM_NAME', 'Example')); + $this->mailFromAddress = $this->getConfig('mail_from_address', env('MAIL_FROM_ADDRESS', 'hello@example.com')); + $this->mailTimeout = $this->getConfig('mail_timeout', env('MAIL_TIMEOUT', 15)); + $this->mailEHLO = $this->getConfig('mail_ehlo', env('MAIL_EHLO', parse_url((string) $this->appUrl, PHP_URL_HOST))); + } + + private function getConfig(string $key, $default = null) + { + return ArrayHelper::getValueFromArray($key, $this->mailConfig) ?? $default; + } +} diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 49cdb20..4a80642 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -2,6 +2,7 @@ return [ App\Providers\AppServiceProvider::class, + App\Providers\DynamicMailConfigServiceProvider::class, App\Providers\Filament\DashPanelProvider::class, App\Providers\FortifyServiceProvider::class, ]; diff --git a/resources/views/filament/pages/mail-settings.blade.php b/resources/views/filament/pages/mail-settings.blade.php new file mode 100644 index 0000000..96876a6 --- /dev/null +++ b/resources/views/filament/pages/mail-settings.blade.php @@ -0,0 +1,8 @@ + +
+ {{ $this->form }} + + Last update: {{ $this->lastUpdatedAt(timezone: 'UTC', format: 'F j, Y, H:i:s') . ' UTC' ?? 'Never' }} + +
+