mirror of
https://github.com/devcode-it/openstamanager.git
synced 2025-02-23 06:47:40 +01:00
feat: ✨ Aggiunto reset password
This commit is contained in:
parent
3020cf0293
commit
f8bab49852
@ -2,9 +2,14 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
|
||||
@ -39,21 +44,41 @@ class AuthController extends Controller
|
||||
], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
#[ArrayShape(['username' => 'string', 'password' => 'string', 'remember' => 'string'])]
|
||||
private function rules(Request $request): array
|
||||
public function forgotPassword(Request $request): Response|JsonResponse
|
||||
{
|
||||
$additional_validation = '';
|
||||
$db_field = 'username';
|
||||
if (filter_var($request->input('username'), FILTER_VALIDATE_EMAIL)) {
|
||||
$additional_validation = '|email';
|
||||
$db_field = 'email';
|
||||
}
|
||||
$request->validate([
|
||||
'email' => 'required|email|exists:users,email',
|
||||
]);
|
||||
|
||||
return [
|
||||
'username' => "required|string|exists:users,$db_field|$additional_validation",
|
||||
'password' => 'required|string',
|
||||
'remember' => 'boolean',
|
||||
];
|
||||
$response = Password::broker()->sendResetLink($request->input('email'));
|
||||
|
||||
return $response === Password::RESET_LINK_SENT
|
||||
? response()->noContent()
|
||||
: \response()->json(['errors' => ['email' => [__($response)]]], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
public function resetPassword(Request $request): JsonResponse|Response
|
||||
{
|
||||
$request->validate([
|
||||
'token' => 'required|string',
|
||||
'email' => 'required|email|exists:users,email',
|
||||
'password' => ['required|string|confirmed', \Illuminate\Validation\Rules\Password::defaults()],
|
||||
]);
|
||||
|
||||
$response = Password::broker()->reset(
|
||||
$request->only(['email', 'password', 'password_confirmation', 'token']),
|
||||
function (User $user, string $password) {
|
||||
$user->password = Hash::make($password);
|
||||
$user->setRememberToken(Str::random(60));
|
||||
$user->save();
|
||||
|
||||
event(new PasswordReset($user));
|
||||
}
|
||||
);
|
||||
|
||||
return $response === Password::PASSWORD_RESET
|
||||
? response()->noContent()
|
||||
: response()->json(['errors' => ['email' => [__($response)]]], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,4 +95,21 @@ class AuthController extends Controller
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
#[ArrayShape(['username' => 'string', 'password' => 'string', 'remember' => 'string'])]
|
||||
private function rules(Request $request): array
|
||||
{
|
||||
$additional_validation = '';
|
||||
$db_field = 'username';
|
||||
if (filter_var($request->input('username'), FILTER_VALIDATE_EMAIL)) {
|
||||
$additional_validation = '|email';
|
||||
$db_field = 'email';
|
||||
}
|
||||
|
||||
return [
|
||||
'username' => "required|string|exists:users,$db_field|$additional_validation",
|
||||
'password' => 'required|string',
|
||||
'remember' => 'boolean',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class User extends Authenticatable
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'username',
|
||||
'email',
|
||||
'password',
|
||||
];
|
||||
|
@ -21,6 +21,7 @@ import {
|
||||
|
||||
export default class LoginPage extends Page {
|
||||
loading: Cash;
|
||||
forgotPasswordLoading: Cash;
|
||||
|
||||
view(vnode) {
|
||||
return (
|
||||
@ -46,9 +47,14 @@ export default class LoginPage extends Page {
|
||||
style="float: right;"
|
||||
onclick={this.onLoginButtonClicked.bind(this)}
|
||||
/>
|
||||
<mwc-button dense label="Password dimenticata" style="margin-top: 16px;">
|
||||
<Mdi icon="lock-question" slot="icon"/>
|
||||
</mwc-button>
|
||||
<LoadingButton
|
||||
dense
|
||||
id="forgot-password-button"
|
||||
label="Password dimenticata"
|
||||
icon="lock-question"
|
||||
style="margin-top: 16px;"
|
||||
onclick={this.onForgotPasswordButtonClicked.bind(this)}
|
||||
/>
|
||||
</form>
|
||||
</mwc-card>
|
||||
);
|
||||
@ -58,6 +64,7 @@ export default class LoginPage extends Page {
|
||||
super.oncreate(vnode);
|
||||
|
||||
this.loading = $(this.element).find('#login-button mwc-circular-progress');
|
||||
this.forgotPasswordLoading = $(this.element).find('#forgot-password-button mwc-circular-progress');
|
||||
}
|
||||
|
||||
async onLoginButtonClicked(event: PointerEvent) {
|
||||
@ -81,6 +88,7 @@ export default class LoginPage extends Page {
|
||||
data: formData
|
||||
});
|
||||
} catch (error) {
|
||||
// noinspection ES6MissingAwait
|
||||
showSnackbar(Object.values(error.data.errors).join(' '), false);
|
||||
this.loading.hide();
|
||||
return;
|
||||
@ -88,4 +96,31 @@ export default class LoginPage extends Page {
|
||||
|
||||
window.location.href = window.route('dashboard');
|
||||
}
|
||||
|
||||
async onForgotPasswordButtonClicked() {
|
||||
this.forgotPasswordLoading.show();
|
||||
const field: HTMLFormElement = document.querySelector('#username');
|
||||
field.type = 'email';
|
||||
if (!field.reportValidity()) {
|
||||
field.type = 'text';
|
||||
return;
|
||||
}
|
||||
field.type = 'text';
|
||||
|
||||
try {
|
||||
await redaxios.post(window.route('password.forgot'), {
|
||||
email: field.value,
|
||||
_token: $('meta[name="csrf-token"]').attr('content')
|
||||
});
|
||||
} catch (error) {
|
||||
// noinspection ES6MissingAwait
|
||||
showSnackbar(Object.values(error.data.errors).join(' '), false);
|
||||
this.loading.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// noinspection ES6MissingAwait
|
||||
showSnackbar(__('La password è stata inviata alla tua email'));
|
||||
this.loading.hide();
|
||||
}
|
||||
}
|
||||
|
103
resources/js/Views/ResetPasswordPage.jsx
Normal file
103
resources/js/Views/ResetPasswordPage.jsx
Normal file
@ -0,0 +1,103 @@
|
||||
// noinspection DuplicatedCode
|
||||
|
||||
import '@maicol07/mwc-card';
|
||||
import '@maicol07/mwc-layout-grid';
|
||||
import '../WebComponents/TextField';
|
||||
|
||||
import {Inertia} from '@inertiajs/inertia';
|
||||
import type {TextField} from '@material/mwc-textfield';
|
||||
import type {Cash} from 'cash-dom';
|
||||
import redaxios from 'redaxios';
|
||||
|
||||
// eslint-disable-next-line import/no-absolute-path
|
||||
import logoUrl from '/images/logo_completo.png';
|
||||
|
||||
import LoadingButton from '../Components/LoadingButton.jsx';
|
||||
import Mdi from '../Components/Mdi.jsx';
|
||||
import Page from '../Components/Page.jsx';
|
||||
import {
|
||||
getFormData,
|
||||
isFormValid,
|
||||
showSnackbar
|
||||
} from '../utils';
|
||||
|
||||
export default class ResetPasswordPage extends Page {
|
||||
loading: Cash;
|
||||
parameters: URLSearchParams;
|
||||
|
||||
oninit(vnode) {
|
||||
super.oninit(vnode);
|
||||
|
||||
this.parameters = new URLSearchParams(window.location.search);
|
||||
}
|
||||
|
||||
view(vnode) {
|
||||
return (
|
||||
<mwc-card outlined className="center ext-container ext-container-small">
|
||||
<img src={logoUrl} className="center stretch" alt={__('OpenSTAManager')}/>
|
||||
<form id="reset-password" style="padding: 16px; text-align: center;">
|
||||
<h3 style="margin-top: 0;">{__('Reimposta password')}</h3>
|
||||
<input hidden id="email" name="email" value={this.parameters.get('email')}/>
|
||||
<input hidden id="token" name="token" value={this.parameters.get('token')}/>
|
||||
<text-field label={__('Password')} id="password" name="password" required type="password">
|
||||
<Mdi icon="lock-outline" slot="icon"/>
|
||||
</text-field>
|
||||
<text-field label={__('Conferma password')} id="password_confirm" name="password_confirm" type="password" required style="margin-top: 16px;">
|
||||
<Mdi icon="repeat-variant" slot="icon"/>
|
||||
</text-field>
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
raised
|
||||
id="reset-password-button"
|
||||
label={__('Resetta password')}
|
||||
icon="lock-reset"
|
||||
style="float: right;"
|
||||
onclick={this.onResetPasswordButtonClicked.bind(this)}
|
||||
/>
|
||||
</form>
|
||||
</mwc-card>
|
||||
);
|
||||
}
|
||||
|
||||
oncreate(vnode) {
|
||||
super.oncreate(vnode);
|
||||
|
||||
this.loading = $(this.element).find('#reset-password mwc-circular-progress');
|
||||
}
|
||||
|
||||
async onResetPasswordButtonClicked(event: PointerEvent) {
|
||||
event.preventDefault();
|
||||
this.loading.show();
|
||||
|
||||
const form = $(this.element).find('#reset-password');
|
||||
const password: TextField = form.find('#password').get(0);
|
||||
const passwordConfirm: TextField = form.find('#password_confirm').get(0);
|
||||
|
||||
passwordConfirm.setCustomValidity(
|
||||
password.value !== passwordConfirm.value ? __('Le password non corrispondono') : ''
|
||||
);
|
||||
|
||||
if (!isFormValid(form)) {
|
||||
this.loading.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = getFormData(form);
|
||||
|
||||
formData._token = $('meta[name="csrf-token"]').attr('content');
|
||||
|
||||
try {
|
||||
await redaxios.put(window.route('password.resetPassword'), formData);
|
||||
} catch (error) {
|
||||
// noinspection ES6MissingAwait
|
||||
showSnackbar(Object.values(error.data.errors).join(' '), false);
|
||||
this.loading.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
Inertia.visit('/');
|
||||
|
||||
// noinspection ES6MissingAwait
|
||||
showSnackbar(__('Reset della password effettuato con successo. Puoi ora accedere.'));
|
||||
}
|
||||
}
|
@ -37,16 +37,27 @@ Route::name('auth.')
|
||||
->middleware('guest')
|
||||
->group(static function () {
|
||||
Route::inertia('login', 'LoginPage')
|
||||
->name('login');
|
||||
/*Route::inertia('password-request', '')
|
||||
->name('password-request');*/
|
||||
|
||||
->name('login');
|
||||
Route::post('login', [AuthController::class, 'authenticate'])
|
||||
->name('authenticate');
|
||||
->name('authenticate');
|
||||
|
||||
/*Route::post('logout', 'Auth\LoginController@logout')
|
||||
->name('auth.logout');*/
|
||||
});
|
||||
|
||||
Route::name('password.')
|
||||
->middleware('guest')
|
||||
->group(static function () {
|
||||
Route::post('forgot', [AuthController::class, 'forgot'])
|
||||
->name('forgot');
|
||||
|
||||
Route::inertia('reset', 'ResetPasswordPage')
|
||||
->name('reset');
|
||||
|
||||
Route::post('reset', [AuthController::class, 'resetPassword'])
|
||||
->name('resetPassword');
|
||||
});
|
||||
|
||||
Route::name('setup.')->group(static function () {
|
||||
Route::inertia('setup', 'SetupPage', [
|
||||
'languages' => cache()->rememberForever('app.languages', fn () => array_map(
|
||||
|
Loading…
x
Reference in New Issue
Block a user