> */ public function all(Amministratore $amministratore): array { $google = Arr::get($amministratore->impostazioni ?? [], 'google', []); $accounts = []; foreach ((array) Arr::get($google, 'accounts', []) as $rawKey => $account) { if (! is_array($account)) { continue; } $key = $this->normalizeAccountKey((string) $rawKey); if ($key === '') { $key = $this->normalizeAccountKey( (string) ($account['email'] ?? $account['google_user_id'] ?? $account['label'] ?? 'google-account') ); } $accounts[$key] = $this->normalizeAccountPayload($account, $key); } $legacyOauth = Arr::get($google, 'oauth', []); if (is_array($legacyOauth) && $this->hasUsableOauthPayload($legacyOauth)) { $legacyKey = $this->normalizeAccountKey( (string) (Arr::get($google, 'default_account_key') ?: Arr::get($legacyOauth, 'google_user_id') ?: Arr::get($legacyOauth, 'email') ?: 'primary') ); if (! isset($accounts[$legacyKey])) { $accounts[$legacyKey] = $this->normalizeAccountPayload($legacyOauth, $legacyKey); } } $defaultKey = $this->normalizeAccountKey((string) Arr::get($google, 'default_account_key', '')); if ($defaultKey === '' && $accounts !== []) { $defaultKey = (string) array_key_first($accounts); } foreach ($accounts as $key => $account) { $accounts[$key]['is_default'] = $key === $defaultKey; } return $accounts; } /** * @return array */ public function options(Amministratore $amministratore): array { $options = []; foreach ($this->all($amministratore) as $key => $account) { $label = trim((string) ($account['label'] ?? '')); $email = trim((string) ($account['email'] ?? '')); $text = $label !== '' ? $label : $key; if ($email !== '') { $text .= ' (' . $email . ')'; } if (! empty($account['is_default'])) { $text .= ' ยท predefinito'; } $options[$key] = $text; } return $options; } /** * @return array|null */ public function get(Amministratore $amministratore, ?string $accountKey = null): ?array { $accounts = $this->all($amministratore); if ($accounts === []) { return null; } $resolvedKey = $this->normalizeAccountKey((string) $accountKey); if ($resolvedKey !== '') { return $accounts[$resolvedKey] ?? null; } foreach ($accounts as $account) { if (! empty($account['is_default'])) { return $account; } } return reset($accounts) ?: null; } public function normalizeAccountKey(?string $value): string { $raw = trim((string) $value); if ($raw === '') { return ''; } return (string) Str::of($raw)->lower()->replace('@', '-at-')->slug('-'); } /** * @param array $payload */ public function upsertAccount(Amministratore $amministratore, string $accountKey, array $payload, bool $setDefault = false): string { $key = $this->normalizeAccountKey($accountKey) ?: 'primary'; $impostazioni = $amministratore->impostazioni ?? []; $google = Arr::get($impostazioni, 'google', []); $accounts = (array) Arr::get($google, 'accounts', []); $existing = isset($accounts[$key]) && is_array($accounts[$key]) ? $accounts[$key] : []; $account = $this->normalizeAccountPayload(array_replace($existing, $payload), $key); if (empty($account['scopes'])) { $account['scopes'] = self::SCOPES; } $accounts[$key] = $account; $google['accounts'] = $accounts; $defaultKey = $this->normalizeAccountKey((string) Arr::get($google, 'default_account_key', '')); if ($setDefault || $defaultKey === '') { $defaultKey = $key; } $google['default_account_key'] = $defaultKey; if ($defaultKey === $key) { $google['oauth'] = $this->toLegacyOauthPayload($account); if (trim((string) ($account['email'] ?? '')) !== '') { $google['workspace_email'] = trim((string) $account['email']); } } $impostazioni['google'] = $google; $amministratore->impostazioni = $impostazioni; $amministratore->save(); return $key; } public function disconnectAccount(Amministratore $amministratore, ?string $accountKey = null): void { $account = $this->get($amministratore, $accountKey); if (! is_array($account)) { return; } $key = (string) ($account['key'] ?? 'primary'); $impostazioni = $amministratore->impostazioni ?? []; $google = Arr::get($impostazioni, 'google', []); $accounts = (array) Arr::get($google, 'accounts', []); $existing = isset($accounts[$key]) && is_array($accounts[$key]) ? $accounts[$key] : $account; $accounts[$key] = array_replace($existing, [ 'connected' => false, 'access_token' => '', 'refresh_token' => '', 'expires_in' => null, 'refreshed_at' => null, 'disconnected_at' => now()->toDateTimeString(), ]); $google['accounts'] = $accounts; if ($this->normalizeAccountKey((string) Arr::get($google, 'default_account_key', '')) === $key) { $google['oauth'] = [ 'connected' => false, 'disconnected_at' => now()->toDateTimeString(), ]; } $impostazioni['google'] = $google; $amministratore->impostazioni = $impostazioni; $amministratore->save(); } public function resolveAccessToken(Amministratore $amministratore, ?string $accountKey = null, bool $forceRefresh = false): ?string { $account = $this->get($amministratore, $accountKey); if (! is_array($account)) { return null; } $accessToken = trim((string) ($account['access_token'] ?? '')); $refreshToken = trim((string) ($account['refresh_token'] ?? '')); if (! $forceRefresh && $accessToken !== '' && ! $this->isExpired($account)) { return $accessToken; } if ($refreshToken === '') { return $accessToken !== '' ? $accessToken : null; } $google = Arr::get($amministratore->impostazioni ?? [], 'google', []); $clientId = (string) ($google['client_id'] ?? config('services.google.client_id')); $clientSecret = (string) ($google['client_secret'] ?? config('services.google.client_secret')); if ($clientId === '' || $clientSecret === '') { return $accessToken !== '' ? $accessToken : null; } $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()) { return $accessToken !== '' ? $accessToken : null; } $payload = $response->json(); $newAccessToken = trim((string) Arr::get($payload, 'access_token', '')); if ($newAccessToken === '') { return $accessToken !== '' ? $accessToken : null; } $this->upsertAccount($amministratore, (string) ($account['key'] ?? 'primary'), array_filter([ 'connected' => true, 'label' => $account['label'] ?? null, 'email' => $account['email'] ?? null, 'name' => $account['name'] ?? null, 'google_user_id' => $account['google_user_id'] ?? null, 'access_token' => $newAccessToken, 'refresh_token' => trim((string) Arr::get($payload, 'refresh_token', '')) ?: $refreshToken, 'expires_in' => (int) Arr::get($payload, 'expires_in', $account['expires_in'] ?? 3600), 'refreshed_at' => now()->toDateTimeString(), 'scopes' => $account['scopes'] ?? self::SCOPES, ], static fn($value) => $value !== null), ! empty($account['is_default'])); return $newAccessToken; } /** * @param array $account * @return array */ private function normalizeAccountPayload(array $account, string $key): array { $label = trim((string) ($account['label'] ?? $account['name'] ?? $account['email'] ?? $key)); return [ 'key' => $key, 'label' => $label, 'connected' => (bool) ($account['connected'] ?? false), 'email' => trim((string) ($account['email'] ?? '')), 'name' => trim((string) ($account['name'] ?? '')), 'google_user_id' => trim((string) ($account['google_user_id'] ?? '')), 'access_token' => trim((string) ($account['access_token'] ?? '')), 'refresh_token' => trim((string) ($account['refresh_token'] ?? '')), 'expires_in' => (int) ($account['expires_in'] ?? 0), 'connected_at' => $account['connected_at'] ?? null, 'refreshed_at' => $account['refreshed_at'] ?? null, 'disconnected_at' => $account['disconnected_at'] ?? null, 'scopes' => array_values(array_filter((array) ($account['scopes'] ?? []))), ]; } /** * @param array $account * @return array */ private function toLegacyOauthPayload(array $account): array { return [ 'connected' => (bool) ($account['connected'] ?? false), 'email' => (string) ($account['email'] ?? ''), 'name' => (string) ($account['name'] ?? ''), 'google_user_id' => (string) ($account['google_user_id'] ?? ''), 'access_token' => (string) ($account['access_token'] ?? ''), 'refresh_token' => (string) ($account['refresh_token'] ?? ''), 'expires_in' => (int) ($account['expires_in'] ?? 0), 'connected_at' => $account['connected_at'] ?? null, 'refreshed_at' => $account['refreshed_at'] ?? null, 'scopes' => $account['scopes'] ?? self::SCOPES, ]; } /** * @param array $account */ private function isExpired(array $account): bool { $refreshedAt = trim((string) ($account['refreshed_at'] ?? $account['connected_at'] ?? '')); $expiresIn = (int) ($account['expires_in'] ?? 0); if ($refreshedAt === '' || $expiresIn <= 0) { return false; } $timestamp = strtotime($refreshedAt); if ($timestamp === false) { return false; } return ($timestamp + max(60, $expiresIn - 120)) <= time(); } /** * @param array $oauth */ private function hasUsableOauthPayload(array $oauth): bool { return (bool) ($oauth['connected'] ?? false) || trim((string) ($oauth['refresh_token'] ?? '')) !== '' || trim((string) ($oauth['access_token'] ?? '')) !== ''; } }