diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 5df0a75b..3dc98ca6 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -135,21 +135,18 @@ protected function sendLoginResponse(Request $request) $user->update(['last_ip' => $request->ip()]); if (! $user->email_verified_at) { - $this->guard()->logout(); - - $request->session()->invalidate(); - $request->session()->regenerateToken(); + // Send verification code - user stays logged in + \App\Http\Controllers\EmailVerificationController::sendVerificationCode($user, $request); if ($request->expectsJson() || $request->ajax()) { return response()->json([ 'redirect' => url('/auth/verify-email'), - 'message' => 'You need to verify your email.', - ], 403); + 'message' => 'Please verify your email to continue.', + 'verification_sent' => true, + ]); } - return redirect()->route('login')->withErrors([ - $this->username() => 'You need to verify your email.', - ]); + return redirect('/auth/verify-email'); } if ((int) $user->status === 6) { diff --git a/app/Http/Controllers/EmailVerificationController.php b/app/Http/Controllers/EmailVerificationController.php index 9df93dda..ced51045 100644 --- a/app/Http/Controllers/EmailVerificationController.php +++ b/app/Http/Controllers/EmailVerificationController.php @@ -15,6 +15,54 @@ class EmailVerificationController extends Controller { + /** + * Send verification code for a user (can be called from other controllers) + * + * Checks if there's already a pending (unverified) code for this user. + * If true, resends the same code (in case original was lost/spam). + * If false, creates a new code and sends the verification email. + * + * @return bool True if a new code was created, false if existing code was resent + */ + public static function sendVerificationCode(User $user, Request $request): bool + { + // Check for existing pending verification code + $existing = UserRegisterVerify::whereEmail($user->email) + ->whereNull('verified_at') + ->latest() + ->first(); + + if ($existing) { + // Resend existing code (in case it was lost or caught in spam) + $request->session()->put('user:reg:session_key', $existing->session_key); + $request->session()->put('user:reg:email', $existing->email); + $request->session()->put('user:reg:id', $existing->id); + + NewAccountEmailVerifyJob::dispatch($existing); + + return false; + } + + // Create new verification code and send email + $sessionKey = Str::random(32); + $reg = new UserRegisterVerify; + $reg->session_key = $sessionKey; + $reg->email = $user->email; + $reg->verify_code = (string) app(VerificationCode::class)->generate(); + $reg->ip_address = $request->ip(); + $reg->user_agent = $request->userAgent(); + $reg->email_last_sent_at = now(); + $reg->save(); + + $request->session()->put('user:reg:session_key', $sessionKey); + $request->session()->put('user:reg:email', $reg->email); + $request->session()->put('user:reg:id', $reg->id); + + NewAccountEmailVerifyJob::dispatch($reg); + + return true; + } + /** * Initiate email verification - send code */ @@ -48,37 +96,7 @@ public function initiate(EmailManualVerificationRequest $request) ], 400); } - $existing = UserRegisterVerify::whereEmail($user->email) - ->whereNull('verified_at') - ->latest() - ->first(); - - if ($existing) { - $request->session()->put('user:reg:session_key', $existing->session_key); - $request->session()->put('user:reg:email', $existing->email); - $request->session()->put('user:reg:id', $existing->id); - - return response()->json([ - 'message' => 'We have already sent a verification code to your email.', - 'expires_in' => 900, - ]); - } - - $sessionKey = Str::random(32); - $reg = new UserRegisterVerify; - $reg->session_key = $sessionKey; - $reg->email = $user->email; - $reg->verify_code = (string) app(VerificationCode::class)->generate(); - $reg->ip_address = $request->ip(); - $reg->user_agent = $request->userAgent(); - $reg->email_last_sent_at = now(); - $reg->save(); - - $request->session()->put('user:reg:session_key', $sessionKey); - $request->session()->put('user:reg:email', $reg->email); - $request->session()->put('user:reg:id', $reg->id); - - NewAccountEmailVerifyJob::dispatch($reg); + self::sendVerificationCode($user, $request); return response()->json([ 'message' => 'Verification code sent to your email.', @@ -217,4 +235,41 @@ public function resend(Request $request) 'message' => 'New verification code sent to your email.', ]); } + + /** + * Check if there's a pending email verification session + */ + public function status(Request $request) + { + $sEmail = $request->session()->get('user:reg:email'); + $sKey = $request->session()->get('user:reg:session_key'); + $sId = $request->session()->get('user:reg:id'); + + if (! $sEmail || ! $sKey || ! $sId) { + return response()->json([ + 'has_pending_verification' => false, + ]); + } + + // Verify the session is still valid + $verify = UserRegisterVerify::where('session_key', $sKey) + ->whereNull('verified_at') + ->find($sId); + + if (! $verify) { + return response()->json([ + 'has_pending_verification' => false, + ]); + } + + // Mask the email for privacy (show first 2 chars and domain) + $emailParts = explode('@', $sEmail); + $maskedEmail = substr($emailParts[0], 0, 2).'***@'.$emailParts[1]; + + return response()->json([ + 'has_pending_verification' => true, + 'email' => $sEmail, + 'masked_email' => $maskedEmail, + ]); + } } diff --git a/resources/js/components/AuthModal.vue b/resources/js/components/AuthModal.vue index 3d1a278d..7c7ee518 100644 --- a/resources/js/components/AuthModal.vue +++ b/resources/js/components/AuthModal.vue @@ -1427,6 +1427,8 @@ const handleLogin = async () => { if (res.data.has_2fa) { currentMode.value = 'two-factor' setSuccess(t('common.pleaseEnterYour2FACode')) + } else if (res.data.verification_sent) { + window.location.href = '/auth/verify-email' } else if (res.data.redirect) { window.location.href = res.data.redirect } else { diff --git a/resources/js/pages/auth/manuallyVerifyEmail.vue b/resources/js/pages/auth/manuallyVerifyEmail.vue index 9131d6c7..9ecc55e7 100644 --- a/resources/js/pages/auth/manuallyVerifyEmail.vue +++ b/resources/js/pages/auth/manuallyVerifyEmail.vue @@ -4,328 +4,347 @@ class="grid min-h-full w-full place-items-center bg-white dark:bg-slate-950 px-6 py-24 sm:py-32 lg:px-8" >
- {{ getSubtitle() }} -
-- {{ t('common.yourEmailHasBeenVerifiedYouCanNowSignIn') }} -
- -{{ t('common.loading') }}...
+ {{ getSubtitle() }} +
+- {{ errorMessage }} -
-+ {{ t('common.yourEmailHasBeenVerifiedYouCanNowSignIn') }} +
+ +- {{ error }} -
+ ++ {{ errorMessage }} +
++ {{ t('common.thisVerificationLinkWillExpireIn24Hours') }} +
+