diff --git a/app/Notifications/Application/RestartLimitReached.php b/app/Notifications/Application/RestartLimitReached.php index 687fd30867..de9de1f981 100644 --- a/app/Notifications/Application/RestartLimitReached.php +++ b/app/Notifications/Application/RestartLimitReached.php @@ -2,8 +2,11 @@ namespace App\Notifications\Application; +use App\Models\Application; use App\Models\ApplicationPreview; use App\Models\BaseModel; +use App\Models\ServiceApplication; +use App\Models\ServiceDatabase; use App\Notifications\CustomEmailNotification; use App\Notifications\Dto\DiscordMessage; use App\Notifications\Dto\PushoverMessage; @@ -49,14 +52,19 @@ class RestartLimitReached extends CustomEmailNotification if (str($this->fqdn)->explode(',')->count() > 1) { $this->fqdn = str($this->fqdn)->explode(',')->first(); } - $service = data_get($resource, 'service'); - $this->resource_url = match (true) { - method_exists($this->resource, 'link') => $this->resource->link(), - $resource instanceof ApplicationPreview => $resource->application->link(), - is_object($service) && method_exists($service, 'link') => $service->link(), - default => null, + $this->resource_url = $this->resolveResourceUrl($resource); + } + + private function resolveResourceUrl(BaseModel $resource): string + { + [$type, $uuid] = match (true) { + $resource instanceof Application => ['application', $resource->uuid], + $resource instanceof ApplicationPreview => ['application', $resource->application->uuid], + $resource instanceof ServiceApplication, $resource instanceof ServiceDatabase => ['service', $resource->service->uuid], + default => ['database', $resource->uuid], }; - $this->resource_url ??= base_url()."/project/{$this->project_uuid}/environment/{$this->environment_uuid}"; + + return base_url()."/project/{$this->project_uuid}/environment/{$this->environment_uuid}/{$type}/{$uuid}"; } public function via(object $notifiable): array diff --git a/tests/Feature/ApplicationStoppedAfterRestartLimitTest.php b/tests/Feature/ApplicationStoppedAfterRestartLimitTest.php index 3e6e04629d..58ebb8c703 100644 --- a/tests/Feature/ApplicationStoppedAfterRestartLimitTest.php +++ b/tests/Feature/ApplicationStoppedAfterRestartLimitTest.php @@ -6,10 +6,21 @@ use App\Jobs\ApplicationDeploymentJob; use App\Models\Application; use App\Models\ApplicationPreview; use App\Models\BaseModel; +use App\Models\InstanceSettings; use App\Models\Server; +use App\Models\Service; +use App\Models\ServiceApplication; +use App\Models\StandalonePostgresql; use App\Notifications\Application\RestartLimitReached; +use Illuminate\Foundation\Testing\RefreshDatabase; use Mockery\MockInterface; +uses(RefreshDatabase::class); + +beforeEach(function () { + InstanceSettings::forceCreate(['id' => 0, 'fqdn' => 'https://coolify.test']); +}); + function applicationWithRestartState(array $attributes = []): Application { $application = new Application; @@ -161,14 +172,8 @@ it('preserves restart-limit applications only while their exited container exist ->and($sentinelJob)->toContain('if ($application->stoppedAfterRestartLimit() && $containerStatuses->every('); }); -it('uses the application link for restart limit notifications', function () { - $application = new class extends Application - { - public function link() - { - return 'https://coolify.test/project/link-from-model'; - } - }; +it('builds restart limit notification urls from the instance base url', function () { + $application = new Application; $application->forceFill([ 'name' => 'crashy-app', 'uuid' => 'application-uuid', @@ -183,7 +188,33 @@ it('uses the application link for restart limit notifications', function () { $notification = new RestartLimitReached($application); - expect($notification->resource_url)->toBe('https://coolify.test/project/link-from-model'); + expect($notification->resource_url)->toBe('https://coolify.test/project/project-uuid/environment/environment-uuid/application/application-uuid'); +}); + +it('links preview, service resource and database restart limit notifications to their pages', function () { + $environment = (object) ['uuid' => 'environment-uuid', 'name' => 'production', 'project' => (object) ['uuid' => 'project-uuid']]; + + $application = new Application; + $application->forceFill(['name' => 'app', 'uuid' => 'application-uuid']); + $application->setRelation('environment', $environment); + $preview = new ApplicationPreview; + $preview->forceFill(['uuid' => 'preview-uuid', 'pull_request_id' => 42, 'restart_count' => 2, 'max_restart_count' => 2]); + $preview->setRelation('application', $application); + + $service = new Service; + $service->forceFill(['uuid' => 'service-uuid']); + $service->setRelation('environment', $environment); + $serviceApplication = new ServiceApplication; + $serviceApplication->forceFill(['name' => 'database', 'uuid' => 'service-application-uuid', 'restart_count' => 2, 'max_restart_count' => 2]); + $serviceApplication->setRelation('service', $service); + + $database = new StandalonePostgresql; + $database->forceFill(['name' => 'postgres', 'uuid' => 'database-uuid', 'restart_count' => 2, 'max_restart_count' => 2]); + $database->setRelation('environment', $environment); + + expect((new RestartLimitReached($preview))->resource_url)->toBe('https://coolify.test/project/project-uuid/environment/environment-uuid/application/application-uuid') + ->and((new RestartLimitReached($serviceApplication))->resource_url)->toBe('https://coolify.test/project/project-uuid/environment/environment-uuid/service/service-uuid') + ->and((new RestartLimitReached($database))->resource_url)->toBe('https://coolify.test/project/project-uuid/environment/environment-uuid/database/database-uuid'); }); it('uses the resolved environment project name in Slack restart limit notifications', function () {