diff --git a/app/Actions/Fortify/PasswordValidationRules.php b/app/Actions/Fortify/PasswordValidationRules.php new file mode 100644 index 000000000..76b19d330 --- /dev/null +++ b/app/Actions/Fortify/PasswordValidationRules.php @@ -0,0 +1,18 @@ +|string> + */ + protected function passwordRules(): array + { + return ['required', 'string', Password::default(), 'confirmed']; + } +} diff --git a/app/Actions/Fortify/ResetUserPassword.php b/app/Actions/Fortify/ResetUserPassword.php new file mode 100644 index 000000000..688d62f3b --- /dev/null +++ b/app/Actions/Fortify/ResetUserPassword.php @@ -0,0 +1,28 @@ + $input + */ + public function reset(User $user, array $input): void + { + Validator::make($input, [ + 'password' => $this->passwordRules(), + ])->validate(); + + $user->forceFill([ + 'password' => $input['password'], + ])->save(); + } +} diff --git a/app/Http/Controllers/Auth/NewPasswordController.php b/app/Http/Controllers/Auth/NewPasswordController.php deleted file mode 100644 index d610210f6..000000000 --- a/app/Http/Controllers/Auth/NewPasswordController.php +++ /dev/null @@ -1,69 +0,0 @@ - $request->email, - 'token' => $request->route('token'), - ]); - } - - /** - * Handle an incoming new password request. - * - * @throws \Illuminate\Validation\ValidationException - */ - public function store(Request $request): RedirectResponse - { - $request->validate([ - 'token' => 'required', - 'email' => 'required|email', - 'password' => ['required', 'confirmed', Rules\Password::defaults()], - ]); - - // Here we will attempt to reset the user's password. If it is successful we - // will update the password on an actual user model and persist it to the - // database. Otherwise we will parse the error and return the response. - $status = Password::reset( - $request->only('email', 'password', 'password_confirmation', 'token'), - function (User $user) use ($request) { - $user->forceFill([ - 'password' => $request->password, - 'remember_token' => Str::random(60), - ])->save(); - - event(new PasswordReset($user)); - } - ); - - // If the password was successfully reset, we will redirect the user back to - // the application's home authenticated view. If there is an error we can - // redirect them back to where they came from with their error message. - if ($status == Password::PasswordReset) { - return to_route('login')->with('status', __($status)); - } - - throw ValidationException::withMessages([ - 'email' => [__($status)], - ]); - } -} diff --git a/app/Http/Controllers/Auth/PasswordResetLinkController.php b/app/Http/Controllers/Auth/PasswordResetLinkController.php deleted file mode 100644 index 9fcfe49d0..000000000 --- a/app/Http/Controllers/Auth/PasswordResetLinkController.php +++ /dev/null @@ -1,41 +0,0 @@ - $request->session()->get('status'), - ]); - } - - /** - * Handle an incoming password reset link request. - * - * @throws \Illuminate\Validation\ValidationException - */ - public function store(Request $request): RedirectResponse - { - $request->validate([ - 'email' => 'required|email', - ]); - - Password::sendResetLink( - $request->only('email') - ); - - return back()->with('status', __('A reset link will be sent if the account exists.')); - } -} diff --git a/app/Providers/FortifyServiceProvider.php b/app/Providers/FortifyServiceProvider.php index e8fc91508..961914ce2 100644 --- a/app/Providers/FortifyServiceProvider.php +++ b/app/Providers/FortifyServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Actions\Fortify\ResetUserPassword; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Http\Request; use Illuminate\Support\Facades\RateLimiter; @@ -26,10 +27,19 @@ public function register(): void */ public function boot(): void { + $this->configureActions(); $this->configureViews(); $this->configureRateLimiting(); } + /** + * Configure Fortify actions. + */ + private function configureActions(): void + { + Fortify::resetUserPasswordsUsing(ResetUserPassword::class); + } + /** * Configure Fortify views. */ @@ -44,6 +54,15 @@ private function configureViews(): void 'status' => $request->session()->get('status'), ])); + Fortify::requestPasswordResetLinkView(fn (Request $request) => Inertia::render('auth/forgot-password', [ + 'status' => $request->session()->get('status'), + ])); + + Fortify::resetPasswordView(fn (Request $request) => Inertia::render('auth/reset-password', [ + 'email' => $request->email, + 'token' => $request->route('token'), + ])); + Fortify::twoFactorChallengeView(fn () => Inertia::render('auth/two-factor-challenge')); Fortify::confirmPasswordView(fn () => Inertia::render('auth/confirm-password')); diff --git a/config/fortify.php b/config/fortify.php index 0846d4498..9dd5999b2 100644 --- a/config/fortify.php +++ b/config/fortify.php @@ -145,10 +145,8 @@ 'features' => [ // Features::registration(), - // Features::resetPasswords(), + Features::resetPasswords(), Features::emailVerification(), - // Features::updateProfileInformation(), - // Features::updatePasswords(), Features::twoFactorAuthentication([ 'confirm' => true, 'confirmPassword' => true, diff --git a/resources/js/layouts/settings/layout.tsx b/resources/js/layouts/settings/layout.tsx index c128d82c5..1939af84e 100644 --- a/resources/js/layouts/settings/layout.tsx +++ b/resources/js/layouts/settings/layout.tsx @@ -3,9 +3,9 @@ import { Button } from '@/components/ui/button'; import { Separator } from '@/components/ui/separator'; import { cn } from '@/lib/utils'; import { edit as editAppearance } from '@/routes/appearance'; -import { edit as editPassword } from '@/routes/password'; import { edit } from '@/routes/profile'; import { show } from '@/routes/two-factor'; +import { edit as editPassword } from '@/routes/user-password'; import { type NavItem } from '@/types'; import { Link } from '@inertiajs/react'; import { type PropsWithChildren } from 'react'; diff --git a/resources/js/pages/auth/forgot-password.tsx b/resources/js/pages/auth/forgot-password.tsx index 0e8803e28..3d32f16e9 100644 --- a/resources/js/pages/auth/forgot-password.tsx +++ b/resources/js/pages/auth/forgot-password.tsx @@ -1,6 +1,6 @@ // Components -import PasswordResetLinkController from '@/actions/App/Http/Controllers/Auth/PasswordResetLinkController'; import { login } from '@/routes'; +import { email } from '@/routes/password'; import { Form, Head } from '@inertiajs/react'; import { LoaderCircle } from 'lucide-react'; @@ -26,7 +26,7 @@ export default function ForgotPassword({ status }: { status?: string }) { )}