chore: remove deprecated notification channels and related settings (#2798)

Co-authored-by: Alex Justesen <1144087+alexjustesen@users.noreply.github.com>
This commit is contained in:
Alex Justesen
2026-05-29 20:57:17 -04:00
committed by GitHub
parent de19975b91
commit c09b148f91
52 changed files with 10 additions and 2588 deletions
@@ -1,37 +0,0 @@
<?php
namespace App\Actions\Notifications;
use Filament\Notifications\Notification;
use Lorisleiva\Actions\Concerns\AsAction;
use Spatie\WebhookServer\WebhookCall;
class SendDiscordTestNotification
{
use AsAction;
public function handle(array $webhooks)
{
if (! count($webhooks)) {
Notification::make()
->title('You need to add Discord urls!')
->warning()
->send();
return;
}
foreach ($webhooks as $webhook) {
WebhookCall::create()
->url($webhook['url'])
->payload(['content' => '👋 Testing the Discord notification channel.'])
->doNotSign()
->dispatch();
}
Notification::make()
->title('Test Discord notification sent.')
->success()
->send();
}
}
@@ -1,37 +0,0 @@
<?php
namespace App\Actions\Notifications;
use Filament\Notifications\Notification;
use Lorisleiva\Actions\Concerns\AsAction;
use Spatie\WebhookServer\WebhookCall;
class SendGotifyTestNotification
{
use AsAction;
public function handle(array $webhooks)
{
if (! count($webhooks)) {
Notification::make()
->title('You need to add Gotify urls!')
->warning()
->send();
return;
}
foreach ($webhooks as $webhook) {
WebhookCall::create()
->url($webhook['url'])
->payload(['message' => '👋 Testing the Gotify notification channel.'])
->doNotSign()
->dispatch();
}
Notification::make()
->title('Test Gotify notification sent.')
->success()
->send();
}
}
@@ -1,37 +0,0 @@
<?php
namespace App\Actions\Notifications;
use Filament\Notifications\Notification;
use Lorisleiva\Actions\Concerns\AsAction;
use Spatie\WebhookServer\WebhookCall;
class SendHealthCheckTestNotification
{
use AsAction;
public function handle(array $webhooks)
{
if (! count($webhooks)) {
Notification::make()
->title('You need to add HealthCheck.io urls!')
->warning()
->send();
return;
}
foreach ($webhooks as $webhook) {
WebhookCall::create()
->url($webhook['url'])
->payload(['message' => '👋 Testing the HealthCheck.io notification channel.'])
->doNotSign()
->dispatch();
}
Notification::make()
->title('Test HealthCheck.io notification sent.')
->success()
->send();
}
}
@@ -1,49 +0,0 @@
<?php
namespace App\Actions\Notifications;
use Filament\Notifications\Notification;
use Lorisleiva\Actions\Concerns\AsAction;
use Spatie\WebhookServer\WebhookCall;
class SendNtfyTestNotification
{
use AsAction;
public function handle(array $webhooks)
{
if (! count($webhooks)) {
Notification::make()
->title('You need to add ntfy urls!')
->warning()
->send();
return;
}
foreach ($webhooks as $webhook) {
$webhookCall = WebhookCall::create()
->url($webhook['url'])
->payload([
'topic' => $webhook['topic'],
'message' => '👋 Testing the ntfy notification channel.',
])
->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()
->title('Test ntfy notification sent.')
->success()
->send();
}
}
@@ -1,41 +0,0 @@
<?php
namespace App\Actions\Notifications;
use Filament\Notifications\Notification;
use Lorisleiva\Actions\Concerns\AsAction;
use Spatie\WebhookServer\WebhookCall;
class SendPushoverTestNotification
{
use AsAction;
public function handle(array $webhooks)
{
if (! count($webhooks)) {
Notification::make()
->title('You need to add Pushover URLs!')
->warning()
->send();
return;
}
foreach ($webhooks as $webhook) {
WebhookCall::create()
->url($webhook['url'])
->payload([
'token' => $webhook['api_token'],
'user' => $webhook['user_key'],
'message' => '👋 Testing the Pushover notification channel.',
])
->doNotSign()
->dispatch();
}
Notification::make()
->title('Test Pushover notification sent.')
->success()
->send();
}
}
@@ -1,37 +0,0 @@
<?php
namespace App\Actions\Notifications;
use Filament\Notifications\Notification;
use Lorisleiva\Actions\Concerns\AsAction;
use Spatie\WebhookServer\WebhookCall;
class SendSlackTestNotification
{
use AsAction;
public function handle(array $webhooks)
{
if (! count($webhooks)) {
Notification::make()
->title('You need to add Slack URLs!')
->warning()
->send();
return;
}
foreach ($webhooks as $webhook) {
WebhookCall::create()
->url($webhook['url'])
->payload(['text' => '👋 Testing the Slack notification channel.'])
->doNotSign()
->dispatch();
}
Notification::make()
->title('Test Slack notification sent.')
->success()
->send();
}
}
@@ -1,35 +0,0 @@
<?php
namespace App\Actions\Notifications;
use App\Notifications\Telegram\TestNotification;
use Filament\Notifications\Notification;
use Illuminate\Support\Facades\Notification as FacadesNotification;
use Lorisleiva\Actions\Concerns\AsAction;
class SendTelegramTestNotification
{
use AsAction;
public function handle(array $recipients)
{
if (! count($recipients)) {
Notification::make()
->title('You need to add Telegram recipients!')
->warning()
->send();
return;
}
foreach ($recipients as $recipient) {
FacadesNotification::route('telegram_chat_id', $recipient['telegram_chat_id'])
->notify(new TestNotification);
}
Notification::make()
->title('Test Telegram notification sent.')
->success()
->send();
}
}
-359
View File
@@ -4,14 +4,7 @@ namespace App\Filament\Pages\Settings;
use App\Actions\Notifications\SendAppriseTestNotification;
use App\Actions\Notifications\SendDatabaseTestNotification;
use App\Actions\Notifications\SendDiscordTestNotification;
use App\Actions\Notifications\SendGotifyTestNotification;
use App\Actions\Notifications\SendHealthCheckTestNotification;
use App\Actions\Notifications\SendMailTestNotification;
use App\Actions\Notifications\SendNtfyTestNotification;
use App\Actions\Notifications\SendPushoverTestNotification;
use App\Actions\Notifications\SendSlackTestNotification;
use App\Actions\Notifications\SendTelegramTestNotification;
use App\Actions\Notifications\SendWebhookTestNotification;
use App\Rules\AppriseScheme;
use App\Rules\ContainsString;
@@ -26,7 +19,6 @@ use Filament\Pages\SettingsPage;
use Filament\Schemas\Components\Actions;
use Filament\Schemas\Components\Fieldset;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Components\Tabs\Tab;
use Filament\Schemas\Components\Utilities\Get;
@@ -290,357 +282,6 @@ class Notification extends SettingsPage
]),
])
->columnSpanFull(),
// ! DEPRECATED CHANNELS
SimpleAlert::make('deprecation_warning')
->title('Deprecated Notification Channels')
->description('The following notification channels are deprecated and will be removed in a future release!')
->border()
->warning()
->columnSpanFull(),
Grid::make([
'default' => 1,
'md' => 3,
])
->columnSpan('full')
->schema([
Grid::make([
'default' => 1,
])
->schema([
Section::make('Pushover')
->description('⚠️ Pushover is deprecated and will be removed in a future release.')
->schema([
Toggle::make('pushover_enabled')
->label('Enable Pushover webhook notifications')
->reactive()
->columnSpanFull(),
Grid::make([
'default' => 1,
])
->hidden(fn (Get $get) => $get('pushover_enabled') !== true)
->schema([
Fieldset::make('Triggers')
->schema([
Toggle::make('pushover_on_speedtest_run')
->label('Notify on every speedtest run')
->columnSpanFull(),
Toggle::make('pushover_on_threshold_failure')
->label('Notify on threshold failures')
->columnSpanFull(),
]),
Repeater::make('pushover_webhooks')
->label('Pushover Webhooks')
->schema([
TextInput::make('url')
->label('URL')
->placeholder('http://api.pushover.net/1/messages.json')
->maxLength(2000)
->required()
->url(),
TextInput::make('user_key')
->label('User Key')
->placeholder('Your Pushover User Key')
->maxLength(200)
->required(),
TextInput::make('api_token')
->label('API Token')
->placeholder('Your Pushover API Token')
->maxLength(200)
->required(),
])
->columnSpanFull(),
Actions::make([
Action::make('test pushover')
->label('Test Pushover webhook')
->action(fn (Get $get) => SendPushoverTestNotification::run(
webhooks: $get('pushover_webhooks')
))
->hidden(fn (Get $get) => ! count($get('pushover_webhooks'))),
]),
]),
])
->compact()
->columnSpan('full'),
Section::make('Discord')
->description('⚠️ Discord is deprecated and will be removed in a future release.')
->schema([
Toggle::make('discord_enabled')
->label('Enable Discord webhook notifications')
->reactive()
->columnSpanFull(),
Grid::make([
'default' => 1,
])
->hidden(fn (Get $get) => $get('discord_enabled') !== true)
->schema([
Fieldset::make('Triggers')
->schema([
Toggle::make('discord_on_speedtest_run')
->label('Notify on every speedtest run')
->columnSpanFull(),
Toggle::make('discord_on_threshold_failure')
->label('Notify on threshold failures')
->columnSpanFull(),
]),
Repeater::make('discord_webhooks')
->label('Webhooks')
->schema([
TextInput::make('url')
->placeholder('https://discord.com/api/webhooks/longstringofcharacters')
->maxLength(2000)
->required()
->url(),
])
->columnSpanFull(),
Actions::make([
Action::make('test discord')
->label('Test Discord webhook')
->action(fn (Get $get) => SendDiscordTestNotification::run(webhooks: $get('discord_webhooks')))
->hidden(fn (Get $get) => ! count($get('discord_webhooks'))),
]),
]),
])
->compact()
->columnSpan('full'),
Section::make('Gotify')
->description('⚠️ Gotify is deprecated and will be removed in a future release.')
->schema([
Toggle::make('gotify_enabled')
->label('Enable Gotify webhook notifications')
->reactive()
->columnSpanFull(),
Grid::make([
'default' => 1,
])
->hidden(fn (Get $get) => $get('gotify_enabled') !== true)
->schema([
Fieldset::make('Triggers')
->schema([
Toggle::make('gotify_on_speedtest_run')
->label('Notify on every speedtest run')
->columnSpanFull(),
Toggle::make('gotify_on_threshold_failure')
->label('Notify on threshold failures')
->columnSpanFull(),
]),
Repeater::make('gotify_webhooks')
->label('Webhooks')
->schema([
TextInput::make('url')
->placeholder('https://example.com/message?token=<apptoken>')
->maxLength(2000)
->required()
->url(),
])
->columnSpanFull(),
Actions::make([
Action::make('test gotify')
->label('Test Gotify webhook')
->action(fn (Get $get) => SendGotifyTestNotification::run(webhooks: $get('gotify_webhooks')))
->hidden(fn (Get $get) => ! count($get('gotify_webhooks'))),
]),
]),
])
->compact()
->columnSpan('full'),
Section::make('Slack')
->description('⚠️ Slack is deprecated and will be removed in a future release.')
->schema([
Toggle::make('slack_enabled')
->label('Enable Slack webhook notifications')
->reactive()
->columnSpanFull(),
Grid::make([
'default' => 1,
])
->hidden(fn (Get $get) => $get('slack_enabled') !== true)
->schema([
Fieldset::make('Triggers')
->schema([
Toggle::make('slack_on_speedtest_run')
->label('Notify on every speedtest run')
->columnSpanFull(),
Toggle::make('slack_on_threshold_failure')
->label('Notify on threshold failures')
->columnSpanFull(),
]),
Repeater::make('slack_webhooks')
->label('Webhooks')
->schema([
TextInput::make('url')
->placeholder('https://hooks.slack.com/services/abc/xyz')
->maxLength(2000)
->required()
->url(),
])
->columnSpanFull(),
Actions::make([
Action::make('test Slack')
->label('Test slack webhook')
->action(fn (Get $get) => SendSlackTestNotification::run(webhooks: $get('slack_webhooks')))
->hidden(fn (Get $get) => ! count($get('slack_webhooks'))),
]),
]),
])
->compact()
->columnSpan('full'),
Section::make('Ntfy')
->description('⚠️ Ntfy is deprecated and will be removed in a future release.')
->schema([
Toggle::make('ntfy_enabled')
->label('Enable Ntfy webhook notifications')
->reactive()
->columnSpanFull(),
Grid::make([
'default' => 1,
])
->hidden(fn (Get $get) => $get('ntfy_enabled') !== true)
->schema([
Fieldset::make('Triggers')
->schema([
Toggle::make('ntfy_on_speedtest_run')
->label('Notify on every speedtest run')
->columnSpanFull(),
Toggle::make('ntfy_on_threshold_failure')
->label('Notify on threshold failures')
->columnSpanFull(),
]),
Repeater::make('ntfy_webhooks')
->label('Webhooks')
->schema([
TextInput::make('url')
->maxLength(2000)
->placeholder('Your ntfy server url')
->required()
->url(),
TextInput::make('topic')
->label('Topic')
->placeholder('Your ntfy Topic')
->maxLength(200)
->required(),
TextInput::make('username')
->label('Username')
->placeholder('Username for Basic Auth (optional)')
->maxLength(200),
TextInput::make('password')
->label('Password')
->placeholder('Password for Basic Auth (optional)')
->password()
->maxLength(200),
])
->columnSpanFull(),
Actions::make([
Action::make('test ntfy')
->label('Test Ntfy webhook')
->action(fn (Get $get) => SendNtfyTestNotification::run(webhooks: $get('ntfy_webhooks')))
->hidden(fn (Get $get) => ! count($get('ntfy_webhooks'))),
]),
]),
])
->compact()
->columnSpan('full'),
Section::make('Healthcheck.io')
->description('⚠️ Healthcheck.io is deprecated and will be removed in a future release.')
->schema([
Toggle::make('healthcheck_enabled')
->label('Enable healthcheck.io webhook notifications')
->reactive()
->columnSpanFull(),
Grid::make([
'default' => 1,
])
->hidden(fn (Get $get) => $get('healthcheck_enabled') !== true)
->schema([
Fieldset::make('Triggers')
->schema([
Toggle::make('healthcheck_on_speedtest_run')
->label('Notify on every speedtest run')
->columnSpanFull(),
Toggle::make('healthcheck_on_threshold_failure')
->label('Notify on threshold failures')
->helperText('Threshold notifications will be sent to the /fail path of the URL.')
->columnSpanFull(),
]),
Repeater::make('healthcheck_webhooks')
->label('webhooks')
->schema([
TextInput::make('url')
->placeholder('https://hc-ping.com/your-uuid-here')
->maxLength(2000)
->required()
->url(),
])
->columnSpanFull(),
Actions::make([
Action::make('test healthcheck')
->label('Test healthcheck.io webhook')
->action(fn (Get $get) => SendHealthCheckTestNotification::run(webhooks: $get('healthcheck_webhooks')))
->hidden(fn (Get $get) => ! count($get('healthcheck_webhooks'))),
]),
]),
])
->compact()
->columnSpan('full'),
Section::make('Telegram')
->description('⚠️ Telegram is deprecated and will be removed in a future release.')
->schema([
Toggle::make('telegram_enabled')
->label('Enable telegram notifications')
->reactive()
->columnSpanFull(),
Grid::make([
'default' => 1,
])
->hidden(fn (Get $get) => $get('telegram_enabled') !== true)
->schema([
Fieldset::make('Options')
->schema([
Toggle::make('telegram_disable_notification')
->label('Send the message silently to the user')
->columnSpanFull(),
]),
Fieldset::make('Triggers')
->schema([
Toggle::make('telegram_on_speedtest_run')
->label('Notify on every speedtest run')
->columnSpanFull(),
Toggle::make('telegram_on_threshold_failure')
->label('Notify on threshold failures')
->columnSpanFull(),
]),
Repeater::make('telegram_recipients')
->label('Recipients')
->schema([
TextInput::make('telegram_chat_id')
->placeholder('12345678910')
->label('Telegram Chat ID')
->maxLength(50)
->required(),
])
->columnSpanFull(),
Actions::make([
Action::make('test telegram')
->label('Test Telegram channel')
->action(fn (Get $get) => SendTelegramTestNotification::run(recipients: $get('telegram_recipients')))
->hidden(fn (Get $get) => ! count($get('telegram_recipients')) || blank(config('telegram.bot'))),
]),
]),
])
->compact()
->columnSpan('full'),
])
->columnSpan([
'md' => 2,
]),
]),
]);
}
}
@@ -1,59 +0,0 @@
<?php
namespace App\Listeners\Discord;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestCompletedNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->discord_enabled) {
return;
}
if (! $notificationSettings->discord_on_speedtest_run) {
return;
}
if (! count($notificationSettings->discord_webhooks)) {
Log::warning('Discord urls not found, check Discord notification channel settings.');
return;
}
$payload = [
'content' => view('discord.speedtest-completed', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'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,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render(),
];
foreach ($notificationSettings->discord_webhooks as $url) {
WebhookCall::create()
->url($url['url'])
->payload($payload)
->doNotSign()
->dispatch();
}
}
}
@@ -1,133 +0,0 @@
<?php
namespace App\Listeners\Discord;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use App\Settings\ThresholdSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestThresholdNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->discord_enabled) {
return;
}
if (! $notificationSettings->discord_on_threshold_failure) {
return;
}
if (! count($notificationSettings->discord_webhooks)) {
Log::warning('Discord urls not found, check Discord 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 Discord thresholds not found, won\'t send notification.');
return;
}
$payload = [
'content' => view('discord.speedtest-threshold', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'serverName' => $event->result->server_name,
'serverId' => $event->result->server_id,
'isp' => $event->result->isp,
'metrics' => $failed,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render(),
];
foreach ($notificationSettings->discord_webhooks as $url) {
WebhookCall::create()
->url($url['url'])
->payload($payload)
->doNotSign()
->dispatch();
}
}
/**
* Build Discord 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 Discord 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 Discord 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',
];
}
}
@@ -1,64 +0,0 @@
<?php
namespace App\Listeners\Gotify;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestCompletedNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->gotify_enabled) {
return;
}
if (! $notificationSettings->gotify_on_speedtest_run) {
return;
}
if (! count($notificationSettings->gotify_webhooks)) {
Log::warning('Gotify urls not found, check Gotify notification channel settings.');
return;
}
$payload = [
'message' => view('gotify.speedtest-completed', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'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,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render(),
'extras' => [
'client::display' => [
'contentType' => 'text/markdown',
],
],
];
foreach ($notificationSettings->gotify_webhooks as $url) {
WebhookCall::create()
->url($url['url'])
->payload($payload)
->doNotSign()
->dispatch();
}
}
}
@@ -1,138 +0,0 @@
<?php
namespace App\Listeners\Gotify;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use App\Settings\ThresholdSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestThresholdNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->gotify_enabled) {
return;
}
if (! $notificationSettings->gotify_on_threshold_failure) {
return;
}
if (! count($notificationSettings->gotify_webhooks)) {
Log::warning('Gotify urls not found, check gotify 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 Gotify thresholds not found, won\'t send notification.');
return;
}
$payload = [
'message' => view('gotify.speedtest-threshold', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'serverName' => $event->result->server_name,
'serverId' => $event->result->server_id,
'isp' => $event->result->isp,
'metrics' => $failed,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render(),
'extras' => [
'client::display' => [
'contentType' => 'text/markdown',
],
],
];
foreach ($notificationSettings->gotify_webhooks as $url) {
WebhookCall::create()
->url($url['url'])
->payload($payload)
->doNotSign()
->dispatch();
}
}
/**
* Build gotify 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 gotify 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 gotify 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',
];
}
}
@@ -1,51 +0,0 @@
<?php
namespace App\Listeners\HealthCheck;
use App\Events\SpeedtestCompleted;
use App\Settings\NotificationSettings;
use Illuminate\Support\Facades\Log;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestCompletedNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->healthcheck_enabled) {
return;
}
if (! $notificationSettings->healthcheck_on_speedtest_run) {
return;
}
if (! count($notificationSettings->healthcheck_webhooks)) {
Log::warning('healthcheck urls not found, check healthcheck notification channel settings.');
return;
}
foreach ($notificationSettings->healthcheck_webhooks as $url) {
WebhookCall::create()
->url($url['url'])
->payload([
'result_id' => $event->result->id,
'site_name' => config('app.name'),
'isp' => $event->result->isp,
'ping' => $event->result->ping,
'download' => $event->result->downloadBits,
'upload' => $event->result->uploadBits,
'packetLoss' => $event->result->packet_loss,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])
->doNotSign()
->dispatch();
}
}
}
@@ -1,126 +0,0 @@
<?php
namespace App\Listeners\HealthCheck;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use App\Settings\ThresholdSettings;
use Illuminate\Support\Facades\Log;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestThresholdNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->healthcheck_enabled) {
return;
}
if (! $notificationSettings->healthcheck_on_threshold_failure) {
return;
}
if (! count($notificationSettings->healthcheck_webhooks)) {
Log::warning('HealthCheck urls not found, check healthcheck 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 healthcheck thresholds not found, won\'t send notification.');
return;
}
foreach ($notificationSettings->healthcheck_webhooks as $url) {
WebhookCall::create()
->url($url['url'].'/fail')
->payload([
'result_id' => $event->result->id,
'site_name' => config('app.name'),
'isp' => $event->result->isp,
'metrics' => $failed,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])
->doNotSign()
->dispatch();
}
}
/**
* Build HealthCheck 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 Healthcheck 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 Healthcheck 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',
];
}
}
@@ -1,69 +0,0 @@
<?php
namespace App\Listeners\Ntfy;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestCompletedNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->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->getLabel()),
'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,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render();
foreach ($notificationSettings->ntfy_webhooks as $url) {
$webhookCall = WebhookCall::create()
->url($url['url'])
->payload([
'topic' => $url['topic'],
'message' => $payload,
])
->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();
}
}
}
@@ -1,144 +0,0 @@
<?php
namespace App\Listeners\Ntfy;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use App\Settings\ThresholdSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestThresholdNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->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->getLabel()),
'serverName' => $event->result->server_name,
'serverId' => $event->result->server_id,
'isp' => $event->result->isp,
'metrics' => $failed,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render();
foreach ($notificationSettings->ntfy_webhooks as $url) {
$webhookCall = WebhookCall::create()
->url($url['url'])
->payload([
'topic' => $url['topic'],
'message' => $payload,
])
->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();
}
}
/**
* 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',
];
}
}
@@ -1,63 +0,0 @@
<?php
namespace App\Listeners\Pushover;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestCompletedNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->pushover_enabled) {
return;
}
if (! $notificationSettings->pushover_on_speedtest_run) {
return;
}
if (! count($notificationSettings->pushover_webhooks)) {
Log::warning('Pushover urls not found, check Pushover notification channel settings.');
return;
}
$payload = [
view('pushover.speedtest-completed', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'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,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render(),
];
foreach ($notificationSettings->pushover_webhooks as $url) {
WebhookCall::create()
->url($url['url'])
->payload([
'token' => $url['api_token'],
'user' => $url['user_key'],
'message' => $payload,
])
->doNotSign()
->dispatch();
}
}
}
@@ -1,137 +0,0 @@
<?php
namespace App\Listeners\Pushover;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use App\Settings\ThresholdSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestThresholdNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->pushover_enabled) {
return;
}
if (! $notificationSettings->pushover_on_threshold_failure) {
return;
}
if (! count($notificationSettings->pushover_webhooks)) {
Log::warning('Pushover urls not found, check Pushover 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 Pushover thresholds not found, won\'t send notification.');
return;
}
$payload = [
view('pushover.speedtest-threshold', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'serverName' => $event->result->server_name,
'serverId' => $event->result->server_id,
'isp' => $event->result->isp,
'metrics' => $failed,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render(),
];
foreach ($notificationSettings->pushover_webhooks as $url) {
WebhookCall::create()
->url($url['url'])
->payload([
'token' => $url['api_token'],
'user' => $url['user_key'],
'message' => $payload,
])
->doNotSign()
->dispatch();
}
}
/**
* Build Pushover 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 Pushover 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 Pushover 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',
];
}
}
@@ -1,59 +0,0 @@
<?php
namespace App\Listeners\Slack;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestCompletedNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->slack_enabled) {
return;
}
if (! $notificationSettings->slack_on_speedtest_run) {
return;
}
if (! count($notificationSettings->slack_webhooks)) {
Log::warning('Slack URLs not found, check Slack notification channel settings.');
return;
}
$payload = [
'text' => view('slack.speedtest-completed', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'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,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render(),
];
foreach ($notificationSettings->slack_webhooks as $url) {
WebhookCall::create()
->url($url['url'])
->payload($payload)
->doNotSign()
->dispatch();
}
}
}
@@ -1,133 +0,0 @@
<?php
namespace App\Listeners\Slack;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Settings\NotificationSettings;
use App\Settings\ThresholdSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Spatie\WebhookServer\WebhookCall;
class SendSpeedtestThresholdNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->slack_enabled) {
return;
}
if (! $notificationSettings->slack_on_threshold_failure) {
return;
}
if (! count($notificationSettings->slack_webhooks)) {
Log::warning('Slack urls not found, check Slack 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 Slack thresholds not found, won\'t send notification.');
return;
}
$payload = [
'text' => view('slack.speedtest-threshold', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'serverName' => $event->result->server_name,
'serverId' => $event->result->server_id,
'isp' => $event->result->isp,
'metrics' => $failed,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render(),
];
foreach ($notificationSettings->slack_webhooks as $url) {
WebhookCall::create()
->url($url['url'])
->payload($payload)
->doNotSign()
->dispatch();
}
}
/**
* Build Slack 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 Slack 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 Slack 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',
];
}
}
@@ -1,55 +0,0 @@
<?php
namespace App\Listeners\Telegram;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Notifications\Telegram\SpeedtestNotification;
use App\Settings\NotificationSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Str;
class SendSpeedtestCompletedNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->telegram_enabled) {
return;
}
if (! $notificationSettings->telegram_on_speedtest_run) {
return;
}
if (! count($notificationSettings->telegram_recipients)) {
Log::warning('Telegram recipients not found, check Telegram notification channel settings.');
return;
}
$content = view('telegram.speedtest-completed', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'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' => is_numeric($event->result->packet_loss) ? round($event->result->packet_loss, 2) : 'n/a',
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render();
foreach ($notificationSettings->telegram_recipients as $recipient) {
Notification::route('telegram_chat_id', $recipient['telegram_chat_id'])
->notify(new SpeedtestNotification($content, $notificationSettings->telegram_disable_notification));
}
}
}
@@ -1,129 +0,0 @@
<?php
namespace App\Listeners\Telegram;
use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Notifications\Telegram\SpeedtestNotification;
use App\Settings\NotificationSettings;
use App\Settings\ThresholdSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Str;
class SendSpeedtestThresholdNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;
if (! $notificationSettings->telegram_enabled) {
return;
}
if (! $notificationSettings->telegram_on_threshold_failure) {
return;
}
if (! count($notificationSettings->telegram_recipients) > 0) {
Log::warning('Telegram recipients not found, check Telegram 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 Telegram thresholds not found, won\'t send notification.');
return;
}
$content = view('telegram.speedtest-threshold', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'serverName' => $event->result->server_name,
'serverId' => $event->result->server_id,
'isp' => $event->result->isp,
'metrics' => $failed,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render();
foreach ($notificationSettings->telegram_recipients as $recipient) {
Notification::route('telegram_chat_id', $recipient['telegram_chat_id'])
->notify(new SpeedtestNotification($content, $notificationSettings->telegram_disable_notification));
}
}
/**
* Build Telegram 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 Telegram 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 Telegram 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',
];
}
}
@@ -1,66 +0,0 @@
<?php
namespace App\Livewire;
use App\Settings\NotificationSettings;
use Livewire\Attributes\Computed;
use Livewire\Component;
class DeprecatedNotificationChannelsBanner extends Component
{
#[Computed]
public function hasDeprecatedChannels(): bool
{
$settings = app(NotificationSettings::class);
return $settings->discord_enabled
|| $settings->gotify_enabled
|| $settings->healthcheck_enabled
|| $settings->ntfy_enabled
|| $settings->pushover_enabled
|| $settings->slack_enabled
|| $settings->telegram_enabled;
}
#[Computed]
public function deprecatedChannelsList(): array
{
$settings = app(NotificationSettings::class);
$channels = [];
if ($settings->discord_enabled) {
$channels[] = 'Discord';
}
if ($settings->gotify_enabled) {
$channels[] = 'Gotify';
}
if ($settings->healthcheck_enabled) {
$channels[] = 'Healthchecks';
}
if ($settings->ntfy_enabled) {
$channels[] = 'Ntfy';
}
if ($settings->pushover_enabled) {
$channels[] = 'Pushover';
}
if ($settings->slack_enabled) {
$channels[] = 'Slack';
}
if ($settings->telegram_enabled) {
$channels[] = 'Telegram';
}
return $channels;
}
public function render()
{
return view('livewire.deprecated-notification-channels-banner');
}
}
@@ -1,44 +0,0 @@
<?php
namespace App\Notifications\Telegram;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use NotificationChannels\Telegram\TelegramMessage;
class SpeedtestNotification extends Notification implements ShouldQueue
{
use Queueable;
/**
* Create a new notification instance.
*/
public function __construct(
public string $content,
public bool $disableNotification = false,
) {}
/**
* Get the notification's delivery channels.
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return ['telegram'];
}
/**
* Get the Telegram message representation of the notification.
*
* @param mixed $notifiable
*/
public function toTelegram($notifiable): TelegramMessage
{
return TelegramMessage::create()
->to($notifiable->routes['telegram_chat_id'])
->content($this->content)
->disableNotification($this->disableNotification);
}
}
@@ -1,49 +0,0 @@
<?php
namespace App\Notifications\Telegram;
use App\Settings\NotificationSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use NotificationChannels\Telegram\TelegramMessage;
class TestNotification extends Notification implements ShouldQueue
{
use Queueable;
protected $settings;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct()
{
$this->settings = new NotificationSettings;
}
/**
* Get the notification's delivery channels.
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return ['telegram'];
}
/**
* Get the Telegram representation of the notification.
*
* @return array<string, mixed>
*/
public function toTelegram(object $notifiable): TelegramMessage
{
return TelegramMessage::create()
->to($notifiable->routes['telegram_chat_id'])
->disableNotification($this->settings->telegram_disable_notification)
->content('👋 Testing the Telegram notification channel.');
}
}
-58
View File
@@ -20,16 +20,6 @@ class NotificationSettings extends Settings
public ?array $mail_recipients;
public bool $telegram_enabled;
public bool $telegram_disable_notification;
public bool $telegram_on_speedtest_run;
public bool $telegram_on_threshold_failure;
public ?array $telegram_recipients;
public bool $webhook_enabled;
public bool $webhook_on_speedtest_run;
@@ -38,54 +28,6 @@ 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 bool $ntfy_enabled;
public bool $ntfy_on_speedtest_run;
public bool $ntfy_on_threshold_failure;
public ?array $ntfy_webhooks;
public bool $pushover_enabled;
public bool $pushover_on_speedtest_run;
public bool $pushover_on_threshold_failure;
public ?array $pushover_webhooks;
public bool $healthcheck_enabled;
public bool $healthcheck_on_speedtest_run;
public bool $healthcheck_on_threshold_failure;
public ?array $healthcheck_webhooks;
public bool $slack_enabled;
public bool $slack_on_speedtest_run;
public bool $slack_on_threshold_failure;
public ?array $slack_webhooks;
public bool $gotify_enabled;
public bool $gotify_on_speedtest_run;
public bool $gotify_on_threshold_failure;
public ?array $gotify_webhooks;
public bool $apprise_enabled;
public ?string $apprise_server_url;
+8 -9
View File
@@ -18,32 +18,31 @@
"chrisullyott/php-filesize": "^4.2.1",
"codewithdennis/filament-simple-alert": "^4.0.5",
"dragonmantank/cron-expression": "^3.6.0",
"filament/filament": "^5.6.4",
"filament/spatie-laravel-settings-plugin": "^5.6.4",
"filament/filament": "^5.6.6",
"filament/spatie-laravel-settings-plugin": "^5.6.6",
"influxdata/influxdb-client-php": "^3.8",
"laravel-notification-channels/telegram": "^7.0",
"laravel/framework": "^13.11.2",
"laravel/framework": "^13.12.0",
"laravel/prompts": "^0.3.18",
"laravel/sanctum": "^4.3.2",
"livewire/livewire": "^4.3.0",
"lorisleiva/laravel-actions": "^2.10.1",
"maennchen/zipstream-php": "^2.4",
"promphp/prometheus_client_php": "^2.15.0",
"promphp/prometheus_client_php": "^2.15.1",
"secondnetwork/blade-tabler-icons": "^3.44.0",
"spatie/laravel-json-api-paginate": "^2.0.1",
"spatie/laravel-query-builder": "^6.4.4",
"spatie/laravel-settings": "^3.8.0",
"spatie/laravel-settings": "^3.9.0",
"spatie/laravel-webhook-server": "^3.10.0",
"spatie/ping": "^1.2.1",
"spatie/ping": "^1.2.2",
"zircote/swagger-php": "^5.8.3"
},
"require-dev": {
"fakerphp/faker": "^1.24.1",
"laravel/boost": "^2.4.8",
"laravel/pail": "^1.2.6",
"laravel/pail": "^1.2.7",
"laravel/pao": "^1.0.6",
"laravel/pint": "^1.29.1",
"laravel/sail": "^1.60.0",
"laravel/sail": "^1.61.0",
"laravel/tinker": "^3.0.2",
"mockery/mockery": "^1.6.12",
"nunomaduro/collision": "^8.9.4",
Generated
+1 -73
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c5a59bc77d544419232b8ce714c1e282",
"content-hash": "94e7776a4146e6839c72b5f67be9afed",
"packages": [
{
"name": "blade-ui-kit/blade-heroicons",
@@ -2350,78 +2350,6 @@
},
"time": "2026-05-28T20:35:55+00:00"
},
{
"name": "laravel-notification-channels/telegram",
"version": "7.0.0",
"source": {
"type": "git",
"url": "https://github.com/laravel-notification-channels/telegram.git",
"reference": "948b3a73a893950f271f5b0fc2df45883d176fc8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel-notification-channels/telegram/zipball/948b3a73a893950f271f5b0fc2df45883d176fc8",
"reference": "948b3a73a893950f271f5b0fc2df45883d176fc8",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/guzzle": "^7.8",
"illuminate/contracts": "^12.0 || ^13.0",
"illuminate/notifications": "^12.0 || ^13.0",
"illuminate/support": "^12.0 || ^13.0",
"php": "^8.3"
},
"require-dev": {
"larastan/larastan": "^3.0",
"mockery/mockery": "^1.4.4",
"orchestra/testbench": "^10.0 || ^11.0",
"pestphp/pest": "^4.0",
"pestphp/pest-plugin-laravel": "^4.0",
"phpstan/extension-installer": "^1.2",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-phpunit": "^2.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"NotificationChannels\\Telegram\\TelegramServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"NotificationChannels\\Telegram\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Irfaq Syed",
"email": "github@lukonet.net",
"homepage": "https://lukonet.com",
"role": "Developer"
}
],
"description": "Telegram Notifications Channel for Laravel",
"homepage": "https://github.com/laravel-notification-channels/telegram",
"keywords": [
"laravel",
"notification",
"telegram",
"telegram notification",
"telegram notifications channel"
],
"support": {
"issues": "https://github.com/laravel-notification-channels/telegram/issues",
"source": "https://github.com/laravel-notification-channels/telegram/tree/7.0.0"
},
"time": "2026-03-19T18:58:46+00:00"
},
{
"name": "laravel/framework",
"version": "v13.12.0",
+1 -3
View File
@@ -2,8 +2,6 @@
return [
'telegram-bot-api' => [
'token' => env('TELEGRAM_BOT_TOKEN'),
],
//
];
@@ -1,14 +0,0 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
class CreateTelegramNotificationSettings extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('notification.telegram_enabled', false);
$this->migrator->add('notification.telegram_on_speedtest_run', false);
$this->migrator->add('notification.telegram_on_threshold_failure', false);
$this->migrator->add('notification.telegram_recipients', null);
}
}
@@ -1,11 +0,0 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('notification.telegram_disable_notification', false);
}
};
@@ -1,14 +0,0 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('notification.healthcheck_enabled', false);
$this->migrator->add('notification.healthcheck_on_speedtest_run', false);
$this->migrator->add('notification.healthcheck_on_threshold_failure', false);
$this->migrator->add('notification.healthcheck_webhooks', null);
}
};
@@ -1,14 +0,0 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->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);
}
};
@@ -1,14 +0,0 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->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);
}
};
@@ -1,14 +0,0 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('notification.slack_enabled', false);
$this->migrator->add('notification.slack_on_speedtest_run', false);
$this->migrator->add('notification.slack_on_threshold_failure', false);
$this->migrator->add('notification.slack_webhooks', null);
}
};
@@ -1,14 +0,0 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('notification.gotify_enabled', false);
$this->migrator->add('notification.gotify_on_speedtest_run', false);
$this->migrator->add('notification.gotify_on_threshold_failure', false);
$this->migrator->add('notification.gotify_webhooks', null);
}
};
@@ -1,14 +0,0 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('notification.pushover_enabled', false);
$this->migrator->add('notification.pushover_on_speedtest_run', false);
$this->migrator->add('notification.pushover_on_threshold_failure', false);
$this->migrator->add('notification.pushover_webhooks', null);
}
};
-2
View File
@@ -1,7 +1,5 @@
<x-app-layout title="Dashboard">
<div class="space-y-6 md:space-y-12 dashboard-page">
<livewire:deprecated-notification-channels-banner />
<livewire:next-speedtest-banner />
<livewire:latest-result-stats />
@@ -1,15 +0,0 @@
**Deprecation Notice: The Discord notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Discord and many other services.**
**Speedtest Completed - #{{ $id }}**
A new speedtest on **{{ config('app.name') }}** was completed using **{{ $service }}**.
- **Server name:** {{ $serverName }}
- **Server ID:** {{ $serverId }}
- **ISP:** {{ $isp }}
- **Ping:** {{ $ping }}
- **Download:** {{ $download }}
- **Upload:** {{ $upload }}
- **Packet Loss:** {{ $packetLoss }} **%**
- **Ookla Speedtest:** {{ $speedtest_url }}
- **URL:** {{ $url }}
@@ -1,11 +0,0 @@
**Deprecation Notice: The Discord notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Discord and many other services.**
**Speedtest Threshold Breached - #{{ $id }}**
A new speedtest on **{{ config('app.name') }}** was completed using **{{ $service }}** on **{{ $isp }}** but a threshold was breached.
@foreach ($metrics as $item)
- **{{ $item['name'] }}** {{ $item['threshold'] }}: {{ $item['value'] }}
@endforeach
- **Ookla Speedtest:** {{ $speedtest_url }}
- **URL:** {{ $url }}
@@ -1,7 +1,5 @@
<x-filament-panels::page class="dashboard-page">
<div class="space-y-6 md:space-y-12">
<livewire:deprecated-notification-channels-banner />
<livewire:next-speedtest-banner />
<livewire:platform-stats />
@@ -1,15 +0,0 @@
**Deprecation Notice: The Gotify notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Gotify and many other services.**
**Speedtest Completed - #{{ $id }}**
A new speedtest on **{{ config('app.name') }}** was completed using **{{ $service }}**.
- **Server name:** {{ $serverName }}
- **Server ID:** {{ $serverId }}
- **ISP:** {{ $isp }}
- **Ping:** {{ $ping }}
- **Download:** {{ $download }}
- **Upload:** {{ $upload }}
- **Packet Loss:** {{ $packetLoss }} **%**
- **Ookla Speedtest:** [{{ $speedtest_url }}]({{ $speedtest_url }})
- **URL:** [{{ $url }}]({{ $url }})
@@ -1,11 +0,0 @@
**Deprecation Notice: The Gotify notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Gotify and many other services.**
**Speedtest Threshold Breached - #{{ $id }}**
A new speedtest on **{{ config('app.name') }}** was completed using **{{ $service }}** on **{{ $isp }}** but a threshold was breached.
@foreach ($metrics as $item)
- {{ $item['name'] }} {{ $item['threshold'] }}: **{{ $item['value'] }}**
@endforeach
- **Ookla Speedtest:** [{{ $speedtest_url }}]({{ $speedtest_url }})
- **URL:** [{{ $url }}]({{ $url }})
@@ -1,25 +0,0 @@
<div>
@if ($this->hasDeprecatedChannels)
<div class="rounded-md bg-amber-50 dark:bg-amber-500/10 p-4 outline outline-amber-500/20">
<div class="flex">
<div class="shrink-0">
<x-tabler-alert-triangle class="size-5 text-amber-400" />
</div>
<div class="ml-3 flex-1">
<h3 class="text-sm font-medium text-amber-800 dark:text-amber-300">
Deprecated Notification Channels
</h3>
<div class="mt-2 text-sm text-amber-700 dark:text-amber-400">
<p>
You are currently using the following deprecated notification channels: <strong>{{ implode(', ', $this->deprecatedChannelsList) }}</strong>.
</p>
<p class="mt-1">
These channels will be removed at the end of January 2026. As of that moment you will no longer receive notifications. Please migrate to <a href="{{ url('/admin/notification') }}" class="font-medium underline hover:text-amber-900 dark:hover:text-amber-200">Apprise</a> which supports all these services and more.
</p>
</div>
</div>
</div>
</div>
@endif
</div>
@@ -1,15 +0,0 @@
Deprecation Notice: The Ntfy notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Ntfy and many other services.
Speedtest Completed - #{{ $id }}
A new speedtest on {{ config('app.name') }} was completed using {{ $service }}.
Server name: {{ $serverName }}
Server ID: {{ $serverId }}
ISP: {{ $isp }}
Ping: {{ $ping }}
Download: {{ $download }}
Upload: {{ $upload }}
Packet Loss: {{ $packetLoss }} %
Ookla Speedtest: {{ $speedtest_url }}
URL: {{ $url }}
@@ -1,11 +0,0 @@
Deprecation Notice: The Ntfy notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Ntfy and many other services.
Speedtest Threshold Breached - #{{ $id }}
A new speedtest on **{{ config('app.name') }}** was completed using **{{ $service }}** on **{{ $isp }}** but a threshold was breached.
@foreach ($metrics as $item)
- {{ $item['name'] }} {{ $item['threshold'] }}: {{ $item['value'] }}
@endforeach
- Ookla Speedtest: {{ $speedtest_url }}
- URL: {{ $url }}
@@ -1,15 +0,0 @@
Deprecation Notice: The Pushover notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Pushover and many other services.
Speedtest Completed - #{{ $id }}
A new speedtest on {{ config('app.name') }} was completed using {{ $service }}.
- Server name: {{ $serverName }}
- Server ID: {{ $serverId }}
- ISP: {{ $isp }}
- Ping: {{ $ping }}
- Download: {{ $download }}
- Upload: {{ $upload }}
- Packet Loss: {{ $packetLoss }} %
- Ookla Speedtest: {{ $speedtest_url }}
- URL: {{ $url }}
@@ -1,11 +0,0 @@
Deprecation Notice: The Pushover notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Pushover and many other services.
Speedtest Threshold Breached - #{{ $id }}
A new speedtest on **{{ config('app.name') }}** was completed using **{{ $service }}** on **{{ $isp }}** but a threshold was breached.
@foreach ($metrics as $item)
- {{ $item['name'] }} {{ $item['threshold'] }}: {{ $item['value'] }}
@endforeach
- Ookla Speedtest: {{ $speedtest_url }}
- URL: {{ $url }}
@@ -1,15 +0,0 @@
*Deprecation Notice: The Slack notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Slack and many other services.*
*Speedtest Completed - #{{ $id }}*
A new speedtest on *{{ config('app.name') }}* was completed using *{{ $service }}*.
- *Server name:* {{ $serverName }}
- *Server ID:* {{ $serverId }}
- *ISP:* {{ $isp }}
- *Ping:* {{ $ping }}
- *Download:* {{ $download }}
- *Upload:* {{ $upload }}
- *Packet Loss:* {{ $packetLoss }} *%*
- *Ookla Speedtest:* {{ $speedtest_url }}
- *URL:* {{ $url }}
@@ -1,11 +0,0 @@
*Deprecation Notice: The Slack notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Slack and many other services.*
**Speedtest Threshold Breached - #{{ $id }}**
A new speedtest on **{{ config('app.name') }}** was completed using **{{ $service }}** on **{{ $isp }}** but a threshold was breached.
@foreach ($metrics as $item)
- *{{ $item['name'] }}* {{ $item['threshold'] }}: {{ $item['value'] }}
@endforeach
- *Ookla Speedtest:* {{ $speedtest_url }}
- *URL:* {{ $url }}
@@ -1,15 +0,0 @@
**Deprecation Notice: The Telegram notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Telegram and many other services.**
*Speedtest Completed - #{{ $id }}*
A new speedtest on *{{ config('app.name') }}* was completed using *{{ $service }}*.
- *Server name:* {{ $serverName }}
- *Server ID:* {{ $serverId }}
- **ISP:** {{ $isp }}
- *Ping:* {{ $ping }}
- *Download:* {{ $download }}
- *Upload:* {{ $upload }}
- **Packet Loss:** {{ $packetLoss }}**%**
- **Ookla Speedtest:** {{ $speedtest_url }}
- **URL:** {{ $url }}
@@ -1,11 +0,0 @@
**Deprecation Notice: The Telegram notification channel will stop working at the end of January 2026. Please migrate to Apprise which supports Telegram and many other services.**
**Speedtest Threshold Breached - #{{ $id }}**
A new speedtest on **{{ config('app.name') }}** was completed using **{{ $service }}** on **{{ $isp }}** but a threshold was breached.
@foreach ($metrics as $item)
- **{{ $item['name'] }}** {{ $item['threshold'] }}: {{ $item['value'] }}
@endforeach
- **Ookla Speedtest:** {{ $speedtest_url }}
- **URL:** {{ $url }}