diff --git a/app/Http/Livewire/Notifications/DiscordSettings.php b/app/Http/Livewire/Notifications/DiscordSettings.php
index ac64c9184..03cac4753 100644
--- a/app/Http/Livewire/Notifications/DiscordSettings.php
+++ b/app/Http/Livewire/Notifications/DiscordSettings.php
@@ -15,6 +15,7 @@ class DiscordSettings extends Component
'model.discord_notifications_test' => 'nullable|boolean',
'model.discord_notifications_deployments' => 'nullable|boolean',
'model.discord_notifications_status_changes' => 'nullable|boolean',
+ 'model.discord_notifications_database_backups' => 'nullable|boolean',
];
protected $validationAttributes = [
'model.discord_webhook_url' => 'Discord Webhook',
diff --git a/app/Http/Livewire/Notifications/EmailSettings.php b/app/Http/Livewire/Notifications/EmailSettings.php
index 8c7389afd..eceb4e88b 100644
--- a/app/Http/Livewire/Notifications/EmailSettings.php
+++ b/app/Http/Livewire/Notifications/EmailSettings.php
@@ -26,6 +26,7 @@ class EmailSettings extends Component
'model.smtp_notifications_test' => 'nullable|boolean',
'model.smtp_notifications_deployments' => 'nullable|boolean',
'model.smtp_notifications_status_changes' => 'nullable|boolean',
+ 'model.smtp_notifications_database_backups' => 'nullable|boolean',
];
protected $validationAttributes = [
'model.smtp_from_address' => 'From Address',
diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php
index ddb5f743f..82dd85623 100644
--- a/app/Jobs/DatabaseBackupJob.php
+++ b/app/Jobs/DatabaseBackupJob.php
@@ -8,6 +8,8 @@ use App\Models\ScheduledDatabaseBackupExecution;
use App\Models\Server;
use App\Models\StandalonePostgresql;
use App\Models\Team;
+use App\Notifications\Database\BackupFailed;
+use App\Notifications\Database\BackupSuccess;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -73,10 +75,10 @@ class DatabaseBackupJob implements ShouldQueue
}
$this->calculate_size();
$this->remove_old_backups();
- $this->save_backup_logs();
if ($this->backup->save_s3) {
- $this->upload_to_s3();
+// $this->upload_to_s3();
}
+ $this->save_backup_logs();
// TODO: Notify user
}
@@ -98,10 +100,13 @@ class DatabaseBackupJob implements ShouldQueue
ray('Backup done for ' . $this->database->uuid . ' at ' . $this->server->name . ':' . $this->backup_filename);
$this->backup_status = 'success';
+ throw new \Error('test');
+ $this->team->notify(new BackupSuccess($this->backup, $this->database));
} catch (Throwable $th) {
$this->backup_status = 'failed';
$this->add_to_backup_output($th->getMessage());
ray('Backup failed for ' . $this->database->uuid . ' at ' . $this->server->name . ':' . $this->backup_filename . '\n\nError:' . $th->getMessage());
+ $this->team->notify(new BackupFailed($this->backup, $this->database));
} finally {
$this->backup_log->update([
'status' => $this->backup_status,
@@ -130,7 +135,6 @@ class DatabaseBackupJob implements ShouldQueue
} else {
$deletable = $this->backup->executions()->where('status', 'success')->orderByDesc('created_at')->skip($this->backup->number_of_backups_locally);
}
- ray($deletable->get());
foreach ($deletable->get() as $execution) {
delete_backup_locally($execution->filename, $this->server);
$execution->delete();
@@ -159,13 +163,15 @@ class DatabaseBackupJob implements ShouldQueue
$bucket = $this->s3->bucket;
$endpoint = $this->s3->endpoint;
$backup_dir = backup_dir() . "/{$this->database->uuid}";
+
$base_command = "docker run -t --network {$this->database->destination->network} -v {$this->backup_filename}:{$this->backup_filename}:ro --rm --entrypoint=/bin/sh minio/mc -c \"mc config host add temporary {$endpoint} $key $secret && mc cp $this->backup_filename temporary/$bucket/$backup_dir/ \"";
+
instant_remote_process([$base_command], $this->server);
+
$this->add_to_backup_output('Uploaded to S3.');
} catch (\Throwable $th) {
$this->add_to_backup_output($th->getMessage());
ray($th->getMessage());
- //throw $th;
}
}
}
diff --git a/app/Notifications/Database/BackupFailed.php b/app/Notifications/Database/BackupFailed.php
new file mode 100644
index 000000000..839ec0da9
--- /dev/null
+++ b/app/Notifications/Database/BackupFailed.php
@@ -0,0 +1,55 @@
+message = "❌ Database backup for {$database->name} with frequency of $backup->frequency was FAILED.";
+ }
+
+ public function via(object $notifiable): array
+ {
+ $channels = [];
+ $isEmailEnabled = data_get($notifiable, 'smtp_enabled');
+ $isDiscordEnabled = data_get($notifiable, 'discord_enabled');
+ $isSubscribedToEmailEvent = data_get($notifiable, 'smtp_notifications_database_backups');
+ $isSubscribedToDiscordEvent = data_get($notifiable, 'discord_notifications_database_backups');
+
+ if ($isEmailEnabled && $isSubscribedToEmailEvent) {
+ $channels[] = EmailChannel::class;
+ }
+ if ($isDiscordEnabled && $isSubscribedToDiscordEvent) {
+ $channels[] = DiscordChannel::class;
+ }
+ ray($channels);
+ return $channels;
+ }
+
+ public function toMail(): MailMessage
+ {
+ $mail = new MailMessage();
+ $mail->subject("❌ Backup FAILED for {$this->database->name}");
+ $mail->line($this->message);
+ return $mail;
+ }
+
+ public function toDiscord(): string
+ {
+ return $this->message;
+ }
+}
diff --git a/app/Notifications/Database/BackupSuccess.php b/app/Notifications/Database/BackupSuccess.php
new file mode 100644
index 000000000..36c8961ba
--- /dev/null
+++ b/app/Notifications/Database/BackupSuccess.php
@@ -0,0 +1,55 @@
+message = "✅ Database backup for {$database->name} with frequency of $backup->frequency was successful.";
+ }
+
+ public function via(object $notifiable): array
+ {
+ $channels = [];
+ $isEmailEnabled = data_get($notifiable, 'smtp_enabled');
+ $isDiscordEnabled = data_get($notifiable, 'discord_enabled');
+ $isSubscribedToEmailEvent = data_get($notifiable, 'smtp_notifications_database_backups');
+ $isSubscribedToDiscordEvent = data_get($notifiable, 'discord_notifications_database_backups');
+
+ if ($isEmailEnabled && $isSubscribedToEmailEvent) {
+ $channels[] = EmailChannel::class;
+ }
+ if ($isDiscordEnabled && $isSubscribedToDiscordEvent) {
+ $channels[] = DiscordChannel::class;
+ }
+ ray($channels);
+ return $channels;
+ }
+
+ public function toMail(): MailMessage
+ {
+ $mail = new MailMessage();
+ $mail->subject("✅ Backup success for {$this->database->name}");
+ $mail->line($this->message);
+ return $mail;
+ }
+
+ public function toDiscord(): string
+ {
+ return $this->message;
+ }
+}
diff --git a/app/Notifications/TransactionalEmails/InvitationLink.php b/app/Notifications/TransactionalEmails/InvitationLink.php
index f08c36fbc..409234fd5 100644
--- a/app/Notifications/TransactionalEmails/InvitationLink.php
+++ b/app/Notifications/TransactionalEmails/InvitationLink.php
@@ -15,7 +15,7 @@ class InvitationLink extends Notification implements ShouldQueue
{
use Queueable;
- public function via()
+ public function via(): array
{
return [TransactionalEmailChannel::class];
}
diff --git a/config/coolify.php b/config/coolify.php
index 459fefcc6..b0ae2ea2d 100644
--- a/config/coolify.php
+++ b/config/coolify.php
@@ -9,6 +9,6 @@ return [
'lemon_squeezy_checkout_id_3' => env('LEMON_SQUEEZY_CHECKOUT_ID_3'),
'mux_enabled' => env('MUX_ENABLED', true),
'dev_webhook' => env('SERVEO_URL'),
- 'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
+ 'base_config_path' => env('BASE_CONFIG_PATH', '/_data/coolify'),
'dev_config_path' => env('DEV_CONFIG_PATH', './_data/coolify'),
];
diff --git a/database/migrations/2023_08_10_201311_add_backup_notifications_to_teams.php b/database/migrations/2023_08_10_201311_add_backup_notifications_to_teams.php
new file mode 100644
index 000000000..865403d8e
--- /dev/null
+++ b/database/migrations/2023_08_10_201311_add_backup_notifications_to_teams.php
@@ -0,0 +1,23 @@
+boolean('smtp_notifications_database_backups')->default(true);
+ $table->boolean('discord_notifications_database_backups')->default(true);
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::table('teams', function (Blueprint $table) {
+ $table->dropColumn('smtp_notifications_database_backups');
+ $table->dropColumn('discord_notifications_database_backups');
+ });
+ }
+};
diff --git a/resources/views/livewire/notifications/discord-settings.blade.php b/resources/views/livewire/notifications/discord-settings.blade.php
index 9ec66ea1c..ba6f182a4 100644
--- a/resources/views/livewire/notifications/discord-settings.blade.php
+++ b/resources/views/livewire/notifications/discord-settings.blade.php
@@ -21,16 +21,20 @@
id="model.discord_webhook_url" label="Webhook"/>
@if (data_get($model, 'discord_enabled'))
-
Subscribe to events
-
+
Subscribe to events
+
@if (is_dev())
@endif
-
Applications
+ General
+
+ Applications
-
+ Databases
+
@endif
diff --git a/resources/views/livewire/notifications/email-settings.blade.php b/resources/views/livewire/notifications/email-settings.blade.php
index 09d0f5acb..775694564 100644
--- a/resources/views/livewire/notifications/email-settings.blade.php
+++ b/resources/views/livewire/notifications/email-settings.blade.php
@@ -63,10 +63,15 @@
@if (is_dev())
@endif
- Applications
-
+ General
+ label="Container Status Changes"/>
+ Applications
+
+ Databases
+
@endif
diff --git a/resources/views/vendor/mail/html/button.blade.php b/resources/views/vendor/mail/html/button.blade.php
new file mode 100644
index 000000000..4a9bf7d00
--- /dev/null
+++ b/resources/views/vendor/mail/html/button.blade.php
@@ -0,0 +1,24 @@
+@props([
+ 'url',
+ 'color' => 'primary',
+ 'align' => 'center',
+])
+
diff --git a/resources/views/vendor/mail/html/footer.blade.php b/resources/views/vendor/mail/html/footer.blade.php
new file mode 100644
index 000000000..3ff41f89c
--- /dev/null
+++ b/resources/views/vendor/mail/html/footer.blade.php
@@ -0,0 +1,11 @@
+
+
+
+ |
+
diff --git a/resources/views/vendor/mail/html/header.blade.php b/resources/views/vendor/mail/html/header.blade.php
new file mode 100644
index 000000000..6e30a3df9
--- /dev/null
+++ b/resources/views/vendor/mail/html/header.blade.php
@@ -0,0 +1,12 @@
+@props(['url'])
+
+
+
diff --git a/resources/views/vendor/mail/html/layout.blade.php b/resources/views/vendor/mail/html/layout.blade.php
new file mode 100644
index 000000000..e55f6a6d9
--- /dev/null
+++ b/resources/views/vendor/mail/html/layout.blade.php
@@ -0,0 +1,57 @@
+
+
+
+{{ config('app.name') }}
+
+
+
+
+
+
+
+
+
+
+
+
+{{ $header ?? '' }}
+
+
+
+
+
+
+
+
+{{ Illuminate\Mail\Markdown::parse($slot) }}
+
+{{ $subcopy ?? '' }}
+ |
+
+
+ |
+
+
+{{ $footer ?? '' }}
+
+ |
+
+
+
+
diff --git a/resources/views/vendor/mail/html/message.blade.php b/resources/views/vendor/mail/html/message.blade.php
new file mode 100644
index 000000000..f272460da
--- /dev/null
+++ b/resources/views/vendor/mail/html/message.blade.php
@@ -0,0 +1,27 @@
+
+{{-- Header --}}
+
+
+{{ config('app.name') }}
+
+
+
+{{-- Body --}}
+{{ $slot }}
+
+{{-- Subcopy --}}
+@isset($subcopy)
+
+
+{{ $subcopy }}
+
+
+@endisset
+
+{{-- Footer --}}
+
+
+© {{ date('Y') }} {{ config('app.name') }}. @lang('All rights reserved.')
+
+
+
diff --git a/resources/views/vendor/mail/html/panel.blade.php b/resources/views/vendor/mail/html/panel.blade.php
new file mode 100644
index 000000000..2975a60a0
--- /dev/null
+++ b/resources/views/vendor/mail/html/panel.blade.php
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+{{ Illuminate\Mail\Markdown::parse($slot) }}
+ |
+
+
+ |
+
+
+
diff --git a/resources/views/vendor/mail/html/subcopy.blade.php b/resources/views/vendor/mail/html/subcopy.blade.php
new file mode 100644
index 000000000..790ce6c24
--- /dev/null
+++ b/resources/views/vendor/mail/html/subcopy.blade.php
@@ -0,0 +1,7 @@
+
+
+
+{{ Illuminate\Mail\Markdown::parse($slot) }}
+ |
+
+
diff --git a/resources/views/vendor/mail/html/table.blade.php b/resources/views/vendor/mail/html/table.blade.php
new file mode 100644
index 000000000..a5f3348b2
--- /dev/null
+++ b/resources/views/vendor/mail/html/table.blade.php
@@ -0,0 +1,3 @@
+
+{{ Illuminate\Mail\Markdown::parse($slot) }}
+
diff --git a/resources/views/vendor/mail/html/themes/default.css b/resources/views/vendor/mail/html/themes/default.css
new file mode 100644
index 000000000..03d811653
--- /dev/null
+++ b/resources/views/vendor/mail/html/themes/default.css
@@ -0,0 +1,290 @@
+/* Base */
+
+body,
+body *:not(html):not(style):not(br):not(tr):not(code) {
+ box-sizing: border-box;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,
+ 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
+ position: relative;
+}
+
+body {
+ -webkit-text-size-adjust: none;
+ background-color: #ffffff;
+ color: #718096;
+ height: 100%;
+ line-height: 1.4;
+ margin: 0;
+ padding: 0;
+ width: 100% !important;
+}
+
+p,
+ul,
+ol,
+blockquote {
+ line-height: 1.4;
+ text-align: left;
+}
+
+a {
+ color: #3869d4;
+}
+
+a img {
+ border: none;
+}
+
+/* Typography */
+
+h1 {
+ color: #3d4852;
+ font-size: 18px;
+ font-weight: bold;
+ margin-top: 0;
+ text-align: left;
+}
+
+h2 {
+ font-size: 16px;
+ font-weight: bold;
+ margin-top: 0;
+ text-align: left;
+}
+
+h3 {
+ font-size: 14px;
+ font-weight: bold;
+ margin-top: 0;
+ text-align: left;
+}
+
+p {
+ font-size: 16px;
+ line-height: 1.5em;
+ margin-top: 0;
+ text-align: left;
+}
+
+p.sub {
+ font-size: 12px;
+}
+
+img {
+ max-width: 100%;
+}
+
+/* Layout */
+
+.wrapper {
+ -premailer-cellpadding: 0;
+ -premailer-cellspacing: 0;
+ -premailer-width: 100%;
+ background-color: #edf2f7;
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+.content {
+ -premailer-cellpadding: 0;
+ -premailer-cellspacing: 0;
+ -premailer-width: 100%;
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+/* Header */
+
+.header {
+ padding: 25px 0;
+ text-align: center;
+}
+
+.header a {
+ color: #3d4852;
+ font-size: 19px;
+ font-weight: bold;
+ text-decoration: none;
+}
+
+/* Logo */
+
+.logo {
+ height: 75px;
+ max-height: 75px;
+ width: 75px;
+}
+
+/* Body */
+
+.body {
+ -premailer-cellpadding: 0;
+ -premailer-cellspacing: 0;
+ -premailer-width: 100%;
+ background-color: #edf2f7;
+ border-bottom: 1px solid #edf2f7;
+ border-top: 1px solid #edf2f7;
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+.inner-body {
+ -premailer-cellpadding: 0;
+ -premailer-cellspacing: 0;
+ -premailer-width: 570px;
+ background-color: #ffffff;
+ border-color: #e8e5ef;
+ border-radius: 2px;
+ border-width: 1px;
+ box-shadow: 0 2px 0 rgba(0, 0, 150, 0.025), 2px 4px 0 rgba(0, 0, 150, 0.015);
+ margin: 0 auto;
+ padding: 0;
+ width: 570px;
+}
+
+/* Subcopy */
+
+.subcopy {
+ border-top: 1px solid #e8e5ef;
+ margin-top: 25px;
+ padding-top: 25px;
+}
+
+.subcopy p {
+ font-size: 14px;
+}
+
+/* Footer */
+
+.footer {
+ -premailer-cellpadding: 0;
+ -premailer-cellspacing: 0;
+ -premailer-width: 570px;
+ margin: 0 auto;
+ padding: 0;
+ text-align: center;
+ width: 570px;
+}
+
+.footer p {
+ color: #b0adc5;
+ font-size: 12px;
+ text-align: center;
+}
+
+.footer a {
+ color: #b0adc5;
+ text-decoration: underline;
+}
+
+/* Tables */
+
+.table table {
+ -premailer-cellpadding: 0;
+ -premailer-cellspacing: 0;
+ -premailer-width: 100%;
+ margin: 30px auto;
+ width: 100%;
+}
+
+.table th {
+ border-bottom: 1px solid #edeff2;
+ margin: 0;
+ padding-bottom: 8px;
+}
+
+.table td {
+ color: #74787e;
+ font-size: 15px;
+ line-height: 18px;
+ margin: 0;
+ padding: 10px 0;
+}
+
+.content-cell {
+ max-width: 100vw;
+ padding: 32px;
+}
+
+/* Buttons */
+
+.action {
+ -premailer-cellpadding: 0;
+ -premailer-cellspacing: 0;
+ -premailer-width: 100%;
+ margin: 30px auto;
+ padding: 0;
+ text-align: center;
+ width: 100%;
+}
+
+.button {
+ -webkit-text-size-adjust: none;
+ border-radius: 4px;
+ color: #fff;
+ display: inline-block;
+ overflow: hidden;
+ text-decoration: none;
+}
+
+.button-blue,
+.button-primary {
+ background-color: #2d3748;
+ border-bottom: 8px solid #2d3748;
+ border-left: 18px solid #2d3748;
+ border-right: 18px solid #2d3748;
+ border-top: 8px solid #2d3748;
+}
+
+.button-green,
+.button-success {
+ background-color: #48bb78;
+ border-bottom: 8px solid #48bb78;
+ border-left: 18px solid #48bb78;
+ border-right: 18px solid #48bb78;
+ border-top: 8px solid #48bb78;
+}
+
+.button-red,
+.button-error {
+ background-color: #e53e3e;
+ border-bottom: 8px solid #e53e3e;
+ border-left: 18px solid #e53e3e;
+ border-right: 18px solid #e53e3e;
+ border-top: 8px solid #e53e3e;
+}
+
+/* Panels */
+
+.panel {
+ border-left: #2d3748 solid 4px;
+ margin: 21px 0;
+}
+
+.panel-content {
+ background-color: #edf2f7;
+ color: #718096;
+ padding: 16px;
+}
+
+.panel-content p {
+ color: #718096;
+}
+
+.panel-item {
+ padding: 0;
+}
+
+.panel-item p:last-of-type {
+ margin-bottom: 0;
+ padding-bottom: 0;
+}
+
+/* Utilities */
+
+.break-all {
+ word-break: break-all;
+}
diff --git a/resources/views/vendor/mail/text/button.blade.php b/resources/views/vendor/mail/text/button.blade.php
new file mode 100644
index 000000000..97444ebdc
--- /dev/null
+++ b/resources/views/vendor/mail/text/button.blade.php
@@ -0,0 +1 @@
+{{ $slot }}: {{ $url }}
diff --git a/resources/views/vendor/mail/text/footer.blade.php b/resources/views/vendor/mail/text/footer.blade.php
new file mode 100644
index 000000000..3338f620e
--- /dev/null
+++ b/resources/views/vendor/mail/text/footer.blade.php
@@ -0,0 +1 @@
+{{ $slot }}
diff --git a/resources/views/vendor/mail/text/header.blade.php b/resources/views/vendor/mail/text/header.blade.php
new file mode 100644
index 000000000..aaa3e5754
--- /dev/null
+++ b/resources/views/vendor/mail/text/header.blade.php
@@ -0,0 +1 @@
+[{{ $slot }}]({{ $url }})
diff --git a/resources/views/vendor/mail/text/layout.blade.php b/resources/views/vendor/mail/text/layout.blade.php
new file mode 100644
index 000000000..9378baa07
--- /dev/null
+++ b/resources/views/vendor/mail/text/layout.blade.php
@@ -0,0 +1,9 @@
+{!! strip_tags($header) !!}
+
+{!! strip_tags($slot) !!}
+@isset($subcopy)
+
+{!! strip_tags($subcopy) !!}
+@endisset
+
+{!! strip_tags($footer) !!}
diff --git a/resources/views/vendor/mail/text/message.blade.php b/resources/views/vendor/mail/text/message.blade.php
new file mode 100644
index 000000000..80bce2112
--- /dev/null
+++ b/resources/views/vendor/mail/text/message.blade.php
@@ -0,0 +1,27 @@
+
+ {{-- Header --}}
+
+
+ {{ config('app.name') }}
+
+
+
+ {{-- Body --}}
+ {{ $slot }}
+
+ {{-- Subcopy --}}
+ @isset($subcopy)
+
+
+ {{ $subcopy }}
+
+
+ @endisset
+
+ {{-- Footer --}}
+
+
+ © {{ date('Y') }} {{ config('app.name') }}. @lang('All rights reserved.')
+
+
+
diff --git a/resources/views/vendor/mail/text/panel.blade.php b/resources/views/vendor/mail/text/panel.blade.php
new file mode 100644
index 000000000..3338f620e
--- /dev/null
+++ b/resources/views/vendor/mail/text/panel.blade.php
@@ -0,0 +1 @@
+{{ $slot }}
diff --git a/resources/views/vendor/mail/text/subcopy.blade.php b/resources/views/vendor/mail/text/subcopy.blade.php
new file mode 100644
index 000000000..3338f620e
--- /dev/null
+++ b/resources/views/vendor/mail/text/subcopy.blade.php
@@ -0,0 +1 @@
+{{ $slot }}
diff --git a/resources/views/vendor/mail/text/table.blade.php b/resources/views/vendor/mail/text/table.blade.php
new file mode 100644
index 000000000..3338f620e
--- /dev/null
+++ b/resources/views/vendor/mail/text/table.blade.php
@@ -0,0 +1 @@
+{{ $slot }}