310 lines
12 KiB
PHP
Executable File
310 lines
12 KiB
PHP
Executable File
<?php
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Amministratore;
|
|
use App\Models\ChiamataPostIt;
|
|
use App\Models\Stabile;
|
|
use App\Models\Ticket;
|
|
use App\Support\PhoneNumber;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
class GoogleImportKeepNotesCommand extends Command
|
|
{
|
|
protected $signature = 'google:import-keep-notes
|
|
{--admin-id=* : Limita import a uno o piu ID amministratore}
|
|
{--limit=100 : Numero massimo note da importare per admin}
|
|
{--stabile-id= : Stabile di default per creazione ticket}
|
|
{--create-ticket : Se presente, crea ticket dalle note importate}';
|
|
|
|
protected $description = 'Importa note Google Keep in Post-it chiamate e opzionalmente le converte in ticket.';
|
|
|
|
public function handle(): int
|
|
{
|
|
$limit = max(1, (int) $this->option('limit'));
|
|
$defaultStabileId = (int) ($this->option('stabile-id') ?: 0);
|
|
$createTicket = (bool) $this->option('create-ticket');
|
|
|
|
$filterAdminIds = collect((array) $this->option('admin-id'))
|
|
->map(fn($v) => (int) $v)
|
|
->filter(fn(int $v) => $v > 0)
|
|
->values()
|
|
->all();
|
|
|
|
$query = Amministratore::query();
|
|
if ($filterAdminIds !== []) {
|
|
$query->whereIn('id', $filterAdminIds);
|
|
}
|
|
|
|
$amministratori = $query->get();
|
|
if ($amministratori->isEmpty()) {
|
|
$this->warn('Nessun amministratore trovato per i filtri richiesti.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
foreach ($amministratori as $amministratore) {
|
|
$google = Arr::get($amministratore->impostazioni ?? [], 'google', []);
|
|
$oauth = Arr::get($google, 'oauth', []);
|
|
|
|
if (! (bool) Arr::get($oauth, 'connected', false)) {
|
|
$this->line("Admin {$amministratore->id}: Google non collegato, salto.");
|
|
continue;
|
|
}
|
|
|
|
$token = $this->resolveAccessToken($amministratore, $google, $oauth);
|
|
if ($token === null) {
|
|
$this->warn("Admin {$amministratore->id}: token non disponibile, salto.");
|
|
continue;
|
|
}
|
|
|
|
$imported = 0;
|
|
$skipped = 0;
|
|
$tickets = 0;
|
|
$nextPageToken = null;
|
|
$creatorUserId = (int) ($amministratore->user_id ?? 0) > 0 ? (int) $amministratore->user_id : null;
|
|
|
|
while ($imported < $limit) {
|
|
$response = Http::withToken($token)
|
|
->acceptJson()
|
|
->get('https://keep.googleapis.com/v1/notes', [
|
|
'pageSize' => min(50, $limit),
|
|
'pageToken' => $nextPageToken,
|
|
]);
|
|
|
|
if ($response->status() === 401) {
|
|
$token = $this->resolveAccessToken($amministratore, $google, $oauth, true) ?? $token;
|
|
$response = Http::withToken($token)
|
|
->acceptJson()
|
|
->get('https://keep.googleapis.com/v1/notes', [
|
|
'pageSize' => min(50, $limit),
|
|
'pageToken' => $nextPageToken,
|
|
]);
|
|
}
|
|
|
|
if (! $response->successful()) {
|
|
$err = $this->extractGoogleError($response);
|
|
$this->warn("Admin {$amministratore->id}: errore Keep API ({$response->status()}) {$err}");
|
|
break;
|
|
}
|
|
|
|
$notes = $response->json('notes');
|
|
if (! is_array($notes) || count($notes) === 0) {
|
|
break;
|
|
}
|
|
|
|
foreach ($notes as $note) {
|
|
if ($imported >= $limit) {
|
|
break;
|
|
}
|
|
|
|
$resourceId = (string) (Arr::get($note, 'name') ?: Arr::get($note, 'id') ?: Arr::get($note, 'resourceName') ?: '');
|
|
if ($resourceId === '') {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
$already = ChiamataPostIt::query()
|
|
->where('origine', 'google_keep')
|
|
->where('origine_id', $resourceId)
|
|
->exists();
|
|
|
|
if ($already) {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
$title = trim((string) (Arr::get($note, 'title') ?: Arr::get($note, 'textContent', '')));
|
|
$body = trim((string) (Arr::get($note, 'body.text') ?: Arr::get($note, 'textContent') ?: Arr::get($note, 'body') ?: ''));
|
|
if ($title === '' && $body === '') {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
$fullText = trim($title . "\n" . $body);
|
|
$telefono = $this->extractPhone($fullText);
|
|
$direzione = $this->extractDirection($fullText);
|
|
$priorita = $this->extractPriority($fullText);
|
|
|
|
$chiamataIl = Arr::get($note, 'createTime') ?: Arr::get($note, 'createdTime');
|
|
$chiamataIl = is_string($chiamataIl) ? Carbon::parse($chiamataIl) : now();
|
|
|
|
$postIt = ChiamataPostIt::query()->create([
|
|
'telefono' => $telefono,
|
|
'nome_chiamante' => null,
|
|
'direzione' => $direzione,
|
|
'esito' => 'importata da Google Keep',
|
|
'oggetto' => $title !== '' ? $title : 'Nota Keep',
|
|
'nota' => $body !== '' ? $body : $title,
|
|
'priorita' => $priorita,
|
|
'stato' => 'post_it',
|
|
'creato_da_user_id' => $creatorUserId,
|
|
'chiamata_il' => $chiamataIl,
|
|
'origine' => 'google_keep',
|
|
'origine_id' => $resourceId,
|
|
]);
|
|
|
|
if ($createTicket) {
|
|
$stabileId = $this->extractStabileId($fullText) ?: $defaultStabileId;
|
|
if ($stabileId > 0 && Stabile::query()->whereKey($stabileId)->exists()) {
|
|
$ticket = Ticket::query()->create([
|
|
'stabile_id' => $stabileId,
|
|
'aperto_da_user_id' => (int) ($amministratore->user_id ?: 1),
|
|
'titolo' => $title !== '' ? $title : 'Nota Keep importata',
|
|
'descrizione' => ($body !== '' ? $body : $title) . "\n\nOrigine: Google Keep ({$resourceId})",
|
|
'data_apertura' => now(),
|
|
'stato' => 'Aperto',
|
|
'priorita' => $priorita,
|
|
]);
|
|
|
|
$postIt->ticket_id = $ticket->id;
|
|
$postIt->stato = 'ticket';
|
|
$postIt->save();
|
|
$tickets++;
|
|
}
|
|
}
|
|
|
|
$imported++;
|
|
}
|
|
|
|
$nextPageToken = $response->json('nextPageToken');
|
|
if (! is_string($nextPageToken) || $nextPageToken === '') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
$this->info("Admin {$amministratore->id}: importate {$imported}, saltate {$skipped}, ticket creati {$tickets}.");
|
|
}
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
private function extractStabileId(string $text): int
|
|
{
|
|
if (preg_match('/stabile\s*[:#-]?\s*(\d+)/i', $text, $m) === 1) {
|
|
return (int) ($m[1] ?? 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private function extractPhone(string $text): ?string
|
|
{
|
|
if (preg_match('/(\+?\d[\d\s\-\(\)]{7,}\d)/', $text, $m) !== 1) {
|
|
return null;
|
|
}
|
|
|
|
return PhoneNumber::toE164Italy((string) ($m[1] ?? ''));
|
|
}
|
|
|
|
private function extractDirection(string $text): string
|
|
{
|
|
$t = strtolower($text);
|
|
if (str_contains($t, '#uscita') || str_contains($t, 'in uscita')) {
|
|
return 'in_uscita';
|
|
}
|
|
if (str_contains($t, '#persa') || str_contains($t, 'chiamata persa')) {
|
|
return 'persa';
|
|
}
|
|
|
|
return 'in_arrivo';
|
|
}
|
|
|
|
private function extractPriority(string $text): string
|
|
{
|
|
$t = strtolower($text);
|
|
if (str_contains($t, '#urgente') || str_contains($t, 'urgente')) {
|
|
return 'Urgente';
|
|
}
|
|
if (str_contains($t, '#alta') || str_contains($t, 'alta priorita')) {
|
|
return 'Alta';
|
|
}
|
|
if (str_contains($t, '#bassa') || str_contains($t, 'bassa priorita')) {
|
|
return 'Bassa';
|
|
}
|
|
|
|
return 'Media';
|
|
}
|
|
|
|
private function extractGoogleError($response): string
|
|
{
|
|
$msg = (string) (Arr::get($response->json(), 'error.message') ?: Arr::get($response->json(), 'error.status') ?: '');
|
|
return trim($msg);
|
|
}
|
|
|
|
private function resolveAccessToken(Amministratore $amministratore, array $google, array $oauth, bool $forceRefresh = false): ?string
|
|
{
|
|
$accessToken = trim((string) Arr::get($oauth, 'access_token', ''));
|
|
$refreshToken = trim((string) Arr::get($oauth, 'refresh_token', ''));
|
|
|
|
if (! $forceRefresh && $accessToken !== '') {
|
|
return $accessToken;
|
|
}
|
|
|
|
if ($refreshToken === '') {
|
|
return null;
|
|
}
|
|
|
|
$settingsClientId = trim((string) Arr::get($google, 'client_id', ''));
|
|
$settingsClientSecret = trim((string) Arr::get($google, 'client_secret', ''));
|
|
$configClientId = trim((string) config('services.google.client_id'));
|
|
$configClientSecret = trim((string) config('services.google.client_secret'));
|
|
|
|
$credentialPairs = [];
|
|
if ($settingsClientId !== '' && $settingsClientSecret !== '') {
|
|
$credentialPairs[] = [$settingsClientId, $settingsClientSecret];
|
|
}
|
|
if (
|
|
$configClientId !== ''
|
|
&& $configClientSecret !== ''
|
|
&& ($configClientId !== $settingsClientId || $configClientSecret !== $settingsClientSecret)
|
|
) {
|
|
$credentialPairs[] = [$configClientId, $configClientSecret];
|
|
}
|
|
|
|
if ($credentialPairs === []) {
|
|
return null;
|
|
}
|
|
|
|
foreach ($credentialPairs as [$clientId, $clientSecret]) {
|
|
$response = Http::asForm()->post('https://oauth2.googleapis.com/token', [
|
|
'client_id' => $clientId,
|
|
'client_secret' => $clientSecret,
|
|
'refresh_token' => $refreshToken,
|
|
'grant_type' => 'refresh_token',
|
|
]);
|
|
|
|
if (! $response->successful()) {
|
|
continue;
|
|
}
|
|
|
|
$payload = $response->json();
|
|
$newAccessToken = trim((string) Arr::get($payload, 'access_token', ''));
|
|
if ($newAccessToken === '') {
|
|
continue;
|
|
}
|
|
|
|
$impostazioni = $amministratore->impostazioni ?? [];
|
|
$impostazioniGoogle = Arr::get($impostazioni, 'google', []);
|
|
$impostazioniOauth = Arr::get($impostazioniGoogle, 'oauth', []);
|
|
|
|
$impostazioniOauth['access_token'] = $newAccessToken;
|
|
$impostazioniOauth['expires_in'] = (int) Arr::get($payload, 'expires_in', 3600);
|
|
$impostazioniOauth['refreshed_at'] = Carbon::now()->toDateTimeString();
|
|
if (isset($payload['refresh_token']) && is_string($payload['refresh_token']) && $payload['refresh_token'] !== '') {
|
|
$impostazioniOauth['refresh_token'] = $payload['refresh_token'];
|
|
}
|
|
|
|
$impostazioniGoogle['oauth'] = $impostazioniOauth;
|
|
$impostazioni['google'] = $impostazioniGoogle;
|
|
$amministratore->impostazioni = $impostazioni;
|
|
$amministratore->save();
|
|
|
|
return $newAccessToken;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|