Skip to content

Commit 5328af6

Browse files
committed
feat: add webhook notifications
1 parent 05badf4 commit 5328af6

File tree

7 files changed

+186
-0
lines changed

7 files changed

+186
-0
lines changed

app/Filament/Pages/Settings/NotificationPage.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Forms\Components\TestDatabaseNotification;
66
use App\Forms\Components\TestMailNotification;
7+
use App\Forms\Components\TestWebhookNotification;
78
use App\Forms\Components\TestTelegramNotification;
89
use App\Mail\Test;
910
use App\Notifications\Telegram\TestNotification as TelegramTestNotification;
@@ -20,6 +21,7 @@
2021
use Filament\Forms\Components\View;
2122
use Filament\Notifications\Notification;
2223
use Filament\Pages\SettingsPage;
24+
use Illuminate\Support\Facades\Http;
2325
use Illuminate\Support\Facades\Mail;
2426
use Illuminate\Support\Facades\Notification as FacadesNotification;
2527

@@ -164,6 +166,44 @@ protected function getFormSchema(): array
164166
'default' => 1,
165167
'md' => 2,
166168
]),
169+
Section::make('Webhook')
170+
->schema([
171+
Toggle::make('webhook_enabled')
172+
->label('Enable webhook notifications')
173+
->reactive()
174+
->columnSpan(2),
175+
Grid::make([
176+
'default' => 1, ])
177+
->hidden(fn (Closure $get) => $get('webhook_enabled') !== true)
178+
->schema([
179+
Fieldset::make('Triggers')
180+
->schema([
181+
Toggle::make('webhook_on_speedtest_run')
182+
->label('Notify on every speedtest run')
183+
->columnSpan(2),
184+
Toggle::make('webhook_on_threshold_failure')
185+
->label('Notify on threshold failures')
186+
->columnSpan(2),
187+
]),
188+
]),
189+
Repeater::make('webhook_urls')
190+
->label('Urls')
191+
->schema([
192+
TextInput::make('url')
193+
->maxLength(100)
194+
->required()
195+
->columnSpan(['md' => 2]),
196+
])
197+
->hidden(fn (Closure $get) => $get('webhook_enabled') !== true)
198+
->columnSpan(['md' => 2]),
199+
TestWebhookNotification::make('test channel')
200+
->hidden(fn (Closure $get) => $get('webhook_enabled') !== true),
201+
])
202+
->compact()
203+
->columns([
204+
'default' => 1,
205+
'md' => 2,
206+
]),
167207
])
168208
->columnSpan([
169209
'md' => 2,
@@ -260,4 +300,34 @@ public function sendTestTelegramNotification(): void
260300
->success()
261301
->send();
262302
}
303+
304+
public function sendTestWebhookNotification(): void
305+
{
306+
$notificationSettings = new (NotificationSettings::class);
307+
308+
if (blank($notificationSettings->webhook_urls)) {
309+
Notification::make()
310+
->title('You need to add webhook URLs.')
311+
->body('Make sure to click "Save changes" before testing mail notifications.')
312+
->warning()
313+
->send();
314+
315+
return;
316+
}
317+
318+
foreach ($notificationSettings->webhook_urls as $url) {
319+
Http::post($url['url'], [
320+
'result_id' => 0,
321+
'site_name' => 'test',
322+
'ping' => sprintf('%.2f', rand(5, 50)),
323+
'download' => sprintf('%.2f', rand(50, 1000)),
324+
'upload' => sprintf('%.2f', rand(10, 100)),
325+
]);
326+
}
327+
328+
Notification::make()
329+
->title('Test webhook notification sent.')
330+
->success()
331+
->send();
332+
}
263333
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace App\Forms\Components;
4+
5+
use Filament\Forms\Components\Field;
6+
7+
class TestWebhookNotification extends Field
8+
{
9+
protected string $view = 'forms.components.test-webhook-notification';
10+
}

app/Listeners/SpeedtestCompletedListener.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use App\Settings\NotificationSettings;
99
use App\Telegram\TelegramNotification;
1010
use Filament\Notifications\Notification;
11+
use Illuminate\Support\Facades\Http;
1112
use Illuminate\Support\Facades\Mail;
1213

1314
class SpeedtestCompletedListener
@@ -73,5 +74,19 @@ public function handle(ResultCreated $event): void
7374
}
7475
}
7576
}
77+
78+
if ($this->notificationSettings->webhook_enabled) {
79+
if ($this->notificationSettings->webhook_on_speedtest_run && count($this->notificationSettings->webhook_urls)) {
80+
foreach ($this->notificationSettings->webhook_urls as $url) {
81+
Http::post($url['url'], [
82+
'result_id' => $event->result->id,
83+
'site_name' => $this->generalSettings->site_name,
84+
'ping' => $event->result->ping,
85+
'download' => toBits(convertSize($event->result->download)),
86+
'upload' => toBits(convertSize($event->result->upload)),
87+
]);
88+
}
89+
}
90+
}
7691
}
7792
}

app/Listeners/Threshold/AbsoluteListener.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use App\Telegram\TelegramNotification;
1111
use Filament\Notifications\Notification;
1212
use Illuminate\Contracts\Queue\ShouldQueue;
13+
use Illuminate\Support\Facades\Http;
1314
use Illuminate\Support\Facades\Log;
1415
use Illuminate\Support\Facades\Mail;
1516

@@ -60,6 +61,11 @@ public function handle(ResultCreated $event): void
6061
if ($this->notificationSettings->telegram_enabled == true && $this->notificationSettings->telegram_on_threshold_failure == true) {
6162
$this->telegramChannel($event);
6263
}
64+
65+
// Webhook notification channel
66+
if ($this->notificationSettings->webhook_enabled == true && $this->notificationSettings->webhook_on_threshold_failure == true) {
67+
$this->webhookChannel($event);
68+
}
6369
}
6470

6571
/**
@@ -211,4 +217,59 @@ protected function telegramChannel(ResultCreated $event): void
211217
}
212218
}
213219
}
220+
221+
/**
222+
* Handle webhook notifications.
223+
*/
224+
protected function webhookChannel(ResultCreated $event): void
225+
{
226+
$failedThresholds = [];
227+
228+
if (! count($this->notificationSettings->webhook_urls) > 0) {
229+
Log::info('Skipping sending webhook notification, no urls.');
230+
}
231+
232+
// Download threshold
233+
if ($this->thresholdSettings->absolute_download > 0) {
234+
if (absoluteDownloadThresholdFailed($this->thresholdSettings->absolute_download, $event->result->download)) {
235+
array_push($failedThresholds, [
236+
'name' => 'Download',
237+
'threshold' => $this->thresholdSettings->absolute_download,
238+
'value' => toBits(convertSize($event->result->download), 2),
239+
]);
240+
}
241+
}
242+
243+
// Upload threshold
244+
if ($this->thresholdSettings->absolute_upload > 0) {
245+
if (absoluteUploadThresholdFailed($this->thresholdSettings->absolute_upload, $event->result->upload)) {
246+
array_push($failedThresholds, [
247+
'name' => 'Upload',
248+
'threshold' => $this->thresholdSettings->absolute_upload,
249+
'value' => toBits(convertSize($event->result->upload), 2),
250+
]);
251+
}
252+
}
253+
254+
// Ping threshold
255+
if ($this->thresholdSettings->absolute_ping > 0) {
256+
if (absolutePingThresholdFailed($this->thresholdSettings->absolute_ping, $event->result->ping)) {
257+
array_push($failedThresholds, [
258+
'name' => 'Ping',
259+
'threshold' => $this->thresholdSettings->absolute_ping,
260+
'value' => round($event->result->ping, 2),
261+
]);
262+
}
263+
}
264+
265+
if (count($failedThresholds)) {
266+
foreach ($this->notificationSettings->webhook_urls as $url) {
267+
Http::post($url['url'], [
268+
'result_id' => $event->result->id,
269+
'site_name' => $this->generalSettings->site_name,
270+
'metrics' => $failedThresholds,
271+
]);
272+
}
273+
}
274+
}
214275
}

app/Settings/NotificationSettings.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ class NotificationSettings extends Settings
2828

2929
public ?array $telegram_recipients;
3030

31+
public bool $webhook_enabled;
32+
33+
public bool $webhook_on_speedtest_run;
34+
35+
public bool $webhook_on_threshold_failure;
36+
37+
public ?array $webhook_urls;
38+
3139
public static function group(): string
3240
{
3341
return 'notification';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
use Spatie\LaravelSettings\Migrations\SettingsMigration;
4+
5+
return new class extends SettingsMigration
6+
{
7+
/**
8+
* Run the migrations.
9+
*/
10+
public function up(): void
11+
{
12+
$this->migrator->add('notification.webhook_enabled', false);
13+
$this->migrator->add('notification.webhook_on_speedtest_run', false);
14+
$this->migrator->add('notification.webhook_on_threshold_failure', false);
15+
$this->migrator->add('notification.webhook_urls', null);
16+
}
17+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div>
2+
<x-filament::button wire:click="sendTestWebhookNotification()">
3+
Test webhook channel
4+
</x-filament::button>
5+
</div>

0 commit comments

Comments
 (0)