TenantAtlas/app/Support/Middleware/EnsureFilamentTenantSelected.php

126 lines
3.1 KiB
PHP

<?php
namespace App\Support\Middleware;
use App\Models\Tenant;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Auth\CapabilityResolver;
use App\Support\Workspaces\WorkspaceContext;
use Closure;
use Filament\Facades\Filament;
use Filament\Models\Contracts\HasTenants;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureFilamentTenantSelected
{
/**
* @param Closure(Request): Response $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->route()?->hasParameter('tenant')) {
$user = $request->user();
if ($user === null) {
return $next($request);
}
if (! $user instanceof HasTenants) {
abort(404);
}
$panel = Filament::getCurrentOrDefaultPanel();
if (! $panel->hasTenancy()) {
return $next($request);
}
$tenantParameter = $request->route()->parameter('tenant');
$tenant = $panel->getTenant($tenantParameter);
if (! $tenant instanceof Tenant) {
abort(404);
}
$workspaceContext = app(WorkspaceContext::class);
$workspaceId = $workspaceContext->currentWorkspaceId($request);
if ($workspaceId === null) {
abort(404);
}
if ((int) $tenant->workspace_id !== (int) $workspaceId) {
abort(404);
}
$workspace = Workspace::query()->whereKey($workspaceId)->first();
if (! $workspace instanceof Workspace) {
abort(404);
}
if (! $user instanceof User || ! $workspaceContext->isMember($user, $workspace)) {
abort(404);
}
if (! $user->canAccessTenant($tenant)) {
abort(404);
}
Filament::setTenant($tenant, true);
return $next($request);
}
if (filled(Filament::getTenant())) {
return $next($request);
}
$user = $request->user();
if (! $user instanceof User) {
return $next($request);
}
$tenant = null;
try {
$tenant = Tenant::current();
} catch (\RuntimeException) {
$tenant = null;
}
if ($tenant instanceof Tenant && ! app(CapabilityResolver::class)->isMember($user, $tenant)) {
$tenant = null;
}
if (! $tenant) {
$tenant = $user->tenants()
->whereNull('deleted_at')
->where('status', 'active')
->first();
}
if (! $tenant) {
$tenant = $user->tenants()
->whereNull('deleted_at')
->first();
}
if (! $tenant) {
$tenant = $user->tenants()
->withTrashed()
->first();
}
if ($tenant) {
Filament::setTenant($tenant, true);
}
return $next($request);
}
}