updates
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\SiteSetting;
|
||||
use App\Models\SonarDeskRelease;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
final class ReleaseController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('admin.releases.index', [
|
||||
'releases' => SonarDeskRelease::latest()->paginate(30),
|
||||
'publishedCount' => SonarDeskRelease::where('is_published', true)->count(),
|
||||
'downloadCount' => SonarDeskRelease::sum('download_count'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create() { return view('admin.releases.form', ['release' => new SonarDeskRelease]); }
|
||||
public function edit(SonarDeskRelease $release) { return view('admin.releases.form', compact('release')); }
|
||||
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$release = new SonarDeskRelease;
|
||||
$this->persist($request, $release);
|
||||
return redirect()->route('admin.releases.index')->with('status', 'Release created.');
|
||||
}
|
||||
|
||||
public function update(Request $request, SonarDeskRelease $release): RedirectResponse
|
||||
{
|
||||
$this->persist($request, $release);
|
||||
return redirect()->route('admin.releases.index')->with('status', 'Release updated.');
|
||||
}
|
||||
|
||||
public function destroy(SonarDeskRelease $release): RedirectResponse
|
||||
{
|
||||
if ($release->file_path) Storage::disk('local')->delete($release->file_path);
|
||||
$release->delete();
|
||||
return back()->with('status', 'Release deleted.');
|
||||
}
|
||||
|
||||
public function settings()
|
||||
{
|
||||
$keys = ['downloads.eyebrow','downloads.title','downloads.intro','downloads.requirements','downloads.support_text'];
|
||||
$settings = collect($keys)->mapWithKeys(fn ($key) => [$key => SiteSetting::valueFor($key)]);
|
||||
return view('admin.releases.settings', compact('settings'));
|
||||
}
|
||||
|
||||
public function updateSettings(Request $request): RedirectResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'eyebrow' => ['required','string','max:80'], 'title' => ['required','string','max:120'],
|
||||
'intro' => ['required','string','max:500'], 'requirements' => ['required','string','max:500'],
|
||||
'support_text' => ['required','string','max:500'],
|
||||
]);
|
||||
foreach ($data as $key => $value) SiteSetting::put('downloads.'.$key, $value);
|
||||
return back()->with('status', 'Download page content updated.');
|
||||
}
|
||||
|
||||
private function persist(Request $request, SonarDeskRelease $release): void
|
||||
{
|
||||
$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','max:20000'], 'sparkle_signature' => ['nullable','string','max:2000'],
|
||||
'package' => [
|
||||
$release->exists ? 'nullable' : 'required',
|
||||
'file',
|
||||
'max:1048576',
|
||||
function (string $attribute, $value, \Closure $fail): void {
|
||||
$extension = strtolower($value->getClientOriginalExtension());
|
||||
if (! in_array($extension, ['dmg', 'zip'], true)) {
|
||||
$fail('The package must be a DMG or ZIP file.');
|
||||
}
|
||||
},
|
||||
],
|
||||
'is_published' => ['nullable','boolean'], 'is_featured' => ['nullable','boolean'],
|
||||
]);
|
||||
$data['is_published'] = $request->boolean('is_published');
|
||||
$data['is_featured'] = $request->boolean('is_featured');
|
||||
if ($data['is_featured']) SonarDeskRelease::query()->update(['is_featured' => false]);
|
||||
|
||||
if ($request->hasFile('package')) {
|
||||
if ($release->file_path) Storage::disk('local')->delete($release->file_path);
|
||||
$file = $request->file('package');
|
||||
$path = $file->store('sonardesk/releases', 'local');
|
||||
$data['file_path'] = $path;
|
||||
$data['original_filename'] = $file->getClientOriginalName();
|
||||
$data['file_size'] = $file->getSize();
|
||||
$data['sha256'] = hash_file('sha256', $file->getRealPath());
|
||||
}
|
||||
unset($data['package']);
|
||||
$data['published_at'] = $data['is_published'] ? ($release->published_at ?: now()) : null;
|
||||
$release->fill($data)->save();
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,10 @@ final class CheckoutController extends Controller
|
||||
}
|
||||
|
||||
$plans = [
|
||||
'personal-monthly' => ['name' => 'Personal', 'billing' => 'Monthly', 'display_price' => '£2.99 / month', 'price_id' => $paddle['personal_monthly_price_id'], 'activation_limit' => 1],
|
||||
'personal-annual' => ['name' => 'Personal', 'billing' => 'Annual', 'display_price' => '£24.99 / year', 'price_id' => $paddle['personal_annual_price_id'], 'activation_limit' => 1],
|
||||
'professional-monthly' => ['name' => 'Professional', 'billing' => 'Monthly', 'display_price' => '£4.99 / month', 'price_id' => $paddle['professional_monthly_price_id'], 'activation_limit' => 3],
|
||||
'professional-annual' => ['name' => 'Professional', 'billing' => 'Annual', 'display_price' => '£44.99 / year', 'price_id' => $paddle['professional_annual_price_id'], 'activation_limit' => 3],
|
||||
'personal-monthly' => ['name' => 'Personal', 'billing' => 'Monthly', 'display_price' => '£4.99 / month', 'price_id' => $paddle['personal_monthly_price_id'], 'activation_limit' => 1],
|
||||
'personal-annual' => ['name' => 'Personal', 'billing' => 'Annual', 'display_price' => '£39.99 / year', 'price_id' => $paddle['personal_annual_price_id'], 'activation_limit' => 1],
|
||||
'professional-monthly' => ['name' => 'Professional', 'billing' => 'Monthly', 'display_price' => '£8.99 / month', 'price_id' => $paddle['professional_monthly_price_id'], 'activation_limit' => 3],
|
||||
'professional-annual' => ['name' => 'Professional', 'billing' => 'Annual', 'display_price' => '£79.99 / year', 'price_id' => $paddle['professional_annual_price_id'], 'activation_limit' => 3],
|
||||
];
|
||||
|
||||
foreach ($plans as $plan) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\SiteSetting;
|
||||
use App\Models\SonarDeskRelease;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
final class ReleaseController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$latest = SonarDeskRelease::published()->where('is_featured', true)->orderByDesc('published_at')->first()
|
||||
?? SonarDeskRelease::published()->where('channel', 'stable')->orderByDesc('published_at')->orderByDesc('id')->first();
|
||||
$releases = SonarDeskRelease::published()->orderByDesc('published_at')->paginate(12);
|
||||
$settings = $this->settings();
|
||||
|
||||
return view('downloads.index', compact('latest', 'releases', '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 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.'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user