fix(ui): hide tenant-scoped admin nav without tenant
This commit is contained in:
parent
c1eda3b19f
commit
98c7408c00
@ -4,7 +4,11 @@
|
||||
|
||||
use App\Filament\Clusters\Inventory\InventoryCluster;
|
||||
use App\Filament\Widgets\Inventory\InventoryKpiHeader;
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use App\Services\Auth\CapabilityResolver;
|
||||
use App\Services\Inventory\CoverageCapabilitiesResolver;
|
||||
use App\Support\Auth\Capabilities;
|
||||
use App\Support\Inventory\InventoryPolicyTypeMeta;
|
||||
use BackedEnum;
|
||||
use Filament\Pages\Page;
|
||||
@ -24,6 +28,22 @@ class InventoryCoverage extends Page
|
||||
|
||||
protected string $view = 'filament.pages.inventory-coverage';
|
||||
|
||||
public static function canAccess(): bool
|
||||
{
|
||||
$tenant = Tenant::current();
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $tenant instanceof Tenant || ! $user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var CapabilityResolver $resolver */
|
||||
$resolver = app(CapabilityResolver::class);
|
||||
|
||||
return $resolver->isMember($user, $tenant)
|
||||
&& $resolver->can($user, $tenant, Capabilities::TENANT_VIEW);
|
||||
}
|
||||
|
||||
protected function getHeaderWidgets(): array
|
||||
{
|
||||
return [
|
||||
|
||||
@ -49,6 +49,22 @@ class BackupSetResource extends Resource
|
||||
|
||||
protected static string|UnitEnum|null $navigationGroup = 'Backups & Restore';
|
||||
|
||||
public static function canViewAny(): bool
|
||||
{
|
||||
$tenant = Tenant::current();
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $tenant instanceof Tenant || ! $user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var CapabilityResolver $resolver */
|
||||
$resolver = app(CapabilityResolver::class);
|
||||
|
||||
return $resolver->isMember($user, $tenant)
|
||||
&& $resolver->can($user, $tenant, Capabilities::TENANT_VIEW);
|
||||
}
|
||||
|
||||
public static function canCreate(): bool
|
||||
{
|
||||
$tenant = Tenant::current();
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
use App\Models\Policy;
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use App\Services\Auth\CapabilityResolver;
|
||||
use App\Services\Intune\PolicyNormalizer;
|
||||
use App\Services\OperationRunService;
|
||||
use App\Services\Operations\BulkSelectionIdentity;
|
||||
@ -58,6 +59,22 @@ class PolicyResource extends Resource
|
||||
|
||||
protected static string|UnitEnum|null $navigationGroup = 'Inventory';
|
||||
|
||||
public static function canViewAny(): bool
|
||||
{
|
||||
$tenant = Tenant::current();
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $tenant instanceof Tenant || ! $user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var CapabilityResolver $resolver */
|
||||
$resolver = app(CapabilityResolver::class);
|
||||
|
||||
return $resolver->isMember($user, $tenant)
|
||||
&& $resolver->can($user, $tenant, Capabilities::TENANT_VIEW);
|
||||
}
|
||||
|
||||
public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
|
||||
{
|
||||
return ActionSurfaceDeclaration::forResource(ActionSurfaceProfile::CrudListAndView)
|
||||
|
||||
@ -57,6 +57,22 @@ class PolicyVersionResource extends Resource
|
||||
|
||||
protected static string|UnitEnum|null $navigationGroup = 'Inventory';
|
||||
|
||||
public static function canViewAny(): bool
|
||||
{
|
||||
$tenant = Tenant::current();
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $tenant instanceof Tenant || ! $user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var CapabilityResolver $resolver */
|
||||
$resolver = app(CapabilityResolver::class);
|
||||
|
||||
return $resolver->isMember($user, $tenant)
|
||||
&& $resolver->can($user, $tenant, Capabilities::TENANT_VIEW);
|
||||
}
|
||||
|
||||
public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
|
||||
{
|
||||
return ActionSurfaceDeclaration::forResource(ActionSurfaceProfile::CrudListAndView)
|
||||
|
||||
@ -72,6 +72,14 @@ public function handle(Request $request, Closure $next): Response
|
||||
$tenantParameter = $request->query('tenant');
|
||||
}
|
||||
|
||||
if (
|
||||
$tenantParameter === null
|
||||
&& ! filled(Filament::getTenant())
|
||||
&& $this->adminPathRequiresTenantSelection($path)
|
||||
) {
|
||||
return redirect()->route('filament.admin.pages.choose-tenant');
|
||||
}
|
||||
|
||||
if ($tenantParameter !== null) {
|
||||
$user = $request->user();
|
||||
|
||||
@ -208,4 +216,13 @@ private function configureNavigationForRequest(\Filament\Panel $panel): void
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private function adminPathRequiresTenantSelection(string $path): bool
|
||||
{
|
||||
if (! str_starts_with($path, '/admin/')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return preg_match('#^/admin/(inventory|policies|policy-versions|backup-sets)(/|$)#', $path) === 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\Tenant;
|
||||
use App\Models\TenantMembership;
|
||||
use App\Models\User;
|
||||
use App\Models\Workspace;
|
||||
use App\Models\WorkspaceMembership;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('redirects tenant-scoped admin surfaces to choose-tenant when no tenant is selected', function (): void {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$workspace = Workspace::factory()->create();
|
||||
|
||||
WorkspaceMembership::factory()->create([
|
||||
'workspace_id' => $workspace->getKey(),
|
||||
'user_id' => $user->getKey(),
|
||||
'role' => 'owner',
|
||||
]);
|
||||
|
||||
$tenants = Tenant::factory()->count(2)->create([
|
||||
'status' => 'active',
|
||||
'workspace_id' => $workspace->getKey(),
|
||||
]);
|
||||
|
||||
foreach ($tenants as $tenant) {
|
||||
TenantMembership::query()->create([
|
||||
'tenant_id' => $tenant->getKey(),
|
||||
'user_id' => $user->getKey(),
|
||||
'role' => 'owner',
|
||||
'source' => 'manual',
|
||||
'source_ref' => null,
|
||||
'created_by_user_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get('/admin/policies')
|
||||
->assertRedirect('/admin/choose-tenant');
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get('/admin/policy-versions')
|
||||
->assertRedirect('/admin/choose-tenant');
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get('/admin/backup-sets')
|
||||
->assertRedirect('/admin/choose-tenant');
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get('/admin/inventory')
|
||||
->assertRedirect('/admin/choose-tenant');
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user