- Can click password recovery button/link - Can request recovery mail by input mail address and confirm - Can set new password after forwarded from recovery mail For AR: - click on Forgot Password in CSC login screen - after submitting, login into mysql in your development env and execute 'select * from billing.password_resets;' - copy the most recent uuid - go to localhost:8080/#/recoverpassword?token=uuid and proceed with password reset Change-Id: Iff10165f98daa65a0ac85ec55c5d62926513fe0dmr9.1.1
parent
1cd9ff14fa
commit
cd9c2a8bcb
@ -1,6 +1,15 @@
|
||||
|
||||
import Vuelidate from 'vuelidate'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default ({ Vue, store }) => {
|
||||
export default ({ Vue, app }) => {
|
||||
Vue.use(Vuelidate)
|
||||
Vue.prototype.$errorMessage = (def) => {
|
||||
let message = null
|
||||
_.forEach(def.$params, (param, paramName) => {
|
||||
if (def[paramName] === false) {
|
||||
message = app.i18n.t('validators.' + paramName)
|
||||
}
|
||||
})
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<csc-dialog
|
||||
:value="value"
|
||||
title-icon="vpn_key"
|
||||
:title="$t('pages.login.forgotPassword')"
|
||||
@input="$emit('input')"
|
||||
@hide="resetForm()"
|
||||
>
|
||||
<template
|
||||
v-slot:content
|
||||
>
|
||||
<q-form>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-input
|
||||
v-model.trim="username"
|
||||
clearable
|
||||
dense
|
||||
:label="$t('pages.login.username')"
|
||||
type="text"
|
||||
:error="$v.username.$error"
|
||||
:error-message="$errorMessage($v.username)"
|
||||
@blur="$v.username.$touch()"
|
||||
>
|
||||
<template
|
||||
v-slot:prepend
|
||||
>
|
||||
<q-icon
|
||||
name="fas fa-user-cog"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-form>
|
||||
</template>
|
||||
<template
|
||||
v-slot:actions
|
||||
>
|
||||
<q-btn
|
||||
icon="check"
|
||||
unelevated
|
||||
color="primary"
|
||||
:label="$t('toasts.send')"
|
||||
:loading="newPasswordRequesting"
|
||||
:disable="!username || username.length < 1 || newPasswordRequesting"
|
||||
@click="submit()"
|
||||
/>
|
||||
</template>
|
||||
</csc-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
required
|
||||
} from 'vuelidate/lib/validators'
|
||||
import {
|
||||
mapActions,
|
||||
mapState
|
||||
} from 'vuex'
|
||||
import CscDialog from './CscDialog'
|
||||
export default {
|
||||
name: 'CscRetrievePasswordDialog',
|
||||
components: {
|
||||
CscDialog
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
username: ''
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
username: {
|
||||
required
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('user', [
|
||||
'newPasswordRequesting'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
...mapActions('user', [
|
||||
'resetPassword'
|
||||
]),
|
||||
async submit () {
|
||||
this.$v.$touch()
|
||||
if (!this.$v.$invalid) {
|
||||
try {
|
||||
const res = await this.resetPassword(this.username)
|
||||
this.$q.notify({
|
||||
position: 'top',
|
||||
color: 'positive',
|
||||
icon: 'check',
|
||||
message: res.data.message
|
||||
})
|
||||
} catch (err) {
|
||||
this.$q.notify({
|
||||
position: 'top',
|
||||
color: 'negative',
|
||||
icon: 'error',
|
||||
message: this.$t('toasts.errorPasswordReset')
|
||||
})
|
||||
} finally {
|
||||
this.$emit('close')
|
||||
}
|
||||
}
|
||||
},
|
||||
resetForm () {
|
||||
this.$v.$reset()
|
||||
this.username = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<q-layout view="hHh lpR fFf">
|
||||
<q-page-container>
|
||||
<router-view />
|
||||
</q-page-container>
|
||||
</q-layout>
|
||||
</template>
|
@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<q-page
|
||||
class="flex flex-center"
|
||||
>
|
||||
<csc-change-password-dialog
|
||||
v-model="showDialog"
|
||||
:title="$t('pages.login.recoverPassword')"
|
||||
:loading="isPasswordChanging"
|
||||
@change-password="recoverPassword({ password: $event.password, token: token })"
|
||||
@dialog-closed="redirectToLogin()"
|
||||
/>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
mapActions,
|
||||
mapGetters,
|
||||
mapState
|
||||
} from 'vuex'
|
||||
import {
|
||||
RequestState
|
||||
} from 'src/store/common'
|
||||
import CscChangePasswordDialog from '../components/CscChangePasswordDialog'
|
||||
export default {
|
||||
name: 'CscRecoverPassword',
|
||||
components: {
|
||||
CscChangePasswordDialog
|
||||
},
|
||||
props: {
|
||||
token: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showDialog: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('user', [
|
||||
'changePasswordState',
|
||||
'changePasswordError'
|
||||
]),
|
||||
...mapGetters('user', [
|
||||
'isPasswordChanging'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
changePasswordState (state) {
|
||||
if (state === RequestState.succeeded) {
|
||||
this.$q.notify({
|
||||
position: 'top',
|
||||
color: 'positive',
|
||||
icon: 'check',
|
||||
message: this.$t('toasts.passwordChangedSuccessfully')
|
||||
})
|
||||
this.redirectToLogin()
|
||||
} else if (state === RequestState.failed) {
|
||||
this.$q.notify({
|
||||
position: 'top',
|
||||
color: 'negative',
|
||||
icon: 'error',
|
||||
message: this.changePasswordError || this.$t('toasts.errorPasswordReset')
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (!this.token) {
|
||||
this.redirectToLogin()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('user', [
|
||||
'recoverPassword'
|
||||
]),
|
||||
redirectToLogin () {
|
||||
this.$router.push({ path: '/login' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
Reference in new issue