LearnMood/app/Http/Controllers/Auth/ForgotPasswordController.php

197 lines
6.9 KiB
PHP

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\PasswordReset;
use Carbon\Carbon;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
class ForgotPasswordController extends Controller
{
/**
* Tampilkan form request OTP
*/
public function showForgotForm()
{
return view('auth.forgot-password');
}
/**
* Kirim OTP ke email menggunakan Laravel Mail
*/
public function sendOtp(Request $request)
{
$request->validate([
'email' => 'required|email|exists:users,email',
], [
'email.exists' => 'Email tidak terdaftar dalam sistem.'
]);
$user = User::where('email', $request->email)->first();
// Generate OTP 6 digit
$otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
// Simpan OTP ke database (expired 5 menit)
PasswordReset::updateOrCreate(
['email' => $request->email],
[
'token' => $otp,
'created_at' => Carbon::now(),
]
);
// Kirim email menggunakan Laravel Mail
try {
Mail::send([], [], function ($message) use ($user, $otp) {
$message->to($user->email, $user->name)
->subject('Kode OTP Reset Password - LearnMood')
->html($this->getEmailTemplate($user->name, $otp, $user->email));
});
return redirect()->route('password.verify.form', ['email' => $request->email])
->with('success', 'Kode OTP telah dikirim ke email Anda. Cek inbox/spam folder.');
} catch (\Exception $e) {
// Log error
\Log::error('Email error: ' . $e->getMessage());
// Untuk development, tampilkan OTP di session
return redirect()->route('password.verify.form', ['email' => $request->email])
->with('dev_otp', $otp)
->with('success', '🔧 Mode Development - Gagal kirim email. Gunakan kode OTP berikut:');
}
}
/**
* Tampilkan form verifikasi OTP
*/
public function showVerifyForm(Request $request)
{
return view('auth.verify-code', ['email' => $request->email]);
}
/**
* Verifikasi OTP
*/
public function verifyOtp(Request $request)
{
$request->validate([
'email' => 'required|email',
'otp' => 'required|string|size:6',
]);
$reset = PasswordReset::where('email', $request->email)
->where('token', $request->otp)
->first();
if (!$reset) {
return back()->with('error', 'Kode OTP tidak valid.');
}
// Cek apakah OTP sudah expired (lebih dari 5 menit)
if (Carbon::parse($reset->created_at)->addMinutes(5)->isPast()) {
$reset->delete();
return back()->with('error', 'Kode OTP sudah kadaluarsa. Silakan minta kode baru.');
}
// OTP valid, arahkan ke form reset password
return redirect()->route('password.reset.form', [
'email' => $request->email,
'token' => $request->otp
])->with('success', 'Kode valid. Silakan buat password baru.');
}
/**
* Tampilkan form reset password
*/
public function showResetForm(Request $request)
{
return view('auth.reset-password', [
'email' => $request->email,
'token' => $request->token
]);
}
/**
* Reset password dengan OTP
*/
public function resetPassword(Request $request)
{
$request->validate([
'email' => 'required|email',
'token' => 'required|string|size:6',
'password' => 'required|string|min:8|confirmed',
]);
// Verifikasi OTP sekali lagi
$reset = PasswordReset::where('email', $request->email)
->where('token', $request->token)
->first();
if (!$reset || Carbon::parse($reset->created_at)->addMinutes(5)->isPast()) {
return back()->with('error', 'Kode OTP tidak valid atau sudah kadaluarsa.');
}
// Update password user
$user = User::where('email', $request->email)->first();
$user->password = Hash::make($request->password);
$user->save();
// Hapus data reset
$reset->delete();
return redirect()->route('login')
->with('success', 'Password berhasil direset. Silakan login dengan password baru.');
}
/**
* Template email HTML
*/
private function getEmailTemplate($toName, $otp, $toEmail)
{
return "
<!DOCTYPE html>
<html>
<head>
<title>Kode OTP Reset Password</title>
</head>
<body style='font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 20px;'>
<div style='max-width: 500px; margin: 0 auto; background-color: white; border-radius: 10px; padding: 30px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>
<div style='text-align: center; margin-bottom: 25px;'>
<h1 style='color: #4A90E2; margin: 0;'>Learn<span style='color: #333;'>Mood</span></h1>
</div>
<p style='font-size: 16px; color: #333;'>Halo <strong>{$toName}</strong>,</p>
<p style='font-size: 14px; color: #666;'>Kami menerima permintaan reset password untuk akun Anda. Gunakan kode OTP berikut untuk melanjutkan:</p>
<div style='background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; text-align: center; border-radius: 8px; margin: 25px 0;'>
<p style='margin: 0; font-size: 14px; color: rgba(255,255,255,0.9);'>Kode Verifikasi</p>
<h1 style='font-size: 48px; letter-spacing: 8px; color: white; margin: 10px 0; font-family: monospace;'>{$otp}</h1>
</div>
<div style='background-color: #f8f9fa; padding: 15px; border-radius: 8px; margin: 20px 0;'>
<p style='margin: 0; font-size: 13px; color: #666;'>
<strong>⏰ Berlaku selama:</strong> 5 menit<br>
<strong>📧 Email:</strong> {$toEmail}
</p>
</div>
<p style='font-size: 13px; color: #999; border-top: 1px solid #eee; padding-top: 20px; margin-top: 20px;'>
Jika Anda tidak meminta reset password, abaikan email ini.
</p>
<p style='font-size: 12px; color: #999; text-align: center; margin-top: 20px;'>
&copy; " . date('Y') . " LearnMood. All rights reserved.
</p>
</div>
</body>
</html>
";
}
}