## Summary - remove legacy tenant-scoped routing and middleware paths in favor of the current environment/workspace context flow - update Filament pages and resources to use the cleaned-up admin surface and environment filter context - add the related spec 317 artifacts and targeted tests for environment filter state and legacy context cleanup ## Testing - not run as part of this commit/push/PR workflow Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #372
215 lines
7.4 KiB
PHP
215 lines
7.4 KiB
PHP
<?php
|
|
|
|
namespace App\Support\Middleware;
|
|
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\User;
|
|
use App\Support\Navigation\AdminSurfaceScope;
|
|
use App\Support\Navigation\NavigationScope;
|
|
use App\Support\Navigation\WorkspaceHubRegistry;
|
|
use App\Support\Navigation\WorkspaceSidebarNavigation;
|
|
use App\Support\OperateHub\OperateHubShell;
|
|
use App\Support\Workspaces\WorkspaceContext;
|
|
use Closure;
|
|
use Filament\Facades\Filament;
|
|
use Filament\Navigation\NavigationBuilder;
|
|
use Illuminate\Http\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class EnsureEnvironmentContextSelected
|
|
{
|
|
/**
|
|
* @param Closure(Request): Response $next
|
|
*/
|
|
public function handle(Request $request, Closure $next): Response
|
|
{
|
|
$panel = Filament::getCurrentOrDefaultPanel();
|
|
$resolvedContext = app(OperateHubShell::class)->resolvedContext($request);
|
|
|
|
$path = '/'.ltrim($request->path(), '/');
|
|
|
|
$workspaceContext = app(WorkspaceContext::class);
|
|
$workspaceId = $workspaceContext->currentWorkspaceId($request);
|
|
|
|
$existingTenant = Filament::getTenant();
|
|
if ($existingTenant instanceof ManagedEnvironment && $workspaceId !== null && (int) $existingTenant->workspace_id !== (int) $workspaceId) {
|
|
Filament::setTenant(null, true);
|
|
$existingTenant = null;
|
|
}
|
|
|
|
$user = $request->user();
|
|
if ($existingTenant instanceof ManagedEnvironment && $user instanceof User && ! $user->canAccessTenant($existingTenant)) {
|
|
Filament::setTenant(null, true);
|
|
$existingTenant = null;
|
|
}
|
|
|
|
if ($existingTenant instanceof ManagedEnvironment && ($existingTenant->isRemovedFromWorkspace() || $existingTenant->workspace?->isClosed())) {
|
|
Filament::setTenant(null, true);
|
|
$existingTenant = null;
|
|
}
|
|
|
|
if ($this->isLivewireUpdatePath($path)) {
|
|
$refererPath = parse_url((string) $request->headers->get('referer', ''), PHP_URL_PATH) ?? '';
|
|
$refererPath = '/'.ltrim((string) $refererPath, '/');
|
|
|
|
if ($this->isCanonicalWorkspaceRecordViewerPath($refererPath)) {
|
|
$this->configureNavigationForRequest($panel, $request);
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
if ($this->isWorkspaceScopedPageWithTenant($refererPath)) {
|
|
$this->configureNavigationForRequest($panel, $request);
|
|
|
|
return $next($request);
|
|
}
|
|
}
|
|
|
|
if ($this->isCanonicalWorkspaceRecordViewerPath($path)) {
|
|
$this->configureNavigationForRequest($panel, $request);
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
if (in_array($path, ['/admin/findings/my-work', '/admin/findings/intake', '/admin/findings/hygiene'], true)) {
|
|
$this->configureNavigationForRequest($panel, $request);
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
if (preg_match('#^/admin/workspaces/[^/]+/operations(?:/[^/]+)?$#', $path) === 1) {
|
|
$this->configureNavigationForRequest($panel, $request);
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
if (
|
|
! $resolvedContext->hasTenant()
|
|
&& $this->adminPathRequiresTenantSelection($path)
|
|
) {
|
|
if ($this->requestHasExplicitTenantHint($request)) {
|
|
abort(404);
|
|
}
|
|
|
|
$workspace = $workspaceContext->currentWorkspace($request);
|
|
|
|
if ($workspace !== null) {
|
|
return redirect()->route('admin.workspace.managed-environments.index', ['workspace' => $workspace]);
|
|
}
|
|
|
|
return redirect()->route('filament.admin.pages.choose-environment');
|
|
}
|
|
|
|
if ($resolvedContext->pageCategory === AdminSurfaceScope::EnvironmentBound && ! $resolvedContext->hasTenant()) {
|
|
abort(404);
|
|
}
|
|
|
|
if ($resolvedContext->hasTenant() && $resolvedContext->tenant?->isRemovedFromWorkspace() && str_starts_with($path, '/admin/workspaces/')) {
|
|
abort(404);
|
|
}
|
|
|
|
if ($resolvedContext->hasTenant() && $resolvedContext->tenant?->workspace?->isClosed() && str_starts_with($path, '/admin/workspaces/')) {
|
|
abort(404);
|
|
}
|
|
|
|
if (
|
|
$resolvedContext->hasTenant()
|
|
&& (
|
|
! $this->isWorkspaceScopedPageWithTenant($path)
|
|
&& $resolvedContext->pageCategory === AdminSurfaceScope::EnvironmentBound
|
|
)
|
|
) {
|
|
Filament::setTenant($resolvedContext->tenant, true);
|
|
} elseif (! $resolvedContext->hasTenant()) {
|
|
Filament::setTenant(null, true);
|
|
}
|
|
|
|
if (
|
|
str_starts_with($path, '/admin/workspaces/')
|
|
|| in_array($path, ['/admin', '/admin/choose-workspace', '/admin/choose-environment', '/admin/no-access', '/admin/alerts', '/admin/audit-log', '/admin/onboarding', '/admin/settings/workspace', '/admin/findings/my-work', '/admin/findings/intake', '/admin/findings/hygiene'], true)
|
|
) {
|
|
$this->configureNavigationForRequest($panel, $request);
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
if (filled(Filament::getTenant())) {
|
|
$this->configureNavigationForRequest($panel, $request);
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
if (! $user instanceof User) {
|
|
$this->configureNavigationForRequest($panel, $request);
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
$this->configureNavigationForRequest($panel, $request);
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
private function configureNavigationForRequest(\Filament\Panel $panel, Request $request): void
|
|
{
|
|
if (NavigationScope::isEnvironmentSurface($request)) {
|
|
$panel->navigation(true);
|
|
|
|
return;
|
|
}
|
|
|
|
$panel->navigation(function (WorkspaceSidebarNavigation $navigation): NavigationBuilder {
|
|
return $navigation->build();
|
|
});
|
|
}
|
|
|
|
private function isWorkspaceScopedPageWithTenant(string $path): bool
|
|
{
|
|
return preg_match('#^/admin/workspaces/[^/]+/environments/[^/]+/(required-permissions|diagnostics|access-scopes)$#', $path) === 1;
|
|
}
|
|
|
|
private function isLivewireUpdatePath(string $path): bool
|
|
{
|
|
return preg_match('#^/livewire(?:-[^/]+)?/update$#', $path) === 1;
|
|
}
|
|
|
|
private function isCanonicalWorkspaceRecordViewerPath(string $path): bool
|
|
{
|
|
return AdminSurfaceScope::fromPath($path) === AdminSurfaceScope::CanonicalWorkspaceRecordViewer;
|
|
}
|
|
|
|
private function requestHasExplicitTenantHint(Request $request): bool
|
|
{
|
|
if (WorkspaceHubRegistry::isWorkspaceHubPath('/'.ltrim((string) $request->path(), '/'))) {
|
|
return false;
|
|
}
|
|
|
|
return filled($request->query('tenant')) || filled($request->query('managed_environment_id'));
|
|
}
|
|
|
|
private function adminPathRequiresTenantSelection(string $path): bool
|
|
{
|
|
if (! str_starts_with($path, '/admin/')) {
|
|
return false;
|
|
}
|
|
|
|
if (str_starts_with($path, '/admin/finding-exceptions/queue')) {
|
|
return false;
|
|
}
|
|
|
|
if (str_starts_with($path, '/admin/findings/my-work')) {
|
|
return false;
|
|
}
|
|
|
|
if (str_starts_with($path, '/admin/findings/intake')) {
|
|
return false;
|
|
}
|
|
|
|
if (str_starts_with($path, '/admin/findings/hygiene')) {
|
|
return false;
|
|
}
|
|
|
|
return preg_match('#^/admin/(inventory|policies|policy-versions|backup-sets|backup-schedules|findings|finding-exceptions)(/|$)#', $path) === 1;
|
|
}
|
|
}
|