user(); if (! $user instanceof PlatformUser) { return false; } return $user->hasCapability(PlatformCapabilities::USE_BREAK_GLASS); } /** * @return array */ protected function getHeaderActions(): array { $breakGlass = app(BreakGlassSession::class); return [ Action::make('assign_owner') ->label('Assign owner (break-glass)') ->color('danger') ->requiresConfirmation() ->modalHeading('Assign workspace owner') ->modalDescription('This is a recovery action. It is audited and should only be used when the workspace owner set is broken.') ->form([ Select::make('workspace_id') ->label('Workspace') ->required() ->searchable() ->getSearchResultsUsing(function (string $search): array { return Workspace::query() ->where('name', 'like', "%{$search}%") ->orderBy('name') ->limit(25) ->pluck('name', 'id') ->all(); }) ->getOptionLabelUsing(function ($value): ?string { if (! is_numeric($value)) { return null; } return Workspace::query()->whereKey((int) $value)->value('name'); }), Select::make('target_user_id') ->label('User') ->required() ->searchable() ->getSearchResultsUsing(function (string $search): array { return User::query() ->where('email', 'like', "%{$search}%") ->orderBy('email') ->limit(25) ->pluck('email', 'id') ->all(); }) ->getOptionLabelUsing(function ($value): ?string { if (! is_numeric($value)) { return null; } return User::query()->whereKey((int) $value)->value('email'); }), Textarea::make('reason') ->label('Reason') ->required() ->minLength(5) ->maxLength(500) ->rows(4), ]) ->action(function (array $data, BreakGlassSession $breakGlass, WorkspaceAuditLogger $auditLogger): void { $platformUser = auth('platform')->user(); if (! $platformUser instanceof PlatformUser) { abort(403); } if (! $platformUser->hasCapability(PlatformCapabilities::USE_BREAK_GLASS)) { abort(403); } if (! $breakGlass->isActive()) { abort(403); } $workspaceId = (int) ($data['workspace_id'] ?? 0); $targetUserId = (int) ($data['target_user_id'] ?? 0); $reason = (string) ($data['reason'] ?? ''); $workspace = Workspace::query()->whereKey($workspaceId)->firstOrFail(); $targetUser = User::query()->whereKey($targetUserId)->firstOrFail(); $membership = WorkspaceMembership::query()->firstOrNew([ 'workspace_id' => (int) $workspace->getKey(), 'user_id' => (int) $targetUser->getKey(), ]); $fromRole = $membership->exists ? (string) $membership->role : null; $membership->forceFill([ 'role' => WorkspaceRole::Owner->value, ])->save(); $auditLogger->log( workspace: $workspace, action: AuditActionId::WorkspaceMembershipBreakGlassAssignOwner->value, context: [ 'metadata' => [ 'workspace_id' => (int) $workspace->getKey(), 'actor_user_id' => (int) $platformUser->getKey(), 'target_user_id' => (int) $targetUser->getKey(), 'attempted_role' => WorkspaceRole::Owner->value, 'from_role' => $fromRole, 'reason' => trim($reason), 'source' => 'break_glass', ], ], actor: null, status: 'success', resourceType: 'workspace', resourceId: (string) $workspace->getKey(), actorId: (int) $platformUser->getKey(), actorEmail: $platformUser->email, actorName: $platformUser->name, ); Notification::make() ->title('Owner assigned') ->success() ->send(); }) ->disabled(fn (): bool => ! $breakGlass->isActive()), ]; } }