File: /var/www/console.fixgini.com/app/Http/Controllers/Authentication/Register.php
<?php
namespace App\Http\Controllers\Authentication;
use App\Models\User;
use App\Mail\AccountDeleteOtpMail;
use App\Mail\OtpMail;
use App\Models\Country;
use App\Models\Wallet;
use App\Mail\WelcomeMail;
use Illuminate\Http\Request;
use App\Models\OtpVerification;
use App\Services\ActivityLogger;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\ValidationException;
class Register extends Controller
{
public function register(Request $request)
{
DB::beginTransaction();
try {
if (User::where('email', $request->email)->exists()) {
return response()->json([
'status' => 'error',
'message' => 'Email already exists.'
], 409); // Conflict status code
}
if (User::where('phone', $request->phone)->exists()) {
return response()->json([
'status' => 'error',
'message' => 'Phone already exists.'
], 409);
}
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'phone' => 'nullable|numeric|unique:users,phone',
'role' => 'required|string|max:255',
'device_name' => 'required|string|max:255',
'password' => 'required|valid_password',
'ip_address' => 'required',
'nationality_id' => 'required|exists:countries,id',
], [
'nationality_id.required' => 'The nationality field is required.',
'nationality_id.exists' => 'The selected nationality is invalid.',
]);
info($validatedData);
$ip = $validatedData['ip_address'];
$location = $this->ipInfo($ip);
$user = User::create([
'name' => ucwords(strtolower($validatedData['name'])),
'email' => $validatedData['email'],
'phone' => $validatedData['phone'] ?? '',
'city' => $location['city'] ?? '',
'state' => $location['state'] ?? '',
'latitude' => $location['latitude'] ?? '',
'longitude' => $location['longitude'] ?? '',
'nationality_id' => $validatedData['nationality_id'],
'role' => $validatedData['role'],
'is_fingerprint' => false,
'is_pin' => false,
'profile_photo_url' => 'https://console.fixgini.com/icon.png',
'password' => Hash::make($validatedData['password']),
]);
$currency = Country::where('id', $validatedData['nationality_id'])->first();
Wallet::create([
'user_id' => $user->id,
'currency' => $currency->symbol
]);
$device = $validatedData['device_name'];
// Log the user activity
$activityLogger = app(ActivityLogger::class);
$activityLogger->log('New account registration', $user->id, $user->role, $device);
// Send welcome email
Mail::to($validatedData['email'])->send(new WelcomeMail($user));
// Send confirmation email code
if($validatedData['role'] == 'buyer'){
info('email verification code sent to buyer');
$this->sendEmailOtp($user);
}
// Generate authentication token
$token = $user->createToken('api_token')->plainTextToken;
DB::commit();
return response()->json(['status' => 'success', 'user' => $user, 'message' => 'Registration successful.', 'token' => $token], 200);
} catch (\Exception $e) {
DB::rollBack();
Log::error('Unable to register: ' . $e->getMessage());
return response()->json(['status' => 'error', 'message' => $e->getMessage()], 500);
}
}
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");
info($response->json());
if ($response->successful()) {
$data = $response->json();
$latitude = $data['latitude'] ?? '';
$longitude = $data['longitude'] ?? '';
$city = $data['city_name'] ?? '';
$state = $data['region_name'] ?? '';
// 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
} 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 ipInfo($clientIp)
{
$response = Http::get("https://ipinfo.io/{$clientIp}?token=dff86f66bbd177");
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 ?? '',
];
} else{
$this->getLocation($clientIp);
}
}
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();
info($data);
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(),
];
}
}
private function sendEmailOtp($user)
{
try {
$user = User::where('email', $user['email'])->first();
if ($user->email_verified_at) {
return response()->json(['status' => 'failed', 'message' => 'Email already verified'], 401);
}
// Email OTP Services
$otp = random_int(100000, 999999);
Mail::to($user->email)->send(new OtpMail($otp));
OtpVerification::updateOrCreate(
['email' => $user->email],
['otp' => $otp]
);
return response()->json(['status' => 'success', 'message' => 'Email confirmation code sent successfully'], 200);
} catch (\Throwable $th) {
Log::error($th->getMessage());
return response()->json(['status' => 'failed', 'message' => 'Network Issue! Pls try again later'], 400);
}
}
public function sendMailOtp2(Request $request)
{
try {
// $user = User::where('email', $user['email'])->first();
// $user = User::where('email', $request->email)->first();
$request->validate([
'email' => 'required|email',
]);
/*
if ($user->email_verified_at) {
return response()->json(['status' => 'failed', 'message' => 'Email already verified'], 401);
} */
// Email OTP Services
$otp = random_int(100000, 999999);
Mail::to($request->email)->send(new AccountDeleteOtpMail($otp));
OtpVerification::updateOrCreate(
['email' => $request->email],
['otp' => $otp]
);
return response()->json(['status' => 'success', 'message' => 'Account deletion OTP sent successfully'], 200);
} catch (\Throwable $th) {
Log::error($th->getMessage());
return response()->json(['status' => 'failed', 'message' => 'Network Issue! Pls try again later'], 400);
}
}
public function verifyEmailOtp(Request $request)
{
try {
$validatedData = $request->validate([
'email' => 'required|email|exists:users,email',
'otp' => 'required|digits:6|exists:otp_verifications,otp',
]);
$otpRecord = OtpVerification::where([
['email', '=', $validatedData['email']],
['otp', '=', $validatedData['otp']],
['status', '=', 'unverified']
])->latest()->first();
if (!$otpRecord) {
return response()->json(['message' => 'Invalid OTP. Pls try again', 'status' => 'error'], 401);
}
$otpRecord->update(['status' => 'verified']);
$user = User::where('email', $validatedData['email'])->first();
if ($user) {
$user->update(['email_verified_at' => now(), 'status' => 'active']);
}
$otpRecord->delete();
return response()->json(['message' => 'Email verified successfully', 'status' => 'success'], 200);
} catch (ValidationException $e) {
Log::error($e->getMessage());
return response()->json(['status' => 'error', 'message' => 'Please retry, Something happened'], 422);
}
}
// verify delete account otp
public function verifyDeleteOtp(Request $request)
{
try {
$validatedData = $request->validate([
'email' => 'required|email|exists:users,email',
'otp' => 'required|digits:6|exists:otp_verifications,otp',
]);
$otpRecord = OtpVerification::where([
['email', '=', $validatedData['email']],
['otp', '=', $validatedData['otp']],
['delete_status', '=', 'unverified']
])->latest()->first();
if (!$otpRecord) {
return response()->json(['message' => 'Invalid OTP. Pls try again', 'status' => 'error'], 401);
}
$otpRecord->update(['delete_status' => 'verified']);
return response()->json(['message' => 'Otp verified successfully', 'status' => 'success'], 200);
} catch (ValidationException $e) {
Log::error($e->getMessage());
return response()->json(['status' => 'error', 'message' => 'Please retry, Something happened'], 422);
}
}
//verify delete account otp
public function requestAccountDeletion(Request $request)
{
try {
$validatedData = $request->validate([
'email' => 'required|email|exists:users,email',
]);
$user = User::where('email', $validatedData['email'])->first();
if (!$user) {
return response()->json(['status' => 'error', 'message' => 'User not found'], 404);
}
// Generate OTP
$otp = random_int(100000, 999999);
Mail::to($user->email)->send(new OtpMail($otp));
OtpVerification::updateOrCreate(
['email' => $user->email],
['otp' => $otp, 'status' => 'unverified']
);
return response()->json(['status' => 'success', 'message' => 'OTP sent for account deletion'], 200);
} catch (\Throwable $th) {
Log::error('Error sending OTP for account deletion: ' . $th->getMessage());
return response()->json(['status' => 'error', 'message' => 'Network issue! Please try again later'], 500);
}
}
public function confirmAccountDeletion(Request $request)
{
try {
$validatedData = $request->validate([
'email' => 'required|email|exists:users,email',
'otp' => 'required|digits:6|exists:otp_verifications,otp',
]);
$otpRecord = OtpVerification::where([
['email', '=', $validatedData['email']],
['otp', '=', $validatedData['otp']],
['delete_status', '=', 'unverified']
])->latest()->first();
if (!$otpRecord) {
return response()->json(['status' => 'error', 'message' => 'Invalid OTP. Please try again'], 401);
}
$user = User::where('email', $validatedData['email'])->first();
if (!$user) {
return response()->json(['status' => 'error', 'message' => 'User not found'], 404);
}
DB::beginTransaction();
$otpRecord->delete();
$user->delete();
DB::commit();
return response()->json(['status' => 'success', 'message' => 'Account deleted successfully'], 200);
} catch (ValidationException $e) {
return response()->json(['status' => 'error', 'message' => $e->getMessage()], 422);
} catch (\Exception $e) {
DB::rollBack();
Log::error('Account deletion error: ' . $e->getMessage());
return response()->json(['status' => 'error', 'message' => 'Something went wrong. Please try again.'], 500);
}
}
}