$policyIds */ public function __construct( public int $tenantId, public int $userId, public array $policyIds, ?OperationRun $operationRun = null, ) { $this->operationRun = $operationRun; } public function middleware(): array { return [new TrackOperationRun]; } public function handle(OperationRunService $operationRunService): void { $tenant = Tenant::query()->find($this->tenantId); if (! $tenant instanceof Tenant) { throw new \RuntimeException('Tenant not found.'); } $user = User::query()->find($this->userId); if (! $user instanceof User) { throw new \RuntimeException('User not found.'); } try { $succeeded = 0; $failed = 0; $skipped = 0; $failures = []; $ids = collect($this->policyIds) ->map(static fn ($id): int => (int) $id) ->unique() ->sort() ->values() ->all(); foreach ($ids as $policyId) { try { $policy = Policy::query() ->where('tenant_id', $tenant->getKey()) ->find($policyId); if (! $policy) { $failed++; $failures[] = [ 'code' => 'policy.not_found', 'message' => "Policy {$policyId} not found.", ]; continue; } if (! $policy->ignored_at) { $skipped++; continue; } $policy->unignore(); $succeeded++; } catch (Throwable $e) { $failed++; $failures[] = [ 'code' => 'policy.unignore.failed', 'message' => $e->getMessage(), ]; } } $total = count($ids); $outcome = OperationRunOutcome::Succeeded->value; if ($failed > 0 && $failed < $total) { $outcome = OperationRunOutcome::PartiallySucceeded->value; } if ($failed >= $total && $total > 0) { $outcome = OperationRunOutcome::Failed->value; } if ($this->operationRun) { $operationRunService->updateRun( $this->operationRun, status: OperationRunStatus::Completed->value, outcome: $outcome, summaryCounts: [ 'total' => $total, 'processed' => $total, 'succeeded' => $succeeded, 'failed' => $failed, 'skipped' => $skipped, ], failures: $failures, ); } if ($user) { $message = "Restored {$succeeded} policies"; if ($skipped > 0) { $message .= " ({$skipped} skipped)"; } if ($failed > 0) { $message .= " ({$failed} failed)"; } $message .= '.'; Notification::make() ->title('Bulk Restore Completed') ->body($message) ->icon('heroicon-o-check-circle') ->success() ->actions($this->operationRun ? [ \Filament\Actions\Action::make('view_run') ->label('View run') ->url(OperationRunLinks::view($this->operationRun, $tenant)), ] : []) ->sendToDatabase($user) ->send(); } } catch (Throwable $e) { if ($this->operationRun) { $operationRunService->updateRun( $this->operationRun, status: OperationRunStatus::Completed->value, outcome: OperationRunOutcome::Failed->value, failures: [ ['code' => 'exception.unhandled', 'message' => $e->getMessage()], ], ); } if (isset($user) && $user instanceof User) { Notification::make() ->title('Bulk Restore Failed') ->body($e->getMessage()) ->icon('heroicon-o-x-circle') ->danger() ->actions($this->operationRun ? [ \Filament\Actions\Action::make('view_run') ->label('View run') ->url(OperationRunLinks::view($this->operationRun, $tenant)), ] : []) ->sendToDatabase($user) ->send(); } throw $e; } } }