From 817fe088cf990cbf9c99febce805b0c53f8a28c8 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Mon, 13 Apr 2026 01:36:04 +0100 Subject: [PATCH] Show license preview page for admins and plugin owners Allow admins and plugin authors to view the license page for paid plugins before they are approved, matching the existing preview behavior on the plugin show page. Adds an amber preview banner explaining the plugin's visibility status. Co-Authored-By: Claude Opus 4.6 --- .../Controllers/PluginDirectoryController.php | 14 +- resources/views/plugin-license.blade.php | 13 ++ tests/Feature/PluginLicensePreviewTest.php | 171 ++++++++++++++++++ 3 files changed, 193 insertions(+), 5 deletions(-) create mode 100644 tests/Feature/PluginLicensePreviewTest.php diff --git a/app/Http/Controllers/PluginDirectoryController.php b/app/Http/Controllers/PluginDirectoryController.php index 6e2496bb..6b71c4bb 100644 --- a/app/Http/Controllers/PluginDirectoryController.php +++ b/app/Http/Controllers/PluginDirectoryController.php @@ -85,19 +85,23 @@ public function license(string $vendor, string $package): View { $plugin = Plugin::findByVendorPackageOrFail($vendor, $package); - abort_unless($plugin->isApproved(), 404); + $user = Auth::user(); + + $isAdmin = $user?->isAdmin() ?? false; + $isOwner = $user && $plugin->user_id === $user->id; + abort_unless($plugin->isPaid(), 404); abort_unless($plugin->license_html, 404); + abort_unless(($plugin->isApproved() && $plugin->is_active) || $isAdmin || $isOwner, 404); - $user = Auth::user(); - - // For paid plugins, check if user has an accessible price - if (! $plugin->hasAccessiblePriceFor($user)) { + // For paid plugins, check if user has an accessible price (admins and owners bypass) + if (! $isAdmin && ! $isOwner && ! $plugin->hasAccessiblePriceFor($user)) { abort(404); } return view('plugin-license', [ 'plugin' => $plugin, + 'isAdminPreview' => (! $plugin->isApproved() || ! $plugin->is_active) && ($isAdmin || $isOwner), ]); } } diff --git a/resources/views/plugin-license.blade.php b/resources/views/plugin-license.blade.php index 91d9c589..d4e78b1a 100644 --- a/resources/views/plugin-license.blade.php +++ b/resources/views/plugin-license.blade.php @@ -3,6 +3,19 @@ class="mx-auto mt-10 w-full max-w-3xl px-5 md:mt-14" aria-labelledby="license-title" > + @if ($isAdminPreview ?? false) +
+

+ Preview — This plugin is not publicly visible. + @if ($plugin->isApproved() && ! $plugin->is_active) + It has been de-listed. + @else + Status: {{ $plugin->status->label() }} + @endif +

+
+ @endif +
{{-- Back button --}}
paid() + ->create(array_merge([ + 'license_html' => '

License agreement content

', + ], $pluginAttributes)); + + PluginPrice::factory()->regular()->create([ + 'plugin_id' => $plugin->id, + 'amount' => 2999, + ]); + + return $plugin; + } + + public function test_guest_cannot_view_pending_paid_plugin_license(): void + { + $plugin = $this->createPaidPluginWithLicense(); + + $this->get(route('plugins.license', $plugin->routeParams())) + ->assertStatus(404); + } + + public function test_regular_user_cannot_view_pending_paid_plugin_license(): void + { + $user = User::factory()->create(); + $plugin = $this->createPaidPluginWithLicense(); + + $this->actingAs($user) + ->get(route('plugins.license', $plugin->routeParams())) + ->assertStatus(404); + } + + public function test_admin_can_view_pending_paid_plugin_license(): void + { + $admin = User::factory()->create(['email' => 'admin@test.com']); + config(['filament.users' => ['admin@test.com']]); + + $plugin = $this->createPaidPluginWithLicense(); + + $this->actingAs($admin) + ->get(route('plugins.license', $plugin->routeParams())) + ->assertStatus(200); + } + + public function test_owner_can_view_pending_paid_plugin_license(): void + { + $owner = User::factory()->create(); + $plugin = $this->createPaidPluginWithLicense(['user_id' => $owner->id]); + + $this->actingAs($owner) + ->get(route('plugins.license', $plugin->routeParams())) + ->assertStatus(200); + } + + public function test_admin_sees_preview_banner_on_pending_paid_plugin_license(): void + { + $admin = User::factory()->create(['email' => 'admin@test.com']); + config(['filament.users' => ['admin@test.com']]); + + $plugin = $this->createPaidPluginWithLicense(); + + $this->actingAs($admin) + ->get(route('plugins.license', $plugin->routeParams())) + ->assertSee('Preview') + ->assertSee('This plugin is not publicly visible') + ->assertSee('Pending Review'); + } + + public function test_owner_sees_preview_banner_on_pending_paid_plugin_license(): void + { + $owner = User::factory()->create(); + $plugin = $this->createPaidPluginWithLicense(['user_id' => $owner->id]); + + $this->actingAs($owner) + ->get(route('plugins.license', $plugin->routeParams())) + ->assertSee('Preview') + ->assertSee('This plugin is not publicly visible') + ->assertSee('Pending Review'); + } + + public function test_approved_paid_plugin_license_does_not_show_preview_banner(): void + { + $plugin = $this->createPaidPluginWithLicense(['status' => 'approved', 'approved_at' => now()]); + + $this->get(route('plugins.license', $plugin->routeParams())) + ->assertStatus(200) + ->assertDontSee('This plugin is not publicly visible'); + } + + public function test_admin_sees_preview_banner_on_delisted_paid_plugin_license(): void + { + $admin = User::factory()->create(['email' => 'admin@test.com']); + config(['filament.users' => ['admin@test.com']]); + + $plugin = $this->createPaidPluginWithLicense([ + 'status' => 'approved', + 'approved_at' => now(), + 'is_active' => false, + ]); + + $this->actingAs($admin) + ->get(route('plugins.license', $plugin->routeParams())) + ->assertSee('Preview') + ->assertSee('It has been de-listed'); + } + + public function test_guest_cannot_view_delisted_paid_plugin_license(): void + { + $plugin = $this->createPaidPluginWithLicense([ + 'status' => 'approved', + 'approved_at' => now(), + 'is_active' => false, + ]); + + $this->get(route('plugins.license', $plugin->routeParams())) + ->assertStatus(404); + } + + public function test_free_plugin_license_returns_404(): void + { + $plugin = Plugin::factory()->approved()->free()->create([ + 'license_html' => '

License content

', + ]); + + $this->get(route('plugins.license', $plugin->routeParams())) + ->assertStatus(404); + } + + public function test_paid_plugin_without_license_html_returns_404(): void + { + $admin = User::factory()->create(['email' => 'admin@test.com']); + config(['filament.users' => ['admin@test.com']]); + + $plugin = Plugin::factory()->pending()->paid()->create([ + 'license_html' => null, + ]); + + PluginPrice::factory()->regular()->create([ + 'plugin_id' => $plugin->id, + ]); + + $this->actingAs($admin) + ->get(route('plugins.license', $plugin->routeParams())) + ->assertStatus(404); + } +}