diff --git a/app/Data/SmtpConfiguration.php b/app/Data/SmtpConfiguration.php new file mode 100644 index 000000000..1aac317de --- /dev/null +++ b/app/Data/SmtpConfiguration.php @@ -0,0 +1,23 @@ + 'nullable|boolean', 'model.extra_attributes.discord_webhook' => 'required|url', + 'model.extra_attributes.notifications_test' => 'nullable|boolean', + 'model.extra_attributes.notifications_deployments' => 'nullable|boolean', ]; protected $validationAttributes = [ 'model.extra_attributes.discord_webhook' => 'Discord Webhook', ]; - + public function instantSaveEvents() + { + $this->saveModel(); + } public function instantSave() { try { @@ -35,6 +40,7 @@ class DiscordSettings extends Component if (is_a($this->model, Team::class)) { session(['currentTeam' => $this->model]); } + $this->emit('success', 'Settings saved.'); } public function submit() { diff --git a/app/Http/Livewire/Notifications/EmailSettings.php b/app/Http/Livewire/Notifications/EmailSettings.php index 28ecd7aa2..186ca7898 100644 --- a/app/Http/Livewire/Notifications/EmailSettings.php +++ b/app/Http/Livewire/Notifications/EmailSettings.php @@ -24,6 +24,8 @@ class EmailSettings extends Component 'model.extra_attributes.smtp_password' => 'nullable', 'model.extra_attributes.smtp_timeout' => 'nullable', 'model.extra_attributes.smtp_test_recipients' => 'nullable', + 'model.extra_attributes.notifications_deployments' => 'nullable|boolean', + 'model.extra_attributes.notifications_test' => 'nullable|boolean', ]; protected $validationAttributes = [ 'model.extra_attributes.smtp_from_address' => 'From Address', @@ -66,11 +68,16 @@ class EmailSettings extends Component if (is_a($this->model, Team::class)) { session(['currentTeam' => $this->model]); } + $this->emit('success', 'Settings saved.'); } public function sendTestNotification() { Notification::send($this->model, new TestNotification); } + public function instantSaveEvents() + { + $this->saveModel(); + } public function instantSave() { try { diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 51bc5d741..450e5a8cc 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -9,12 +9,14 @@ use App\Enums\ProcessStatus; use App\Models\Application; use App\Models\ApplicationDeploymentQueue; use App\Models\ApplicationPreview; +use App\Notifications\Notifications\ApplicationDeployedNotification; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Notification; use Illuminate\Support\Facades\Storage; use Spatie\Activitylog\Models\Activity; use Symfony\Component\Yaml\Yaml; @@ -315,6 +317,7 @@ COPY --from=$this->build_image_name /app/{$this->application->publish_directory} dispatch(new InstanceProxyCheckJob()); } queue_next_deployment($this->application); + Notification::send($this->application->environment->project->team, new ApplicationDeployedNotification($this->application, $this->deployment_uuid)); } private function execute_in_builder(string $command) { diff --git a/app/Models/Project.php b/app/Models/Project.php index 68b594067..a790b191d 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -26,7 +26,10 @@ class Project extends BaseModel { return Project::whereTeamId(session('currentTeam')->id); } - + public function team() + { + return $this->belongsTo(Team::class); + } public function environments() { return $this->hasMany(Environment::class); diff --git a/app/Notifications/Channels/EmailChannel.php b/app/Notifications/Channels/EmailChannel.php index 03fb46e2c..8db504f40 100644 --- a/app/Notifications/Channels/EmailChannel.php +++ b/app/Notifications/Channels/EmailChannel.php @@ -11,20 +11,14 @@ class EmailChannel public function send(SendsEmail $notifiable, Notification $notification): void { $this->bootConfigs($notifiable); - $is_test_notification = $notification instanceof \App\Notifications\Notifications\TestNotification; - if ($is_test_notification) { - $bcc = $notifiable->routeNotificationForEmail('smtp_test_recipients'); - if (count($bcc) === 0) { - if ($notifiable instanceof \App\Models\Team) { - $bcc = $notifiable->members()->pluck('email')->toArray(); - } + $bcc = $notifiable->routeNotificationForEmail('smtp_test_recipients'); + if (count($bcc) === 0) { + if ($notifiable instanceof \App\Models\Team) { + $bcc = $notifiable->members()->pluck('email')->toArray(); } - } else { - $bcc = $notifiable->routeNotificationForEmail(); } $mailMessage = $notification->toMail($notifiable); - Mail::send( [], [], diff --git a/app/Notifications/Notifications/ApplicationDeployedNotification.php b/app/Notifications/Notifications/ApplicationDeployedNotification.php new file mode 100644 index 000000000..8718b5a61 --- /dev/null +++ b/app/Notifications/Notifications/ApplicationDeployedNotification.php @@ -0,0 +1,67 @@ +application = $application; + $this->application_name = data_get($application, 'name'); + $this->deployment_uuid = $deployment_uuid; + $this->project_uuid = data_get($application, 'environment.project.uuid'); + $this->environment_name = data_get($application, 'environment.name'); + $this->fqdn = data_get($application, 'fqdn'); + if (Str::of($this->fqdn)->explode(',')->count() > 1) { + $this->fqdn = Str::of($this->fqdn)->explode(',')->first(); + } + $this->deployment_url = base_url() . "/project/{$this->project_uuid}/{$this->environment_name}/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}"; + } + public function via(object $notifiable): array + { + $channels = []; + if ($notifiable->extra_attributes?->get('email_active') && $notifiable->extra_attributes?->get('notifications_deployments')) { + $channels[] = EmailChannel::class; + } + if ($notifiable->extra_attributes?->get('discord_active') && $notifiable->extra_attributes?->get('notifications_deployments')) { + $channels[] = DiscordChannel::class; + } + return $channels; + } + public function toMail(Team $team): MailMessage + { + $mail = new MailMessage(); + $mail->subject("New version is deployed of {$this->application_name}"); + $mail->view('emails.application-deployed', [ + 'name' => $this->application_name, + 'fqdn' => $this->fqdn, + 'url' => $this->deployment_url, + ]); + return $mail; + } + + public function toDiscord(): string + { + return '⚒️ A new version has been deployed of **' . $this->application_name . '**. +[Application Link](' . $this->fqdn . ') | [Deployment logs](' . $this->deployment_url . ')'; + } +} diff --git a/app/Notifications/Notifications/TestNotification.php b/app/Notifications/Notifications/TestNotification.php index e953c3c61..9f535e0a3 100644 --- a/app/Notifications/Notifications/TestNotification.php +++ b/app/Notifications/Notifications/TestNotification.php @@ -15,20 +15,26 @@ class TestNotification extends Notification implements ShouldQueue public function via(object $notifiable): array { $channels = []; - $notifiable->extra_attributes?->get('smtp_active') && $channels[] = EmailChannel::class; - $notifiable->extra_attributes?->get('discord_active') && $channels[] = DiscordChannel::class; + if ($notifiable->extra_attributes?->get('email_active') && $notifiable->extra_attributes?->get('notifications_test')) { + $channels[] = EmailChannel::class; + } + if ($notifiable->extra_attributes?->get('discord_active') && $notifiable->extra_attributes?->get('notifications_test')) { + $channels[] = DiscordChannel::class; + } return $channels; } public function toMail(): MailMessage { - return (new MailMessage) - ->subject('Coolify Test Notification') - ->line('Congratulations!') - ->line('You have successfully received a test Email notification from Coolify. 🥳'); + $mail = new MailMessage(); + $mail->subject("Coolify Test Notification"); + $mail->view('emails.test'); + return $mail; } public function toDiscord(): string { - return 'You have successfully received a test Discord notification from Coolify. 🥳 [Go to your dashboard](' . base_url() . ')'; + return 'This is a test Discord notification from Coolify. + +[Go to your dashboard](' . base_url() . ')'; } } diff --git a/database/seeders/InstanceSettingsSeeder.php b/database/seeders/InstanceSettingsSeeder.php index 959d0c49c..937e147ab 100644 --- a/database/seeders/InstanceSettingsSeeder.php +++ b/database/seeders/InstanceSettingsSeeder.php @@ -2,6 +2,7 @@ namespace Database\Seeders; +use App\Data\SmtpConfiguration; use App\Models\InstanceSettings; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\Process; @@ -16,14 +17,14 @@ class InstanceSettingsSeeder extends Seeder InstanceSettings::create([ 'id' => 0, 'is_registration_enabled' => true, - 'extra_attributes' => [ + 'extra_attributes' => SmtpConfiguration::from([ 'smtp_active' => true, 'smtp_test_recipients' => 'test@example.com,test2@example.com', 'smtp_host' => 'coolify-mail', 'smtp_port' => 1025, 'smtp_from_address' => 'hi@localhost.com', 'smtp_from_name' => 'Coolify', - ] + ]) ]); try { $ipv4 = Process::run('curl -4s https://ifconfig.io')->output(); diff --git a/resources/views/components/forms/checkbox.blade.php b/resources/views/components/forms/checkbox.blade.php index b734736d7..0ab5c22ef 100644 --- a/resources/views/components/forms/checkbox.blade.php +++ b/resources/views/components/forms/checkbox.blade.php @@ -35,5 +35,5 @@
+ @if ($instantSave) wire:click='{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}' wire:model.defer={{ $id }} @else wire:model.defer={{ $value ?? $id }} @endif /> diff --git a/resources/views/components/notification-subscription.blade.php b/resources/views/components/notification-subscription.blade.php new file mode 100644 index 000000000..781220867 --- /dev/null +++ b/resources/views/components/notification-subscription.blade.php @@ -0,0 +1,9 @@ +

Subscribe to events

+
+ @if (isDev()) + + @endif + +
diff --git a/resources/views/emails/application-deployed.blade.php b/resources/views/emails/application-deployed.blade.php new file mode 100644 index 000000000..ee5a11a10 --- /dev/null +++ b/resources/views/emails/application-deployed.blade.php @@ -0,0 +1,7 @@ +Hello,

+ +A new version of your application "{{ $name }}" has been deployed to {{ $fqdn }}

+ +Click the following link to view the deployment logs: View + Deployment

diff --git a/resources/views/emails/test.blade.php b/resources/views/emails/test.blade.php index 9c931db19..c06e333f0 100644 --- a/resources/views/emails/test.blade.php +++ b/resources/views/emails/test.blade.php @@ -1 +1,3 @@ -Hello from test email. If you are seeing this, it means that your SMTP settings are working. +Hello,

+ +If you are seeing this, it means that your SMTP settings are correct. diff --git a/resources/views/livewire/notifications/discord-settings.blade.php b/resources/views/livewire/notifications/discord-settings.blade.php index 6272608ce..aa66c5ff4 100644 --- a/resources/views/livewire/notifications/discord-settings.blade.php +++ b/resources/views/livewire/notifications/discord-settings.blade.php @@ -12,11 +12,12 @@ @endif -
+
+
diff --git a/resources/views/livewire/notifications/email-settings.blade.php b/resources/views/livewire/notifications/email-settings.blade.php index 0f1939c9b..81c1b78ba 100644 --- a/resources/views/livewire/notifications/email-settings.blade.php +++ b/resources/views/livewire/notifications/email-settings.blade.php @@ -17,7 +17,7 @@ @endif -
+
@@ -53,4 +53,5 @@
+