diff --git a/app/Console/Commands/ResetCardsCommand.php b/app/Console/Commands/ResetCardsCommand.php index d3c3db6..b8068e0 100644 --- a/app/Console/Commands/ResetCardsCommand.php +++ b/app/Console/Commands/ResetCardsCommand.php @@ -19,7 +19,15 @@ class ResetCardsCommand extends Command public function handle() { - $this->adminService->resetAllCards(); - $this->info('Successfully reset all cards for active members to 0!'); + try { + $this->adminService->resetAllCards(); + $this->info('Successfully reset all cards for active members to 0!'); + } catch (\Throwable $e) { + \Illuminate\Support\Facades\Log::error('Lỗi xảy ra khi chạy command reset thẻ hàng tháng (cards:reset): ' . $e->getMessage()); + $this->error('Reset cards failed: ' . $e->getMessage()); + return Command::FAILURE; + } + + return Command::SUCCESS; } } diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index 41605d8..caa1271 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -74,4 +74,26 @@ class AuthController extends Controller $this->authService->logout($request); return redirect('/login'); } + + public function forgotPassword(Request $request) + { + $validator = \Illuminate\Support\Facades\Validator::make($request->all(), [ + 'mail' => 'required|email|max:255', + ], [ + 'mail.required' => config('constants.MSG_FORGOT_PWD_EMAIL_REQUIRED'), + 'mail.email' => config('constants.MSG_FORGOT_PWD_EMAIL_INVALID'), + ]); + + if ($validator->fails()) { + return back()->withInput()->with('dialog_forgot_error', $validator->errors()->first()); + } + + $result = $this->authService->forgotPassword($request->input('mail')); + + if (!$result['success']) { + return back()->withInput()->with('dialog_forgot_error', $result['error_msg']); + } + + return back()->with('dialog_forgot_success', $result['message']); + } } diff --git a/app/Mail/ResetPasswordMail.php b/app/Mail/ResetPasswordMail.php new file mode 100644 index 0000000..30c4933 --- /dev/null +++ b/app/Mail/ResetPasswordMail.php @@ -0,0 +1,39 @@ +count(); + User::where('status', config('constants.STATUS_ACTIVE'))->update([ 'card' => 0, 'flag_send' => config('constants.FLAG_SEND_DISABLED'), ]); + + \Illuminate\Support\Facades\Log::info("Thực hiện reset thẻ hàng tháng thành công cho {$activeUserCount} tài khoản active."); } public function updateAddCard(int $id, array $data): void diff --git a/app/Services/Auth/AuthService.php b/app/Services/Auth/AuthService.php index b5d87d2..b1cfbe7 100644 --- a/app/Services/Auth/AuthService.php +++ b/app/Services/Auth/AuthService.php @@ -47,4 +47,36 @@ class AuthService implements AuthServiceInterface return route('user.dashboard'); } + + public function forgotPassword(string $email): array + { + $email = \Illuminate\Support\Str::lower(trim($email)); + $user = User::where('mail', $email)->first(); + + if (!$user) { + return ['success' => false, 'error_msg' => config('constants.MSG_FORGOT_PWD_EMAIL_NOT_FOUND')]; + } + + if ($user->status != config('constants.STATUS_ACTIVE')) { + return ['success' => false, 'error_msg' => config('constants.MSG_FORGOT_PWD_ACCOUNT_INACTIVE')]; + } + + // Generate random password (8 characters) + $newPassword = \Illuminate\Support\Str::random(8); + + // Update password with md5 and set first_login flag to 1 + $user->pass = md5($newPassword); + $user->first_login = config('constants.FIRST_LOGIN_TRUE'); + $user->save(); + + // Send Email + try { + \Illuminate\Support\Facades\Mail::to($user->mail)->send(new \App\Mail\ResetPasswordMail($user, $newPassword)); + } catch (\Exception $e) { + \Illuminate\Support\Facades\Log::error('Failed to send reset password email: ' . $e->getMessage()); + return ['success' => false, 'error_msg' => config('constants.MSG_FORGOT_PWD_MAIL_FAILED')]; + } + + return ['success' => true, 'message' => config('constants.MSG_FORGOT_PWD_SUCCESS')]; + } } \ No newline at end of file diff --git a/app/Services/Auth/Contracts/AuthServiceInterface.php b/app/Services/Auth/Contracts/AuthServiceInterface.php index b11b29a..e474c6e 100644 --- a/app/Services/Auth/Contracts/AuthServiceInterface.php +++ b/app/Services/Auth/Contracts/AuthServiceInterface.php @@ -12,4 +12,6 @@ interface AuthServiceInterface public function logout(Request $request): void; public function getRedirectRouteForUser(User $user): string; + + public function forgotPassword(string $email): array; } \ No newline at end of file diff --git a/config/constants.php b/config/constants.php index 989e45f..02c4aaa 100644 --- a/config/constants.php +++ b/config/constants.php @@ -38,4 +38,11 @@ return [ 'CHATOPS_API_URL' => env('CHATOPS_API_URL', 'http://10.1.12.160/aiapi/sent-message-user'), 'CHATOPS_API_TOKEN' => env('CHATOPS_API_TOKEN', 'ifOgk13pXIa6p2q6vvJB'), + + 'MSG_FORGOT_PWD_EMAIL_REQUIRED' => 'Vui lòng nhập địa chỉ email.', + 'MSG_FORGOT_PWD_EMAIL_INVALID' => 'Địa chỉ email không đúng định dạng.', + 'MSG_FORGOT_PWD_EMAIL_NOT_FOUND' => 'Email không tồn tại trong hệ thống. Vui lòng kiểm tra lại.', + 'MSG_FORGOT_PWD_ACCOUNT_INACTIVE' => 'Tài khoản của bạn đã bị khóa hoặc ngừng hoạt động. Vui lòng liên hệ quản trị viên.', + 'MSG_FORGOT_PWD_MAIL_FAILED' => 'Không thể gửi email lúc này. Vui lòng thử lại sau.', + 'MSG_FORGOT_PWD_SUCCESS' => 'Mật khẩu mới đã được gửi tới email của bạn. Vui lòng kiểm tra hòm thư!', ]; diff --git a/config/mail.php b/config/mail.php index e32e88d..0a6e89d 100644 --- a/config/mail.php +++ b/config/mail.php @@ -112,7 +112,7 @@ return [ 'from' => [ 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), - 'name' => env('MAIL_FROM_NAME', env('APP_NAME', 'Laravel')), + 'name' => env('MAIL_FROM_NAME', 'Thanks Card'), ], ]; diff --git a/resources/views/emails/reset_password.blade.php b/resources/views/emails/reset_password.blade.php new file mode 100644 index 0000000..569292f --- /dev/null +++ b/resources/views/emails/reset_password.blade.php @@ -0,0 +1,107 @@ + + + + + + Cấp mật khẩu mới - ThankCard System + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ Thanks card +
+
+ GMO-Z.com RUNSYSTEM +
+
+ + +
+

+ Mật khẩu mới của bạn +

+

+ Hệ thống đã nhận được yêu cầu khôi phục mật khẩu cho tài khoản của bạn. +

+
+ + +

+ Xin chào {{ $user->name }}, +

+

+ Dưới đây là mật khẩu ngẫu nhiên tạm thời được cấp cho tài khoản ({{ $user->mail }}): +

+ + + + + + +
+
+ Mật khẩu mới ngẫu nhiên +
+
+ {{ $newPassword }} +
+
+ + + + + + +
+
+ Lưu ý bảo mật: Để đảm bảo an toàn, hệ thống sẽ yêu cầu bạn đổi sang mật khẩu cá nhân mới ngay lần đăng nhập đầu tiên với mật khẩu tạm thời này. +
+
+ + + + + + +
+ + Đăng nhập ngay + +
+ +

+ Nếu bạn không thực hiện yêu cầu này, vui lòng liên hệ ngay với Quản trị viên hệ thống để bảo vệ tài khoản. +

+
+
© {{ date('Y') }} GMO-Z.com RUNSYSTEM. All rights reserved.
+
ThankCard System - Lan tỏa lời cảm ơn & kết nối đồng nghiệp.
+
+
+ + + diff --git a/resources/views/login.blade.php b/resources/views/login.blade.php index 57b89d8..4637c2d 100644 --- a/resources/views/login.blade.php +++ b/resources/views/login.blade.php @@ -89,7 +89,12 @@
- +
+ + +
@@ -179,6 +184,45 @@
+ + + @if(session('dialog_error_permission')) @@ -196,6 +240,14 @@ @endif + @if(session('dialog_forgot_error')) + + @endif + + @if(session('dialog_forgot_success')) + + @endif + diff --git a/routes/web.php b/routes/web.php index dea4026..0747d66 100644 --- a/routes/web.php +++ b/routes/web.php @@ -29,6 +29,7 @@ Route::get('/test-modal', function() { }); Route::get('/login', [AuthController::class, 'showLoginForm'])->name('login'); Route::post('/login', [AuthController::class, 'login']); +Route::post('/forgot-password', [AuthController::class, 'forgotPassword'])->name('forgot_password'); Route::get('/notification-showcase', function () { return view('notification-showcase');