migrant-web/app/Http/Controllers/Employer/EmployerAuthController.php
2026-05-21 10:39:23 +05:30

350 lines
12 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
auth()->login($user);
session(['user' => (object)[
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'role' => $user->role,
'subscription_status' => $user->subscription_status ?? 'active',
'verification_status' => $verification_status,
]]);
$request->session()->regenerate();
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' => 'required|string|max:255',
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255',
'phone' => 'required|string|regex:/^\+?[0-9\s\-()]{7,20}$/',
], [
'phone.regex' => 'The phone number must be a valid mobile number format.',
]);
// 2. Email uniqueness check (Check DB, return 409 if duplicate)
if (User::where('email', $request->email)->exists()) {
return response()->json([
'errors' => [
'email' => 'This email address is already registered. Please login or use a different email.'
]
], 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,
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone,
],
'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 in local environment for automated testing)
$isLocalDebug = app()->environment('local') && $request->otp === '000000';
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.create-password')
->with('success', 'Email verified successfully. Please set your password.');
}
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 showCreatePassword()
{
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/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')) {
return redirect()->route('employer.register')
->with('error', 'Registration session expired. Please start over.');
}
$pending = session('pending_employer_registration');
// Create user
$user = User::create([
'name' => $pending['name'],
'email' => $pending['email'],
'password' => Hash::make($request->password),
'role' => 'employer',
'subscription_status' => 'active', // Auto-active for direct entry
'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,
]);
// Create a default active premium subscription record
\Illuminate\Support\Facades\DB::table('subscriptions')->insert([
'user_id' => $user->id,
'plan_id' => 'premium',
'amount_aed' => 499.00,
'starts_at' => now(),
'expires_at' => now()->addDays(30),
'paytabs_transaction_id' => 'TXN-' . strtoupper(bin2hex(random_bytes(6))),
'status' => 'active',
'created_at' => now(),
'updated_at' => now(),
]);
// Auto-login (Laravel + Session)
auth()->login($user);
session(['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'
]);
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');
}
}