move into sonardesk

This commit is contained in:
Mark Gregory
2026-10-12 15:24:46 +01:00
parent 729b78ddb9
commit 0ca7a2cf1e
14 changed files with 116 additions and 1 deletions
@@ -0,0 +1,13 @@
<?php
namespace Modules\Licensing\Http\Controllers\Admin;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rule;
use Modules\Licensing\Models\{SonarDeskRelease,DownloadProduct};
final class DistributionAdminController extends Controller {
public function index(){return view('licensing::distribution.admin', ['releases'=>SonarDeskRelease::orderByDesc('created_at')->paginate(20),'products'=>DownloadProduct::orderBy('name')->get()]);}
public function release(Request $request){$data=$request->validate(['version'=>'required|string|max:40','build_number'=>'required|integer|min:1','channel'=>['required',Rule::in(['stable','beta'])],'minimum_macos'=>'nullable|string|max:30','release_notes'=>'nullable|string','sparkle_signature'=>'nullable|string|max:2048','is_published'=>'nullable|boolean','is_featured'=>'nullable|boolean','file'=>'required|file|max:512000|mimes:dmg,zip,pkg']);$file=$request->file('file');$path=$file->store('sonardesk-distribution/releases','local');$release=SonarDeskRelease::create(['version'=>$data['version'],'build_number'=>$data['build_number'],'channel'=>$data['channel'],'minimum_macos'=>$data['minimum_macos']??null,'release_notes'=>$data['release_notes']??null,'sparkle_signature'=>$data['sparkle_signature']??null,'file_path'=>$path,'original_filename'=>$file->getClientOriginalName(),'file_size'=>$file->getSize(),'sha256'=>hash_file('sha256',$file->getRealPath()),'is_published'=>(bool)($data['is_published']??false),'is_featured'=>(bool)($data['is_featured']??false),'published_at'=>!empty($data['is_published'])?now():null]);return redirect()->route('administration.sonardesk.distribution')->with('status','Release '.$release->version.' created');}
public function product(Request $request){$data=$request->validate(['name'=>'required|string|max:150','description'=>'nullable|string','version'=>'nullable|string|max:60','platform'=>'nullable|string|max:60','is_published'=>'nullable|boolean','file'=>'required|file|max:512000']);$file=$request->file('file');$path=$file->store('sonardesk-distribution/products','local');DownloadProduct::create(['name'=>$data['name'],'description'=>$data['description']??null,'version'=>$data['version']??null,'platform'=>$data['platform']??null,'file_path'=>$path,'original_filename'=>$file->getClientOriginalName(),'file_size'=>$file->getSize(),'is_published'=>(bool)($data['is_published']??false)]);return redirect()->route('administration.sonardesk.distribution')->with('status','Download created');}
public function publish(Request $request,SonarDeskRelease $release){$data=$request->validate(['is_published'=>'required|boolean']);$release->update(['is_published'=>(bool)$data['is_published'],'published_at'=>$data['is_published']?($release->published_at??now()):null]);return back()->with('status','Release status updated');}
}
@@ -0,0 +1,17 @@
<?php
namespace Modules\Licensing\Http\Controllers;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Storage;
use Modules\Licensing\Models\{SonarDeskRelease,DownloadProduct};
use Symfony\Component\HttpFoundation\BinaryFileResponse;
final class DistributionController extends Controller {
public function index(){ $latest=SonarDeskRelease::published()->where('channel','stable')->orderByDesc('published_at')->first(); $releases=SonarDeskRelease::published()->orderByDesc('published_at')->paginate(12);$products=DownloadProduct::where('is_published',true)->whereNotNull('file_path')->orderBy('name')->get();return view('licensing::downloads.index',compact('latest','releases','products')); }
public function release(SonarDeskRelease $release){abort_unless($release->is_published && $release->published_at && $release->file_path,404);return view('licensing::downloads.release',compact('release'));}
public function product(DownloadProduct $product){abort_unless($product->is_published && $product->file_path,404);return view('licensing::downloads.product',compact('product'));}
public function latest():BinaryFileResponse{$r=SonarDeskRelease::published()->where('channel','stable')->orderByDesc('published_at')->firstOrFail();return $this->send($r);}
public function download(SonarDeskRelease $release):BinaryFileResponse{abort_unless($release->is_published && $release->published_at,404);return $this->send($release);}
public function productDownload(DownloadProduct $product):BinaryFileResponse{abort_unless($product->is_published,404);$path=$this->safePath($product->file_path);$product->increment('download_count');return response()->download($path,$product->original_filename ?: basename($path));}
private function safePath(?string $relative):string {abort_unless($relative && preg_match('~^sonardesk-distribution/[a-zA-Z0-9_./-]+$~D',$relative) && !str_contains($relative,'..'),404);$disk=Storage::disk('local');abort_unless($disk->exists($relative),404);$base=realpath($disk->path('sonardesk-distribution'));$file=realpath($disk->path($relative));abort_unless($base && $file && str_starts_with($file,$base.DIRECTORY_SEPARATOR),404);return $file;}
private function send(SonarDeskRelease $r):BinaryFileResponse{$path=$this->safePath($r->file_path);$r->increment('download_count');return response()->download($path,$r->original_filename ?: 'SonarDesk-'.$r->version.'.dmg');}
public function appcast(){ $releases=SonarDeskRelease::published()->where('channel','stable')->whereNotNull('sparkle_signature')->orderByDesc('published_at')->limit(20)->get();return response()->view('licensing::downloads.appcast',compact('releases'),200,['Content-Type'=>'application/rss+xml; charset=UTF-8','Cache-Control'=>'public, max-age=300']); }
}