From 4d972f1c6628466530b60a46c8c16afdcbc97dce Mon Sep 17 00:00:00 2001 From: Zao Soula Date: Wed, 11 Dec 2024 15:54:11 +0100 Subject: [PATCH] feat(notification): add Pushover --- app/Console/Commands/NotifyDemo.php | 3 +- app/Jobs/SendMessageToPushoverJob.php | 47 +++++ app/Livewire/Notifications/Pushover.php | 173 ++++++++++++++++++ app/Models/PushoverNotificationSettings.php | 61 ++++++ app/Models/Team.php | 19 +- .../Application/DeploymentFailed.php | 21 +++ .../Application/DeploymentSuccess.php | 33 ++++ .../Application/StatusChanged.php | 16 ++ .../Channels/PushoverChannel.php | 21 +++ app/Notifications/Channels/SendsPushover.php | 8 + .../Container/ContainerRestarted.php | 18 ++ .../Container/ContainerStopped.php | 19 ++ app/Notifications/Database/BackupFailed.php | 10 + app/Notifications/Database/BackupSuccess.php | 12 ++ app/Notifications/Dto/PushoverMessage.php | 34 ++++ .../Internal/GeneralNotification.php | 8 + .../ScheduledTask/TaskFailed.php | 18 ++ .../ScheduledTask/TaskSuccess.php | 18 ++ .../Server/DockerCleanupFailed.php | 8 + .../Server/DockerCleanupSuccess.php | 8 + app/Notifications/Server/ForceDisabled.php | 8 + app/Notifications/Server/ForceEnabled.php | 8 + app/Notifications/Server/HighDiskUsage.php | 8 + app/Notifications/Server/Reachable.php | 8 + app/Notifications/Server/Unreachable.php | 8 + app/Notifications/Test.php | 14 ++ app/Traits/HasNotificationSettings.php | 3 + ...e_pushover_notification_settings_table.php | 47 +++++ .../components/notification/navbar.blade.php | 6 +- .../livewire/notifications/pushover.blade.php | 84 +++++++++ 30 files changed, 745 insertions(+), 4 deletions(-) create mode 100644 app/Jobs/SendMessageToPushoverJob.php create mode 100644 app/Livewire/Notifications/Pushover.php create mode 100644 app/Models/PushoverNotificationSettings.php create mode 100644 app/Notifications/Channels/PushoverChannel.php create mode 100644 app/Notifications/Channels/SendsPushover.php create mode 100644 app/Notifications/Dto/PushoverMessage.php create mode 100644 database/migrations/2024_12_11_135026_create_pushover_notification_settings_table.php create mode 100644 resources/views/livewire/notifications/pushover.blade.php diff --git a/app/Console/Commands/NotifyDemo.php b/app/Console/Commands/NotifyDemo.php index f0131b7b2a..b6e5015f80 100644 --- a/app/Console/Commands/NotifyDemo.php +++ b/app/Console/Commands/NotifyDemo.php @@ -62,6 +62,7 @@ private function showHelp()
  • slack
  • discord
  • telegram
  • +
  • pushover
  • @@ -72,6 +73,6 @@ private function showHelp()
    In which manner you wish a coolified notification?
    - HTML, ['email', 'slack', 'discord', 'telegram']); + HTML, ['email', 'slack', 'discord', 'telegram', 'pushover']); } } diff --git a/app/Jobs/SendMessageToPushoverJob.php b/app/Jobs/SendMessageToPushoverJob.php new file mode 100644 index 0000000000..98be08c312 --- /dev/null +++ b/app/Jobs/SendMessageToPushoverJob.php @@ -0,0 +1,47 @@ +onQueue('high'); + } + + /** + * Execute the job. + */ + public function handle(): void + { + Http::post('https://api.pushover.net/1/messages.json', $this->message->toPayload($this->token, $this->user)); + } +} diff --git a/app/Livewire/Notifications/Pushover.php b/app/Livewire/Notifications/Pushover.php new file mode 100644 index 0000000000..18e2b63a12 --- /dev/null +++ b/app/Livewire/Notifications/Pushover.php @@ -0,0 +1,173 @@ +team = auth()->user()->currentTeam(); + $this->syncData(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function syncData(bool $toModel = false) + { + if ($toModel) { + $this->validate(); + $this->team->pushover_enabled = $this->pushoverEnabled; + $this->team->pushover_user = $this->pushoverUser; + $this->team->pushover_token = $this->pushoverToken; + $this->settings->deployment_success_pushover_notifications = $this->deploymentSuccessPushoverNotifications; + $this->settings->deployment_failure_pushover_notifications = $this->deploymentFailurePushoverNotifications; + $this->settings->status_change_pushover_notifications = $this->statusChangePushoverNotifications; + $this->settings->backup_success_pushover_notifications = $this->backupSuccessPushoverNotifications; + $this->settings->backup_failure_pushover_notifications = $this->backupFailurePushoverNotifications; + $this->settings->scheduled_task_success_pushover_notifications = $this->scheduledTaskSuccessPushoverNotifications; + $this->settings->scheduled_task_failure_pushover_notifications = $this->scheduledTaskFailurePushoverNotifications; + $this->settings->docker_cleanup_success_pushover_notifications = $this->dockerCleanupSuccessPushoverNotifications; + $this->settings->docker_cleanup_failure_pushover_notifications = $this->dockerCleanupFailurePushoverNotifications; + $this->settings->server_disk_usage_pushover_notifications = $this->serverDiskUsagePushoverNotifications; + $this->settings->server_reachable_pushover_notifications = $this->serverReachablePushoverNotifications; + $this->settings->server_unreachable_pushover_notifications = $this->serverUnreachablePushoverNotifications; + $this->settings->save(); + refreshSession(); + } else { + $this->pushoverEnabled = $this->team->pushover_enabled; + $this->pushoverUser = $this->team->pushover_user; + $this->pushoverToken = $this->team->pushover_token; + + $this->deploymentSuccessPushoverNotifications = $this->settings->deployment_success_pushover_notifications; + $this->deploymentFailurePushoverNotifications = $this->settings->deployment_failure_pushover_notifications; + $this->statusChangePushoverNotifications = $this->settings->status_change_pushover_notifications; + $this->backupSuccessPushoverNotifications = $this->settings->backup_success_pushover_notifications; + $this->backupFailurePushoverNotifications = $this->settings->backup_failure_pushover_notifications; + $this->scheduledTaskSuccessPushoverNotifications = $this->settings->scheduled_task_success_pushover_notifications; + $this->scheduledTaskFailurePushoverNotifications = $this->settings->scheduled_task_failure_pushover_notifications; + $this->dockerCleanupSuccessPushoverNotifications = $this->settings->docker_cleanup_success_pushover_notifications; + $this->dockerCleanupFailurePushoverNotifications = $this->settings->docker_cleanup_failure_pushover_notifications; + $this->serverDiskUsagePushoverNotifications = $this->settings->server_disk_usage_pushover_notifications; + $this->serverReachablePushoverNotifications = $this->settings->server_reachable_pushover_notifications; + $this->serverUnreachablePushoverNotifications = $this->settings->server_unreachable_pushover_notifications; + } + } + + public function instantSavePushoverEnabled() + { + try { + $this->validate([ + 'pushoverUser' => 'required', + 'pushoverToken' => 'required', + ], [ + 'pushoverUser.required' => 'Pushover User is required.', + 'pushoverToken.required' => 'Pushover Token is required.', + ]); + $this->saveModel(); + } catch (\Throwable $e) { + $this->pushoverEnabled = false; + + return handleError($e, $this); + } + } + + public function instantSave() + { + try { + $this->syncData(true); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function submit() + { + try { + $this->resetErrorBag(); + $this->syncData(true); + $this->saveModel(); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function saveModel() + { + $this->syncData(true); + refreshSession(); + $this->dispatch('success', 'Settings saved.'); + } + + public function sendTestNotification() + { + try { + $this->team->notify(new Test(channel: 'pushover')); + $this->dispatch('success', 'Test notification sent.'); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + + public function render() + { + return view('livewire.notifications.pushover'); + } +} diff --git a/app/Models/PushoverNotificationSettings.php b/app/Models/PushoverNotificationSettings.php new file mode 100644 index 0000000000..7576a60405 --- /dev/null +++ b/app/Models/PushoverNotificationSettings.php @@ -0,0 +1,61 @@ + 'boolean', + 'pushover_user' => 'encrypted', + 'pushover_token' => 'encrypted', + + 'deployment_success_pushover_notifications' => 'boolean', + 'deployment_failure_pushover_notifications' => 'boolean', + 'status_change_pushover_notifications' => 'boolean', + 'backup_success_pushover_notifications' => 'boolean', + 'backup_failure_pushover_notifications' => 'boolean', + 'scheduled_task_success_pushover_notifications' => 'boolean', + 'scheduled_task_failure_pushover_notifications' => 'boolean', + 'docker_cleanup_pushover_notifications' => 'boolean', + 'server_disk_usage_pushover_notifications' => 'boolean', + 'server_reachable_pushover_notifications' => 'boolean', + 'server_unreachable_pushover_notifications' => 'boolean', + ]; + + public function team() + { + return $this->belongsTo(Team::class); + } + + public function isEnabled() + { + return $this->pushover_enabled; + } +} diff --git a/app/Models/Team.php b/app/Models/Team.php index 07424a55f5..41a136bfe7 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -5,6 +5,7 @@ use App\Notifications\Channels\SendsDiscord; use App\Notifications\Channels\SendsEmail; use App\Notifications\Channels\SendsSlack; +use App\Notifications\Channels\SendsPushover; use App\Traits\HasNotificationSettings; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; @@ -32,7 +33,7 @@ ] )] -class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack +class Team extends Model implements SendsDiscord, SendsEmail, SendsSlack, SendsPushover { use HasNotificationSettings, Notifiable; @@ -154,6 +155,14 @@ public function routeNotificationForSlack() { return data_get($this, 'slack_webhook_url', null); } + + public function routeNotificationForPushover() + { + return [ + 'user' => data_get($this, 'pushover_user', null), + 'token' => data_get($this, 'pushover_token', null), + ]; + } public function getRecipients($notification) { @@ -174,7 +183,8 @@ public function isAnyNotificationEnabled() return $this->getNotificationSettings('email')?->isEnabled() || $this->getNotificationSettings('discord')?->isEnabled() || $this->getNotificationSettings('slack')?->isEnabled() || - $this->getNotificationSettings('telegram')?->isEnabled(); + $this->getNotificationSettings('telegram')?->isEnabled() || + $this->getNotificationSettings('pushover')?->isEnabled(); } public function subscriptionEnded() @@ -276,4 +286,9 @@ public function slackNotificationSettings() { return $this->hasOne(SlackNotificationSettings::class); } + + public function pushoverNotificationSettings() + { + return $this->hasOne(PushoverNotificationSettings::class); + } } diff --git a/app/Notifications/Application/DeploymentFailed.php b/app/Notifications/Application/DeploymentFailed.php index 06a2b48e35..a43e5f7631 100644 --- a/app/Notifications/Application/DeploymentFailed.php +++ b/app/Notifications/Application/DeploymentFailed.php @@ -6,6 +6,7 @@ use App\Models\ApplicationPreview; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -130,6 +131,26 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + if ($this->preview) { + $message = 'Coolify: Pull request #' . $this->preview->pull_request_id . ' of ' . $this->application_name . ' (' . $this->preview->fqdn . ') deployment failed: '; + } else { + $message = 'Coolify: Deployment failed of ' . $this->application_name . ' (' . $this->fqdn . '): '; + } + $buttons[] = [ + 'text' => 'Deployment logs', + 'url' => $this->deployment_url, + ]; + + return new PushoverMessage( + message: $message, + buttons: [ + ...$buttons, + ], + ); + } + public function toSlack(): SlackMessage { if ($this->preview) { diff --git a/app/Notifications/Application/DeploymentSuccess.php b/app/Notifications/Application/DeploymentSuccess.php index 548f5c6e5d..b7add6536b 100644 --- a/app/Notifications/Application/DeploymentSuccess.php +++ b/app/Notifications/Application/DeploymentSuccess.php @@ -6,6 +6,7 @@ use App\Models\ApplicationPreview; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -139,6 +140,38 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + if ($this->preview) { + $message = 'Coolify: New PR' . $this->preview->pull_request_id . ' version successfully deployed of ' . $this->application_name . ''; + if ($this->preview->fqdn) { + $buttons[] = [ + 'text' => 'Open Application', + 'url' => $this->preview->fqdn, + ]; + } + } else { + $message = '✅ New version successfully deployed of ' . $this->application_name . ''; + if ($this->fqdn) { + $buttons[] = [ + 'text' => 'Open Application', + 'url' => $this->fqdn, + ]; + } + } + $buttons[] = [ + 'text' => 'Deployment logs', + 'url' => $this->deployment_url, + ]; + + return new PushoverMessage( + message: $message, + buttons: [ + ...$buttons, + ], + ); + } + public function toSlack(): SlackMessage { if ($this->preview) { diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php index 32a6a659a0..6763c58473 100644 --- a/app/Notifications/Application/StatusChanged.php +++ b/app/Notifications/Application/StatusChanged.php @@ -5,6 +5,7 @@ use App\Models\Application; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -77,6 +78,21 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + $message = 'Coolify: ' . $this->resource_name . ' has been stopped.'; + + return new PushoverMessage( + message: $message, + buttons: [ + [ + 'text' => 'Open Application in Coolify', + 'url' => $this->resource_url, + ], + ], + ); + } + public function toSlack(): SlackMessage { $title = 'Application stopped'; diff --git a/app/Notifications/Channels/PushoverChannel.php b/app/Notifications/Channels/PushoverChannel.php new file mode 100644 index 0000000000..f065a971a3 --- /dev/null +++ b/app/Notifications/Channels/PushoverChannel.php @@ -0,0 +1,21 @@ +toPushover(); + $pushoverSettings = $notifiable->pushoverNotificationSettings; + + if (! $pushoverSettings || ! $pushoverSettings->isEnabled() || ! $pushoverSettings->slack_webhook_url) { + return; + } + + SendMessageToPushoverJob::dispatch($message, $pushoverSettings->pushover_user, $pushoverSettings->pushover_token); + } +} diff --git a/app/Notifications/Channels/SendsPushover.php b/app/Notifications/Channels/SendsPushover.php new file mode 100644 index 0000000000..7922eefb44 --- /dev/null +++ b/app/Notifications/Channels/SendsPushover.php @@ -0,0 +1,8 @@ +name}) has been restarted automatically on {$this->server->name}"; + $buttons = []; + if ($this->url) { + $buttons[] = [ + 'text' => 'Check Proxy in Coolify', + 'url' => $this->url, + ]; + } + + return new PushoverMessage( + message: $message, + buttons: $buttons, + ); + } + public function toSlack(): SlackMessage { $title = 'Resource restarted'; diff --git a/app/Notifications/Container/ContainerStopped.php b/app/Notifications/Container/ContainerStopped.php index bc6e52b6dc..5e007cb663 100644 --- a/app/Notifications/Container/ContainerStopped.php +++ b/app/Notifications/Container/ContainerStopped.php @@ -5,6 +5,7 @@ use App\Models\Server; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -68,6 +69,24 @@ public function toTelegram(): array return $payload; } + public function toPushover(): PushoverMessage + { + $message = "Coolify: A resource ($this->name) has been stopped unexpectedly on {$this->server->name}"; + $buttons = []; + if ($this->url) { + $buttons[] = [ + 'text' => 'Open Application in Coolify', + 'url' => $this->url, + ]; + } + + return new PushoverMessage( + message: $message, + buttons: $buttons, + ); + } + + public function toSlack(): SlackMessage { $title = 'Resource stopped'; diff --git a/app/Notifications/Database/BackupFailed.php b/app/Notifications/Database/BackupFailed.php index 2208f7b1da..d06dba4089 100644 --- a/app/Notifications/Database/BackupFailed.php +++ b/app/Notifications/Database/BackupFailed.php @@ -5,6 +5,7 @@ use App\Models\ScheduledDatabaseBackup; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -64,6 +65,15 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + $message = "Coolify: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was FAILED.\n\nReason:\n{$this->output}"; + + return new PushoverMessage( + message: $message, + ); + } + public function toSlack(): SlackMessage { $title = 'Database backup failed'; diff --git a/app/Notifications/Database/BackupSuccess.php b/app/Notifications/Database/BackupSuccess.php index 10b4ff3dfb..b43688165a 100644 --- a/app/Notifications/Database/BackupSuccess.php +++ b/app/Notifications/Database/BackupSuccess.php @@ -5,6 +5,7 @@ use App\Models\ScheduledDatabaseBackup; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -62,6 +63,17 @@ public function toTelegram(): array ]; } + + public function toPushover(): PushoverMessage + { + $message = "Coolify: Database backup for {$this->name} (db:{$this->database_name}) with frequency of {$this->frequency} was successful."; + + return new PushoverMessage( + message: $message, + ); + } + + public function toSlack(): SlackMessage { $title = 'Database backup successful'; diff --git a/app/Notifications/Dto/PushoverMessage.php b/app/Notifications/Dto/PushoverMessage.php new file mode 100644 index 0000000000..c1ad31c561 --- /dev/null +++ b/app/Notifications/Dto/PushoverMessage.php @@ -0,0 +1,34 @@ + $token, + 'user' => $user, + 'message' => $this->message, + 'html' => 1, + ]; + + foreach ($this->buttons as $button) { + $buttonUrl = data_get($button, 'url'); + $text = data_get($button, 'text', 'Click here'); + if ($buttonUrl && str_contains($buttonUrl, 'http://localhost')) { + $buttonUrl = str_replace('http://localhost', config('app.url'), $buttonUrl); + } + $payload['message'] .= " " . $text . ''; + } + + return $payload; + } +} diff --git a/app/Notifications/Internal/GeneralNotification.php b/app/Notifications/Internal/GeneralNotification.php index 7049e3055d..6dd4953777 100644 --- a/app/Notifications/Internal/GeneralNotification.php +++ b/app/Notifications/Internal/GeneralNotification.php @@ -3,6 +3,7 @@ namespace App\Notifications\Internal; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -40,6 +41,13 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + return new PushoverMessage( + message: $this->message, + ); + } + public function toSlack(): SlackMessage { return new SlackMessage( diff --git a/app/Notifications/ScheduledTask/TaskFailed.php b/app/Notifications/ScheduledTask/TaskFailed.php index 56c410ecb0..5765572067 100644 --- a/app/Notifications/ScheduledTask/TaskFailed.php +++ b/app/Notifications/ScheduledTask/TaskFailed.php @@ -5,6 +5,7 @@ use App\Models\ScheduledTask; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -70,6 +71,23 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + $message = "Coolify: Scheduled task ({$this->task->name}) failed with output: {$this->output}"; + $buttons = []; + if ($this->url) { + $buttons[] = [ + 'text' => 'Open task in Coolify', + 'url' => (string) $this->url, + ]; + } + + return new PushoverMessage( + message: $message, + buttons: $buttons, + ); + } + public function toSlack(): SlackMessage { $title = 'Scheduled task failed'; diff --git a/app/Notifications/ScheduledTask/TaskSuccess.php b/app/Notifications/ScheduledTask/TaskSuccess.php index fc79aea373..d3b397997e 100644 --- a/app/Notifications/ScheduledTask/TaskSuccess.php +++ b/app/Notifications/ScheduledTask/TaskSuccess.php @@ -5,6 +5,7 @@ use App\Models\ScheduledTask; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -70,6 +71,23 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + $message = "Coolify: Scheduled task ({$this->task->name}) succeeded."; + $buttons = []; + if ($this->url) { + $buttons[] = [ + 'text' => 'Open task in Coolify', + 'url' => (string) $this->url, + ]; + } + + return new PushoverMessage( + message: $message, + buttons: $buttons, + ); + } + public function toSlack(): SlackMessage { $title = 'Scheduled task succeeded'; diff --git a/app/Notifications/Server/DockerCleanupFailed.php b/app/Notifications/Server/DockerCleanupFailed.php index 53714925c4..bf20d97086 100644 --- a/app/Notifications/Server/DockerCleanupFailed.php +++ b/app/Notifications/Server/DockerCleanupFailed.php @@ -5,6 +5,7 @@ use App\Models\Server; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -48,6 +49,13 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + return new PushoverMessage( + message: "Coolify: [ACTION REQUIRED] Docker cleanup job failed on {$this->server->name}!\n\n{$this->message}", + ); + } + public function toSlack(): SlackMessage { return new SlackMessage( diff --git a/app/Notifications/Server/DockerCleanupSuccess.php b/app/Notifications/Server/DockerCleanupSuccess.php index 85a819da20..7a25803fed 100644 --- a/app/Notifications/Server/DockerCleanupSuccess.php +++ b/app/Notifications/Server/DockerCleanupSuccess.php @@ -5,6 +5,7 @@ use App\Models\Server; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -48,6 +49,13 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + return new PushoverMessage( + message: "Coolify: Docker cleanup job succeeded on {$this->server->name}!\n\n{$this->message}", + ); + } + public function toSlack(): SlackMessage { return new SlackMessage( diff --git a/app/Notifications/Server/ForceDisabled.php b/app/Notifications/Server/ForceDisabled.php index e122849da3..efdaeab6d2 100644 --- a/app/Notifications/Server/ForceDisabled.php +++ b/app/Notifications/Server/ForceDisabled.php @@ -5,6 +5,7 @@ use App\Models\Server; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -51,6 +52,13 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + return new PushoverMessage( + message: "Coolify: Server ({$this->server->name}) disabled because it is not paid!\n All automations and integrations are stopped.\nPlease update your subscription to enable the server again [here](https://app.coolify.io/subscriptions).", + ); + } + public function toSlack(): SlackMessage { $title = 'Server disabled'; diff --git a/app/Notifications/Server/ForceEnabled.php b/app/Notifications/Server/ForceEnabled.php index a0e0a8b59d..759779a8f2 100644 --- a/app/Notifications/Server/ForceEnabled.php +++ b/app/Notifications/Server/ForceEnabled.php @@ -5,6 +5,7 @@ use App\Models\Server; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -47,6 +48,13 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + return new PushoverMessage( + message: "Coolify: Server ({$this->server->name}) enabled again!", + ); + } + public function toSlack(): SlackMessage { return new SlackMessage( diff --git a/app/Notifications/Server/HighDiskUsage.php b/app/Notifications/Server/HighDiskUsage.php index 9f4826689e..1b2ccb6308 100644 --- a/app/Notifications/Server/HighDiskUsage.php +++ b/app/Notifications/Server/HighDiskUsage.php @@ -5,6 +5,7 @@ use App\Models\Server; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -57,6 +58,13 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + return new PushoverMessage( + message: "Coolify: Server '{$this->server->name}' high disk usage detected!\nDisk usage: {$this->disk_usage}%. Threshold: {$this->server_disk_usage_notification_threshold}%.\nPlease cleanup your disk to prevent data-loss.\nHere are some tips: https://coolify.io/docs/knowledge-base/server/automated-cleanup.", + ); + } + public function toSlack(): SlackMessage { $description = "Server '{$this->server->name}' high disk usage detected!\n"; diff --git a/app/Notifications/Server/Reachable.php b/app/Notifications/Server/Reachable.php index 4917e04f8c..df59ce4395 100644 --- a/app/Notifications/Server/Reachable.php +++ b/app/Notifications/Server/Reachable.php @@ -5,6 +5,7 @@ use App\Models\Server; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -49,6 +50,13 @@ public function toDiscord(): DiscordMessage ); } + public function toPushover(): PushoverMessage + { + return new PushoverMessage( + message: "Coolify: Server '{$this->server->name}' revived. All automations & integrations are turned on again!", + ); + } + public function toTelegram(): array { return [ diff --git a/app/Notifications/Server/Unreachable.php b/app/Notifications/Server/Unreachable.php index 43f176d49d..085e9205a3 100644 --- a/app/Notifications/Server/Unreachable.php +++ b/app/Notifications/Server/Unreachable.php @@ -5,6 +5,7 @@ use App\Models\Server; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Notifications\Messages\MailMessage; @@ -60,6 +61,13 @@ public function toTelegram(): ?array ]; } + public function toPushover(): PushoverMessage + { + return new PushoverMessage( + message: "Coolify: Your server '{$this->server->name}' is unreachable. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server and turn on all automations & integrations.", + ); + } + public function toSlack(): SlackMessage { $description = "Your server '{$this->server->name}' is unreachable.\n"; diff --git a/app/Notifications/Test.php b/app/Notifications/Test.php index da90985008..0d2f81ba55 100644 --- a/app/Notifications/Test.php +++ b/app/Notifications/Test.php @@ -7,6 +7,7 @@ use App\Notifications\Channels\SlackChannel; use App\Notifications\Channels\TelegramChannel; use App\Notifications\Dto\DiscordMessage; +use App\Notifications\Dto\PushoverMessage; use App\Notifications\Dto\SlackMessage; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -85,6 +86,19 @@ public function toTelegram(): array ]; } + public function toPushover(): PushoverMessage + { + return new PushoverMessage( + message: 'Coolify: This is a test Pushover notification from Coolify.', + buttons: [ + [ + 'text' => 'Go to your dashboard', + 'url' => base_url(), + ], + ], + ); + } + public function toSlack(): SlackMessage { return new SlackMessage( diff --git a/app/Traits/HasNotificationSettings.php b/app/Traits/HasNotificationSettings.php index 82cbda6ada..ef858d0b6e 100644 --- a/app/Traits/HasNotificationSettings.php +++ b/app/Traits/HasNotificationSettings.php @@ -6,6 +6,7 @@ use App\Notifications\Channels\EmailChannel; use App\Notifications\Channels\SlackChannel; use App\Notifications\Channels\TelegramChannel; +use App\Notifications\Channels\PushoverChannel; use Illuminate\Database\Eloquent\Model; trait HasNotificationSettings @@ -27,6 +28,7 @@ public function getNotificationSettings(string $channel): ?Model 'discord' => $this->discordNotificationSettings, 'telegram' => $this->telegramNotificationSettings, 'slack' => $this->slackNotificationSettings, + 'pushover' => $this->pushoverNotificationSettings, default => null, }; } @@ -73,6 +75,7 @@ public function getEnabledChannels(string $event): array 'discord' => DiscordChannel::class, 'telegram' => TelegramChannel::class, 'slack' => SlackChannel::class, + 'pushover' => PushoverChannel::class, ]; if ($event === 'general') { diff --git a/database/migrations/2024_12_11_135026_create_pushover_notification_settings_table.php b/database/migrations/2024_12_11_135026_create_pushover_notification_settings_table.php new file mode 100644 index 0000000000..907f7a052f --- /dev/null +++ b/database/migrations/2024_12_11_135026_create_pushover_notification_settings_table.php @@ -0,0 +1,47 @@ +id(); + $table->foreignId('team_id')->constrained()->cascadeOnDelete(); + + $table->boolean('pushover_enabled')->default(false); + $table->text('pushover_user')->nullable(); + $table->text('pushover_token')->nullable(); + + $table->boolean('deployment_success_pushover_notifications')->default(false); + $table->boolean('deployment_failure_pushover_notifications')->default(true); + $table->boolean('status_change_pushover_notifications')->default(false); + $table->boolean('backup_success_pushover_notifications')->default(false); + $table->boolean('backup_failure_pushover_notifications')->default(true); + $table->boolean('scheduled_task_success_pushover_notifications')->default(false); + $table->boolean('scheduled_task_failure_pushover_notifications')->default(true); + $table->boolean('docker_cleanup_success_pushover_notifications')->default(false); + $table->boolean('docker_cleanup_failure_pushover_notifications')->default(true); + $table->boolean('server_disk_usage_pushover_notifications')->default(true); + $table->boolean('server_reachable_pushover_notifications')->default(false); + $table->boolean('server_unreachable_pushover_notifications')->default(true); + + $table->unique(['team_id']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('pushover_notification_settings'); + } +}; + diff --git a/resources/views/components/notification/navbar.blade.php b/resources/views/components/notification/navbar.blade.php index c4dbd25af1..0193cf3cd5 100644 --- a/resources/views/components/notification/navbar.blade.php +++ b/resources/views/components/notification/navbar.blade.php @@ -19,6 +19,10 @@ href="{{ route('notifications.slack') }}"> + + + - \ No newline at end of file + diff --git a/resources/views/livewire/notifications/pushover.blade.php b/resources/views/livewire/notifications/pushover.blade.php new file mode 100644 index 0000000000..d81620848e --- /dev/null +++ b/resources/views/livewire/notifications/pushover.blade.php @@ -0,0 +1,84 @@ +
    + + Notifications | Coolify + + +
    +
    +

    Pushover

    + + Save + + @if ($pushoverEnabled) + + Send Test Notification + + @else + + Send Test Notification + + @endif +
    +
    + +
    + + + +

    Notification Settings

    +

    + Select events for which you would like to receive Pushover notifications. +

    +
    +
    +

    Deployments

    +
    + + + +
    +
    +
    +

    Backups

    +
    + + +
    +
    +
    +

    Scheduled Tasks

    +
    + + +
    +
    +
    +

    Server

    +
    + + + + + +
    +
    +
    +