diff --git a/app/Actions/Notifications/SendDiscordTestNotification.php b/app/Actions/Notifications/SendDiscordTestNotification.php new file mode 100644 index 000000000..1e6ae4560 --- /dev/null +++ b/app/Actions/Notifications/SendDiscordTestNotification.php @@ -0,0 +1,37 @@ +title('You need to add webhook urls!') + ->warning() + ->send(); + + return; + } + + foreach ($webhooks as $webhook) { + $payload = [ + 'content' => '👋 Testing the Webhook notification channel.', + ]; + // Send the request using Laravel's HTTP client + $response = Http::post($webhook['discord_webhook_url'], $payload); + } + + Notification::make() + ->title('Test webhook notification sent.') + ->success() + ->send(); + } +} diff --git a/app/Filament/Pages/Settings/NotificationPage.php b/app/Filament/Pages/Settings/NotificationPage.php index d3a443260..783e8db99 100755 --- a/app/Filament/Pages/Settings/NotificationPage.php +++ b/app/Filament/Pages/Settings/NotificationPage.php @@ -3,6 +3,7 @@ namespace App\Filament\Pages\Settings; use App\Actions\Notifications\SendDatabaseTestNotification; +use App\Actions\Notifications\SendDiscordTestNotification; use App\Actions\Notifications\SendMailTestNotification; use App\Actions\Notifications\SendTelegramTestNotification; use App\Actions\Notifications\SendWebhookTestNotification; @@ -85,6 +86,48 @@ public function form(Form $form): Form 'md' => 2, ]), + Forms\Components\Section::make('Discord') + ->schema([ + Forms\Components\Toggle::make('discord_enabled') + ->label('Enable Discord webhook notifications') + ->reactive() + ->columnSpanFull(), + Forms\Components\Grid::make([ + 'default' => 1, + ]) + ->hidden(fn (Forms\Get $get) => $get('discord_enabled') !== true) + ->schema([ + Forms\Components\Fieldset::make('Triggers') + ->schema([ + Forms\Components\Toggle::make('discord_on_speedtest_run') + ->label('Notify on every speedtest run') + ->columnSpanFull(), + Forms\Components\Toggle::make('discord_on_threshold_failure') + ->label('Notify on threshold failures') + ->columnSpanFull(), + ]), + Forms\Components\Repeater::make('discord_webhooks') + ->label('Webhooks') + ->schema([ + Forms\Components\TextInput::make('discord_webhook_url') + ->label('Webhook URL') + ->required(), + ]) + ->columnSpanFull(), + Forms\Components\Actions::make([ + Forms\Components\Actions\Action::make('test discord') + ->label('Test Discord webhook') + ->action(fn (Forms\Get $get) => SendDiscordTestNotification::run(webhooks: $get('discord_webhooks'))) + ->hidden(fn (Forms\Get $get) => ! count($get('discord_webhooks'))), + ]), + ]), + ]) + ->compact() + ->columns([ + 'default' => 1, + 'md' => 2, + ]), + Forms\Components\Section::make('Mail') ->schema([ Forms\Components\Toggle::make('mail_enabled') diff --git a/app/Listeners/SpeedtestCompletedListener.php b/app/Listeners/SpeedtestCompletedListener.php index 720065724..2ad8d0e70 100644 --- a/app/Listeners/SpeedtestCompletedListener.php +++ b/app/Listeners/SpeedtestCompletedListener.php @@ -8,6 +8,7 @@ use App\Settings\NotificationSettings; use App\Telegram\TelegramNotification; use Filament\Notifications\Notification; +use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Mail; use Spatie\WebhookServer\WebhookCall; @@ -75,6 +76,24 @@ public function handle(ResultCreated $event): void } } + if ($this->notificationSettings->discord_enabled) { + if ($this->notificationSettings->discord_on_speedtest_run && count($this->notificationSettings->discord_webhooks)) { + foreach ($this->notificationSettings->discord_webhooks as $webhook) { + // Construct the payload + $payload = [ + 'content' => 'There are new speedtest results for your network.'. + "\nResult ID: ".$event->result->id. + "\nSite Name: ".$this->generalSettings->site_name. + "\nPing: ".$event->result->ping.' ms'. + "\nDownload: ".($event->result->downloadBits / 1000000).' (Mbps)'. + "\nUpload: ".($event->result->uploadBits / 1000000).' (Mbps)', + ]; + // Send the request using Laravel's HTTP client + $response = Http::post($webhook['discord_webhook_url'], $payload); + } + } + } + if ($this->notificationSettings->webhook_enabled) { if ($this->notificationSettings->webhook_on_speedtest_run && count($this->notificationSettings->webhook_urls)) { foreach ($this->notificationSettings->webhook_urls as $url) { diff --git a/app/Listeners/Threshold/AbsoluteListener.php b/app/Listeners/Threshold/AbsoluteListener.php index 5e141ccb3..c6b52c6b8 100644 --- a/app/Listeners/Threshold/AbsoluteListener.php +++ b/app/Listeners/Threshold/AbsoluteListener.php @@ -63,6 +63,11 @@ public function handle(ResultCreated $event): void $this->telegramChannel($event); } + // Discord notification channel + if ($this->notificationSettings->discord_enabled == true && $this->notificationSettings->discord_on_threshold_failure == true) { + $this->discordChannel($event); + } + // Webhook notification channel if ($this->notificationSettings->webhook_enabled == true && $this->notificationSettings->webhook_on_threshold_failure == true) { $this->webhookChannel($event); @@ -219,6 +224,55 @@ protected function telegramChannel(ResultCreated $event): void } } + /** + * Handle Discord notifications. + */ + protected function discordChannel(ResultCreated $event): void + { + if ($this->notificationSettings->discord_enabled) { + $failedThresholds = []; // Initialize an array to keep track of failed thresholds + + // Check Download threshold + if ($this->thresholdSettings->absolute_download > 0 && absoluteDownloadThresholdFailed($this->thresholdSettings->absolute_download, $event->result->downloadBits)) { + $failedThresholds['Download'] = ($event->result->downloadBits / 1000000).' (Mbps)'; + } + + // Check Upload threshold + if ($this->thresholdSettings->absolute_upload > 0 && absoluteUploadThresholdFailed($this->thresholdSettings->absolute_upload, $event->result->uploadBits)) { + $failedThresholds['Upload'] = ($event->result->uploadBits / 1000000).' (Mbps)'; + } + + // Check Ping threshold + if ($this->thresholdSettings->absolute_ping > 0 && absolutePingThresholdFailed($this->thresholdSettings->absolute_ping, $event->result->ping)) { + $failedThresholds['Ping'] = $event->result->ping.' ms'; + } + + // Proceed with sending notifications only if there are any failed thresholds + if (count($failedThresholds) > 0) { + if ($this->notificationSettings->discord_on_threshold_failure && count($this->notificationSettings->discord_webhooks)) { + foreach ($this->notificationSettings->discord_webhooks as $webhook) { + // Construct the payload with the failed thresholds information + $contentLines = [ + 'Result ID: '.$event->result->id, + 'Site Name: '.$this->generalSettings->site_name, + ]; + + foreach ($failedThresholds as $metric => $result) { + $contentLines[] = "{$metric} threshold failed with result: {$result}."; + } + + $payload = [ + 'content' => implode("\n", $contentLines), + ]; + + // Send the request using Laravel's HTTP client + $response = Http::post($webhook['discord_webhook_url'], $payload); + } + } + } + } + } + /** * Handle webhook notifications. * diff --git a/app/Settings/NotificationSettings.php b/app/Settings/NotificationSettings.php index cb29b6ae5..ff2d4d22a 100644 --- a/app/Settings/NotificationSettings.php +++ b/app/Settings/NotificationSettings.php @@ -38,6 +38,14 @@ class NotificationSettings extends Settings public ?array $webhook_urls; + public bool $discord_enabled; + + public bool $discord_on_speedtest_run; + + public bool $discord_on_threshold_failure; + + public ?array $discord_webhooks; + public static function group(): string { return 'notification'; diff --git a/database/migrations/2024_02_19_000000_create_discord_notification_settings.php b/database/migrations/2024_02_19_000000_create_discord_notification_settings.php new file mode 100644 index 000000000..1aab217aa --- /dev/null +++ b/database/migrations/2024_02_19_000000_create_discord_notification_settings.php @@ -0,0 +1,17 @@ +migrator->add('notification.discord_enabled', false); + $this->migrator->add('notification.discord_on_speedtest_run', false); + $this->migrator->add('notification.discord_on_threshold_failure', false); + $this->migrator->add('notification.discord_webhooks', null); + } +};