- 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 Vuelidate from 'vuelidate'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
export default ({ Vue, store }) => {
|
export default ({ Vue, app }) => {
|
||||||
Vue.use(Vuelidate)
|
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