diff --git a/app/Http/Controllers/Api/V1/SpeedtestController.php b/app/Http/Controllers/Api/V1/SpeedtestController.php index 19519f61e..d605d945c 100644 --- a/app/Http/Controllers/Api/V1/SpeedtestController.php +++ b/app/Http/Controllers/Api/V1/SpeedtestController.php @@ -37,6 +37,7 @@ public function __invoke(Request $request) } $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 1b72f3053..ae5d544e1 100644 --- a/app/Listeners/ProcessCompletedSpeedtest.php +++ b/app/Listeners/ProcessCompletedSpeedtest.php @@ -31,11 +31,17 @@ public function handle(SpeedtestCompleted $event): void { $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 @@ public function handle(SpeedtestCompleted $event): void */ 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 @@ private function notifyAppriseChannels(Result $result): void */ 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 @@ private function notifyDatabaseChannels(Result $result): void } } - /** - * 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 @@ private function notifyMailChannels(Result $result): void */ 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 8ba154387..3cc4d9cd8 100644 --- a/app/Listeners/ProcessFailedSpeedtest.php +++ b/app/Listeners/ProcessFailedSpeedtest.php @@ -4,8 +4,6 @@ use App\Events\SpeedtestFailed; use App\Models\Result; -use Filament\Actions\Action; -use Filament\Notifications\Notification; class ProcessFailedSpeedtest { @@ -16,10 +14,12 @@ public function handle(SpeedtestFailed $event): void { $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 @@ public function handle(SpeedtestFailed $event): void */ 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 4f51e4267..f2e0d419c 100644 --- a/app/Listeners/ProcessUnhealthySpeedtest.php +++ b/app/Listeners/ProcessUnhealthySpeedtest.php @@ -33,11 +33,13 @@ public function handle(SpeedtestBenchmarkFailed $event): void { $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 @@ public function handle(SpeedtestBenchmarkFailed $event): void */ 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 @@ private function formatMetricValue(string $metric, Result $result): string */ 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 @@ private function notifyDatabaseChannels(Result $result): void } } - /** - * 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 @@ private function notifyMailChannels(Result $result): void */ 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 000000000..4ff7dc7c8 --- /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 bba1a37d9..084c04097 100644 --- a/app/Models/Result.php +++ b/app/Models/Result.php @@ -6,6 +6,7 @@ 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 @@ public function dispatchedBy(): BelongsTo { 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, + ); + } } diff --git a/config/speedtest.php b/config/speedtest.php index 94ebcaa84..79c2e84b4 100644 --- a/config/speedtest.php +++ b/config/speedtest.php @@ -6,9 +6,9 @@ /** * General settings. */ - 'build_date' => Carbon::parse('2025-12-19'), + 'build_date' => Carbon::parse('2025-12-26'), - 'build_version' => 'v1.13.3', + 'build_version' => 'v1.13.4', 'content_width' => env('CONTENT_WIDTH', '7xl'), diff --git a/lang/nl_NL/settings/notifications.php b/lang/nl_NL/settings/notifications.php index e7eff7a97..7a37c850a 100644 --- a/lang/nl_NL/settings/notifications.php +++ b/lang/nl_NL/settings/notifications.php @@ -19,19 +19,20 @@ 'enable_apprise_notifications' => 'Inschakelen Apprise meldingen', 'apprise_server' => 'Apprise Server', 'apprise_server_url' => 'Appprise Server-URL', + 'apprise_server_url_helper' => 'De URL van uw Apprise Server. De URL moet eindigen op /notify', 'apprise_verify_ssl' => 'Controleer SSL', - 'apprise_channels' => 'Apprise Kanalen', - 'apprise_channel_url' => 'Kanaal URL', - 'apprise_hint_description' => 'Voor meer informatie over het instellen van Apprise, bekijk de documentatie.', - 'apprise_channel_url_helper' => 'Geef de service eindpunt URL voor meldingen.', + 'apprise_channels' => 'Notificatie kanalen', + 'apprise_channel_url' => 'Service URL', + 'apprise_hint_description' => 'Met Apprise kan je meldingen verzenden naar meer dan 90 diensten. Je moet een Apprise server hebben draaien en onderstaande service URL\'s configureren.', + 'apprise_channel_url_helper' => 'Gebruik Apprise URL formaat. Bijvoorbeeld discord://WebhookID/Token, slack://TokenA/TokenB/TokenC', 'test_apprise_channel' => 'Test Apprise', - 'apprise_channel_url_validation_error' => 'De URL van het Apprise kanaal mag niet beginnen met "http" of "https". Geef een geldig URL-schema op.', + 'apprise_channel_url_validation_error' => 'Ongeldige Apprise URL. De URL moet gebruik maken van Apprise formaat (bijv. discord://, slack://), niet http:// of https://. Zie de Apprise documentatie voor meer informatie', // Webhook 'webhook' => 'Webhook', 'webhooks' => 'Webhooks', 'test_webhook_channel' => 'Test webhook kanaal', - 'webhook_hint_description' => 'Dit zijn generieke webhooks. Raadpleeg de documentatie voor voorbeelden van payloads en implementatiedetails.', + 'webhook_hint_description' => 'Dit zijn algemene webhooks. Voor payload voorbeelden en implementatiegegevens, bekijk de documentatie. Voor diensten zoals Discord, Ntfy etc. gebruik Apprise.', // Common notification messages 'notify_on_every_speedtest_run' => 'Notificatie bij elke geplande snelheidstest',