692 lines
28 KiB
PHP
692 lines
28 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Employer;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use Inertia\Inertia;
|
|
use App\Models\User;
|
|
use App\Models\EmployerProfile;
|
|
use App\Mail\EmployerOtpMail;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Support\Facades\Mail;
|
|
|
|
class EmployerAuthController extends Controller
|
|
{
|
|
public function showLogin()
|
|
{
|
|
return Inertia::render('Employer/Auth/Login');
|
|
}
|
|
|
|
public function login(Request $request)
|
|
{
|
|
$credentials = $request->validate([
|
|
'email' => ['required', 'email'],
|
|
'password' => ['required'],
|
|
]);
|
|
|
|
// Attempt actual database login
|
|
$user = User::where('email', $credentials['email'])->first();
|
|
if ($user && Hash::check($credentials['password'], $user->password) && $user->role === 'employer') {
|
|
$profile = EmployerProfile::where('user_id', $user->id)->first();
|
|
$verification_status = $profile ? $profile->verification_status : 'approved';
|
|
|
|
if ($verification_status === 'pending') {
|
|
return back()->with('status', 'pending_verification');
|
|
}
|
|
|
|
if ($verification_status === 'rejected') {
|
|
return back()->with([
|
|
'status' => 'rejected',
|
|
'reason' => ($profile && $profile->rejection_reason) ? $profile->rejection_reason : 'Emirates ID scan was blurry or illegible. Please provide a high-resolution color scan.',
|
|
]);
|
|
}
|
|
|
|
if ($user->subscription_status === 'expired') {
|
|
return back()->with('status', 'subscription_expired');
|
|
}
|
|
|
|
// Perform standard Laravel authentication (remember=true keeps auth cookie alive)
|
|
auth()->login($user, true);
|
|
|
|
// Regenerate BEFORE writing session data to avoid losing data on ID change
|
|
$request->session()->regenerate();
|
|
|
|
$request->session()->put('user', (object)[
|
|
'id' => $user->id,
|
|
'name' => $user->name,
|
|
'email' => $user->email,
|
|
'role' => $user->role,
|
|
'subscription_status' => $user->subscription_status ?? 'active',
|
|
'verification_status' => $verification_status,
|
|
]);
|
|
|
|
if ($request->source === 'mobile') {
|
|
return redirect('/mobile/employer/home');
|
|
}
|
|
|
|
return redirect()->intended('/employer/dashboard');
|
|
}
|
|
|
|
return back()->withErrors([
|
|
'email' => 'These credentials do not match our records.',
|
|
]);
|
|
}
|
|
|
|
public function showRegister()
|
|
{
|
|
return Inertia::render('Employer/Auth/Register');
|
|
}
|
|
|
|
public function register(Request $request)
|
|
{
|
|
// 1. Validation
|
|
$request->validate([
|
|
'company_name' => 'nullable|string|max:255',
|
|
'name' => 'required|string|max:255',
|
|
'email' => 'required|string|email|max:255',
|
|
'phone' => ['required', 'string', 'regex:/^\+?[0-9]{7,20}$/'],
|
|
'country_code' => 'nullable|string|max:10',
|
|
'address' => 'required|string|max:255',
|
|
], [
|
|
'phone.regex' => 'The mobile number must contain only digits (7-20 characters).',
|
|
]);
|
|
|
|
// 2. Email uniqueness check (Check DB, return 409 if duplicate)
|
|
if (User::where('email', $request->email)->exists() || \App\Models\Sponsor::where('email', $request->email)->exists()) {
|
|
return response()->json([
|
|
'errors' => [
|
|
'email' => 'This email address is already registered. Please login or use a different email.'
|
|
]
|
|
], 409);
|
|
}
|
|
|
|
// 2b. Phone uniqueness check
|
|
$phoneClean = preg_replace('/[^0-9]/', '', $request->phone);
|
|
if (\App\Models\EmployerProfile::where('phone', 'like', '%' . $phoneClean . '%')->exists() || \App\Models\Sponsor::where('mobile', 'like', '%' . $phoneClean . '%')->exists()) {
|
|
return response()->json([
|
|
'errors' => [
|
|
'phone' => 'This mobile number is already registered. Please login or use a different number.'
|
|
]
|
|
], 409);
|
|
}
|
|
|
|
// 3. Generate 6-digit OTP, hash & store with 10-min expiry
|
|
$otp = (string) mt_rand(100000, 999999);
|
|
$hashedOtp = Hash::make($otp);
|
|
|
|
session([
|
|
'pending_employer_registration' => [
|
|
'company_name' => $request->company_name ?: ($request->name . ' Household'),
|
|
'name' => $request->name,
|
|
'email' => $request->email,
|
|
'phone' => $request->phone,
|
|
'country_code' => $request->country_code,
|
|
'address' => $request->address,
|
|
],
|
|
'employer_otp' => [
|
|
'hash' => $hashedOtp,
|
|
'expires_at' => now()->addMinutes(10),
|
|
'attempts' => 0,
|
|
'last_sent_at' => now(),
|
|
]
|
|
]);
|
|
|
|
// 4. Send professional OTP email
|
|
try {
|
|
Mail::to($request->email)->send(new EmployerOtpMail(
|
|
$otp,
|
|
$request->company_name,
|
|
$request->name
|
|
));
|
|
} catch (\Exception $e) {
|
|
// Log error but proceed for local testing/robustness
|
|
logger()->error('Failed to send registration OTP email: ' . $e->getMessage());
|
|
}
|
|
|
|
return redirect()->route('employer.verify-email')
|
|
->with('success', 'Verification code sent to your email.');
|
|
}
|
|
|
|
public function showVerifyEmail()
|
|
{
|
|
if (!session()->has('pending_employer_registration')) {
|
|
return redirect()->route('employer.register')
|
|
->with('error', 'Please submit the registration form first.');
|
|
}
|
|
|
|
return Inertia::render('Employer/Auth/VerifyEmail', [
|
|
'email' => session('pending_employer_registration.email'),
|
|
]);
|
|
}
|
|
|
|
public function verifyEmail(Request $request)
|
|
{
|
|
$request->validate([
|
|
'otp' => 'required|string|size:6',
|
|
]);
|
|
|
|
if (!session()->has('pending_employer_registration') || !session()->has('employer_otp')) {
|
|
return redirect()->route('employer.register')
|
|
->with('error', 'Registration session expired. Please start over.');
|
|
}
|
|
|
|
$otpSession = session('employer_otp');
|
|
|
|
// Check attempts (max 3)
|
|
if ($otpSession['attempts'] >= 3) {
|
|
session()->forget(['pending_employer_registration', 'employer_otp']);
|
|
return redirect()->route('employer.register')
|
|
->with('error', 'Too many failed verification attempts. Please register again.');
|
|
}
|
|
|
|
// Check expiry (10 mins)
|
|
if (now()->greaterThan($otpSession['expires_at'])) {
|
|
return back()->withErrors([
|
|
'otp' => 'The verification code has expired. Please request a new one.'
|
|
]);
|
|
}
|
|
|
|
// Hash comparison (allow 000000 or 111111 in local/testing environment for automated testing)
|
|
$isLocalDebug = (app()->environment('local') || app()->environment('testing')) && ($request->otp === '000000' || $request->otp === '111111');
|
|
if (!$isLocalDebug && !Hash::check($request->otp, $otpSession['hash'])) {
|
|
$otpSession['attempts']++;
|
|
session(['employer_otp' => $otpSession]);
|
|
|
|
$attemptsLeft = 3 - $otpSession['attempts'];
|
|
if ($attemptsLeft <= 0) {
|
|
session()->forget(['pending_employer_registration', 'employer_otp']);
|
|
return redirect()->route('employer.register')
|
|
->with('error', 'Too many failed verification attempts. Please register again.');
|
|
}
|
|
|
|
return back()->withErrors([
|
|
'otp' => "Invalid verification code. You have {$attemptsLeft} attempts remaining."
|
|
]);
|
|
}
|
|
|
|
// Success - mark verified
|
|
session(['employer_email_verified' => true]);
|
|
|
|
return redirect()->route('employer.upload-emirates-id')
|
|
->with('success', 'Email verified successfully! Please upload your Emirates ID.');
|
|
}
|
|
|
|
public function resendOtp(Request $request)
|
|
{
|
|
if (!session()->has('pending_employer_registration')) {
|
|
return response()->json([
|
|
'message' => 'No pending registration session found.'
|
|
], 400);
|
|
}
|
|
|
|
$pending = session('pending_employer_registration');
|
|
$otpSession = session('employer_otp');
|
|
|
|
// Cooldown timer check (60s)
|
|
if ($otpSession && now()->diffInSeconds($otpSession['last_sent_at']) < 60) {
|
|
$secondsRemaining = 60 - now()->diffInSeconds($otpSession['last_sent_at']);
|
|
return response()->json([
|
|
'message' => "Please wait {$secondsRemaining} seconds before requesting a new code."
|
|
], 429);
|
|
}
|
|
|
|
$otp = (string) mt_rand(100000, 999999);
|
|
$hashedOtp = Hash::make($otp);
|
|
|
|
session([
|
|
'employer_otp' => [
|
|
'hash' => $hashedOtp,
|
|
'expires_at' => now()->addMinutes(10),
|
|
'attempts' => 0,
|
|
'last_sent_at' => now(),
|
|
]
|
|
]);
|
|
|
|
try {
|
|
Mail::to($pending['email'])->send(new EmployerOtpMail(
|
|
$otp,
|
|
$pending['company_name'],
|
|
$pending['name']
|
|
));
|
|
} catch (\Exception $e) {
|
|
logger()->error('Failed to resend registration OTP email: ' . $e->getMessage());
|
|
}
|
|
|
|
return response()->json([
|
|
'message' => 'A fresh verification code has been sent to your email.'
|
|
]);
|
|
}
|
|
|
|
public function showUploadEmiratesId()
|
|
{
|
|
if (!session()->has('pending_employer_registration') || !session('employer_email_verified')) {
|
|
return redirect()->route('employer.register')
|
|
->with('error', 'Please complete email verification first.');
|
|
}
|
|
|
|
return Inertia::render('Employer/Auth/UploadEmiratesId', [
|
|
'email' => session('pending_employer_registration.email'),
|
|
]);
|
|
}
|
|
|
|
public function uploadEmiratesId(Request $request)
|
|
{
|
|
if (!session()->has('pending_employer_registration') || !session('employer_email_verified')) {
|
|
return redirect()->route('employer.register')
|
|
->with('error', 'Registration session expired. Please start over.');
|
|
}
|
|
|
|
$request->validate([
|
|
'emirates_id_front' => 'required_without:emirates_id_file|file|mimes:jpeg,png,jpg,pdf|max:10240',
|
|
'emirates_id_back' => 'required_without:emirates_id_file|file|mimes:jpeg,png,jpg,pdf|max:10240',
|
|
'emirates_id_file' => 'required_without_all:emirates_id_front,emirates_id_back|file|mimes:jpeg,png,jpg,pdf|max:10240',
|
|
], [
|
|
'emirates_id_front.required_without' => 'Please upload the front side of your Emirates ID.',
|
|
'emirates_id_back.required_without' => 'Please upload the back side of your Emirates ID.',
|
|
'emirates_id_front.mimes' => 'The Emirates ID front must be an image or a PDF.',
|
|
'emirates_id_back.mimes' => 'The Emirates ID back must be an image or a PDF.',
|
|
]);
|
|
|
|
$extractedIdNumber = null;
|
|
$extractedExpiry = null;
|
|
$extractedName = null;
|
|
$extractedDob = null;
|
|
$extractedNationality = null;
|
|
$extractedIssueDate = null;
|
|
$extractedEmployer = null;
|
|
$extractedIssuePlace = null;
|
|
$extractedOccupation = null;
|
|
$extractedCardNumber = null;
|
|
$extractedGender = null;
|
|
|
|
if ($request->hasFile('emirates_id_front')) {
|
|
$frontFile = $request->file('emirates_id_front');
|
|
$frontOcr = \App\Services\OcrDocumentService::extractEmiratesIdFrontData($frontFile);
|
|
$extractedIdNumber = $frontOcr['emirates_id_number'];
|
|
$extractedName = $frontOcr['name'] ?? null;
|
|
$extractedDob = $frontOcr['date_of_birth'] ?? null;
|
|
$extractedNationality = $frontOcr['nationality'] ?? null;
|
|
$extractedCardNumber = $frontOcr['card_number'] ?? null;
|
|
$extractedGender = $frontOcr['gender'] ?? null;
|
|
$extractedOccupation = $frontOcr['occupation'] ?? null;
|
|
$extractedEmployer = $frontOcr['employer'] ?? null;
|
|
$extractedIssuePlace = $frontOcr['issue_place'] ?? null;
|
|
}
|
|
|
|
if ($request->hasFile('emirates_id_back')) {
|
|
$backFile = $request->file('emirates_id_back');
|
|
$backOcr = \App\Services\OcrDocumentService::extractEmiratesIdBackData($backFile);
|
|
$extractedExpiry = $backOcr['expiry_date'];
|
|
$extractedIssueDate = $backOcr['issue_date'] ?? null;
|
|
}
|
|
|
|
if ($request->hasFile('emirates_id_file')) {
|
|
$file = $request->file('emirates_id_file');
|
|
$frontOcr = \App\Services\OcrDocumentService::extractEmiratesIdFrontData($file);
|
|
$backOcr = \App\Services\OcrDocumentService::extractEmiratesIdBackData($file);
|
|
$extractedIdNumber = $frontOcr['emirates_id_number'];
|
|
$extractedExpiry = $backOcr['expiry_date'];
|
|
$extractedName = $frontOcr['name'] ?? null;
|
|
$extractedDob = $frontOcr['date_of_birth'] ?? null;
|
|
$extractedNationality = $frontOcr['nationality'] ?? null;
|
|
$extractedCardNumber = $frontOcr['card_number'] ?? null;
|
|
$extractedGender = $frontOcr['gender'] ?? null;
|
|
$extractedOccupation = $frontOcr['occupation'] ?? null;
|
|
$extractedEmployer = $frontOcr['employer'] ?? null;
|
|
$extractedIssuePlace = $frontOcr['issue_place'] ?? null;
|
|
$extractedIssueDate = $backOcr['issue_date'] ?? null;
|
|
}
|
|
|
|
if (($request->hasFile('emirates_id_front') || $request->hasFile('emirates_id_file')) && empty($extractedName)) {
|
|
return response()->json([
|
|
'errors' => [
|
|
'emirates_id_front' => ['Failed to extract name from the Emirates ID. Please upload a clear image.']
|
|
]
|
|
], 422);
|
|
}
|
|
|
|
$pending = session('pending_employer_registration');
|
|
$pending['emirates_id_file'] = null;
|
|
$pending['emirates_id_number'] = $extractedIdNumber;
|
|
$pending['emirates_id_expiry'] = $extractedExpiry;
|
|
$pending['emirates_id_name'] = $extractedName;
|
|
$pending['emirates_id_dob'] = $extractedDob;
|
|
$pending['emirates_id_nationality'] = $extractedNationality;
|
|
$pending['emirates_id_card_number'] = $extractedCardNumber;
|
|
$pending['emirates_id_gender'] = $extractedGender;
|
|
$pending['emirates_id_occupation'] = $extractedOccupation;
|
|
$pending['emirates_id_employer'] = $extractedEmployer;
|
|
$pending['emirates_id_issue_place'] = $extractedIssuePlace;
|
|
$pending['emirates_id_issue_date'] = $extractedIssueDate;
|
|
|
|
if (!empty($extractedName)) {
|
|
if (isset($pending['company_name']) && (empty($pending['company_name']) || $pending['company_name'] === ($pending['name'] ?? '') . ' Household')) {
|
|
$pending['company_name'] = $extractedName . ' Household';
|
|
}
|
|
$pending['name'] = $extractedName;
|
|
}
|
|
|
|
session(['pending_employer_registration' => $pending]);
|
|
session(['employer_emirates_id_uploaded' => true]);
|
|
|
|
return redirect()->route('employer.register-payment')
|
|
->with('success', 'Emirates ID uploaded and verified successfully.');
|
|
}
|
|
|
|
public function showRegisterPayment()
|
|
{
|
|
if (!session()->has('pending_employer_registration') || !session('employer_email_verified') || !session('employer_emirates_id_uploaded')) {
|
|
return redirect()->route('employer.register')
|
|
->with('error', 'Please complete Emirates ID upload first.');
|
|
}
|
|
|
|
return Inertia::render('Employer/Auth/RegisterPayment', [
|
|
'email' => session('pending_employer_registration.email'),
|
|
'plans' => [
|
|
[
|
|
'id' => 'basic',
|
|
'name' => 'Basic Search Pass',
|
|
'price' => '99 AED',
|
|
'period' => 'month',
|
|
'features' => ['Browse 500+ verified workers', 'Shortlist up to 10 candidates', 'Standard OCR verification'],
|
|
'popular' => false,
|
|
],
|
|
[
|
|
'id' => 'premium',
|
|
'name' => 'Premium Sponsor Pass',
|
|
'price' => '199 AED',
|
|
'period' => 'month',
|
|
'features' => ['Unlimited shortlisting', 'Direct candidate messaging', 'Priority interview scheduling', 'Dedicated support'],
|
|
'popular' => true,
|
|
],
|
|
[
|
|
'id' => 'enterprise',
|
|
'name' => 'VIP Concierge Pass',
|
|
'price' => '499 AED',
|
|
'period' => 'month',
|
|
'features' => ['All Premium features', 'Assigned recruitment manager', 'Background medical verification guarantee', 'Free replacement within 30 days'],
|
|
'popular' => false,
|
|
],
|
|
]
|
|
]);
|
|
}
|
|
|
|
public function storeRegisterPayment(Request $request)
|
|
{
|
|
$request->validate([
|
|
'plan_id' => 'required|string',
|
|
'amount_aed' => 'required|numeric',
|
|
'paytabs_transaction_id' => 'required|string',
|
|
]);
|
|
|
|
session([
|
|
'pending_employer_payment' => [
|
|
'plan_id' => $request->plan_id,
|
|
'amount_aed' => $request->amount_aed,
|
|
'paytabs_transaction_id' => $request->paytabs_transaction_id,
|
|
]
|
|
]);
|
|
|
|
return response()->json([
|
|
'message' => 'Payment processed successfully.'
|
|
]);
|
|
}
|
|
|
|
public function showCreatePassword()
|
|
{
|
|
if (!session()->has('pending_employer_registration') || !session('employer_email_verified') || !session('employer_emirates_id_uploaded') || !session()->has('pending_employer_payment')) {
|
|
return redirect()->route('employer.register')
|
|
->with('error', 'Please complete payment step first.');
|
|
}
|
|
|
|
return Inertia::render('Employer/Auth/CreatePassword');
|
|
}
|
|
|
|
public function createPassword(Request $request)
|
|
{
|
|
$request->validate([
|
|
'password' => [
|
|
'required',
|
|
'string',
|
|
'min:8',
|
|
'confirmed',
|
|
'regex:/[a-z]/', // 1 lowercase
|
|
'regex:/[A-Z]/', // 1 uppercase
|
|
'regex:/[0-9]/', // 1 number
|
|
'regex:/[^a-zA-Z0-9]/', // 1 special character
|
|
]
|
|
], [
|
|
'password.regex' => 'The password must contain at least 8 characters, including 1 uppercase, 1 lowercase, 1 number, and 1 special character.',
|
|
]);
|
|
|
|
if (!session()->has('pending_employer_registration') || !session('employer_email_verified') || !session('employer_emirates_id_uploaded') || !session()->has('pending_employer_payment')) {
|
|
return redirect()->route('employer.register')
|
|
->with('error', 'Registration session expired. Please start over.');
|
|
}
|
|
|
|
$pending = session('pending_employer_registration');
|
|
$payment = session('pending_employer_payment');
|
|
|
|
// Create user
|
|
$user = User::create([
|
|
'name' => $pending['name'],
|
|
'email' => $pending['email'],
|
|
'password' => Hash::make($request->password),
|
|
'role' => 'employer',
|
|
'subscription_status' => 'active',
|
|
'subscription_expires_at' => now()->addDays(30),
|
|
]);
|
|
|
|
// Create profile
|
|
EmployerProfile::create([
|
|
'user_id' => $user->id,
|
|
'company_name' => $pending['company_name'],
|
|
'phone' => $pending['phone'],
|
|
'country' => 'United Arab Emirates', // Default country since dropdown was removed
|
|
'verification_status' => 'approved',
|
|
'language' => 'English',
|
|
'notifications' => true,
|
|
'emirates_id_front' => null, // We did not store the file
|
|
'emirates_id_number' => $pending['emirates_id_number'] ?? null,
|
|
'emirates_id_expiry' => $pending['emirates_id_expiry'] ?? null,
|
|
'emirates_id_name' => $pending['emirates_id_name'] ?? null,
|
|
'emirates_id_dob' => $pending['emirates_id_dob'] ?? null,
|
|
'emirates_id_issue_date' => $pending['emirates_id_issue_date'] ?? null,
|
|
'emirates_id_employer' => $pending['emirates_id_employer'] ?? null,
|
|
'emirates_id_issue_place' => $pending['emirates_id_issue_place'] ?? null,
|
|
'emirates_id_occupation' => $pending['emirates_id_occupation'] ?? null,
|
|
'emirates_id_card_number' => $pending['emirates_id_card_number'] ?? null,
|
|
'emirates_id_gender' => $pending['emirates_id_gender'] ?? null,
|
|
'nationality' => $pending['emirates_id_nationality'] ?? null,
|
|
'address' => $pending['address'] ?? null,
|
|
]);
|
|
|
|
// Create Sponsor
|
|
\App\Models\Sponsor::create([
|
|
'full_name' => $pending['name'],
|
|
'email' => $pending['email'],
|
|
'mobile' => $pending['phone'],
|
|
'password' => Hash::make($request->password),
|
|
'country_code' => 'AE',
|
|
'subscription_status' => 'active',
|
|
'subscription_plan' => $payment['plan_id'],
|
|
'subscription_start_date' => now(),
|
|
'subscription_end_date' => now()->addDays(30),
|
|
'payment_status' => 'paid',
|
|
'is_verified' => true,
|
|
'otp_verified_at' => now(),
|
|
'status' => 'active',
|
|
'last_login_at' => now(),
|
|
'emirates_id_file' => null, // We did not store the file
|
|
'address' => $pending['address'] ?? null,
|
|
'emirates_id' => $pending['emirates_id_number'] ?? null,
|
|
'emirates_id_name' => $pending['emirates_id_name'] ?? null,
|
|
'emirates_id_dob' => $pending['emirates_id_dob'] ?? null,
|
|
'emirates_id_issue_date' => $pending['emirates_id_issue_date'] ?? null,
|
|
'emirates_id_expiry' => $pending['emirates_id_expiry'] ?? null,
|
|
'emirates_id_employer' => $pending['emirates_id_employer'] ?? null,
|
|
'emirates_id_issue_place' => $pending['emirates_id_issue_place'] ?? null,
|
|
'emirates_id_occupation' => $pending['emirates_id_occupation'] ?? null,
|
|
'emirates_id_card_number' => $pending['emirates_id_card_number'] ?? null,
|
|
'emirates_id_gender' => $pending['emirates_id_gender'] ?? null,
|
|
'nationality' => $pending['emirates_id_nationality'] ?? null,
|
|
]);
|
|
|
|
// Create active subscription in database
|
|
\Illuminate\Support\Facades\DB::table('subscriptions')->insert([
|
|
'user_id' => $user->id,
|
|
'plan_id' => $payment['plan_id'],
|
|
'amount_aed' => $payment['amount_aed'],
|
|
'starts_at' => now(),
|
|
'expires_at' => now()->addDays(30),
|
|
'paytabs_transaction_id' => $payment['paytabs_transaction_id'],
|
|
'status' => 'active',
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
// Auto-login (Laravel + Session) with remember=true for persistence
|
|
auth()->login($user, true);
|
|
|
|
// Regenerate session ID BEFORE writing data
|
|
request()->session()->regenerate();
|
|
|
|
request()->session()->put('user', (object)[
|
|
'id' => $user->id,
|
|
'name' => $user->name,
|
|
'email' => $user->email,
|
|
'role' => 'employer',
|
|
'subscription_status' => 'active',
|
|
'verification_status' => 'approved',
|
|
]);
|
|
|
|
// Flash first_login toast flag
|
|
session()->flash('first_login', true);
|
|
|
|
// Clear registration session keys
|
|
session()->forget([
|
|
'pending_employer_registration',
|
|
'employer_otp',
|
|
'employer_email_verified',
|
|
'employer_emirates_id_uploaded',
|
|
'pending_employer_payment'
|
|
]);
|
|
|
|
return redirect()->route('employer.dashboard')
|
|
->with('success', 'Welcome aboard! Your registration is complete.');
|
|
}
|
|
|
|
public function logout(Request $request)
|
|
{
|
|
session()->forget('user');
|
|
auth()->logout();
|
|
$request->session()->invalidate();
|
|
$request->session()->regenerateToken();
|
|
|
|
return redirect()->route('employer.login')
|
|
->with('success', 'Logged out successfully.');
|
|
}
|
|
|
|
public function forgotPassword(Request $request)
|
|
{
|
|
$request->validate([
|
|
'email' => 'required|email',
|
|
]);
|
|
|
|
$user = User::where('email', $request->email)->where('role', 'employer')->first();
|
|
if (!$user) {
|
|
return response()->json([
|
|
'message' => 'No employer account found with this email address.'
|
|
], 404);
|
|
}
|
|
|
|
$otp = '111111'; // default development OTP
|
|
if (app()->environment('production')) {
|
|
$otp = strval(rand(100000, 999999));
|
|
}
|
|
|
|
\Illuminate\Support\Facades\Cache::put('employer_reset_otp_' . $request->email, [
|
|
'code' => $otp,
|
|
'expires_at' => now()->addMinutes(10)->timestamp
|
|
], 600);
|
|
|
|
// Send reset OTP email
|
|
try {
|
|
Mail::to($request->email)->send(new \App\Mail\EmployerResetOtpMail(
|
|
$otp,
|
|
$user->name
|
|
));
|
|
} catch (\Exception $e) {
|
|
logger()->error('Web Employer Forgot Password Mail Failure: ' . $e->getMessage());
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Verification code sent to your email.'
|
|
]);
|
|
}
|
|
|
|
public function resetPassword(Request $request)
|
|
{
|
|
$request->validate([
|
|
'email' => 'required|email',
|
|
'otp' => 'required|string|size:6',
|
|
'password' => [
|
|
'required',
|
|
'string',
|
|
'min:8',
|
|
'confirmed',
|
|
'regex:/[a-z]/', // 1 lowercase
|
|
'regex:/[A-Z]/', // 1 uppercase
|
|
'regex:/[0-9]/', // 1 number
|
|
'regex:/[^a-zA-Z0-9]/', // 1 special character
|
|
]
|
|
], [
|
|
'password.regex' => 'The password must contain at least 8 characters, including 1 uppercase, 1 lowercase, 1 number, and 1 special character.',
|
|
]);
|
|
|
|
$cachedData = \Illuminate\Support\Facades\Cache::get('employer_reset_otp_' . $request->email);
|
|
|
|
if (!$cachedData || !isset($cachedData['code']) || !isset($cachedData['expires_at'])) {
|
|
return response()->json([
|
|
'message' => 'Invalid or expired verification code.'
|
|
], 400);
|
|
}
|
|
|
|
if ($cachedData['code'] !== $request->otp || now()->timestamp > $cachedData['expires_at']) {
|
|
return response()->json([
|
|
'message' => 'Invalid or expired verification code.'
|
|
], 400);
|
|
}
|
|
|
|
$user = User::where('email', $request->email)->where('role', 'employer')->first();
|
|
$sponsor = \App\Models\Sponsor::where('email', $request->email)->first();
|
|
|
|
if (!$user || !$sponsor) {
|
|
return response()->json([
|
|
'message' => 'User account not found.'
|
|
], 404);
|
|
}
|
|
|
|
\Illuminate\Support\Facades\DB::transaction(function () use ($request, $user, $sponsor) {
|
|
$hashedPassword = Hash::make($request->password);
|
|
|
|
$user->update([
|
|
'password' => $hashedPassword,
|
|
]);
|
|
|
|
$sponsor->update([
|
|
'password' => $hashedPassword,
|
|
]);
|
|
});
|
|
|
|
\Illuminate\Support\Facades\Cache::forget('employer_reset_otp_' . $request->email);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Password reset successfully.'
|
|
]);
|
|
}
|
|
}
|