migrant-web/app/Http/Controllers/Api/SponsorAuthController.php
2026-06-17 22:20:17 +05:30

365 lines
14 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Sponsor;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
class SponsorAuthController extends Controller
{
/**
* Register a new Sponsor account.
*
* Required fields: full_name, mobile, password, license_file
* Optional: organization_name, email, nationality, city, address, country_code
*
* POST /api/sponsors/register
*/
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'full_name' => 'required|string|max:255',
'mobile' => 'required|string|max:50|unique:sponsors,mobile|unique:employer_profiles,phone',
'password' => 'required|string|min:6',
'license_file' => 'nullable|file|mimes:jpeg,png,jpg,pdf|max:10240',
'emirates_id_file' => 'nullable|file|mimes:jpeg,png,jpg,pdf|max:10240',
'organization_name' => 'required|string|max:255',
'email' => 'required|email|max:255|unique:sponsors,email|unique:users,email',
'nationality' => 'required|string|max:100',
'city' => 'required|string|max:100',
'address' => 'required|string|max:255',
'country_code' => 'required|string|max:10',
'license_expiry' => 'nullable|date_format:Y-m-d',
'fcm_token' => 'nullable|string|max:255',
], [
'mobile.unique' => 'This mobile number is already registered.',
'email.unique' => 'This email address is already registered.',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Validation error.',
'errors' => $validator->errors()
], 422);
}
try {
// Auto-generate email if not provided
$mobileClean = preg_replace('/[^0-9]/', '', $request->mobile);
$email = $request->email ?? "sponsor.{$mobileClean}@migrant.ae";
if (!$request->email && Sponsor::where('email', $email)->exists()) {
$email = "sponsor.{$mobileClean}." . rand(10, 99) . "@migrant.ae";
}
$licenseExpiry = $request->license_expiry;
if ($request->hasFile('license_file')) {
$licenseFile = $request->file('license_file');
$ocrLicense = \App\Services\OcrDocumentService::extractSponsorLicenseData($licenseFile);
$licenseExpiry = $licenseExpiry ?? $ocrLicense['expiry_date'];
}
$emiratesIdPath = null;
if ($request->hasFile('emirates_id_file')) {
$emiratesIdFile = $request->file('emirates_id_file');
\App\Services\OcrDocumentService::extractEmiratesIdFrontData($emiratesIdFile);
}
$licensePath = null;
$apiToken = Str::random(80);
$sponsor = DB::transaction(function () use ($request, $email, $licensePath, $emiratesIdPath, $apiToken, $licenseExpiry) {
return Sponsor::create([
'full_name' => $request->full_name,
'organization_name' => $request->organization_name,
'email' => $email,
'mobile' => $request->mobile,
'password' => Hash::make($request->password),
'country_code' => $request->country_code,
'nationality' => $request->nationality,
'city' => $request->city,
'address' => $request->address,
'license_file' => $licensePath,
'emirates_id_file' => $emiratesIdPath,
'license_expiry' => $licenseExpiry,
'status' => 'active',
'is_verified' => false,
'subscription_status' => 'none',
'api_token' => $apiToken,
'fcm_token' => $request->fcm_token,
]);
});
if ($request->filled('fcm_token')) {
\App\Services\FCMService::sendPushNotification(
$request->fcm_token,
'Welcome to Migrant',
'Sponsor account registered successfully. Your license is pending admin review.'
);
}
return response()->json([
'success' => true,
'message' => 'Sponsor account registered successfully. Your license is pending admin review.',
'data' => [
'sponsor' => $sponsor->makeHidden(['password', 'api_token']),
'token' => $apiToken,
]
], 201);
} catch (\Exception $e) {
logger()->error('Sponsor Registration Failure: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'An error occurred during registration. Please try again.',
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
], 500);
}
}
/**
* Authenticate a Sponsor and return their bearer token.
*
* POST /api/sponsors/login
*/
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'mobile' => 'required|string',
'password' => 'required|string',
'fcm_token' => 'nullable|string|max:255',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Validation error.',
'errors' => $validator->errors()
], 422);
}
$sponsor = Sponsor::where('mobile', $request->mobile)->first();
if (!$sponsor || !Hash::check($request->password, $sponsor->password)) {
return response()->json([
'success' => false,
'message' => 'Invalid mobile number or password.'
], 401);
}
if ($sponsor->status === 'suspended') {
return response()->json([
'success' => false,
'message' => 'Your account has been suspended. Please contact support.'
], 403);
}
// Rotate token on each login for security
$apiToken = Str::random(80);
$updateData = [
'api_token' => $apiToken,
'last_login_at' => now(),
];
if ($request->has('fcm_token')) {
$updateData['fcm_token'] = $request->fcm_token;
}
$sponsor->update($updateData);
if ($request->filled('fcm_token')) {
\App\Services\FCMService::sendPushNotification(
$request->fcm_token,
'Successful Login',
'Welcome back to your Migrant sponsor account.'
);
}
return response()->json([
'success' => true,
'message' => 'Login successful.',
'data' => [
'sponsor' => $sponsor->makeHidden(['password', 'api_token']),
'token' => $apiToken,
]
], 200);
}
/**
* Upload Sponsor's Emirates ID Front.
* POST /api/sponsors/register/emirates-front
*/
public function uploadEmiratesIdFront(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255',
'emirates_id_front' => 'required|file|mimes:jpeg,png,jpg,pdf|max:10240',
], [
'email.required' => 'The email address is required.',
'emirates_id_front.required' => 'Please upload the front side of your Emirates ID.',
'emirates_id_front.mimes' => 'The Emirates ID front must be an image or a PDF.',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Validation error.',
'errors' => $validator->errors()
], 422);
}
try {
$sponsor = Sponsor::where('email', $request->email)->first();
if (!$sponsor) {
return response()->json([
'success' => false,
'message' => 'Sponsor account not found.'
], 404);
}
$frontFile = $request->file('emirates_id_front');
$frontOcr = \App\Services\OcrDocumentService::extractEmiratesIdFrontData($frontFile);
$sponsor->update([
'emirates_id_file' => null,
]);
return response()->json([
'success' => true,
'message' => 'Emirates ID front uploaded and processed successfully.',
'ocr_extracted_data' => $frontOcr,
'email' => $request->email,
], 200);
} catch (\Exception $e) {
logger()->error('API Sponsor Emirates ID Front Upload Failure: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'An error occurred while uploading the Emirates ID front.',
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
], 500);
}
}
/**
* Upload Sponsor's Emirates ID Back.
* POST /api/sponsors/register/emirates-back
*/
public function uploadEmiratesIdBack(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255',
'emirates_id_back' => 'required|file|mimes:jpeg,png,jpg,pdf|max:10240',
], [
'email.required' => 'The email address is required.',
'emirates_id_back.required' => 'Please upload the back side of your Emirates ID.',
'emirates_id_back.mimes' => 'The Emirates ID back must be an image or a PDF.',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Validation error.',
'errors' => $validator->errors()
], 422);
}
try {
$sponsor = Sponsor::where('email', $request->email)->first();
if (!$sponsor) {
return response()->json([
'success' => false,
'message' => 'Sponsor account not found.'
], 404);
}
$backFile = $request->file('emirates_id_back');
$backOcr = \App\Services\OcrDocumentService::extractEmiratesIdBackData($backFile);
$sponsor->update([
'emirates_id_file' => null,
]);
return response()->json([
'success' => true,
'message' => 'Emirates ID back uploaded and processed successfully.',
'ocr_extracted_data' => $backOcr,
'email' => $request->email,
], 200);
} catch (\Exception $e) {
logger()->error('API Sponsor Emirates ID Back Upload Failure: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'An error occurred while uploading the Emirates ID back.',
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
], 500);
}
}
/**
* Upload Sponsor's License document.
* POST /api/sponsors/register/license
*/
public function uploadLicense(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:255',
'license_file' => 'required|file|mimes:jpeg,png,jpg,pdf|max:10240',
], [
'email.required' => 'The email address is required.',
'license_file.required' => 'Please upload the organization or trade license.',
'license_file.mimes' => 'The license file must be an image or a PDF.',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Validation error.',
'errors' => $validator->errors()
], 422);
}
try {
$sponsor = Sponsor::where('email', $request->email)->first();
if (!$sponsor) {
return response()->json([
'success' => false,
'message' => 'Sponsor account not found.'
], 404);
}
$licenseFile = $request->file('license_file');
$ocrLicense = \App\Services\OcrDocumentService::extractSponsorLicenseData($licenseFile);
$extractedExpiry = $ocrLicense['expiry_date'];
$sponsor->update([
'license_file' => null,
'license_expiry' => $extractedExpiry,
]);
return response()->json([
'success' => true,
'message' => 'License uploaded and processed successfully.',
'ocr_extracted_data' => $ocrLicense,
'email' => $request->email,
], 200);
} catch (\Exception $e) {
logger()->error('API Sponsor License Upload Failure: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'An error occurred while uploading the license.',
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
], 500);
}
}
}