mirror of
https://github.com/alexjustesen/speedtest-tracker.git
synced 2026-06-23 04:10:25 +00:00
Chore: Improve Apprise Logic & UI Text (#2579)
This commit is contained in:
@@ -3,15 +3,17 @@
|
||||
namespace App\Actions\Notifications;
|
||||
|
||||
use App\Notifications\Apprise\TestNotification;
|
||||
use App\Settings\NotificationSettings;
|
||||
use Filament\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Notification as FacadesNotification;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Throwable;
|
||||
|
||||
class SendAppriseTestNotification
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle(array $channel_urls)
|
||||
public function handle(array $channel_urls): void
|
||||
{
|
||||
if (! count($channel_urls)) {
|
||||
Notification::make()
|
||||
@@ -22,19 +24,41 @@ class SendAppriseTestNotification
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($channel_urls as $row) {
|
||||
$channelUrl = $row['channel_url'] ?? null;
|
||||
if (! $channelUrl) {
|
||||
Notification::make()
|
||||
->title('Skipping missing channel URL!')
|
||||
->warning()
|
||||
->send();
|
||||
$settings = app(NotificationSettings::class);
|
||||
$appriseUrl = rtrim($settings->apprise_server_url ?? '', '/');
|
||||
|
||||
continue;
|
||||
if (empty($appriseUrl)) {
|
||||
Notification::make()
|
||||
->title('Apprise Server URL is not configured')
|
||||
->body('Please configure the Apprise Server URL in the settings above.')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($channel_urls as $row) {
|
||||
$channelUrl = $row['channel_url'] ?? null;
|
||||
if (! $channelUrl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use notifyNow() to send synchronously even though notification implements ShouldQueue
|
||||
// This allows us to catch exceptions and show them in the UI immediately
|
||||
FacadesNotification::route('apprise_urls', $channelUrl)
|
||||
->notifyNow(new TestNotification);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$errorMessage = $this->cleanErrorMessage($e);
|
||||
|
||||
FacadesNotification::route('apprise_urls', $channelUrl)
|
||||
->notify(new TestNotification);
|
||||
Notification::make()
|
||||
->title('Failed to send Apprise test notification')
|
||||
->body($errorMessage)
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Notification::make()
|
||||
@@ -42,4 +66,35 @@ class SendAppriseTestNotification
|
||||
->success()
|
||||
->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up error message for display in UI.
|
||||
*/
|
||||
protected function cleanErrorMessage(Throwable $e): string
|
||||
{
|
||||
$message = $e->getMessage();
|
||||
|
||||
// Get the full Apprise server URL for error messages
|
||||
$settings = app(NotificationSettings::class);
|
||||
$appriseUrl = rtrim($settings->apprise_server_url ?? '', '/');
|
||||
|
||||
// Handle connection errors - extract just the important part
|
||||
if (str_contains($message, 'cURL error')) {
|
||||
if (str_contains($message, 'Could not resolve host')) {
|
||||
return "Could not connect to Apprise server at {$appriseUrl}";
|
||||
}
|
||||
|
||||
if (str_contains($message, 'Connection refused')) {
|
||||
return "Connection refused by Apprise server at {$appriseUrl}";
|
||||
}
|
||||
|
||||
if (str_contains($message, 'Operation timed out')) {
|
||||
return "Connection to Apprise server at {$appriseUrl} timed out";
|
||||
}
|
||||
|
||||
return "Failed to connect to Apprise server at {$appriseUrl}";
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use App\Actions\Notifications\SendSlackTestNotification;
|
||||
use App\Actions\Notifications\SendTelegramTestNotification;
|
||||
use App\Actions\Notifications\SendWebhookTestNotification;
|
||||
use App\Rules\AppriseScheme;
|
||||
use App\Rules\ContainsString;
|
||||
use App\Settings\NotificationSettings;
|
||||
use CodeWithDennis\SimpleAlert\Components\SimpleAlert;
|
||||
use Filament\Actions\Action;
|
||||
@@ -233,10 +234,12 @@ class Notification extends SettingsPage
|
||||
->schema([
|
||||
TextInput::make('apprise_server_url')
|
||||
->label(__('settings/notifications.apprise_server_url'))
|
||||
->placeholder('http://localhost:8000')
|
||||
->placeholder('http://localhost:8000/notify')
|
||||
->helperText(__('settings/notifications.apprise_server_url_helper'))
|
||||
->maxLength(2000)
|
||||
->required()
|
||||
->url()
|
||||
->rule(new ContainsString('/notify'))
|
||||
->columnSpanFull(),
|
||||
Checkbox::make('apprise_verify_ssl')
|
||||
->label(__('settings/notifications.apprise_verify_ssl'))
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Settings\NotificationSettings;
|
||||
use Exception;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Throwable;
|
||||
|
||||
class AppriseChannel
|
||||
{
|
||||
@@ -22,7 +24,7 @@ class AppriseChannel
|
||||
}
|
||||
|
||||
$settings = app(NotificationSettings::class);
|
||||
$appriseUrl = rtrim($settings->apprise_server_url ?? '', '/');
|
||||
$appriseUrl = $settings->apprise_server_url ?? '';
|
||||
|
||||
if (empty($appriseUrl)) {
|
||||
Log::warning('Apprise notification skipped: No Server URL configured');
|
||||
@@ -41,7 +43,7 @@ class AppriseChannel
|
||||
$request = $request->withoutVerifying();
|
||||
}
|
||||
|
||||
$response = $request->post("{$appriseUrl}/notify", [
|
||||
$response = $request->post($appriseUrl, [
|
||||
'urls' => $message->urls,
|
||||
'title' => $message->title,
|
||||
'body' => $message->body,
|
||||
@@ -50,26 +52,25 @@ class AppriseChannel
|
||||
'tag' => $message->tag ?? null,
|
||||
]);
|
||||
|
||||
if ($response->failed()) {
|
||||
Log::error('Apprise notification failed', [
|
||||
'channel' => $message->urls,
|
||||
'instance' => $appriseUrl,
|
||||
'status' => $response->status(),
|
||||
'body' => $response->body(),
|
||||
]);
|
||||
} else {
|
||||
Log::info('Apprise notification sent', [
|
||||
'channel' => $message->urls,
|
||||
'instance' => $appriseUrl,
|
||||
]);
|
||||
// Only accept 200 OK responses as successful
|
||||
if ($response->status() !== 200) {
|
||||
throw new Exception('Apprise returned an error, please check Apprise logs for details');
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Apprise notification exception', [
|
||||
|
||||
Log::info('Apprise notification sent', [
|
||||
'channel' => $message->urls,
|
||||
'instance' => $appriseUrl,
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
Log::error('Apprise notification failed', [
|
||||
'channel' => $message->urls ?? 'unknown',
|
||||
'instance' => $appriseUrl,
|
||||
'message' => $e->getMessage(),
|
||||
'exception' => get_class($e),
|
||||
]);
|
||||
|
||||
// Re-throw the exception so it can be handled by the queue
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
|
||||
class ContainsString implements ValidationRule
|
||||
{
|
||||
public function __construct(
|
||||
protected string $needle,
|
||||
protected bool $caseSensitive = false
|
||||
) {}
|
||||
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
$haystack = $this->caseSensitive ? $value : strtolower($value);
|
||||
$needle = $this->caseSensitive ? $this->needle : strtolower($this->needle);
|
||||
|
||||
if (! str_contains($haystack, $needle)) {
|
||||
$fail("The :attribute must contain '{$this->needle}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,19 +19,20 @@ return [
|
||||
'enable_apprise_notifications' => 'Enable Apprise notifications',
|
||||
'apprise_server' => 'Apprise Server',
|
||||
'apprise_server_url' => 'Apprise Server URL',
|
||||
'apprise_server_url_helper' => 'The URL of your Apprise Server. The URL must end on /notify',
|
||||
'apprise_verify_ssl' => 'Verify SSL',
|
||||
'apprise_channels' => 'Apprise Channels',
|
||||
'apprise_channel_url' => 'Channel URL',
|
||||
'apprise_hint_description' => 'For more information on setting up Apprise, view the documentation.',
|
||||
'apprise_channel_url_helper' => 'Provide the service endpoint URL for notifications.',
|
||||
'apprise_channels' => 'Notification Channels',
|
||||
'apprise_channel_url' => 'Service URL',
|
||||
'apprise_hint_description' => 'Apprise allows you to send notifications to 90+ services. You need to run an Apprise server and configure service URLs below.',
|
||||
'apprise_channel_url_helper' => 'Use Apprise URL format. Examples: discord://WebhookID/Token, slack://TokenA/TokenB/TokenC',
|
||||
'test_apprise_channel' => 'Test Apprise',
|
||||
'apprise_channel_url_validation_error' => 'The Apprise channel URL must not start with "http" or "https". Please provide a valid Apprise URL scheme.',
|
||||
'apprise_channel_url_validation_error' => 'Invalid Apprise URL. Must use Apprise format (e.g., discord://, slack://), not http:// or https://. See the Apprise documentation for more information',
|
||||
|
||||
// Webhook
|
||||
'webhook' => 'Webhook',
|
||||
'webhooks' => 'Webhooks',
|
||||
'test_webhook_channel' => 'Test webhook channel',
|
||||
'webhook_hint_description' => 'These are generic webhooks. For payload examples and implementation details, view the documentation.',
|
||||
'webhook_hint_description' => 'These are generic webhooks. For payload examples and implementation details, view the documentation. For services like Discord, Ntfy etc please use Apprise.',
|
||||
|
||||
// Common notification messages
|
||||
'notify_on_every_speedtest_run' => 'Notify on every scheduled speedtest run',
|
||||
|
||||
Reference in New Issue
Block a user