250 lines
9.9 KiB
PHP
250 lines
9.9 KiB
PHP
<?php
|
|
namespace App\Http\Controllers\Integrations;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Amministratore;
|
|
use App\Models\Fornitore;
|
|
use App\Models\FornitoreDipendente;
|
|
use App\Models\Stabile;
|
|
use App\Models\User;
|
|
use App\Support\StabileContext;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Throwable;
|
|
|
|
class GoogleOAuthController extends Controller
|
|
{
|
|
private const GOOGLE_SCOPES = [
|
|
'openid',
|
|
'email',
|
|
'profile',
|
|
'https://www.googleapis.com/auth/calendar.events',
|
|
'https://www.googleapis.com/auth/contacts',
|
|
'https://www.googleapis.com/auth/drive.file',
|
|
];
|
|
|
|
public function redirect(): RedirectResponse
|
|
{
|
|
$amministratore = $this->resolveAmministratore();
|
|
|
|
if (! $amministratore instanceof Amministratore) {
|
|
abort(403, 'Amministratore non disponibile per questa sessione.');
|
|
}
|
|
|
|
$google = Arr::get($amministratore->impostazioni ?? [], 'google', []);
|
|
$oauth = Arr::get($google, 'oauth', []);
|
|
|
|
$clientId = (string) ($google['client_id'] ?? config('services.google.client_id'));
|
|
$clientSecret = (string) ($google['client_secret'] ?? config('services.google.client_secret'));
|
|
$redirectUri = (string) ($google['redirect_uri'] ?? config('services.google.redirect'));
|
|
|
|
if ($clientId === '' || $clientSecret === '' || $redirectUri === '') {
|
|
return redirect('/admin-filament/impostazioni/scheda-amministratore')
|
|
->with('error', 'Configura Client ID, Client Secret e Redirect URI in Scheda amministratore.');
|
|
}
|
|
|
|
$state = bin2hex(random_bytes(20));
|
|
session()->put('google_oauth_state', $state);
|
|
|
|
$queryParams = [
|
|
'client_id' => $clientId,
|
|
'redirect_uri' => $redirectUri,
|
|
'response_type' => 'code',
|
|
'scope' => implode(' ', self::GOOGLE_SCOPES),
|
|
'access_type' => 'offline',
|
|
'include_granted_scopes' => 'true',
|
|
'state' => $state,
|
|
];
|
|
|
|
if (trim((string) Arr::get($oauth, 'refresh_token', '')) === '') {
|
|
$queryParams['prompt'] = 'consent';
|
|
}
|
|
|
|
$query = http_build_query($queryParams);
|
|
|
|
return redirect()->away('https://accounts.google.com/o/oauth2/v2/auth?' . $query);
|
|
}
|
|
|
|
public function callback(): RedirectResponse
|
|
{
|
|
$amministratore = $this->resolveAmministratore();
|
|
|
|
if (! $amministratore instanceof Amministratore) {
|
|
abort(403, 'Amministratore non disponibile per questa sessione.');
|
|
}
|
|
|
|
$google = Arr::get($amministratore->impostazioni ?? [], 'google', []);
|
|
$existingOauth = Arr::get($google, 'oauth', []);
|
|
$clientId = (string) ($google['client_id'] ?? config('services.google.client_id'));
|
|
$clientSecret = (string) ($google['client_secret'] ?? config('services.google.client_secret'));
|
|
$redirectUri = (string) ($google['redirect_uri'] ?? config('services.google.redirect'));
|
|
|
|
try {
|
|
$incomingState = (string) request()->query('state', '');
|
|
$sessionState = (string) session()->pull('google_oauth_state', '');
|
|
if ($incomingState === '' || $sessionState === '' || ! hash_equals($sessionState, $incomingState)) {
|
|
return redirect('/admin-filament/impostazioni/scheda-amministratore')
|
|
->with('error', 'Stato OAuth non valido. Riprova il collegamento Google.');
|
|
}
|
|
|
|
$code = (string) request()->query('code', '');
|
|
if ($code === '') {
|
|
return redirect('/admin-filament/impostazioni/scheda-amministratore')
|
|
->with('error', 'Google non ha restituito il codice di autorizzazione.');
|
|
}
|
|
|
|
$tokenResponse = Http::asForm()->post('https://oauth2.googleapis.com/token', [
|
|
'client_id' => $clientId,
|
|
'client_secret' => $clientSecret,
|
|
'redirect_uri' => $redirectUri,
|
|
'grant_type' => 'authorization_code',
|
|
'code' => $code,
|
|
]);
|
|
|
|
if (! $tokenResponse->successful()) {
|
|
$message = (string) (Arr::get($tokenResponse->json(), 'error_description') ?: Arr::get($tokenResponse->json(), 'error.message') ?: 'token_exchange_failed');
|
|
return redirect('/admin-filament/impostazioni/scheda-amministratore')
|
|
->with('error', 'Errore scambio token Google: ' . $message);
|
|
}
|
|
|
|
$payload = $tokenResponse->json();
|
|
$accessToken = (string) Arr::get($payload, 'access_token', '');
|
|
$refreshToken = (string) Arr::get($payload, 'refresh_token', '');
|
|
if ($refreshToken === '') {
|
|
$refreshToken = (string) Arr::get($existingOauth, 'refresh_token', '');
|
|
}
|
|
$expiresIn = (int) Arr::get($payload, 'expires_in', 3600);
|
|
|
|
$profileResponse = Http::withToken($accessToken)
|
|
->acceptJson()
|
|
->get('https://openidconnect.googleapis.com/v1/userinfo');
|
|
|
|
$profile = $profileResponse->successful() ? $profileResponse->json() : [];
|
|
$googleUserId = (string) Arr::get($profile, 'sub', '');
|
|
$email = (string) Arr::get($profile, 'email', '');
|
|
$name = (string) Arr::get($profile, 'name', '');
|
|
|
|
$impostazioni = $amministratore->impostazioni ?? [];
|
|
$impostazioni['google'] = array_merge($google, [
|
|
'oauth' => [
|
|
'connected' => true,
|
|
'email' => $email,
|
|
'name' => $name,
|
|
'google_user_id' => $googleUserId,
|
|
'access_token' => $accessToken,
|
|
'refresh_token' => $refreshToken,
|
|
'expires_in' => $expiresIn,
|
|
'connected_at' => now()->toDateTimeString(),
|
|
'refreshed_at' => now()->toDateTimeString(),
|
|
],
|
|
]);
|
|
|
|
$amministratore->impostazioni = $impostazioni;
|
|
$amministratore->save();
|
|
|
|
return redirect('/admin-filament/impostazioni/scheda-amministratore')
|
|
->with('status', 'Account Google collegato con successo.');
|
|
} catch (Throwable $e) {
|
|
Log::error('Google OAuth callback failed', [
|
|
'admin_id' => $amministratore->id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return redirect('/admin-filament/impostazioni/scheda-amministratore')
|
|
->with('error', 'Errore durante il collegamento Google: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function disconnect(): RedirectResponse
|
|
{
|
|
$amministratore = $this->resolveAmministratore();
|
|
|
|
if (! $amministratore instanceof Amministratore) {
|
|
abort(403, 'Amministratore non disponibile per questa sessione.');
|
|
}
|
|
|
|
$impostazioni = $amministratore->impostazioni ?? [];
|
|
$google = Arr::get($impostazioni, 'google', []);
|
|
$google['oauth'] = [
|
|
'connected' => false,
|
|
'disconnected_at' => now()->toDateTimeString(),
|
|
];
|
|
|
|
$impostazioni['google'] = $google;
|
|
$amministratore->impostazioni = $impostazioni;
|
|
$amministratore->save();
|
|
|
|
return redirect('/admin-filament/impostazioni/scheda-amministratore')
|
|
->with('status', 'Collegamento Google rimosso.');
|
|
}
|
|
|
|
private function resolveAmministratore(): ?Amministratore
|
|
{
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
return null;
|
|
}
|
|
|
|
$amministratore = $user->amministratore;
|
|
|
|
if (! $amministratore instanceof Amministratore && $user->hasAnyRole(['super-admin', 'admin'])) {
|
|
$stabile = StabileContext::getActiveStabile($user);
|
|
if ($stabile instanceof Stabile && $stabile->amministratore instanceof Amministratore) {
|
|
$amministratore = $stabile->amministratore;
|
|
}
|
|
}
|
|
|
|
if (! $amministratore instanceof Amministratore && $user->hasRole('fornitore')) {
|
|
$fornitore = $this->resolveCurrentUserSupplier($user);
|
|
if ($fornitore instanceof Fornitore && $fornitore->amministratore instanceof Amministratore) {
|
|
$amministratore = $fornitore->amministratore;
|
|
}
|
|
}
|
|
|
|
return $amministratore instanceof Amministratore ? $amministratore : null;
|
|
}
|
|
|
|
private function resolveCurrentUserSupplier(User $user): ?Fornitore
|
|
{
|
|
$email = mb_strtolower(trim((string) $user->email));
|
|
if ($email === '') {
|
|
return $this->resolveCurrentUserSupplierFromCollaboratore($user);
|
|
}
|
|
|
|
$fornitore = Fornitore::query()
|
|
->whereRaw('LOWER(email) = ?', [$email])
|
|
->first();
|
|
|
|
if ($fornitore instanceof Fornitore) {
|
|
return $fornitore;
|
|
}
|
|
|
|
return $this->resolveCurrentUserSupplierFromCollaboratore($user);
|
|
}
|
|
|
|
private function resolveCurrentUserSupplierFromCollaboratore(User $user): ?Fornitore
|
|
{
|
|
$dipendente = FornitoreDipendente::query()
|
|
->where('attivo', true)
|
|
->where(function ($query) use ($user): void {
|
|
$query->where('user_id', (int) $user->id);
|
|
|
|
$email = mb_strtolower(trim((string) $user->email));
|
|
if ($email !== '') {
|
|
$query->orWhereRaw('LOWER(email) = ?', [$email]);
|
|
}
|
|
})
|
|
->latest('id')
|
|
->first();
|
|
|
|
if (! $dipendente instanceof FornitoreDipendente) {
|
|
return null;
|
|
}
|
|
|
|
return Fornitore::query()->find((int) $dipendente->fornitore_id);
|
|
}
|
|
}
|