From 62f13fb009f6589fe1e976910a587f77bb57de39 Mon Sep 17 00:00:00 2001 From: Alex Justesen Date: Fri, 26 Dec 2025 15:11:39 -0500 Subject: [PATCH] Mark speedtest as scheduled when triggered using the API (#2597) Co-authored-by: Alex Justesen <1144087+alexjustesen@users.noreply.github.com> --- .../Api/V1/SpeedtestController.php | 1 + app/Listeners/ProcessCompletedSpeedtest.php | 51 ++------- app/Listeners/ProcessFailedSpeedtest.php | 35 +----- app/Listeners/ProcessUnhealthySpeedtest.php | 48 +------- app/Listeners/UserNotificationSubscriber.php | 104 ++++++++++++++++++ app/Models/Result.php | 11 ++ 6 files changed, 132 insertions(+), 118 deletions(-) create mode 100644 app/Listeners/UserNotificationSubscriber.php diff --git a/app/Http/Controllers/Api/V1/SpeedtestController.php b/app/Http/Controllers/Api/V1/SpeedtestController.php index 19519f61..d605d945 100644 --- a/app/Http/Controllers/Api/V1/SpeedtestController.php +++ b/app/Http/Controllers/Api/V1/SpeedtestController.php @@ -37,6 +37,7 @@ class SpeedtestController extends ApiController } $result = RunSpeedtestAction::run( + scheduled: true, serverId: $request->input('server_id'), dispatchedBy: $request->user()->id, ); diff --git a/app/Listeners/ProcessCompletedSpeedtest.php b/app/Listeners/ProcessCompletedSpeedtest.php index 1b72f305..ae5d544e 100644 --- a/app/Listeners/ProcessCompletedSpeedtest.php +++ b/app/Listeners/ProcessCompletedSpeedtest.php @@ -31,11 +31,17 @@ class ProcessCompletedSpeedtest { $result = $event->result; - $result->loadMissing(['dispatchedBy']); + if ($result->healthy === false) { + return; + } + + // Don't send notifications for unscheduled speedtests. + if ($result->unscheduled) { + return; + } $this->notifyAppriseChannels($result); $this->notifyDatabaseChannels($result); - $this->notifyDispatchingUser($result); $this->notifyMailChannels($result); $this->notifyWebhookChannels($result); } @@ -45,11 +51,6 @@ class ProcessCompletedSpeedtest */ private function notifyAppriseChannels(Result $result): void { - // Don't send Apprise notification if dispatched by a user or test is unhealthy. - if (filled($result->dispatched_by) || $result->healthy === false) { - return; - } - // Check if Apprise notifications are enabled. if (! $this->notificationSettings->apprise_enabled || ! $this->notificationSettings->apprise_on_speedtest_run) { return; @@ -97,11 +98,6 @@ class ProcessCompletedSpeedtest */ private function notifyDatabaseChannels(Result $result): void { - // Don't send database notification if dispatched by a user or test is unhealthy. - if (filled($result->dispatched_by) || $result->healthy === false) { - return; - } - // Check if database notifications are enabled. if (! $this->notificationSettings->database_enabled || ! $this->notificationSettings->database_on_speedtest_run) { return; @@ -120,37 +116,11 @@ class ProcessCompletedSpeedtest } } - /** - * Notify the user who dispatched the speedtest. - */ - private function notifyDispatchingUser(Result $result): void - { - if (empty($result->dispatched_by) || ! $result->healthy) { - return; - } - - $result->dispatchedBy->notify( - FilamentNotification::make() - ->title(__('results.speedtest_completed')) - ->actions([ - Action::make('view') - ->label(__('general.view')) - ->url(route('filament.admin.resources.results.index')), - ]) - ->success() - ->toDatabase(), - ); - } - /** * Notify mail channels. */ private function notifyMailChannels(Result $result): void { - if (filled($result->dispatched_by) || $result->healthy === false) { - return; - } - if (! $this->notificationSettings->mail_enabled || ! $this->notificationSettings->mail_on_speedtest_run) { return; } @@ -172,11 +142,6 @@ class ProcessCompletedSpeedtest */ private function notifyWebhookChannels(Result $result): void { - // Don't send webhook if dispatched by a user or test is unhealthy. - if (filled($result->dispatched_by) || $result->healthy === false) { - return; - } - // Check if webhook notifications are enabled. if (! $this->notificationSettings->webhook_enabled || ! $this->notificationSettings->webhook_on_speedtest_run) { return; diff --git a/app/Listeners/ProcessFailedSpeedtest.php b/app/Listeners/ProcessFailedSpeedtest.php index 8ba15438..3cc4d9cd 100644 --- a/app/Listeners/ProcessFailedSpeedtest.php +++ b/app/Listeners/ProcessFailedSpeedtest.php @@ -4,8 +4,6 @@ namespace App\Listeners; use App\Events\SpeedtestFailed; use App\Models\Result; -use Filament\Actions\Action; -use Filament\Notifications\Notification; class ProcessFailedSpeedtest { @@ -16,10 +14,12 @@ class ProcessFailedSpeedtest { $result = $event->result; - $result->loadMissing(['dispatchedBy']); + // Don't send notifications for unscheduled speedtests. + if ($result->unscheduled) { + return; + } // $this->notifyAppriseChannels($result); - $this->notifyDispatchingUser($result); } /** @@ -27,33 +27,6 @@ class ProcessFailedSpeedtest */ private function notifyAppriseChannels(Result $result): void { - // Don't send Apprise notification if dispatched by a user or test is unhealthy. - if (filled($result->dispatched_by) || ! $result->healthy) { - return; - } - // } - - /** - * Notify the user who dispatched the speedtest. - */ - private function notifyDispatchingUser(Result $result): void - { - if (empty($result->dispatched_by)) { - return; - } - - $result->dispatchedBy->notify( - Notification::make() - ->title(__('results.speedtest_failed')) - ->actions([ - Action::make('view') - ->label(__('general.view')) - ->url(route('filament.admin.resources.results.index')), - ]) - ->warning() - ->toDatabase(), - ); - } } diff --git a/app/Listeners/ProcessUnhealthySpeedtest.php b/app/Listeners/ProcessUnhealthySpeedtest.php index 4f51e426..f2e0d419 100644 --- a/app/Listeners/ProcessUnhealthySpeedtest.php +++ b/app/Listeners/ProcessUnhealthySpeedtest.php @@ -33,11 +33,13 @@ class ProcessUnhealthySpeedtest { $result = $event->result; - $result->loadMissing(['dispatchedBy']); + // Don't send notifications for unscheduled speedtests. + if ($result->unscheduled) { + return; + } $this->notifyAppriseChannels($result); $this->notifyDatabaseChannels($result); - $this->notifyDispatchingUser($result); $this->notifyMailChannels($result); $this->notifyWebhookChannels($result); } @@ -47,11 +49,6 @@ class ProcessUnhealthySpeedtest */ private function notifyAppriseChannels(Result $result): void { - // Don't send Apprise notification if dispatched by a user. - if (filled($result->dispatched_by)) { - return; - } - if (! $this->notificationSettings->apprise_enabled || ! $this->notificationSettings->apprise_on_threshold_failure) { return; } @@ -132,11 +129,6 @@ class ProcessUnhealthySpeedtest */ private function notifyDatabaseChannels(Result $result): void { - // Don't send database notification if dispatched by a user. - if (filled($result->dispatched_by)) { - return; - } - // Check if database notifications are enabled. if (! $this->notificationSettings->database_enabled || ! $this->notificationSettings->database_on_threshold_failure) { return; @@ -155,38 +147,11 @@ class ProcessUnhealthySpeedtest } } - /** - * Notify the user who dispatched the speedtest. - */ - private function notifyDispatchingUser(Result $result): void - { - if (empty($result->dispatched_by)) { - return; - } - - $result->dispatchedBy->notify( - FilamentNotification::make() - ->title(__('results.speedtest_benchmark_failed')) - ->actions([ - Action::make('view') - ->label(__('general.view')) - ->url(route('filament.admin.resources.results.index')), - ]) - ->warning() - ->toDatabase(), - ); - } - /** * Notify mail channels. */ private function notifyMailChannels(Result $result): void { - // Don't send mail if dispatched by a user. - if (filled($result->dispatched_by)) { - return; - } - // Check if mail notifications are enabled. if (! $this->notificationSettings->mail_enabled || ! $this->notificationSettings->mail_on_threshold_failure) { return; @@ -210,11 +175,6 @@ class ProcessUnhealthySpeedtest */ private function notifyWebhookChannels(Result $result): void { - // Don't send webhook if dispatched by a user. - if (filled($result->dispatched_by)) { - return; - } - // Check if webhook notifications are enabled. if (! $this->notificationSettings->webhook_enabled || ! $this->notificationSettings->webhook_on_threshold_failure) { return; diff --git a/app/Listeners/UserNotificationSubscriber.php b/app/Listeners/UserNotificationSubscriber.php new file mode 100644 index 00000000..4ff7dc7c --- /dev/null +++ b/app/Listeners/UserNotificationSubscriber.php @@ -0,0 +1,104 @@ +result; + + if (empty($result->dispatched_by)) { + return; + } + + $result->loadMissing('dispatchedBy'); + + Notification::make() + ->title(__('results.speedtest_completed')) + ->actions([ + Action::make('view') + ->label(__('general.view')) + ->url(route('filament.admin.resources.results.index')), + ]) + ->success() + ->sendToDatabase($result->dispatchedBy); + } + + /** + * Handle the event. + */ + public function handleBenchmarkFailed(SpeedtestBenchmarkFailed $event): void + { + $result = $event->result; + + if (empty($result->dispatched_by)) { + return; + } + + // Don't send notifications for unscheduled speedtests. + if ($result->unscheduled) { + return; + } + + $result->loadMissing('dispatchedBy'); + + Notification::make() + ->title(__('results.speedtest_benchmark_failed')) + ->actions([ + Action::make('view') + ->label(__('general.view')) + ->url(route('filament.admin.resources.results.index')), + ]) + ->warning() + ->sendToDatabase($result->dispatchedBy); + } + + /** + * Handle the event. + */ + public function handleFailed(SpeedtestFailed $event): void + { + $result = $event->result; + + if (empty($result->dispatched_by)) { + return; + } + + $result->loadMissing('dispatchedBy'); + + Notification::make() + ->title(__('results.speedtest_failed')) + ->actions([ + Action::make('view') + ->label(__('general.view')) + ->url(route('filament.admin.resources.results.index')), + ]) + ->warning() + ->sendToDatabase($result->dispatchedBy); + } + + /** + * Register the listeners for the subscriber. + * + * @return array + */ + public function subscribe(Dispatcher $events): array + { + return [ + SpeedtestCompleted::class => 'handleCompleted', + SpeedtestBenchmarkFailed::class => 'handleBenchmarkFailed', + SpeedtestFailed::class => 'handleFailed', + ]; + } +} diff --git a/app/Models/Result.php b/app/Models/Result.php index bba1a37d..084c0409 100644 --- a/app/Models/Result.php +++ b/app/Models/Result.php @@ -6,6 +6,7 @@ use App\Enums\ResultService; use App\Enums\ResultStatus; use App\Models\Traits\ResultDataAttributes; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Prunable; @@ -54,4 +55,14 @@ class Result extends Model { return $this->belongsTo(User::class, 'dispatched_by'); } + + /** + * Determine if the result was unscheduled. + */ + protected function unscheduled(): Attribute + { + return Attribute::make( + get: fn (): bool => ! $this->scheduled, + ); + } }