- Canonical /admin/onboarding entry point; legacy routes 404\n- Tenantless run viewer at /admin/operations/{run} with membership-based 404\n- RBAC UX (disabled controls + tooltips) and server-side 403\n- DB-only rendering/refresh; contract registry enforced\n- Adds migrations + tests + spec artifacts
46 lines
1.1 KiB
PHP
46 lines
1.1 KiB
PHP
<?php
|
|
|
|
namespace App\Policies;
|
|
|
|
use App\Models\OperationRun;
|
|
use App\Models\User;
|
|
use App\Models\WorkspaceMembership;
|
|
use App\Support\Workspaces\WorkspaceContext;
|
|
use Illuminate\Auth\Access\HandlesAuthorization;
|
|
use Illuminate\Auth\Access\Response;
|
|
|
|
class OperationRunPolicy
|
|
{
|
|
use HandlesAuthorization;
|
|
|
|
public function viewAny(User $user): bool
|
|
{
|
|
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId();
|
|
|
|
if ($workspaceId === null) {
|
|
return false;
|
|
}
|
|
|
|
return WorkspaceMembership::query()
|
|
->where('workspace_id', (int) $workspaceId)
|
|
->where('user_id', (int) $user->getKey())
|
|
->exists();
|
|
}
|
|
|
|
public function view(User $user, OperationRun $run): Response|bool
|
|
{
|
|
$workspaceId = (int) ($run->workspace_id ?? 0);
|
|
|
|
if ($workspaceId <= 0) {
|
|
return Response::denyAsNotFound();
|
|
}
|
|
|
|
$isMember = WorkspaceMembership::query()
|
|
->where('workspace_id', $workspaceId)
|
|
->where('user_id', (int) $user->getKey())
|
|
->exists();
|
|
|
|
return $isMember ? true : Response::denyAsNotFound();
|
|
}
|
|
}
|