validate([ 'user_id' => 'required|exists:users,id', ]); $user = User::findOrFail($request->user_id); // Generate a 6-digit OTP $otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT); // Store OTP in cache keyed by user email — expires in 15 minutes Cache::put('reset_otp_' . $user->email, $otp, now()->addMinutes(15)); return response()->json([ 'status' => 'success', 'otp' => $otp, ]); } /** * Verify the OTP provided by the user against cache. */ public function verifyOtp(Request $request) { $request->validate([ 'otp' => 'required|string|size:6', 'email' => 'required|email|exists:users,email', ]); $cachedOtp = Cache::get('reset_otp_' . $request->email); if (!$cachedOtp) { return response()->json([ 'status' => 'error', 'message' => 'OTP sudah kedaluwarsa. Minta admin untuk generate ulang.', ], 422); } if ($request->otp !== $cachedOtp) { return response()->json([ 'status' => 'error', 'message' => 'Kode OTP salah! Cek lagi kode yang dikirim admin.', ], 422); } // Store verified email in a separate short-lived cache key Cache::put('reset_otp_verified_' . $request->email, true, now()->addMinutes(15)); return response()->json([ 'status' => 'success', 'email' => $request->email, ]); } /** * Update the password for the user whose OTP was verified. */ public function updatePassword(Request $request) { $request->validate([ 'email' => 'required|email|exists:users,email', 'password' => 'required|string|min:8|confirmed', ]); // Ensure OTP was verified if (!Cache::get('reset_otp_verified_' . $request->email)) { return response()->json([ 'status' => 'error', 'message' => 'Sesi tidak valid. Silakan verifikasi OTP terlebih dahulu.', ], 403); } $user = User::where('email', $request->email)->firstOrFail(); $user->password = Hash::make($request->password); $user->save(); // Clear OTP cache data Cache::forget('reset_otp_' . $request->email); Cache::forget('reset_otp_verified_' . $request->email); return response()->json([ 'status' => 'success', 'message' => 'Password berhasil diperbarui.', ]); } }