Implemented password reset function

This commit is contained in:
Ferdinand Thiessen 2021-01-18 16:05:05 +01:00
parent 5a97bfa413
commit 08c29c1cd6
4 changed files with 164 additions and 30 deletions

View File

@ -1,8 +1,5 @@
<template> <template>
<q-page <q-page padding class="fit row justify-center items-center content-center">
padding
class="fit row justify-center items-center content-center"
>
<q-card class="col-xs-11 col-sm-8 col-md-6 col-lg-4 justify-center items-center content-center"> <q-card class="col-xs-11 col-sm-8 col-md-6 col-lg-4 justify-center items-center content-center">
<q-toolbar class="bg-primary text-white"> <q-toolbar class="bg-primary text-white">
<q-toolbar-title> <q-toolbar-title>
@ -11,16 +8,13 @@
</q-toolbar> </q-toolbar>
<q-card-section> <q-card-section>
<q-form <q-form ref="LoginForm" @submit="doLogin" class="q-gutter-md">
ref="LoginForm"
@submit="doLogin"
class="q-gutter-md"
>
<q-input <q-input
filled filled
v-model="userid" v-model="userid"
label="Benutzername oder E-Mail" label="Benutzername oder E-Mail"
:rules="rules" :rules="rules"
tabindex="1"
/> />
<q-input <q-input
filled filled
@ -28,13 +22,17 @@
type="password" type="password"
label="Password" label="Password"
:rules="rules" :rules="rules"
tabindex="2"
/> />
<div class="row justify-end"> <div class="row justify-between">
<q-btn <q-btn
label="Login" label="Passwort vergessen"
type="submit" type="a"
color="primary" @click="doReset"
color="secondary"
tabindex="4"
/> />
<q-btn label="Login" type="submit" color="primary" tabindex="3" />
</div> </div>
</q-form> </q-form>
</q-card-section> </q-card-section>
@ -54,24 +52,20 @@ export default defineComponent({
/* Stuff for the real login page */ /* Stuff for the real login page */
const userid = ref(''); const userid = ref('');
const password = ref(''); const password = ref('');
const rules = [ const rules = [(val: string) => (val && val.length > 0) || 'Feld darf nicht leer sein!'];
(val: string) => (val && val.length > 0) || 'Feld darf nicht leer sein!',
];
function doLogin() { function doLogin() {
Loading.show({ Loading.show({
message: 'Du wirst angemeldet', message: 'Du wirst angemeldet'
}); });
root.$store root.$store
.dispatch('session/login', { .dispatch('session/login', {
userid: userid.value, userid: userid.value,
password: password.value, password: password.value
}) })
.then(() => { .then(() => {
const x = root.$route.query['redirect']; const x = root.$route.query['redirect'];
void root.$router.push( void root.$router.push(typeof x === 'string' ? { path: x } : mainRoute);
typeof x === 'string' ? { path: x } : mainRoute
);
}) })
.catch((error: { status: number } | undefined) => { .catch((error: { status: number } | undefined) => {
if (error && error.status === 401) { if (error && error.status === 401) {
@ -82,7 +76,7 @@ export default defineComponent({
message: 'Benutzername oder Passwort sind falsch.', message: 'Benutzername oder Passwort sind falsch.',
timeout: 10000, timeout: 10000,
progress: true, progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }], actions: [{ icon: 'mdi-close', color: 'white' }]
}); });
} }
}) })
@ -91,7 +85,38 @@ export default defineComponent({
}); });
} }
return { userid, password, doLogin, rules }; function doReset() {
}, if (userid.value == '') {
Notify.create({
group: false,
type: 'negative',
message: 'Der Benutzername darf nicht leer sein.',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
});
return;
}
root.$store
.dispatch('session/requestPasswordReset', {
userid: userid.value
})
.then(() => {
userid.value = '';
password.value = '';
Notify.create({
group: false,
type: 'ongoing',
message:
'Sollte der Benutzername korrekt und vorhanden sein, erhälst du jetzt eine E-Mail.',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
});
});
}
return { userid, password, doLogin, doReset, rules };
}
}); });
</script> </script>

98
src/pages/Reset.vue Normal file
View File

@ -0,0 +1,98 @@
<template>
<q-page padding class="fit row justify-center items-center content-center">
<q-card class="col-xs-11 col-sm-8 col-md-6 col-lg-4 justify-center items-center content-center">
<q-toolbar class="bg-primary text-white">
<q-toolbar-title>
Passwort vergessen
</q-toolbar-title>
</q-toolbar>
<q-card-section>
<q-form ref="ResetForm" @submit="doReset" class="q-gutter-md">
<q-input
filled
v-model="password"
type="password"
label="Passwort"
:rules="rules"
hint="Min. 8 Zeichen"
tabindex="1"
/>
<q-input
filled
v-model="password2"
type="password"
label="Passwort Wiederholung"
:rules="rules"
tabindex="2"
/>
<div class="row justify-end">
<q-btn label="Zurücksetzen" type="submit" color="primary" />
</div>
</q-form>
</q-card-section>
</q-card>
</q-page>
</template>
<script lang="ts">
import { defineComponent, ref } from '@vue/composition-api';
import { Loading, Notify } from 'quasar';
export default defineComponent({
// name: 'PageName'
setup(_, { root }) {
const mainRoute = { name: 'dashboard' };
const password = ref('');
const password2 = ref('');
const rules = [
(val: string) =>
(val && val.length >= 8) || 'Das Passwort muss mindestens 8 Zeichen lang sein!'
];
function doReset() {
if (password.value !== password2.value) {
Notify.create({
group: false,
type: 'negative',
message: 'Die Passwörter stimmen nicht überein!',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
});
password2.value = '';
return;
}
Loading.show({
message: 'Das Passwort wird zurückgesetzt'
});
root.$store
.dispatch('session/resetPassword', {
password: password.value,
token: root.$route.query.token
})
.catch(error => {
if (error.status == 403) {
Notify.create({
group: false,
type: 'negative',
message: 'Der Link ist abgelaufen!',
timeout: 10000,
progress: true,
actions: [{ icon: 'mdi-close', color: 'white' }]
});
}
})
.finally(() => {
Loading.hide();
void root.$router.replace({ name: 'login' });
});
}
return { password, password2, doReset, rules };
}
});
</script>

View File

@ -72,12 +72,10 @@ const actions: ActionTree<SessionInterface, StateInterface> = {
*/ */
logout({ dispatch, rootState }) { logout({ dispatch, rootState }) {
if (rootState.session.currentSession) { if (rootState.session.currentSession) {
dispatch('deleteSession', rootState.session.currentSession.token).catch( dispatch('deleteSession', rootState.session.currentSession.token).catch(error => {
error => {
console.log(error); console.log(error);
void dispatch('clearCurrent', false); void dispatch('clearCurrent', false);
} });
);
} else { } else {
void dispatch('clearCurrent', false); void dispatch('clearCurrent', false);
} }
@ -145,6 +143,14 @@ const actions: ActionTree<SessionInterface, StateInterface> = {
.finally(() => { .finally(() => {
commit('setLoading', false); commit('setLoading', false);
}); });
},
requestPasswordReset({}, data) {
return axios.post('/auth/reset', data);
},
resetPassword({}, data) {
return axios.post('/auth/reset', data).catch((error: AxiosError) => {
return Promise.reject(error.response);
});
} }
}; };

View File

@ -11,6 +11,11 @@ const routes: RouteConfig[] = [
path: 'login', path: 'login',
component: () => import('pages/Login.vue') component: () => import('pages/Login.vue')
}, },
{
name: 'password_reset',
path: 'reset',
component: () => import('pages/Reset.vue')
},
{ {
name: 'about_out', name: 'about_out',
path: 'about', path: 'about',