TenantAtlas/app/Policies/ProviderConnectionPolicy.php
2026-02-12 17:32:08 +01:00

250 lines
7.3 KiB
PHP

<?php
namespace App\Policies;
use App\Models\ProviderConnection;
use App\Models\Tenant;
use App\Models\TenantMembership;
use App\Models\User;
use App\Models\Workspace;
use App\Support\Auth\Capabilities;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
class ProviderConnectionPolicy
{
use HandlesAuthorization;
public function viewAny(User $user): Response|bool
{
$workspace = $this->currentWorkspace($user);
if (! $workspace instanceof Workspace) {
return Response::denyAsNotFound();
}
$entitledTenants = Tenant::query()
->select('tenants.*')
->join('tenant_memberships as policy_memberships', function ($join) use ($user): void {
$join->on('policy_memberships.tenant_id', '=', 'tenants.id')
->where('policy_memberships.user_id', '=', (int) $user->getKey());
})
->where('tenants.workspace_id', (int) $workspace->getKey())
->get();
if ($entitledTenants->isEmpty()) {
return true;
}
foreach ($entitledTenants as $tenant) {
if (Gate::forUser($user)->allows(Capabilities::PROVIDER_VIEW, $tenant)) {
return true;
}
}
return false;
}
public function view(User $user, ProviderConnection $connection): Response|bool
{
$workspace = $this->currentWorkspace($user);
if (! $workspace instanceof Workspace) {
return Response::denyAsNotFound();
}
$tenant = $this->tenantForConnection($connection);
if (! $tenant instanceof Tenant || (int) $tenant->workspace_id !== (int) $workspace->getKey()) {
return Response::denyAsNotFound();
}
if (! $this->isTenantMember($user, $tenant)) {
return Response::denyAsNotFound();
}
if (! Gate::forUser($user)->allows(Capabilities::PROVIDER_VIEW, $tenant)) {
return false;
}
if ((int) $connection->tenant_id !== (int) $tenant->getKey()) {
return Response::denyAsNotFound();
}
if ((int) $connection->workspace_id !== (int) $workspace->getKey()) {
return Response::denyAsNotFound();
}
return true;
}
public function create(User $user): Response|bool
{
$workspace = $this->currentWorkspace($user);
if (! $workspace instanceof Workspace) {
return Response::denyAsNotFound();
}
$tenant = $this->resolveCreateTenant($workspace);
if (! $tenant instanceof Tenant || ! $this->isTenantMember($user, $tenant)) {
return Response::denyAsNotFound();
}
if (! Gate::forUser($user)->allows(Capabilities::PROVIDER_MANAGE, $tenant)) {
return false;
}
return true;
}
public function update(User $user, ProviderConnection $connection): Response|bool
{
$workspace = $this->currentWorkspace($user);
if (! $workspace instanceof Workspace) {
return Response::denyAsNotFound();
}
$tenant = $this->tenantForConnection($connection);
if (! $tenant instanceof Tenant || (int) $tenant->workspace_id !== (int) $workspace->getKey()) {
return Response::denyAsNotFound();
}
if (! $this->isTenantMember($user, $tenant)) {
return Response::denyAsNotFound();
}
if (! Gate::forUser($user)->allows(Capabilities::PROVIDER_MANAGE, $tenant)) {
return false;
}
if ((int) $connection->tenant_id !== (int) $tenant->getKey()) {
return Response::denyAsNotFound();
}
if ((int) $connection->workspace_id !== (int) $workspace->getKey()) {
return Response::denyAsNotFound();
}
return true;
}
public function delete(User $user, ProviderConnection $connection): Response|bool
{
$workspace = $this->currentWorkspace($user);
if (! $workspace instanceof Workspace) {
return Response::denyAsNotFound();
}
$tenant = $this->tenantForConnection($connection);
if (! $tenant instanceof Tenant || (int) $tenant->workspace_id !== (int) $workspace->getKey()) {
return Response::denyAsNotFound();
}
if (! $this->isTenantMember($user, $tenant)) {
return Response::denyAsNotFound();
}
if (! Gate::forUser($user)->allows(Capabilities::PROVIDER_MANAGE, $tenant)) {
return false;
}
if ((int) $connection->tenant_id !== (int) $tenant->getKey()) {
return Response::denyAsNotFound();
}
if ((int) $connection->workspace_id !== (int) $workspace->getKey()) {
return Response::denyAsNotFound();
}
return true;
}
private function currentWorkspace(User $user): ?Workspace
{
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
if (! is_int($workspaceId)) {
$filamentTenant = Filament::getTenant();
if ($filamentTenant instanceof Tenant) {
$workspaceId = (int) $filamentTenant->workspace_id;
}
}
if (! is_int($workspaceId)) {
return null;
}
$workspace = Workspace::query()->whereKey($workspaceId)->first();
if (! $workspace instanceof Workspace) {
return null;
}
if (! app(WorkspaceContext::class)->isMember($user, $workspace)) {
return null;
}
return $workspace;
}
private function resolveCreateTenant(Workspace $workspace): ?Tenant
{
$tenantExternalId = request()->query('tenant_id');
if (! is_string($tenantExternalId) || $tenantExternalId === '') {
$lastTenantId = app(WorkspaceContext::class)->lastTenantId(request());
if (is_int($lastTenantId)) {
return Tenant::query()
->whereKey($lastTenantId)
->where('workspace_id', (int) $workspace->getKey())
->first();
}
$filamentTenant = Filament::getTenant();
if ($filamentTenant instanceof Tenant && (int) $filamentTenant->workspace_id === (int) $workspace->getKey()) {
return $filamentTenant;
}
return null;
}
return Tenant::query()
->where('external_id', $tenantExternalId)
->where('workspace_id', (int) $workspace->getKey())
->first();
}
private function tenantForConnection(ProviderConnection $connection): ?Tenant
{
if ($connection->relationLoaded('tenant') && $connection->tenant instanceof Tenant) {
return $connection->tenant;
}
if (is_int($connection->tenant_id) || is_numeric($connection->tenant_id)) {
return Tenant::query()->whereKey((int) $connection->tenant_id)->first();
}
return null;
}
private function isTenantMember(User $user, Tenant $tenant): bool
{
return TenantMembership::query()
->where('user_id', (int) $user->getKey())
->where('tenant_id', (int) $tenant->getKey())
->exists();
}
}