From d77b6f5c8155df73818c18ce4051a4d92341cbf2 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Wed, 26 Jun 2024 17:11:11 +0200 Subject: [PATCH 1/6] first_push --- .../SendNtfyTestNotification.php | 40 +++++++++++++++ .../Pages/Settings/NotificationPage.php | 50 +++++++++++++++++++ app/Settings/NotificationSettings.php | 8 +++ ...4650_create_ntfy_notification_settings.php | 14 ++++++ 4 files changed, 112 insertions(+) create mode 100644 app/Actions/Notifications/SendNtfyTestNotification.php create mode 100644 database/settings/2024_02_22_144650_create_ntfy_notification_settings.php diff --git a/app/Actions/Notifications/SendNtfyTestNotification.php b/app/Actions/Notifications/SendNtfyTestNotification.php new file mode 100644 index 000000000..81f345e0a --- /dev/null +++ b/app/Actions/Notifications/SendNtfyTestNotification.php @@ -0,0 +1,40 @@ +title('You need to add ntfy urls!') + ->warning() + ->send(); + + return; + } + + foreach ($webhooks as $webhook) { + WebhookCall::create() + ->url($webhook['url']) + ->payload([ + 'topic' => $webhook['topic'], + 'message' => '👋 Testing the Pushover notification channel.', + ]) + ->doNotSign() + ->dispatch(); + } + + Notification::make() + ->title('Test ntfy notification sent.') + ->success() + ->send(); + } +} diff --git a/app/Filament/Pages/Settings/NotificationPage.php b/app/Filament/Pages/Settings/NotificationPage.php index a40a5e080..2e223d458 100755 --- a/app/Filament/Pages/Settings/NotificationPage.php +++ b/app/Filament/Pages/Settings/NotificationPage.php @@ -4,6 +4,7 @@ use App\Actions\Notifications\SendDatabaseTestNotification; use App\Actions\Notifications\SendDiscordTestNotification; +use App\Actions\Notifications\SendNtfyTestNotification; use App\Actions\Notifications\SendMailTestNotification; use App\Actions\Notifications\SendTelegramTestNotification; use App\Actions\Notifications\SendWebhookTestNotification; @@ -127,6 +128,55 @@ public function form(Form $form): Form 'md' => 2, ]), + Forms\Components\Section::make('Ntfy') + ->schema([ + Forms\Components\Toggle::make('ntfy_enabled') + ->label('Enable Ntfy webhook notifications') + ->reactive() + ->columnSpanFull(), + Forms\Components\Grid::make([ + 'default' => 1, + ]) + ->hidden(fn (Forms\Get $get) => $get('ntfy_enabled') !== true) + ->schema([ + Forms\Components\Fieldset::make('Triggers') + ->schema([ + Forms\Components\Toggle::make('ntfy_on_speedtest_run') + ->label('Notify on every speedtest run') + ->columnSpanFull(), + Forms\Components\Toggle::make('ntfy_on_threshold_failure') + ->label('Notify on threshold failures') + ->columnSpanFull(), + ]), + Forms\Components\Repeater::make('ntfy_webhooks') + ->label('Webhooks') + ->schema([ + Forms\Components\TextInput::make('url') + ->maxLength(2000) + ->placeholder('Your ntfy server url') + ->required() + ->url(), + Forms\Components\TextInput::make('topic') + ->label('Topic') + ->placeholder('Your ntfy Topic') + ->maxLength(200) + ->required(), + ]) + ->columnSpanFull(), + Forms\Components\Actions::make([ + Forms\Components\Actions\Action::make('test ntfy') + ->label('Test Ntfy webhook') + ->action(fn (Forms\Get $get) => SendNtfyTestNotification::run(webhooks: $get('ntfy_webhooks'))) + ->hidden(fn (Forms\Get $get) => ! count($get('ntfy_webhooks'))), + ]), + ]), + ]) + ->compact() + ->columns([ + 'default' => 1, + 'md' => 2, + ]), + Forms\Components\Section::make('Mail') ->schema([ Forms\Components\Toggle::make('mail_enabled') diff --git a/app/Settings/NotificationSettings.php b/app/Settings/NotificationSettings.php index ff2d4d22a..346f8b780 100644 --- a/app/Settings/NotificationSettings.php +++ b/app/Settings/NotificationSettings.php @@ -46,6 +46,14 @@ class NotificationSettings extends Settings public ?array $discord_webhooks; + public bool $ntfy_enabled; + + public bool $ntfy_on_speedtest_run; + + public bool $ntfy_on_threshold_failure; + + public ?array $ntfy_webhooks; + public static function group(): string { return 'notification'; diff --git a/database/settings/2024_02_22_144650_create_ntfy_notification_settings.php b/database/settings/2024_02_22_144650_create_ntfy_notification_settings.php new file mode 100644 index 000000000..aca36e39f --- /dev/null +++ b/database/settings/2024_02_22_144650_create_ntfy_notification_settings.php @@ -0,0 +1,14 @@ +migrator->add('notification.ntfy_enabled', false); + $this->migrator->add('notification.ntfy_on_speedtest_run', false); + $this->migrator->add('notification.ntfy_on_threshold_failure', false); + $this->migrator->add('notification.ntfy_webhooks', null); + } +}; From 26968aa11843e13105828edc9954fb6c8ab391b4 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Wed, 26 Jun 2024 21:49:03 +0200 Subject: [PATCH 2/6] Fix_json_payload --- .../SendNtfyTestNotification.php | 2 +- .../Pages/Settings/NotificationPage.php | 4 +- .../SendSpeedtestCompletedNotification.php | 60 ++++++++ .../SendSpeedtestThresholdNotification.php | 134 ++++++++++++++++++ .../views/ntfy/speedtest-completed.blade.php | 12 ++ .../views/ntfy/speedtest-threshold.blade.php | 8 ++ 6 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php create mode 100644 app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php create mode 100644 resources/views/ntfy/speedtest-completed.blade.php create mode 100644 resources/views/ntfy/speedtest-threshold.blade.php diff --git a/app/Actions/Notifications/SendNtfyTestNotification.php b/app/Actions/Notifications/SendNtfyTestNotification.php index 81f345e0a..ce7f744ae 100644 --- a/app/Actions/Notifications/SendNtfyTestNotification.php +++ b/app/Actions/Notifications/SendNtfyTestNotification.php @@ -26,7 +26,7 @@ public function handle(array $webhooks) ->url($webhook['url']) ->payload([ 'topic' => $webhook['topic'], - 'message' => '👋 Testing the Pushover notification channel.', + 'message' => '👋 Testing the ntfy notification channel.', ]) ->doNotSign() ->dispatch(); diff --git a/app/Filament/Pages/Settings/NotificationPage.php b/app/Filament/Pages/Settings/NotificationPage.php index 2e223d458..ee527b69f 100755 --- a/app/Filament/Pages/Settings/NotificationPage.php +++ b/app/Filament/Pages/Settings/NotificationPage.php @@ -4,8 +4,8 @@ use App\Actions\Notifications\SendDatabaseTestNotification; use App\Actions\Notifications\SendDiscordTestNotification; -use App\Actions\Notifications\SendNtfyTestNotification; use App\Actions\Notifications\SendMailTestNotification; +use App\Actions\Notifications\SendNtfyTestNotification; use App\Actions\Notifications\SendTelegramTestNotification; use App\Actions\Notifications\SendWebhookTestNotification; use App\Settings\NotificationSettings; @@ -128,7 +128,7 @@ public function form(Form $form): Form 'md' => 2, ]), - Forms\Components\Section::make('Ntfy') + Forms\Components\Section::make('Ntfy') ->schema([ Forms\Components\Toggle::make('ntfy_enabled') ->label('Enable Ntfy webhook notifications') diff --git a/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php b/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php new file mode 100644 index 000000000..3f9a94d20 --- /dev/null +++ b/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php @@ -0,0 +1,60 @@ +ntfy_enabled) { + return; + } + + if (! $notificationSettings->ntfy_on_speedtest_run) { + return; + } + + if (! count($notificationSettings->ntfy_webhooks)) { + Log::warning('Ntfy urls not found, check Ntfy notification channel settings.'); + + return; + } + + $payload = + view('ntfy.speedtest-completed', [ + 'id' => $event->result->id, + 'service' => Str::title($event->result->service), + 'serverName' => $event->result->server_name, + 'serverId' => $event->result->server_id, + 'isp' => $event->result->isp, + 'ping' => round($event->result->ping).' ms', + 'download' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), + 'upload' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), + 'packetLoss' => $event->result->packet_loss, + 'url' => url('/admin/results'), + ])->render(); + + foreach ($notificationSettings->ntfy_webhooks as $url) { + WebhookCall::create() + ->url($url['url']) + ->payload([ + 'topic' => $url['topic'], + 'message' => $payload, + ]) + ->doNotSign() + ->dispatch(); + } + } +} diff --git a/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php b/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php new file mode 100644 index 000000000..b459db401 --- /dev/null +++ b/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php @@ -0,0 +1,134 @@ +ntfy_enabled) { + return; + } + + if (! $notificationSettings->ntfy_on_threshold_failure) { + return; + } + + if (! count($notificationSettings->ntfy_webhooks)) { + Log::warning('Ntfy urls not found, check Ntfy notification channel settings.'); + + return; + } + + $thresholdSettings = new ThresholdSettings(); + + if (! $thresholdSettings->absolute_enabled) { + return; + } + + $failed = []; + + if ($thresholdSettings->absolute_download > 0) { + array_push($failed, $this->absoluteDownloadThreshold(event: $event, thresholdSettings: $thresholdSettings)); + } + + if ($thresholdSettings->absolute_upload > 0) { + array_push($failed, $this->absoluteUploadThreshold(event: $event, thresholdSettings: $thresholdSettings)); + } + + if ($thresholdSettings->absolute_ping > 0) { + array_push($failed, $this->absolutePingThreshold(event: $event, thresholdSettings: $thresholdSettings)); + } + + $failed = array_filter($failed); + + if (! count($failed)) { + Log::warning('Failed ntfy thresholds not found, won\'t send notification.'); + + return; + } + + $payload = + view('ntfy.speedtest-threshold', [ + 'id' => $event->result->id, + 'service' => Str::title($event->result->service), + 'serverName' => $event->result->server_name, + 'serverId' => $event->result->server_id, + 'isp' => $event->result->isp, + 'metrics' => $failed, + 'url' => url('/admin/results'), + ])->render(); + + foreach ($notificationSettings->ntfy_webhooks as $url) { + WebhookCall::create() + ->url($url['url']) + ->payload([ + 'topic' => $url['topic'], + 'message' => $payload, + ]) + ->doNotSign() + ->dispatch(); + } + } + + /** + * Build Ntfy notification if absolute download threshold is breached. + */ + protected function absoluteDownloadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array + { + if (! absoluteDownloadThresholdFailed($thresholdSettings->absolute_download, $event->result->download)) { + return false; + } + + return [ + 'name' => 'Download', + 'threshold' => $thresholdSettings->absolute_download.' Mbps', + 'value' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), + ]; + } + + /** + * Build Ntfy notification if absolute upload threshold is breached. + */ + protected function absoluteUploadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array + { + if (! absoluteUploadThresholdFailed($thresholdSettings->absolute_upload, $event->result->upload)) { + return false; + } + + return [ + 'name' => 'Upload', + 'threshold' => $thresholdSettings->absolute_upload.' Mbps', + 'value' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), + ]; + } + + /** + * Build Ntfy notification if absolute ping threshold is breached. + */ + protected function absolutePingThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array + { + if (! absolutePingThresholdFailed($thresholdSettings->absolute_ping, $event->result->ping)) { + return false; + } + + return [ + 'name' => 'Ping', + 'threshold' => $thresholdSettings->absolute_ping.' ms', + 'value' => round($event->result->ping, 2).' ms', + ]; + } +} diff --git a/resources/views/ntfy/speedtest-completed.blade.php b/resources/views/ntfy/speedtest-completed.blade.php new file mode 100644 index 000000000..9276d60dc --- /dev/null +++ b/resources/views/ntfy/speedtest-completed.blade.php @@ -0,0 +1,12 @@ +Speedtest Completed - #{{ $id }} + +A new speedtest was completed using {{ $service }}. + +Server name: {{ $serverName }} +Server ID: {{ $serverId }} +ISP: {{ $isp }} +Ping: {{ $ping }} +Download: {{ $download }} +Upload: {{ $upload }} +Packet Loss: {{ $packetLoss }} **%** +URL: {{ $url }} \ No newline at end of file diff --git a/resources/views/ntfy/speedtest-threshold.blade.php b/resources/views/ntfy/speedtest-threshold.blade.php new file mode 100644 index 000000000..150469123 --- /dev/null +++ b/resources/views/ntfy/speedtest-threshold.blade.php @@ -0,0 +1,8 @@ +Speedtest Threshold Breached - #{{ $id }} + +A new speedtest was completed using {{ $service }} on {{ $isp }}** but a threshold was breached. + +@foreach ($metrics as $item) +- {{ $item['name'] }} {{ $item['threshold'] }}: {{ $item['value'] }} +@endforeach +- URL:{{ $url }} From 37ecd0e3be0840299890d29b544e10f40f38ba64 Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Wed, 26 Jun 2024 22:48:05 +0200 Subject: [PATCH 3/6] Add_auth_option --- .../SendNtfyTestNotification.php | 15 ++++++-- .../Pages/Settings/NotificationPage.php | 9 +++++ .../SendSpeedtestCompletedNotification.php | 38 +++++++++++-------- .../SendSpeedtestThresholdNotification.php | 15 ++++++-- .../views/ntfy/speedtest-threshold.blade.php | 2 +- 5 files changed, 57 insertions(+), 22 deletions(-) diff --git a/app/Actions/Notifications/SendNtfyTestNotification.php b/app/Actions/Notifications/SendNtfyTestNotification.php index ce7f744ae..8975febaa 100644 --- a/app/Actions/Notifications/SendNtfyTestNotification.php +++ b/app/Actions/Notifications/SendNtfyTestNotification.php @@ -22,14 +22,23 @@ public function handle(array $webhooks) } foreach ($webhooks as $webhook) { - WebhookCall::create() + $webhookCall = WebhookCall::create() ->url($webhook['url']) ->payload([ 'topic' => $webhook['topic'], 'message' => '👋 Testing the ntfy notification channel.', ]) - ->doNotSign() - ->dispatch(); + ->doNotSign(); + + // Only add authentication if username and password are provided + if (! empty($webhook['username']) && ! empty($webhook['password'])) { + $authHeader = 'Basic '.base64_encode($webhook['username'].':'.$webhook['password']); + $webhookCall->withHeaders([ + 'Authorization' => $authHeader, + ]); + } + + $webhookCall->dispatch(); } Notification::make() diff --git a/app/Filament/Pages/Settings/NotificationPage.php b/app/Filament/Pages/Settings/NotificationPage.php index ee527b69f..6b2119f54 100755 --- a/app/Filament/Pages/Settings/NotificationPage.php +++ b/app/Filament/Pages/Settings/NotificationPage.php @@ -161,6 +161,15 @@ public function form(Form $form): Form ->placeholder('Your ntfy Topic') ->maxLength(200) ->required(), + Forms\Components\TextInput::make('username') + ->label('Username') + ->placeholder('Username for Basic Auth (optional)') + ->maxLength(200), + Forms\Components\TextInput::make('password') + ->label('Password') + ->placeholder('Password for Basic Auth (optional)') + ->password() + ->maxLength(200), ]) ->columnSpanFull(), Forms\Components\Actions::make([ diff --git a/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php b/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php index 3f9a94d20..585db1654 100644 --- a/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php +++ b/app/Listeners/Ntfy/SendSpeedtestCompletedNotification.php @@ -33,28 +33,36 @@ public function handle(SpeedtestCompleted $event): void } $payload = - view('ntfy.speedtest-completed', [ - 'id' => $event->result->id, - 'service' => Str::title($event->result->service), - 'serverName' => $event->result->server_name, - 'serverId' => $event->result->server_id, - 'isp' => $event->result->isp, - 'ping' => round($event->result->ping).' ms', - 'download' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), - 'upload' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), - 'packetLoss' => $event->result->packet_loss, - 'url' => url('/admin/results'), - ])->render(); + view('ntfy.speedtest-completed', [ + 'id' => $event->result->id, + 'service' => Str::title($event->result->service), + 'serverName' => $event->result->server_name, + 'serverId' => $event->result->server_id, + 'isp' => $event->result->isp, + 'ping' => round($event->result->ping).' ms', + 'download' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), + 'upload' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), + 'packetLoss' => $event->result->packet_loss, + 'url' => url('/admin/results'), + ])->render(); foreach ($notificationSettings->ntfy_webhooks as $url) { - WebhookCall::create() + $webhookCall = WebhookCall::create() ->url($url['url']) ->payload([ 'topic' => $url['topic'], 'message' => $payload, ]) - ->doNotSign() - ->dispatch(); + ->doNotSign(); + + // Only add authentication if username and password are provided + if (! empty($url['username']) && ! empty($url['password'])) { + $authHeader = 'Basic '.base64_encode($url['username'].':'.$url['password']); + $webhookCall->withHeaders([ + 'Authorization' => $authHeader, + ]); + } + $webhookCall->dispatch(); } } } diff --git a/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php b/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php index b459db401..62263f1b6 100644 --- a/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php +++ b/app/Listeners/Ntfy/SendSpeedtestThresholdNotification.php @@ -73,14 +73,23 @@ public function handle(SpeedtestCompleted $event): void ])->render(); foreach ($notificationSettings->ntfy_webhooks as $url) { - WebhookCall::create() + $webhookCall = WebhookCall::create() ->url($url['url']) ->payload([ 'topic' => $url['topic'], 'message' => $payload, ]) - ->doNotSign() - ->dispatch(); + ->doNotSign(); + + // Only add authentication if username and password are provided + if (! empty($url['username']) && ! empty($url['password'])) { + $authHeader = 'Basic '.base64_encode($url['username'].':'.$url['password']); + $webhookCall->withHeaders([ + 'Authorization' => $authHeader, + ]); + } + + $webhookCall->dispatch(); } } diff --git a/resources/views/ntfy/speedtest-threshold.blade.php b/resources/views/ntfy/speedtest-threshold.blade.php index 150469123..a84ee245e 100644 --- a/resources/views/ntfy/speedtest-threshold.blade.php +++ b/resources/views/ntfy/speedtest-threshold.blade.php @@ -5,4 +5,4 @@ @foreach ($metrics as $item) - {{ $item['name'] }} {{ $item['threshold'] }}: {{ $item['value'] }} @endforeach -- URL:{{ $url }} +- URL: {{ $url }} From fa46c2d64883f189b20e0cfe630cf1c00cb55b8f Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Wed, 26 Jun 2024 22:58:33 +0200 Subject: [PATCH 4/6] fix lint --- app/Filament/Pages/Settings/NotificationPage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Filament/Pages/Settings/NotificationPage.php b/app/Filament/Pages/Settings/NotificationPage.php index 1100d1c38..02de6ac3d 100755 --- a/app/Filament/Pages/Settings/NotificationPage.php +++ b/app/Filament/Pages/Settings/NotificationPage.php @@ -428,4 +428,4 @@ public function form(Form $form): Form ]), ]); } -} \ No newline at end of file +} From aed5c7d4a0fe9b125eddbd500a3deccf4932da3e Mon Sep 17 00:00:00 2001 From: svenvg93 Date: Sun, 7 Jul 2024 22:20:00 +0200 Subject: [PATCH 5/6] fix packet_loss_% --- resources/views/ntfy/speedtest-completed.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/ntfy/speedtest-completed.blade.php b/resources/views/ntfy/speedtest-completed.blade.php index 9276d60dc..07e9d7eb8 100644 --- a/resources/views/ntfy/speedtest-completed.blade.php +++ b/resources/views/ntfy/speedtest-completed.blade.php @@ -8,5 +8,5 @@ Ping: {{ $ping }} Download: {{ $download }} Upload: {{ $upload }} -Packet Loss: {{ $packetLoss }} **%** +Packet Loss: {{ $packetLoss }} % URL: {{ $url }} \ No newline at end of file From 3dec0cecac3db6daaa70cf7cca0dee8e99f0580e Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Thu, 18 Jul 2024 09:54:59 -0400 Subject: [PATCH 6/6] added eof line --- resources/views/ntfy/speedtest-completed.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/ntfy/speedtest-completed.blade.php b/resources/views/ntfy/speedtest-completed.blade.php index 07e9d7eb8..d51c75ce0 100644 --- a/resources/views/ntfy/speedtest-completed.blade.php +++ b/resources/views/ntfy/speedtest-completed.blade.php @@ -9,4 +9,4 @@ Download: {{ $download }} Upload: {{ $upload }} Packet Loss: {{ $packetLoss }} % -URL: {{ $url }} \ No newline at end of file +URL: {{ $url }}