where('is_featured', true)->orderByDesc('published_at')->first() ?? SonarDeskRelease::published()->where('channel', 'stable')->orderByDesc('published_at')->orderByDesc('id')->first(); $releases = SonarDeskRelease::published() ->when($latest, fn ($query) => $query->whereKeyNot($latest->getKey())) ->orderByDesc('published_at')->paginate(12); $settings = $this->settings(); $products = DownloadProduct::where('is_published', true)->whereNotNull('file_path') ->when($latest, fn ($query) => $query->whereRaw('LOWER(name) <> ?', ['sonardesk'])) ->orderBy('name')->get(); return view('downloads.index', compact('latest', 'releases', 'settings', 'products')); } public function sonarDeskDetails() { $latest = SonarDeskRelease::published()->where('is_featured', true)->orderByDesc('published_at')->first() ?? SonarDeskRelease::published()->where('channel', 'stable')->orderByDesc('published_at')->orderByDesc('id')->firstOrFail(); $settings = $this->settings(); return view('downloads.sonardesk', compact('latest', 'settings')); } public function latest(): BinaryFileResponse { $release = SonarDeskRelease::published()->where('channel', 'stable')->orderByDesc('published_at')->firstOrFail(); return $this->send($release); } public function download(SonarDeskRelease $release): BinaryFileResponse { abort_unless($release->is_published && $release->published_at && $release->file_path, 404); return $this->send($release); } public function productDetails(DownloadProduct $product) { abort_unless($product->is_published && $product->file_path, 404); return view('downloads.product', compact('product')); } public function productDownload(DownloadProduct $product): BinaryFileResponse { abort_unless($product->is_published && $product->file_path && Storage::disk('local')->exists($product->file_path), 404); $product->increment('download_count'); return response()->download(Storage::disk('local')->path($product->file_path), $product->original_filename); } public function appcast(): Response { $releases = SonarDeskRelease::published()->where('channel', 'stable')->orderByDesc('published_at')->limit(20)->get(); return response()->view('downloads.appcast', compact('releases'), 200, ['Content-Type' => 'application/rss+xml; charset=UTF-8']); } private function send(SonarDeskRelease $release): BinaryFileResponse { abort_unless(Storage::disk('local')->exists($release->file_path), 404); $release->increment('download_count'); return response()->download(Storage::disk('local')->path($release->file_path), $release->original_filename ?: 'SonarDesk-'.$release->version.'.dmg'); } private function settings(): array { return [ 'eyebrow' => SiteSetting::valueFor('downloads.eyebrow', 'SonarDesk for macOS'), 'title' => SiteSetting::valueFor('downloads.title', 'Download SonarDesk'), 'intro' => SiteSetting::valueFor('downloads.intro', 'A focused native SonarQube workspace, designed for macOS and built for daily engineering work.'), 'requirements' => SiteSetting::valueFor('downloads.requirements', 'Apple silicon and Intel Macs supported. A SonarQube server and valid SonarDesk licence are required.'), 'support_text' => SiteSetting::valueFor('downloads.support_text', 'Need help installing or activating SonarDesk? Our support team can help.'), ]; } }