From dba907a85fa59ab3a48fe9e57992e1b3b42c0e4f Mon Sep 17 00:00:00 2001 From: michele Date: Wed, 8 Apr 2026 19:17:16 +0000 Subject: [PATCH] Google rubrica import preview and command unification --- .../Widgets/GoogleWorkspaceOverview.php | 177 ++++-------------- .../google-workspace-overview.blade.php | 20 ++ 2 files changed, 60 insertions(+), 137 deletions(-) diff --git a/app/Filament/Widgets/GoogleWorkspaceOverview.php b/app/Filament/Widgets/GoogleWorkspaceOverview.php index b009a19..28d8307 100644 --- a/app/Filament/Widgets/GoogleWorkspaceOverview.php +++ b/app/Filament/Widgets/GoogleWorkspaceOverview.php @@ -15,6 +15,7 @@ use Filament\Widgets\Widget; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Http; @@ -46,6 +47,12 @@ class GoogleWorkspaceOverview extends Widget public bool $showTechnicalBoxes = true; + public ?string $rubricaSyncCommandPreview = null; + + public ?string $rubricaSyncLastOutput = null; + + public ?string $rubricaSyncLastRunLabel = null; + public function mount(): void { $amministratore = $this->resolveAmministratore(); @@ -62,6 +69,7 @@ public function mount(): void $email = (string) Arr::get($oauth, 'email', ''); $this->connectionLabel = $email !== '' ? $email : ($this->googleConnected ? 'Collegato' : 'Non collegato'); $this->calendarId = (string) Arr::get($google, 'calendar_id', 'primary') ?: 'primary'; + $this->rubricaSyncCommandPreview = 'php artisan google:sync-rubrica --admin-id=' . (int) $amministratore->id . ' --max-pages=20'; if (! $this->googleConnected) { $this->errorMessage = 'Google non e collegato. Vai su Scheda amministratore per completare il collegamento.'; @@ -99,7 +107,17 @@ public function getTicketGestioneUrl(int $ticketId): string return TicketGestione::getUrl(['ticket' => $ticketId, 'tab' => 'scheda'], panel: 'admin-filament'); } + public function previewImportContactsToRubrica(): void + { + $this->runRubricaSync(true); + } + public function importContactsToRubrica(): void + { + $this->runRubricaSync(false); + } + + private function runRubricaSync(bool $dryRun): void { $amministratore = $this->resolveAmministratore(); @@ -118,154 +136,39 @@ public function importContactsToRubrica(): void if ($token === null) { Notification::make() - ->title('Import rubrica non riuscito') + ->title($dryRun ? 'Preview rubrica non disponibile' : 'Import rubrica non riuscito') ->warning() ->body($this->errorMessage ?? 'Token Google non disponibile.') ->send(); return; } - $nextPageToken = null; - $created = 0; - $updated = 0; + $params = [ + '--admin-id' => [(string) $amministratore->id], + '--max-pages' => 20, + ]; - // Import limitato a 5 pagine per evitare timeout dashboard. - for ($page = 0; $page < 5; $page++) { - $response = Http::withToken($token) - ->acceptJson() - ->get('https://people.googleapis.com/v1/people/me/connections', [ - 'personFields' => 'names,emailAddresses,phoneNumbers', - 'pageSize' => 200, - 'pageToken' => $nextPageToken, - ]); - - if ($response->status() === 401) { - $token = $this->resolveAccessToken($amministratore, $google, $oauth, true) ?? $token; - $response = Http::withToken($token) - ->acceptJson() - ->get('https://people.googleapis.com/v1/people/me/connections', [ - 'personFields' => 'names,emailAddresses,phoneNumbers', - 'pageSize' => 200, - 'pageToken' => $nextPageToken, - ]); - } - - if (! $response->successful()) { - Notification::make() - ->title('Import rubrica interrotto') - ->warning() - ->body($this->googleErrorBody($response, 'Google People API ha restituito un errore durante l import.')) - ->send(); - return; - } - - $connections = $response->json('connections'); - if (! is_array($connections) || count($connections) === 0) { - break; - } - - foreach ($connections as $person) { - $name = trim((string) Arr::get($person, 'names.0.displayName', '')); - $email = trim((string) Arr::get($person, 'emailAddresses.0.value', '')); - $phone = trim((string) Arr::get($person, 'phoneNumbers.0.value', '')); - - if ($name === '' && $email === '' && $phone === '') { - continue; - } - - [$nome, $cognome] = $this->splitDisplayName($name, $email); - $categoria = $this->inferCategoria($name, $email); - $tipoContatto = $this->inferTipoContatto($name, $email); - $today = now()->toDateString(); - - $existing = RubricaUniversale::withTrashed() - ->where(function ($q) use ($email, $phone): void { - if ($email !== '') { - $q->orWhere('email', $email); - } - if ($phone !== '') { - $q->orWhere('telefono_cellulare', $phone) - ->orWhere('telefono_ufficio', $phone) - ->orWhere('telefono_casa', $phone); - } - }) - ->first(); - - if ($existing instanceof RubricaUniversale) { - if (method_exists($existing, 'trashed') && $existing->trashed()) { - $existing->restore(); - } - - $changed = false; - if (($existing->nome ?? '') === '' && $nome !== '') { - $existing->nome = $nome; - $changed = true; - } - if (($existing->cognome ?? '') === '' && $cognome !== '') { - $existing->cognome = $cognome; - $changed = true; - } - if (($existing->email ?? '') === '' && $email !== '') { - $existing->email = $email; - $changed = true; - } - if (($existing->telefono_cellulare ?? '') === '' && $phone !== '') { - $existing->telefono_cellulare = $phone; - $changed = true; - } - if (($existing->categoria ?? '') === '' || $existing->categoria === 'altro') { - $existing->categoria = $categoria; - $changed = true; - } - if (($existing->tipo_contatto ?? '') === '') { - $existing->tipo_contatto = $tipoContatto; - $changed = true; - } - if (($existing->note ?? '') === '') { - $existing->note = 'Origine contatto: Google Workspace'; - $changed = true; - } - - if ($changed) { - $existing->data_ultima_modifica = $today; - $existing->modificato_da = Auth::id(); - $existing->save(); - $updated++; - } - - continue; - } - - RubricaUniversale::create([ - 'nome' => $nome, - 'cognome' => $cognome, - 'tipo_contatto' => $tipoContatto, - 'telefono_cellulare' => $phone !== '' ? $phone : null, - 'email' => $email !== '' ? $email : null, - 'categoria' => $categoria, - 'stato' => 'attivo', - 'note' => 'Origine contatto: Google Workspace', - 'data_inserimento' => $today, - 'data_ultima_modifica' => $today, - 'creato_da' => Auth::id(), - 'modificato_da' => Auth::id(), - ]); - - $created++; - } - - $nextPageToken = $response->json('nextPageToken'); - if (! is_string($nextPageToken) || $nextPageToken === '') { - break; - } + if ($dryRun) { + $params['--dry-run'] = true; } - $this->loadContactsPreview($token); + $exit = Artisan::call('google:sync-rubrica', $params); + $output = trim((string) Artisan::output()); + + $this->rubricaSyncLastRunLabel = now()->format('d/m/Y H:i:s') . ($dryRun ? ' · dry-run' : ' · apply'); + $this->rubricaSyncLastOutput = $output !== '' ? $output : 'Nessun output disponibile.'; + $this->rubricaSyncCommandPreview = 'php artisan google:sync-rubrica --admin-id=' . (int) $amministratore->id . ' --max-pages=20' . ($dryRun ? ' --dry-run' : ''); + + if (! $dryRun) { + $this->loadContactsPreview($token); + } Notification::make() - ->title('Import rubrica completato') - ->success() - ->body("Creati {$created} contatti, aggiornati {$updated} contatti.") + ->title($exit === 0 + ? ($dryRun ? 'Preview import rubrica completata' : 'Import rubrica completato') + : ($dryRun ? 'Preview import rubrica con errori' : 'Import rubrica con errori')) + ->body((string) collect(preg_split('/\R/', $this->rubricaSyncLastOutput) ?: [])->filter()->last()) + ->{$exit === 0 ? 'success' : 'warning'}() ->send(); } diff --git a/resources/views/filament/widgets/google-workspace-overview.blade.php b/resources/views/filament/widgets/google-workspace-overview.blade.php index 6db694a..1e86cc8 100644 --- a/resources/views/filament/widgets/google-workspace-overview.blade.php +++ b/resources/views/filament/widgets/google-workspace-overview.blade.php @@ -17,6 +17,9 @@ Apri rubrica interna + @@ -95,6 +98,23 @@ @endif + @if(($showTechnicalBoxes ?? true) === true) +
+
Import rubrica operativo
+
Usa `Preview` per controllare cosa entrerebbe in rubrica, poi `Importa` per applicare davvero usando il comando unificato lato Laravel.
+
{{ $rubricaSyncCommandPreview ?: 'php artisan google:sync-rubrica --admin-id=... --max-pages=20 --dry-run' }}
+ + @if($rubricaSyncLastRunLabel) +
Ultima esecuzione
+
{{ $rubricaSyncLastRunLabel }}
+ @endif + + @if($rubricaSyncLastOutput) +
{{ $rubricaSyncLastOutput }}
+ @endif +
+ @endif +
Ticket aperti (operativi)