Google rubrica import preview and command unification
This commit is contained in:
parent
478c0a120b
commit
dba907a85f
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@
|
|||
<a href="{{ $this->getRubricaUrl() }}" class="inline-flex items-center rounded-md bg-gray-700 px-3 py-1.5 text-xs font-medium text-white hover:bg-gray-600">
|
||||
Apri rubrica interna
|
||||
</a>
|
||||
<button type="button" wire:click="previewImportContactsToRubrica" class="inline-flex items-center rounded-md bg-slate-700 px-3 py-1.5 text-xs font-medium text-white hover:bg-slate-600">
|
||||
Preview import rubrica
|
||||
</button>
|
||||
<button type="button" wire:click="importContactsToRubrica" class="inline-flex items-center rounded-md bg-emerald-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-emerald-500">
|
||||
Importa in Rubrica NetGescon
|
||||
</button>
|
||||
|
|
@ -95,6 +98,23 @@
|
|||
@endif
|
||||
</div>
|
||||
|
||||
@if(($showTechnicalBoxes ?? true) === true)
|
||||
<div class="rounded-lg border border-gray-200 p-3">
|
||||
<div class="mb-2 text-sm font-semibold text-gray-800">Import rubrica operativo</div>
|
||||
<div class="text-xs text-gray-500">Usa `Preview` per controllare cosa entrerebbe in rubrica, poi `Importa` per applicare davvero usando il comando unificato lato Laravel.</div>
|
||||
<pre class="mt-3 overflow-x-auto rounded-lg bg-slate-900 p-3 text-xs text-slate-100">{{ $rubricaSyncCommandPreview ?: 'php artisan google:sync-rubrica --admin-id=... --max-pages=20 --dry-run' }}</pre>
|
||||
|
||||
@if($rubricaSyncLastRunLabel)
|
||||
<div class="mt-3 text-[11px] font-semibold uppercase tracking-wide text-slate-500">Ultima esecuzione</div>
|
||||
<div class="mt-1 text-xs text-slate-700">{{ $rubricaSyncLastRunLabel }}</div>
|
||||
@endif
|
||||
|
||||
@if($rubricaSyncLastOutput)
|
||||
<pre class="mt-3 max-h-72 overflow-auto rounded-lg bg-slate-50 p-3 text-xs text-slate-700">{{ $rubricaSyncLastOutput }}</pre>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="rounded-lg border border-gray-200 p-3">
|
||||
<div class="mb-2 text-sm font-semibold text-gray-800">Ticket aperti (operativi)</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user