From 4b119726d97eab2d5c25dc38871d40ccadfd1d58 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:08:40 +0100 Subject: [PATCH] Fix Traefik email notification with clickable server links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add URL generation to notification class using base_url() helper - Replace config('app.url') with proper base_url() for accurate instance URL - Make server names clickable links to proxy configuration page - Use data_get() with fallback values for safer template data access - Add comprehensive tests for URL generation and email rendering 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Server/TraefikVersionOutdated.php | 12 ++- .../emails/traefik-version-outdated.blade.php | 30 ++++--- tests/Feature/CheckTraefikVersionJobTest.php | 87 +++++++++++++++++++ 3 files changed, 115 insertions(+), 14 deletions(-) diff --git a/app/Notifications/Server/TraefikVersionOutdated.php b/app/Notifications/Server/TraefikVersionOutdated.php index 09ef4257d..c94cc1732 100644 --- a/app/Notifications/Server/TraefikVersionOutdated.php +++ b/app/Notifications/Server/TraefikVersionOutdated.php @@ -43,9 +43,19 @@ public function toMail($notifiable = null): MailMessage $mail = new MailMessage; $count = $this->servers->count(); + // Transform servers to include URLs + $serversWithUrls = $this->servers->map(function ($server) { + return [ + 'name' => $server->name, + 'uuid' => $server->uuid, + 'url' => base_url().'/server/'.$server->uuid.'/proxy', + 'outdatedInfo' => $server->outdatedInfo ?? [], + ]; + }); + $mail->subject("Coolify: Traefik proxy outdated on {$count} server(s)"); $mail->view('emails.traefik-version-outdated', [ - 'servers' => $this->servers, + 'servers' => $serversWithUrls, 'count' => $count, ]); diff --git a/resources/views/emails/traefik-version-outdated.blade.php b/resources/views/emails/traefik-version-outdated.blade.php index 28effabf3..91c627a73 100644 --- a/resources/views/emails/traefik-version-outdated.blade.php +++ b/resources/views/emails/traefik-version-outdated.blade.php @@ -5,10 +5,12 @@ @foreach ($servers as $server) @php - $info = $server->outdatedInfo ?? []; - $current = $info['current'] ?? 'unknown'; - $latest = $info['latest'] ?? 'unknown'; - $isPatch = ($info['type'] ?? 'patch_update') === 'patch_update'; + $serverName = data_get($server, 'name', 'Unknown Server'); + $serverUrl = data_get($server, 'url', '#'); + $info = data_get($server, 'outdatedInfo', []); + $current = data_get($info, 'current', 'unknown'); + $latest = data_get($info, 'latest', 'unknown'); + $isPatch = (data_get($info, 'type', 'patch_update') === 'patch_update'); $hasNewerBranch = isset($info['newer_branch_target']); $hasUpgrades = $hasUpgrades ?? false; if (!$isPatch || $hasNewerBranch) { @@ -19,8 +21,9 @@ $latest = str_starts_with($latest, 'v') ? $latest : "v{$latest}"; // For minor upgrades, use the upgrade_target (e.g., "v3.6") - if (!$isPatch && isset($info['upgrade_target'])) { - $upgradeTarget = str_starts_with($info['upgrade_target'], 'v') ? $info['upgrade_target'] : "v{$info['upgrade_target']}"; + if (!$isPatch && data_get($info, 'upgrade_target')) { + $upgradeTarget = data_get($info, 'upgrade_target'); + $upgradeTarget = str_starts_with($upgradeTarget, 'v') ? $upgradeTarget : "v{$upgradeTarget}"; } else { // For patch updates, show the full version $upgradeTarget = $latest; @@ -28,22 +31,23 @@ // Get newer branch info if available if ($hasNewerBranch) { - $newerBranchTarget = $info['newer_branch_target']; - $newerBranchLatest = str_starts_with($info['newer_branch_latest'], 'v') ? $info['newer_branch_latest'] : "v{$info['newer_branch_latest']}"; + $newerBranchTarget = data_get($info, 'newer_branch_target', 'unknown'); + $newerBranchLatest = data_get($info, 'newer_branch_latest', 'unknown'); + $newerBranchLatest = str_starts_with($newerBranchLatest, 'v') ? $newerBranchLatest : "v{$newerBranchLatest}"; } @endphp @if ($isPatch && $hasNewerBranch) -- **{{ $server->name }}**: {{ $current }} → {{ $upgradeTarget }} (patch update available) | Also available: {{ $newerBranchTarget }} (latest patch: {{ $newerBranchLatest }}) - new minor version +- [**{{ $serverName }}**]({{ $serverUrl }}): {{ $current }} → {{ $upgradeTarget }} (patch update available) | Also available: {{ $newerBranchTarget }} (latest patch: {{ $newerBranchLatest }}) - new minor version @elseif ($isPatch) -- **{{ $server->name }}**: {{ $current }} → {{ $upgradeTarget }} (patch update available) +- [**{{ $serverName }}**]({{ $serverUrl }}): {{ $current }} → {{ $upgradeTarget }} (patch update available) @else -- **{{ $server->name }}**: {{ $current }} (latest patch: {{ $latest }}) → {{ $upgradeTarget }} (new minor version available) +- [**{{ $serverName }}**]({{ $serverUrl }}): {{ $current }} (latest patch: {{ $latest }}) → {{ $upgradeTarget }} (new minor version available) @endif @endforeach ## Recommendation -It is recommended to test the new Traefik version before switching it in production environments. You can update your proxy configuration through your [Coolify Dashboard]({{ config('app.url') }}). +It is recommended to test the new Traefik version before switching it in production environments. You can update your proxy configuration by clicking on any server name above. @if ($hasUpgrades ?? false) **Important for minor version upgrades:** Before upgrading to a new minor version, please read the [Traefik changelog](https://github.com/traefik/traefik/releases) to understand breaking changes and new features. @@ -58,5 +62,5 @@ --- -You can manage your server proxy settings in your Coolify Dashboard. +Click on any server name above to manage its proxy settings. diff --git a/tests/Feature/CheckTraefikVersionJobTest.php b/tests/Feature/CheckTraefikVersionJobTest.php index b7c5dd50d..cee156485 100644 --- a/tests/Feature/CheckTraefikVersionJobTest.php +++ b/tests/Feature/CheckTraefikVersionJobTest.php @@ -214,3 +214,90 @@ expect($notification->servers)->toHaveCount(1); expect($notification->servers->first()->outdatedInfo['type'])->toBe('patch_update'); }); + +it('notification generates correct server proxy URLs', function () { + $team = Team::factory()->create(); + $server = Server::factory()->create([ + 'name' => 'Test Server', + 'team_id' => $team->id, + 'uuid' => 'test-uuid-123', + ]); + + $server->outdatedInfo = [ + 'current' => '3.5.0', + 'latest' => '3.5.6', + 'type' => 'patch_update', + ]; + + $notification = new TraefikVersionOutdated(collect([$server])); + $mail = $notification->toMail($team); + + // Verify the mail has the transformed servers with URLs + expect($mail->viewData['servers'])->toHaveCount(1); + expect($mail->viewData['servers'][0]['name'])->toBe('Test Server'); + expect($mail->viewData['servers'][0]['uuid'])->toBe('test-uuid-123'); + expect($mail->viewData['servers'][0]['url'])->toBe(base_url().'/server/test-uuid-123/proxy'); + expect($mail->viewData['servers'][0]['outdatedInfo'])->toBeArray(); +}); + +it('notification transforms multiple servers with URLs correctly', function () { + $team = Team::factory()->create(); + $server1 = Server::factory()->create([ + 'name' => 'Server 1', + 'team_id' => $team->id, + 'uuid' => 'uuid-1', + ]); + $server1->outdatedInfo = [ + 'current' => '3.5.0', + 'latest' => '3.5.6', + 'type' => 'patch_update', + ]; + + $server2 = Server::factory()->create([ + 'name' => 'Server 2', + 'team_id' => $team->id, + 'uuid' => 'uuid-2', + ]); + $server2->outdatedInfo = [ + 'current' => '3.4.0', + 'latest' => '3.6.0', + 'type' => 'minor_upgrade', + 'upgrade_target' => 'v3.6', + ]; + + $servers = collect([$server1, $server2]); + $notification = new TraefikVersionOutdated($servers); + $mail = $notification->toMail($team); + + // Verify both servers have URLs + expect($mail->viewData['servers'])->toHaveCount(2); + + expect($mail->viewData['servers'][0]['name'])->toBe('Server 1'); + expect($mail->viewData['servers'][0]['url'])->toBe(base_url().'/server/uuid-1/proxy'); + + expect($mail->viewData['servers'][1]['name'])->toBe('Server 2'); + expect($mail->viewData['servers'][1]['url'])->toBe(base_url().'/server/uuid-2/proxy'); +}); + +it('notification uses base_url helper not config app.url', function () { + $team = Team::factory()->create(); + $server = Server::factory()->create([ + 'name' => 'Test Server', + 'team_id' => $team->id, + 'uuid' => 'test-uuid', + ]); + + $server->outdatedInfo = [ + 'current' => '3.5.0', + 'latest' => '3.5.6', + 'type' => 'patch_update', + ]; + + $notification = new TraefikVersionOutdated(collect([$server])); + $mail = $notification->toMail($team); + + // Verify URL starts with base_url() not config('app.url') + $generatedUrl = $mail->viewData['servers'][0]['url']; + expect($generatedUrl)->toStartWith(base_url()); + expect($generatedUrl)->not->toContain('localhost'); +});