record instanceof Tenant ? $this->record : null; } public function startVerification(StartVerification $verification): void { $user = auth()->user(); if (! $user instanceof User) { abort(403); } $tenant = $this->resolveTenant(); if (! $tenant instanceof Tenant) { abort(404); } if (! $user->canAccessTenant($tenant)) { abort(404); } $result = $verification->providerConnectionCheckForTenant( tenant: $tenant, initiator: $user, extraContext: [ 'surface' => [ 'kind' => 'tenant_verification_widget', ], ], ); $runUrl = OperationRunLinks::tenantlessView($result->run); if ($result->status === 'scope_busy') { Notification::make() ->title('Another operation is already running') ->body('Please wait for the active run to finish.') ->warning() ->actions([ Action::make('view_run') ->label('View run') ->url($runUrl), ]) ->send(); return; } if ($result->status === 'deduped') { Notification::make() ->title('Verification already running') ->body('A verification run is already queued or running.') ->warning() ->actions([ Action::make('view_run') ->label('View run') ->url($runUrl), ]) ->send(); return; } if ($result->status === 'blocked') { $reasonCode = is_string($result->run->context['reason_code'] ?? null) ? (string) $result->run->context['reason_code'] : 'unknown_error'; $actions = [ Action::make('view_run') ->label('View run') ->url($runUrl), ]; $nextSteps = $result->run->context['next_steps'] ?? []; $nextSteps = is_array($nextSteps) ? $nextSteps : []; foreach ($nextSteps as $index => $step) { if (! is_array($step)) { continue; } $label = is_string($step['label'] ?? null) ? trim((string) $step['label']) : ''; $url = is_string($step['url'] ?? null) ? trim((string) $step['url']) : ''; if ($label === '' || $url === '') { continue; } $actions[] = Action::make('next_step_'.$index) ->label($label) ->url($url); break; } Notification::make() ->title('Verification blocked') ->body("Blocked by provider configuration ({$reasonCode}).") ->warning() ->actions($actions) ->send(); return; } Notification::make() ->title('Verification started') ->success() ->actions([ Action::make('view_run') ->label('View run') ->url($runUrl), ]) ->send(); } /** * @return array */ protected function getViewData(): array { $tenant = $this->resolveTenant(); if (! $tenant instanceof Tenant) { return [ 'tenant' => null, 'run' => null, 'runData' => null, 'runUrl' => null, 'report' => null, 'isInProgress' => false, 'canStart' => false, 'startTooltip' => null, ]; } $run = OperationRun::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('type', 'provider.connection.check') ->orderByDesc('id') ->first(); $report = $run instanceof OperationRun ? VerificationReportViewer::report($run) : null; $isInProgress = $run instanceof OperationRun && (string) $run->status !== OperationRunStatus::Completed->value; $user = auth()->user(); $isTenantMember = $user instanceof User && $user->canAccessTenant($tenant); $canStart = $isTenantMember && $user->can(Capabilities::PROVIDER_RUN, $tenant); $runData = null; if ($run instanceof OperationRun) { $context = is_array($run->context ?? null) ? $run->context : []; $targetScope = $context['target_scope'] ?? []; $targetScope = is_array($targetScope) ? $targetScope : []; $runData = [ 'id' => (int) $run->getKey(), 'type' => (string) $run->type, 'status' => (string) $run->status, 'outcome' => (string) $run->outcome, 'initiator_name' => (string) $run->initiator_name, 'started_at' => $run->started_at?->toJSON(), 'completed_at' => $run->completed_at?->toJSON(), 'target_scope' => $targetScope, 'failures' => is_array($run->failure_summary ?? null) ? $run->failure_summary : [], ]; } return [ 'tenant' => $tenant, 'run' => $run, 'runData' => $runData, 'runUrl' => $run instanceof OperationRun ? OperationRunLinks::tenantlessView($run) : null, 'report' => $report, 'isInProgress' => $isInProgress, 'canStart' => $canStart, 'startTooltip' => $isTenantMember && ! $canStart ? UiTooltips::insufficientPermission() : null, ]; } }