mirror of
https://github.com/Bubka/2FAuth.git
synced 2024-11-26 02:04:52 +01:00
Add Password and Profile update
This commit is contained in:
parent
ad18021019
commit
4e38e0bbfb
@ -7,6 +7,7 @@
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
@ -105,7 +106,7 @@ public function register(Request $request)
|
|||||||
*/
|
*/
|
||||||
public function getDetails()
|
public function getDetails()
|
||||||
{
|
{
|
||||||
return response()->json(Auth::user(), 200);
|
return response()->json(Auth::user()->only('name', 'email'), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -121,10 +122,17 @@ public function update(Request $request)
|
|||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'name' => 'required',
|
'name' => 'required',
|
||||||
'email' => 'required|email|unique:users,email,'.$user->id,
|
'email' => 'required|email|unique:users,email,'.Auth::id(),
|
||||||
|
'password' => 'required',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return tap($user)->update($request->only('name', 'email'));
|
if (!Hash::check( $request->password, Auth::user()->password) ) {
|
||||||
|
return response()->json(['message' => __('errors.wrong_current_password')], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
tap($user)->update($request->only('name', 'email'));
|
||||||
|
|
||||||
|
return response()->json(['message' => __('auth.forms.profile_saved')]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -134,14 +142,21 @@ public function update(Request $request)
|
|||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function changePassword(Request $request)
|
public function updatePassword(Request $request)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
|
'currentPassword' => 'required',
|
||||||
'password' => 'required|confirmed|min:8',
|
'password' => 'required|confirmed|min:8',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (!Hash::check( $request->currentPassword, Auth::user()->password) ) {
|
||||||
|
return response()->json(['message' => __('errors.wrong_current_password')], 400);
|
||||||
|
}
|
||||||
|
|
||||||
$request->user()->update([
|
$request->user()->update([
|
||||||
'password' => bcrypt($request->password),
|
'password' => bcrypt($request->password),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
return response()->json(['message' => __('auth.forms.password_successfully_changed')]);
|
||||||
}
|
}
|
||||||
}
|
}
|
14
resources/js/langs/locales.js
vendored
14
resources/js/langs/locales.js
vendored
@ -21,13 +21,19 @@ export default {
|
|||||||
"request_password_reset": "Request a password reset",
|
"request_password_reset": "Request a password reset",
|
||||||
"reset_password": "Reset password",
|
"reset_password": "Reset password",
|
||||||
"new_password": "New password",
|
"new_password": "New password",
|
||||||
|
"current_password": "Current password",
|
||||||
"change_password": "Change password",
|
"change_password": "Change password",
|
||||||
"send_password_reset_link": "Send password reset link"
|
"send_password_reset_link": "Send password reset link",
|
||||||
|
"change_your_password": "Change your password",
|
||||||
|
"your_password_has_been_changed": "Your password has been successfully changed ",
|
||||||
|
"profile_saved": "Profile successfully updated!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commons": {
|
"commons": {
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"copy_to_clipboard": "Copy to clipboard"
|
"update": "Update",
|
||||||
|
"copy_to_clipboard": "Copy to clipboard",
|
||||||
|
"profile": "Profile"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"resource_not_found": "Resource not found",
|
"resource_not_found": "Resource not found",
|
||||||
@ -39,7 +45,9 @@ export default {
|
|||||||
"response": {
|
"response": {
|
||||||
"no_valid_totp": "No valid TOTP resource in this QR code"
|
"no_valid_totp": "No valid TOTP resource in this QR code"
|
||||||
},
|
},
|
||||||
"something_wrong_with_server": "Something is wrong with your server"
|
"something_wrong_with_server": "Something is wrong with your server",
|
||||||
|
"Unable_to_decrypt_uri": "Unable to decrypt uri",
|
||||||
|
"wrong_current_password": "Wrong current password, nothing has changed"
|
||||||
},
|
},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"previous": "« Previous",
|
"previous": "« Previous",
|
||||||
|
4
resources/js/routes.js
vendored
4
resources/js/routes.js
vendored
@ -8,8 +8,10 @@ import Create from './views/twofaccounts/Create'
|
|||||||
import Edit from './views/twofaccounts/Edit'
|
import Edit from './views/twofaccounts/Edit'
|
||||||
import Login from './views/auth/Login'
|
import Login from './views/auth/Login'
|
||||||
import Register from './views/auth/Register'
|
import Register from './views/auth/Register'
|
||||||
|
import PasswordUpdate from './views/auth/password/Update'
|
||||||
import PasswordRequest from './views/auth/password/Request'
|
import PasswordRequest from './views/auth/password/Request'
|
||||||
import PasswordReset from './views/auth/password/Reset'
|
import PasswordReset from './views/auth/password/Reset'
|
||||||
|
import Profile from './views/profile/Edit'
|
||||||
import NotFound from './views/Error'
|
import NotFound from './views/Error'
|
||||||
|
|
||||||
const router = new Router({
|
const router = new Router({
|
||||||
@ -18,9 +20,11 @@ const router = new Router({
|
|||||||
{ path: '/', name: 'accounts', component: Accounts, props: true },
|
{ path: '/', name: 'accounts', component: Accounts, props: true },
|
||||||
{ path: '/login', name: 'login',component: Login },
|
{ path: '/login', name: 'login',component: Login },
|
||||||
{ path: '/register', name: 'register',component: Register },
|
{ path: '/register', name: 'register',component: Register },
|
||||||
|
{ path: '/profile', name: 'profile',component: Profile },
|
||||||
{ path: '/create', name: 'create',component: Create },
|
{ path: '/create', name: 'create',component: Create },
|
||||||
{ path: '/edit/:twofaccountId', name: 'edit',component: Edit },
|
{ path: '/edit/:twofaccountId', name: 'edit',component: Edit },
|
||||||
|
|
||||||
|
{ path: '/password/update', name: 'password.update',component: PasswordUpdate },
|
||||||
{ path: '/password/request', name: 'password.request', component: PasswordRequest },
|
{ path: '/password/request', name: 'password.request', component: PasswordRequest },
|
||||||
{ path: '/password/reset/:token', name: 'password.reset', component: PasswordReset },
|
{ path: '/password/reset/:token', name: 'password.reset', component: PasswordReset },
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content has-text-centered">
|
<div class="content has-text-centered">
|
||||||
{{ $t('auth.hello', {username: username}) }} <a class="has-text-grey" @click="logout">{{ $t('auth.sign_out') }}</a>
|
{{ $t('auth.hello', {username: username}) }} <router-link :to="{ name: 'profile' }" class="has-text-grey">{{ $t('commons.profile') }}</router-link> - <a class="has-text-grey" @click="logout">{{ $t('auth.sign_out') }}</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
94
resources/js/views/auth/password/Update.vue
Normal file
94
resources/js/views/auth/password/Update.vue
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div class="section">
|
||||||
|
<div class="columns is-mobile is-centered">
|
||||||
|
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
|
||||||
|
<h1 class="title">{{ $t('auth.forms.change_password') }}</h1>
|
||||||
|
<form @submit.prevent="handleSubmit" @keydown="form.onKeydown($event)">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">{{ $t('auth.forms.current_password') }}</label>
|
||||||
|
<div class="control">
|
||||||
|
<input id="currentPassword" type="password" class="input" v-model="form.currentPassword" />
|
||||||
|
</div>
|
||||||
|
<field-error :form="form" field="currentPassword" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">{{ $t('auth.forms.new_password') }}</label>
|
||||||
|
<div class="control">
|
||||||
|
<input id="password" type="password" class="input" v-model="form.password" />
|
||||||
|
</div>
|
||||||
|
<field-error :form="form" field="password" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">{{ $t('auth.forms.confirm_password') }}</label>
|
||||||
|
<div class="control">
|
||||||
|
<input id="password_confirmation" type="password" class="input" v-model="form.password_confirmation" />
|
||||||
|
</div>
|
||||||
|
<field-error :form="form" field="password_confirmation" />
|
||||||
|
</div>
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<div class="control">
|
||||||
|
<v-button :isLoading="form.isBusy" >{{ $t('auth.forms.change_password') }}</v-button>
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<router-link :to="{ name: 'profile' }" class="button is-text">{{ $t('commons.cancel') }}</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field" v-if="errorMessage">
|
||||||
|
<span class="tag is-danger">
|
||||||
|
{{ errorMessage }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="columns is-mobile is-centered" v-if="response">
|
||||||
|
<div class="has-text-link column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
|
||||||
|
<span class="tag is-success">
|
||||||
|
{{ response }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import Form from './../../../components/Form'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
response: '',
|
||||||
|
errorMessage: '',
|
||||||
|
form: new Form({
|
||||||
|
currentPassword : '',
|
||||||
|
password : '',
|
||||||
|
password_confirmation : '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods : {
|
||||||
|
handleSubmit(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.errorMessage = ''
|
||||||
|
this.response = ''
|
||||||
|
|
||||||
|
this.form.patch('/api/password')
|
||||||
|
.then(response => {
|
||||||
|
|
||||||
|
this.response = response.data.message
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if( error.response.status === 400 ) {
|
||||||
|
this.errorMessage = error.response.data.message
|
||||||
|
}
|
||||||
|
else if( error.response.status !== 422 ) {
|
||||||
|
this.$router.push({ name: 'genericError', params: { err: error.response } });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
111
resources/js/views/profile/Edit.vue
Normal file
111
resources/js/views/profile/Edit.vue
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<template>
|
||||||
|
<div class="section">
|
||||||
|
<div class="columns is-mobile is-centered">
|
||||||
|
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
|
||||||
|
<h1 class="title">{{ $t('commons.profile') }}</h1>
|
||||||
|
<form @submit.prevent="handleSubmit" @keydown="form.onKeydown($event)">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">{{ $t('auth.forms.name') }}</label>
|
||||||
|
<div class="control">
|
||||||
|
<input id="name" type="text" class="input" v-model="form.name" autofocus />
|
||||||
|
</div>
|
||||||
|
<field-error :form="form" field="name" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">{{ $t('auth.forms.email') }}</label>
|
||||||
|
<div class="control">
|
||||||
|
<input id="email" type="email" class="input" v-model="form.email" />
|
||||||
|
</div>
|
||||||
|
<field-error :form="form" field="email" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">{{ $t('auth.forms.password') }}</label>
|
||||||
|
<div class="control">
|
||||||
|
<input id="password" type="password" class="input" v-model="form.password" />
|
||||||
|
</div>
|
||||||
|
<field-error :form="form" field="password" />
|
||||||
|
</div>
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<div class="control">
|
||||||
|
<v-button :isLoading="form.isBusy" >{{ $t('commons.update') }}</v-button>
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<router-link :to="{ name: 'accounts' }" class="button is-text">{{ $t('commons.cancel') }}</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field" v-if="errorMessage">
|
||||||
|
<span class="tag is-danger">
|
||||||
|
{{ errorMessage }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="columns is-mobile is-centered">
|
||||||
|
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
|
||||||
|
<router-link :to="{ name: 'password.update' }" class="is-link">
|
||||||
|
{{ $t('auth.forms.change_your_password') }}
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="columns is-mobile is-centered" v-if="response">
|
||||||
|
<div class="has-text-link column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
|
||||||
|
<span class="tag is-success">
|
||||||
|
{{ response }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import Form from './../../components/Form'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
response: '',
|
||||||
|
errorMessage: '',
|
||||||
|
form: new Form({
|
||||||
|
name : '',
|
||||||
|
email : '',
|
||||||
|
password : '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted: function() {
|
||||||
|
this.form.get('/api/user')
|
||||||
|
.then(response => {
|
||||||
|
this.form.fill(response.data)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$router.push({ name: 'genericError', params: { err: error.response } });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
methods : {
|
||||||
|
handleSubmit(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.errorMessage = ''
|
||||||
|
this.response = ''
|
||||||
|
|
||||||
|
this.form.patch('/api/user')
|
||||||
|
.then(response => {
|
||||||
|
|
||||||
|
this.response = response.data.message
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if( error.response.status === 400 ) {
|
||||||
|
this.errorMessage = error.response.data.message
|
||||||
|
}
|
||||||
|
else if( error.response.status !== 422 ) {
|
||||||
|
this.$router.push({ name: 'genericError', params: { err: error.response } });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
@ -33,8 +33,12 @@
|
|||||||
'request_password_reset' => 'Request a password reset',
|
'request_password_reset' => 'Request a password reset',
|
||||||
'reset_password' => 'Reset password',
|
'reset_password' => 'Reset password',
|
||||||
'new_password' => 'New password',
|
'new_password' => 'New password',
|
||||||
|
'current_password' => 'Current password',
|
||||||
'change_password' => 'Change password',
|
'change_password' => 'Change password',
|
||||||
'send_password_reset_link' => 'Send password reset link',
|
'send_password_reset_link' => 'Send password reset link',
|
||||||
|
'change_your_password' => 'Change your password',
|
||||||
|
'password_successfully_changed' => 'Password successfully changed ',
|
||||||
|
'profile_saved' => 'Profile successfully updated!'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
'cancel' => 'Cancel',
|
'cancel' => 'Cancel',
|
||||||
|
'update' => 'Update',
|
||||||
'copy_to_clipboard' => 'Copy to clipboard',
|
'copy_to_clipboard' => 'Copy to clipboard',
|
||||||
|
'profile' => 'Profile',
|
||||||
|
|
||||||
];
|
];
|
@ -22,7 +22,8 @@
|
|||||||
'response' => [
|
'response' => [
|
||||||
'no_valid_totp' => 'No valid TOTP resource in this QR code',
|
'no_valid_totp' => 'No valid TOTP resource in this QR code',
|
||||||
],
|
],
|
||||||
'something_wrong_with_server' => 'Something is wrong with your server',,
|
'something_wrong_with_server' => 'Something is wrong with your server',
|
||||||
'Unable_to_decrypt_uri' => 'Unable to decrypt uri',
|
'Unable_to_decrypt_uri' => 'Unable to decrypt uri',
|
||||||
|
'wrong_current_password' => 'Wrong current password, nothing has changed'
|
||||||
|
|
||||||
];
|
];
|
@ -27,8 +27,8 @@
|
|||||||
Route::group(['middleware' => 'auth:api'], function() {
|
Route::group(['middleware' => 'auth:api'], function() {
|
||||||
|
|
||||||
Route::post('logout', 'UserController@logout');
|
Route::post('logout', 'UserController@logout');
|
||||||
Route::patch('user/edit', 'UserController@update');
|
Route::patch('password', 'UserController@updatePassword');
|
||||||
Route::patch('user/password', 'UserController@changePassword');
|
Route::patch('user', 'UserController@update');
|
||||||
Route::get('user', 'UserController@getDetails');
|
Route::get('user', 'UserController@getDetails');
|
||||||
|
|
||||||
Route::apiResource('twofaccounts', 'TwoFAccountController');
|
Route::apiResource('twofaccounts', 'TwoFAccountController');
|
||||||
|
Loading…
Reference in New Issue
Block a user