diff --git a/app/Listeners/Mail/SendSpeedtestCompletedNotification.php b/app/Listeners/Mail/SendSpeedtestCompletedNotification.php new file mode 100644 index 000000000..d162666c4 --- /dev/null +++ b/app/Listeners/Mail/SendSpeedtestCompletedNotification.php @@ -0,0 +1,39 @@ +mail_enabled) { + return; + } + + if (! $notificationSettings->mail_on_speedtest_run) { + return; + } + + if (! count($notificationSettings->mail_recipients)) { + Log::warning('Mail recipients not found, check mail notification channel settings.'); + + return; + } + + foreach ($notificationSettings->mail_recipients as $recipient) { + Mail::to($recipient) + ->send(new SpeedtestCompletedMail($event->result)); + } + } +} diff --git a/app/Listeners/Mail/SendSpeedtestThresholdNotification.php b/app/Listeners/Mail/SendSpeedtestThresholdNotification.php new file mode 100644 index 000000000..391251efd --- /dev/null +++ b/app/Listeners/Mail/SendSpeedtestThresholdNotification.php @@ -0,0 +1,109 @@ +mail_enabled) { + return; + } + + if (! $notificationSettings->mail_on_threshold_failure) { + return; + } + + if (! count($notificationSettings->mail_recipients) > 0) { + Log::warning('Mail recipients not found, check mail notification channel settings.'); + + return; + } + + $thresholdSettings = new ThresholdSettings(); + + $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)); + } + + if (! count($failed)) { + return; + } + + foreach ($notificationSettings->mail_recipients as $recipient) { + Mail::to($recipient) + ->send(new SpeedtestThresholdMail($event->result, $failed)); + } + } + + /** + * Build mail notification if absolute download threshold is breached. + */ + protected function absoluteDownloadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): array + { + if (! absoluteDownloadThresholdFailed($thresholdSettings->absolute_download, $event->result->download)) { + return []; + } + + return [ + 'name' => 'Download', + 'threshold' => $thresholdSettings->absolute_download.' Mbps', + 'value' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), + ]; + } + + /** + * Build webhook notification if absolute upload threshold is breached. + */ + protected function absoluteUploadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): array + { + if (! absoluteUploadThresholdFailed($thresholdSettings->absolute_upload, $event->result->upload)) { + return []; + } + + return [ + 'name' => 'Upload', + 'threshold' => $thresholdSettings->absolute_upload.' Mbps', + 'value' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), + ]; + } + + /** + * Build webhook notification if absolute ping threshold is breached. + */ + protected function absolutePingThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): array + { + if (! absolutePingThresholdFailed($thresholdSettings->absolute_ping, $event->result->ping)) { + return []; + } + + return [ + 'name' => 'Ping', + 'threshold' => $thresholdSettings->absolute_ping.' ms', + 'value' => round($event->result->ping, 2).' ms', + ]; + } +} diff --git a/app/Listeners/SpeedtestCompletedListener.php b/app/Listeners/SpeedtestCompletedListener.php index a12982a54..55aa82958 100644 --- a/app/Listeners/SpeedtestCompletedListener.php +++ b/app/Listeners/SpeedtestCompletedListener.php @@ -3,11 +3,9 @@ namespace App\Listeners; use App\Events\SpeedtestCompleted; -use App\Mail\SpeedtestCompletedMail; use App\Settings\GeneralSettings; use App\Settings\NotificationSettings; use App\Telegram\TelegramNotification; -use Illuminate\Support\Facades\Mail; use Spatie\WebhookServer\WebhookCall; class SpeedtestCompletedListener @@ -33,15 +31,6 @@ public function __construct() */ public function handle(SpeedtestCompleted $event): void { - if ($this->notificationSettings->mail_enabled) { - if ($this->notificationSettings->mail_on_speedtest_run && count($this->notificationSettings->mail_recipients)) { - foreach ($this->notificationSettings->mail_recipients as $recipient) { - Mail::to($recipient) - ->send(new SpeedtestCompletedMail($event->result)); - } - } - } - if ($this->notificationSettings->telegram_enabled) { if ($this->notificationSettings->telegram_on_speedtest_run && count($this->notificationSettings->telegram_recipients)) { foreach ($this->notificationSettings->telegram_recipients as $recipient) { diff --git a/app/Listeners/Threshold/AbsoluteListener.php b/app/Listeners/Threshold/AbsoluteListener.php index 635f7be33..0204cdb28 100644 --- a/app/Listeners/Threshold/AbsoluteListener.php +++ b/app/Listeners/Threshold/AbsoluteListener.php @@ -3,14 +3,12 @@ namespace App\Listeners\Threshold; use App\Events\SpeedtestCompleted; -use App\Mail\Threshold\AbsoluteMail; use App\Settings\GeneralSettings; use App\Settings\NotificationSettings; use App\Settings\ThresholdSettings; use App\Telegram\TelegramNotification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Facades\Mail; use Spatie\WebhookServer\WebhookCall; class AbsoluteListener implements ShouldQueue @@ -44,11 +42,6 @@ public function handle(SpeedtestCompleted $event): void return; } - // Mail notification channel - if ($this->notificationSettings->mail_enabled == true && $this->notificationSettings->mail_on_threshold_failure == true) { - $this->mailChannel($event); - } - // Telegram notification channel if ($this->notificationSettings->telegram_enabled == true && $this->notificationSettings->telegram_on_threshold_failure == true) { $this->telegramChannel($event); @@ -60,58 +53,6 @@ public function handle(SpeedtestCompleted $event): void } } - /** - * Handle database notifications. - */ - protected function mailChannel(SpeedtestCompleted $event): void - { - $failedThresholds = []; - - if (! count($this->notificationSettings->mail_recipients) > 0) { - Log::info('Skipping sending mail notification, no recipients.'); - } - - // Download threshold - if ($this->thresholdSettings->absolute_download > 0) { - if (absoluteDownloadThresholdFailed($this->thresholdSettings->absolute_download, $event->result->download)) { - array_push($failedThresholds, [ - 'name' => 'Download', - 'threshold' => $this->thresholdSettings->absolute_download.' Mbps', - 'value' => toBits(convertSize($event->result->download), 2).' Mbps', - ]); - } - } - - // Upload threshold - if ($this->thresholdSettings->absolute_upload > 0) { - if (absoluteUploadThresholdFailed($this->thresholdSettings->absolute_upload, $event->result->upload)) { - array_push($failedThresholds, [ - 'name' => 'Upload', - 'threshold' => $this->thresholdSettings->absolute_upload.' Mbps', - 'value' => toBits(convertSize($event->result->upload), 2).'Mbps', - ]); - } - } - - // Ping threshold - if ($this->thresholdSettings->absolute_ping > 0) { - if (absolutePingThresholdFailed($this->thresholdSettings->absolute_ping, $event->result->ping)) { - array_push($failedThresholds, [ - 'name' => 'Ping', - 'threshold' => $this->thresholdSettings->absolute_ping.' ms', - 'value' => round($event->result->ping, 2).' ms', - ]); - } - } - - if (count($failedThresholds)) { - foreach ($this->notificationSettings->mail_recipients as $recipient) { - Mail::to($recipient) - ->send(new AbsoluteMail($event->result, $failedThresholds)); - } - } - } - /** * Handle telegram notifications. */ diff --git a/app/Listeners/Webhook/SendSpeedtestThresholdNotification.php b/app/Listeners/Webhook/SendSpeedtestThresholdNotification.php index f622d3b31..a1fb3840b 100644 --- a/app/Listeners/Webhook/SendSpeedtestThresholdNotification.php +++ b/app/Listeners/Webhook/SendSpeedtestThresholdNotification.php @@ -79,7 +79,7 @@ protected function absoluteDownloadThreshold(SpeedtestCompleted $event, Threshol return [ 'name' => 'Download', - 'threshold' => $thresholdSettings->absolute_download, + 'threshold' => $thresholdSettings->absolute_download.' Mbps', 'value' => Number::toBitRate(bits: $event->result->download_bits, precision: 2), ]; } @@ -95,7 +95,7 @@ protected function absoluteUploadThreshold(SpeedtestCompleted $event, ThresholdS return [ 'name' => 'Upload', - 'threshold' => $thresholdSettings->absolute_upload, + 'threshold' => $thresholdSettings->absolute_upload.' Mbps', 'value' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2), ]; } @@ -111,8 +111,8 @@ protected function absolutePingThreshold(SpeedtestCompleted $event, ThresholdSet return [ 'name' => 'Ping', - 'threshold' => $thresholdSettings->absolute_ping, - 'value' => round($event->result->ping, 2), + 'threshold' => $thresholdSettings->absolute_ping.' ms', + 'value' => round($event->result->ping, 2).' ms', ]; } } diff --git a/app/Mail/SpeedtestCompletedMail.php b/app/Mail/SpeedtestCompletedMail.php index f4da30ab2..344d6817e 100644 --- a/app/Mail/SpeedtestCompletedMail.php +++ b/app/Mail/SpeedtestCompletedMail.php @@ -2,6 +2,7 @@ namespace App\Mail; +use App\Helpers\Number; use App\Models\Result; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -9,21 +10,20 @@ use Illuminate\Mail\Mailables\Content; use Illuminate\Mail\Mailables\Envelope; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Str; class SpeedtestCompletedMail extends Mailable implements ShouldQueue { use Queueable, SerializesModels; - public $result; - /** * Create a new message instance. * * @return void */ - public function __construct(Result $result) - { - $this->result = $result; + public function __construct( + public Result $result, + ) { } /** @@ -32,7 +32,7 @@ public function __construct(Result $result) public function envelope(): Envelope { return new Envelope( - subject: 'Speedtest Result #'.$this->result->id.' - Completed', + subject: 'Speedtest Completed - #'.$this->result->id, ); } @@ -45,16 +45,14 @@ public function content(): Content markdown: 'emails.speedtest-completed', with: [ 'id' => $this->result->id, + 'service' => Str::title($this->result->service), + 'serverName' => $this->result->server_name, + 'serverId' => $this->result->server_id, + 'ping' => round($this->result->ping, 2).' ms', + 'download' => Number::toBitRate(bits: $this->result->download_bits, precision: 2), + 'upload' => Number::toBitRate(bits: $this->result->upload_bits, precision: 2), 'url' => url('/admin/results'), ], ); } - - /** - * Get the attachments for the message. - */ - public function attachments(): array - { - return []; - } } diff --git a/app/Mail/Threshold/AbsoluteMail.php b/app/Mail/SpeedtestThresholdMail.php similarity index 61% rename from app/Mail/Threshold/AbsoluteMail.php rename to app/Mail/SpeedtestThresholdMail.php index 87a7b04c2..f148b123b 100644 --- a/app/Mail/Threshold/AbsoluteMail.php +++ b/app/Mail/SpeedtestThresholdMail.php @@ -1,6 +1,6 @@ result = $result; - - $this->metrics = $metrics; + public function __construct( + public Result $result, + public array $metrics, + ) { } /** @@ -36,7 +32,7 @@ public function __construct(Result $result, array $metrics) public function envelope(): Envelope { return new Envelope( - subject: 'Speedtest Result #'.$this->result->id.' - Absolute threshold failed', + subject: 'Speedtest Threshold Breached - #'.$this->result->id, ); } @@ -46,9 +42,12 @@ public function envelope(): Envelope public function content(): Content { return new Content( - markdown: 'emails.threshold.absolute', + markdown: 'emails.speedtest-threshold', with: [ 'id' => $this->result->id, + 'service' => Str::title($this->result->service), + 'serverName' => $this->result->server_name, + 'serverId' => $this->result->server_id, 'url' => url('/admin/results'), 'metrics' => $this->metrics, ], diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 54ed38cb4..083c318bc 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -9,6 +9,8 @@ use App\Listeners\Data\InfluxDb2Listener; use App\Listeners\Database\SendSpeedtestCompletedNotification as DatabaseSendSpeedtestCompletedNotification; use App\Listeners\Database\SendSpeedtestThresholdNotification as DatabaseSendSpeedtestThresholdNotification; +use App\Listeners\Mail\SendSpeedtestCompletedNotification as MailSendSpeedtestCompletedNotification; +use App\Listeners\Mail\SendSpeedtestThresholdNotification as MailSendSpeedtestThresholdNotification; use App\Listeners\SpeedtestCompletedListener; use App\Listeners\Threshold\AbsoluteListener; use App\Listeners\Webhook\SendSpeedtestCompletedNotification as WebhookSendSpeedtestCompletedNotification; @@ -45,6 +47,10 @@ class EventServiceProvider extends ServiceProvider DatabaseSendSpeedtestCompletedNotification::class, DatabaseSendSpeedtestThresholdNotification::class, + // Mail notification listeners + MailSendSpeedtestCompletedNotification::class, + MailSendSpeedtestThresholdNotification::class, + // Webhook notification listeners WebhookSendSpeedtestCompletedNotification::class, WebhookSendSpeedtestThresholdNotification::class, diff --git a/resources/views/emails/speedtest-completed.blade.php b/resources/views/emails/speedtest-completed.blade.php index b868d0d47..645e0cb67 100644 --- a/resources/views/emails/speedtest-completed.blade.php +++ b/resources/views/emails/speedtest-completed.blade.php @@ -1,7 +1,17 @@ -# Speedtest Result #{{ $id }} - Completed +# Speedtest Completed - #{{ $id }} -A speedtest was successfully run, click the button below to view the results. +A new speedtest was completed using **{{ $service }}**. + + +| **Metric** | **Value** | +|-------------|------------------:| +| Server name | {{ $serverName }} | +| Server ID | {{ $serverId }} | +| Ping | {{ $ping }} | +| Download | {{ $download }} | +| Upload | {{ $upload }} | + View Results diff --git a/resources/views/emails/speedtest-threshold.blade.php b/resources/views/emails/speedtest-threshold.blade.php new file mode 100644 index 000000000..3af4cd299 --- /dev/null +++ b/resources/views/emails/speedtest-threshold.blade.php @@ -0,0 +1,20 @@ + +# Speedtest Thresholds Breached - #{{ $id }} + +A new speedtest was completed using **{{ $service }}** but a threshold was breached. + + +| **Metric** | **Threshold** | **Value** | +|------------|--------------:|----------:| +@foreach ($metrics as $item) +| {{ $item['name'] }} | {{ $item['threshold'] }} | {{ $item['value'] }} | +@endforeach + + + +View Results + + +Thanks,
+{{ config('app.name') }} +
diff --git a/resources/views/emails/threshold/absolute.blade.php b/resources/views/emails/threshold/absolute.blade.php deleted file mode 100644 index de3fa5506..000000000 --- a/resources/views/emails/threshold/absolute.blade.php +++ /dev/null @@ -1,18 +0,0 @@ - -# Speedtest Result #{{ $id }} - Absolute Threshold Failed - - -| Name | Threshold | Value | -| ------------- |:-------------:| --------:| -@foreach ($metrics as $item) - | {{ $item['name'] }} | {{ $item['threshold'] }} | {{ $item['value'] }} | -@endforeach - - - -View Results - - -Thanks,
-{{ config('app.name') }} -