GOOD SHELL MAS BOY
Server: Apache/2.4.52 (Ubuntu)
System: Linux vmi1836763.contaboserver.net 5.15.0-130-generic #140-Ubuntu SMP Wed Dec 18 17:59:53 UTC 2024 x86_64
User: www-data (33)
PHP: 8.4.10
Disabled: NONE
Upload Files
File: /var/www/console.fixgini.com/app/Http/Controllers/Authentication/Google.php
<?php

namespace App\Http\Controllers\Authentication;

use App\Http\Controllers\Controller;
use App\Mail\WelcomeMail;
use App\Models\Country;
use App\Models\SellerNin;
use App\Models\Shop;
use App\Models\User;
use App\Models\Wallet;
use App\Services\ActivityLogger;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\Rule;
use Laravel\Sanctum\PersonalAccessToken;

class Google extends Controller
{
    public function callBack(Request $request)
    {
        try {
            // Validate incoming request
            $validatedData = $request->validate([
                'google_id' => 'required|string|max:255',
                'name' => 'nullable|string|max:255',
                'lastname' => 'nullable|string|max:255',
                'email' => 'required|email',
                'nationality_id' => 'nullable|exists:countries,id',
                'role' => 'nullable|string|in:buyer,seller',
                'ip_address' => 'required|string',
                'device_name' => 'nullable|string|max:255',
                'photo' => 'nullable|string',
                'middlename' => 'nullable|string|max:255',
                'phone' => 'nullable',
                'dob' => 'nullable|string|max:100',
                'gender' => 'nullable',
                'nin' => 'nullable|string|unique:seller_nins,nin',
            ]);
        } catch (\Exception $e) {
            Log::info($e->getMessage());
            return response()->json(['status' => 'error', 'message' => $e->getMessage()], 500);
        }
            $location = $this->getLocation($validatedData['ip_address']);
            $user = User::where('email', $validatedData['email'])->whereNotNull('google_id')->first();
            if ($user) {
                return $this->login($validatedData);
            } else {
                return $this->register($validatedData);
            }

    }

    public function login($credentials)
    {
        try {
            $user = User::where('email', $credentials['email'])->first();
            if ($user->status == 'inactive') {
                return response()->json(['status' => 'failed', 'message' => 'Account is inactive, Please contact support to continue'], 404);
            }

            $ip = $credentials['ip_address'];
            $activityIp = optional($user->activity)->ip;

            // Check if the activity IP matches the incoming IP; if not, fetch location
            $location = ($activityIp && $activityIp === $ip) ? $activityIp : $this->getLocation($ip);

            // Update user location details
            $user->latitude = $location['latitude'] ?? $user->latitude;
            $user->longitude = $location['longitude'] ?? $user->longitude;
            $user->save();

            // Generate authentication token
            $token = $user->createToken('api_token')->plainTextToken;

            // Log the user activity
            $device = $credentials['device_name'];
            $activityLogger = app(ActivityLogger::class);
            $activityLogger->log('User login from mobile phone (API)', $user->id, $user->role, $device);

            // Check if the user has an associated shop
            $isShop = Shop::where('user_id', $user->id)->exists();
            $isNin = SellerNin::where('user_id', $user->id)->exists();

            return response()->json([
                'status' => 'success',
                'message' => 'Login successfully',
                'token' => $token,
                'user' => $user,
                'is_shop' => $isShop,
                'is_nin' => $isNin,
            ], 200);
        } catch (\Throwable $th) {
            // Handle any unexpected errors
            $message = $th->getMessage();
            Log::info($message);
            return response()->json([
                'status' => 'failed',
                'message' => 'Oops, Service Unavailable. Please try again later ',
                'reason' => $message
            ], 400);
        }
    }

    public function register($validatedData)
    {
        $user = User::where('email', $validatedData['email'])->exists();
        if ($user) {
            return response()->json(['status' => 'failed', 'message' => 'Please continue with email and password. Thank you'], 404);
        }
        // Create a new user if not found
        $user = User::create([
            'google_id' => $validatedData['google_id'] ?? '',
            'name' => $validatedData['name'],
            'lastname' => $validatedData['lastname'] ?? '',
            'email' => $validatedData['email'],
            'phone' => $validatedData['phone'] ?? '',
            'status' => 'active',
            'city' => $location['city'] ?? '',
            'state' => $location['state'] ?? '',
            'latitude' => $location['latitude'] ?? '',
            'longitude' => $location['longitude'] ?? '',
            'profile_photo_url' => $validatedData['photo'] ?? '',
            'nationality_id' => $validatedData['nationality_id'] ?? '1',
            'role' => $validatedData['role'] ?? 'buyer',
            'email_verified_at' => now(),
            'is_fingerprint' => false,
            'is_pin' => false,
        ]);

        // Create Wallet for the user
        $currency = Country::where('id', $validatedData['nationality_id'])->first();

        Wallet::create([
            'user_id' => $user->id,
            'balance' => 0.0,
            'currency' => $currency->symbol
        ]);

        // Handle Seller-specific data if role is seller
        if ($validatedData['role'] == 'seller') {
            SellerNin::create([
                'user_id' => $user->id,
                'name' => $validatedData['name'] ?? '',
                'lastname' => $validatedData['lastname'] ?? '',
                'middlename' => $validatedData['middlename'] ?? '',
                'dob' => $validatedData['dob'] ?? '',
                'gender' => $validatedData['gender'] ?? '',
                'nin' => $validatedData['nin'] ?? '',
            ]);
        }

        // Send Welcome Email
        Mail::to($validatedData['email'])->send(new WelcomeMail($user));
        $token = $user->createToken('api_token')->plainTextToken;
         return response()->json([
                'status' => 'success',
                'message' => 'Registration was successful.',
                'is_shop' => Shop::where('user_id', $user->id)->exists(),
                'is_nin' => SellerNin::where('user_id', $user->id)->exists(),
                'user' => $user,
                'token' => $token
            ], 200);
    }

    private function getLocation($ip)
    {
        try {
            $clientIp = $ip;

            // Attempt the first API call to api.ip2location.io
            $apiKey = env('IP2LOCATION_API_KEY');
            $response = Http::get("https://api.ip2location.io/?key={$apiKey}&ip={$clientIp}&format=json");

            if ($response->successful()) {
                $data = $response->json();
                $latitude = $data['latitude'] ?? '';
                $longitude = $data['longitude'] ?? '';

                // If lat/lng exists, perform reverse geocoding
                if ($latitude && $longitude) {
                    return $this->reverseGeocode($latitude, $longitude);
                }
            } else {
                // Check for specific error in the first API response
                $error = $response->json('error') ?? [];
                if (isset($error['error_code']) && $error['error_code'] === 10000) {
                    Log::warning('IP2Location API error: ' . $error['error_message']);
                }
            }

            // Fallback to ipinfo.io API
            $response = Http::get("https://ipinfo.io/{$clientIp}?token=55690b2a8bf492");
            if ($response->successful()) {
                $data = $response->json();

                // Extract location data from ipinfo response
                $location = explode(',', $data['loc'] ?? '');
                $latitude = $location[0] ?? '';
                $longitude = $location[1] ?? '';

                // Include city and state in the response
                return [
                    'city' => $data['city'] ?? '',
                    'state' => $data['region'] ?? '',
                    'country' => $data['country'] ?? '',
                    'latitude' => $latitude ?? '',
                    'longitude' => $longitude ?? '',
                ];
            }
        } catch (\Exception $e) {
            Log::error('Location fetching error: ' . $e->getMessage());
        }

        // Return a default response if all attempts fail
        return [
            'city' => '',
            'state' => '',
            'country' => '',
            'latitude' => '',
            'longitude' => '',
        ];
    }

    private function reverseGeocode($latitude, $longitude)
    {
        try {
            $response = Http::get('https://maps.googleapis.com/maps/api/geocode/json', [
                'latlng' => "{$latitude},{$longitude}",
                'key' => env('GOOGLE_API_KEY'),
            ]);

            if ($response->successful()) {
                $data = $response->json();
                if (isset($data['results']) && count($data['results']) > 0) {
                    $components = $data['results'][0]['address_components'];
                    $locationInfo = [
                        'city' => null,
                        'state' => null,
                        'latitude' => $latitude,
                        'longitude' => $longitude,
                    ];

                    foreach ($components as $component) {
                        if (in_array('locality', $component['types'])) {
                            $locationInfo['city'] = $component['long_name'];
                        }
                        if (in_array('administrative_area_level_1', $component['types'])) {
                            $locationInfo['state'] = $component['long_name'];
                        }
                    }
                    return $locationInfo;
                } else {
                    return [
                        'error' => true,
                        'message' => 'No results found.',
                    ];
                }
            } else {
                return [
                    'error' => true,
                    'message' => 'Failed to retrieve location data.',
                ];
            }
        } catch (\Exception $e) {
            return [
                'error' => true,
                'message' => $e->getMessage(),
            ];
        }
    }
    
}