Reset hesla
This commit is contained in:
+1
-1
@@ -36,7 +36,7 @@ services:
|
|||||||
- ./src-ssr:/app/src-ssr
|
- ./src-ssr:/app/src-ssr
|
||||||
- ./public:/app/public
|
- ./public:/app/public
|
||||||
# - ./node_modules:/app/node_modules:delegated
|
# - ./node_modules:/app/node_modules:delegated
|
||||||
command: quasar dev -m ssr
|
command: quasar dev # -m ssr
|
||||||
environment:
|
environment:
|
||||||
API_URL: "http://127.0.0.1:8000"
|
API_URL: "http://127.0.0.1:8000"
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,18 @@ const props = defineProps({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="text-h4">
|
<div class="text-h4">
|
||||||
<router-link :class="`text-${props.textColor}`" :to="{name: 'publicFlightDetail', params: {username: flight.pilot.publicUsername, flightSlug: flight.urlSlug}}">
|
<router-link
|
||||||
|
:class="`text-${props.textColor}`"
|
||||||
|
:to="{name: 'publicFlightDetail', params: {username: flight.pilot.publicUsername, flightSlug: flight.urlSlug}}"
|
||||||
|
>
|
||||||
{{ flightName(flight) }}
|
{{ flightName(flight) }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<router-link :class="`text-${props.textColor}`" :to="{name: 'publicProfileDetail', params: {username: flight.pilot.publicUsername}}">
|
|
||||||
|
<router-link
|
||||||
|
:class="`text-${props.textColor}`"
|
||||||
|
:to="{name: 'publicProfileDetail', params: {username: flight.pilot.publicUsername}}"
|
||||||
|
>
|
||||||
@{{ flight.pilot.publicUsername }}
|
@{{ flight.pilot.publicUsername }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script setup></script>
|
<script setup>
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-timeline color="primary" class="q-my-lg">
|
<q-timeline color="primary" class="q-my-lg">
|
||||||
@@ -8,19 +9,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</q-timeline-entry>
|
</q-timeline-entry>
|
||||||
|
|
||||||
|
|
||||||
<q-timeline-entry title="Vyber a nahraj fotky">
|
|
||||||
<div>
|
|
||||||
Máš nějaké fotky z letu? Nahraj je ke svému letu! A pokud mají v sobě uloženou informaci o poloze, polétání.cz ti zobrazí i místo kde fotka vznikla.
|
|
||||||
</div>
|
|
||||||
</q-timeline-entry>
|
|
||||||
|
|
||||||
<q-timeline-entry title="Ulož trasu">
|
<q-timeline-entry title="Ulož trasu">
|
||||||
<div>
|
<div>
|
||||||
Polétání.cz umí pracovat s trasou ve formátu GPX. Pokud ale tento záznam nemáš, můžeš si naklikat trasu ručně.
|
Polétání.cz umí pracovat s trasou ve formátu GPX. Pokud ale tento záznam nemáš, můžeš si naklikat trasu ručně.
|
||||||
</div>
|
</div>
|
||||||
</q-timeline-entry>
|
</q-timeline-entry>
|
||||||
|
|
||||||
|
<q-timeline-entry title="Vyber a nahraj fotky">
|
||||||
|
<div>A pokud mají v sobě uloženou informaci o poloze, p
|
||||||
|
Máš nějaké fotky z letu? Nahraj je ke svému letu! Polétání.cz ti zobrazí i místo kde fotka vznikla.
|
||||||
|
</div>
|
||||||
|
</q-timeline-entry>
|
||||||
|
|
||||||
<q-timeline-entry title="Popiš zážitek">
|
<q-timeline-entry title="Popiš zážitek">
|
||||||
<div>
|
<div>
|
||||||
Určitě se po ceste stalo něco vzrušujícího. Proč o tom nenapsat pár vět?
|
Určitě se po ceste stalo něco vzrušujícího. Proč o tom nenapsat pár vět?
|
||||||
@@ -29,7 +29,8 @@
|
|||||||
|
|
||||||
<q-timeline-entry title="Sdílej">
|
<q-timeline-entry title="Sdílej">
|
||||||
<div>
|
<div>
|
||||||
Létat v sóle je super, ale ještě lepší je se o zážitek podělit. Jedním kliknutím můžeš svůj let zveřejnit a sdílet odkaz kde chceš. Třeba s tvým kopilotem.
|
Létat v sóle je super, ale ještě lepší je se o zážitek podělit. Jedním kliknutím můžeš svůj let zveřejnit a
|
||||||
|
sdílet odkaz kde chceš. Třeba s tvým kopilotem.
|
||||||
</div>
|
</div>
|
||||||
</q-timeline-entry>
|
</q-timeline-entry>
|
||||||
</q-timeline>
|
</q-timeline>
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ import SidebarNavigation from "components/navigation/SidebarNavigation.vue";
|
|||||||
import TopMenuButton from "components/navigation/TopMenuButton.vue";
|
import TopMenuButton from "components/navigation/TopMenuButton.vue";
|
||||||
import {metaData} from "src/composables/meta";
|
import {metaData} from "src/composables/meta";
|
||||||
import AvatarFromPhoto from "components/avatars/AvatarFromPhoto.vue";
|
import AvatarFromPhoto from "components/avatars/AvatarFromPhoto.vue";
|
||||||
|
import {useAuthStore} from "stores/Auth";
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const $router = useRouter();
|
const $router = useRouter();
|
||||||
@@ -117,7 +118,7 @@ const toggleLeftDrawer = () => {
|
|||||||
const {isQueryRunning, user} = storeToRefs(useLoggedUserStore());
|
const {isQueryRunning, user} = storeToRefs(useLoggedUserStore());
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
useLoggedUserStore().logout().then(() => {
|
useAuthStore().logout().then(() => {
|
||||||
$q.notify(successObject("Odhlášení bylo úspěšné"));
|
$q.notify(successObject("Odhlášení bylo úspěšné"));
|
||||||
$router.push({name: "homepage"});
|
$router.push({name: "homepage"});
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,35 +17,29 @@ useMeta(() => metaData({
|
|||||||
title: "Zapomenuté heslo",
|
title: "Zapomenuté heslo",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const registerUser = () => {
|
const requestPasswordChange = () => {
|
||||||
if (!form.value.validate()) return;
|
if (!form.value.validate()) return;
|
||||||
|
|
||||||
return api.post('/forgotten-password', formData).then(response => {
|
return api.post('/forgotten-password/request', formData).then(response => {
|
||||||
useAuthStore().login({email: formData.email, password: formData.password}).then(() => {
|
$q.notify(successObject("Žádost o změnu hesla odeslána, zkontroluj si svůj e-mail."))
|
||||||
$q.notify(successObject("Registrace úspěšná, vítej!"));
|
|
||||||
router.push({name: "myFlights"});
|
|
||||||
})
|
|
||||||
|
|
||||||
}).catch(({response}) => {
|
}).catch(({response}) => {
|
||||||
if (response.detail === 'User already exists') {
|
if (response.status === 404) {
|
||||||
$q.notify(errorObject("Uživatel s tímto e-mailem je již registrovaný. Zkus se přihlásit."));
|
$q.notify(errorObject(`E-mail ${formData.email} není registrovaný.`));
|
||||||
} else {
|
} else {
|
||||||
$q.notify(errorObject("Registrace se nepovedla, zkus to prosím znovu za chvíli"));
|
console.error(response)
|
||||||
|
$q.notify(errorObject("Při odesílání se stala chyba. Zkus to za chvíli znovu."));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const form = ref(null);
|
const form = ref(null);
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
name: "",
|
|
||||||
email: "",
|
email: "",
|
||||||
password: ""
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
email: [isRequired, isValidEmail],
|
email: [isRequired, isValidEmail],
|
||||||
password: [isRequired, minLength(4)]
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -62,7 +56,7 @@ const rules = {
|
|||||||
<q-form
|
<q-form
|
||||||
ref="form"
|
ref="form"
|
||||||
class="q-px-sm q-pt-xl q-pb-lg"
|
class="q-px-sm q-pt-xl q-pb-lg"
|
||||||
@submit.prevent="registerUser"
|
@submit.prevent="requestPasswordChange"
|
||||||
>
|
>
|
||||||
|
|
||||||
<q-input square clearable v-model="formData.email" type="email" label="E-mail" :rules="rules.email">
|
<q-input square clearable v-model="formData.email" type="email" label="E-mail" :rules="rules.email">
|
||||||
@@ -75,7 +69,7 @@ const rules = {
|
|||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-actions class="q-px-lg">
|
<q-card-actions class="q-px-lg">
|
||||||
<q-btn
|
<q-btn
|
||||||
@click="registerUser"
|
@click="requestPasswordChange"
|
||||||
unelevated
|
unelevated
|
||||||
size="lg"
|
size="lg"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
<script setup>
|
||||||
|
import {onMounted, reactive, ref} from "vue";
|
||||||
|
import {useRoute, useRouter} from "vue-router";
|
||||||
|
import {useMeta, useQuasar} from "quasar";
|
||||||
|
import {errorObject, successObject} from "src/composables/dialog";
|
||||||
|
import {useAppStore} from "stores/App";
|
||||||
|
import {isRequired, isValidEmail, minLength} from "src/composables/form/rules";
|
||||||
|
import {api} from "boot/axios";
|
||||||
|
import {useAuthStore} from "stores/Auth";
|
||||||
|
import {metaData} from "src/composables/meta";
|
||||||
|
import {formatDatetime} from "../../../composables/datetimeUtils";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
const $q = useQuasar();
|
||||||
|
|
||||||
|
useAppStore().setPageTitle("Změna hesla");
|
||||||
|
useMeta(() => metaData({
|
||||||
|
title: "Změna hesla",
|
||||||
|
}));
|
||||||
|
|
||||||
|
const tokenInfo = reactive({
|
||||||
|
email: "",
|
||||||
|
name: "",
|
||||||
|
validity: null
|
||||||
|
});
|
||||||
|
const loadingTokenInfo = ref(true);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
api.get(`/forgotten-password/token/${route.params.token}`).then((resp) => {
|
||||||
|
tokenInfo.email = resp.data.user_email;
|
||||||
|
tokenInfo.name = resp.data.user_name;
|
||||||
|
tokenInfo.validity = new Date(resp.data.token_validity);
|
||||||
|
}).finally(() => loadingTokenInfo.value = false);
|
||||||
|
})
|
||||||
|
|
||||||
|
const resetPassword = () => {
|
||||||
|
if (!form.value.validate()) return;
|
||||||
|
|
||||||
|
return api.post('/forgotten-password/reset', formData).then(response => {
|
||||||
|
useAuthStore().login({email: tokenInfo.email, password: formData.password}).then(() => {
|
||||||
|
$q.notify(successObject("Heslo úspěšně změněno. Vítej zpět!"));
|
||||||
|
router.push({name: "myFlights"});
|
||||||
|
});
|
||||||
|
}).catch(({response}) => {
|
||||||
|
console.error(response)
|
||||||
|
$q.notify(errorObject("Při odesílání se stala chyba. Zkus to za chvíli znovu."));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = ref(null);
|
||||||
|
const formData = reactive({
|
||||||
|
password: "",
|
||||||
|
token: route.params.token
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
password: [isRequired],
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-layout view="lHh Lpr lFf">
|
||||||
|
<q-page-container>
|
||||||
|
<q-page class="row justify-center">
|
||||||
|
<q-card flat square style="width:95%; max-width: 450px; height: 500px">
|
||||||
|
<q-card-section class="bg-primary">
|
||||||
|
<h4 class="text-h5 text-white q-my-md">Změna hesla</h4>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section>
|
||||||
|
<q-form
|
||||||
|
ref="form"
|
||||||
|
class="q-px-sm q-pt-xl q-pb-lg"
|
||||||
|
@submit.prevent="resetPassword"
|
||||||
|
>
|
||||||
|
|
||||||
|
<div v-if="loadingTokenInfo" class="text-center">
|
||||||
|
<q-spinner size="70px" color="blue-3"/>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
|
||||||
|
<q-banner class="bg-blue-1 q-mb-lg ">
|
||||||
|
Token pro reset hesla je platný do {{ formatDatetime(tokenInfo.validity) }}.
|
||||||
|
</q-banner>
|
||||||
|
|
||||||
|
|
||||||
|
<q-input square clearable :model-value="tokenInfo.email" disable type="email" label="E-mail">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="email"/>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
|
||||||
|
<q-input square clearable v-model="formData.password" type="password" label="Nové heslo" :rules="rules.password">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="lock"/>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</q-form>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions class="q-px-lg">
|
||||||
|
<q-btn
|
||||||
|
@click="resetPassword"
|
||||||
|
:disable="loadingTokenInfo"
|
||||||
|
unelevated
|
||||||
|
size="lg"
|
||||||
|
color="primary"
|
||||||
|
class="full-width"
|
||||||
|
label="Resetovat heslo"
|
||||||
|
/>
|
||||||
|
</q-card-actions>
|
||||||
|
<q-card-section class="text-center q-pa-sm">
|
||||||
|
<router-link :to="{name: 'login'}" class="text-grey-6">Zpět na login</router-link>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-page>
|
||||||
|
</q-page-container>
|
||||||
|
</q-layout>
|
||||||
|
</template>
|
||||||
@@ -4,6 +4,7 @@ const routes = [
|
|||||||
{path: '/login', name: "login", component: () => import('pages/public/user/LoginPage.vue'), meta: {layout: PlainLayout}},
|
{path: '/login', name: "login", component: () => import('pages/public/user/LoginPage.vue'), meta: {layout: PlainLayout}},
|
||||||
{path: '/registrace', name: "registration", component: () => import('pages/public/user/RegisterPage.vue'), meta: {layout: PlainLayout}},
|
{path: '/registrace', name: "registration", component: () => import('pages/public/user/RegisterPage.vue'), meta: {layout: PlainLayout}},
|
||||||
{path: '/zapomenute-heslo', name: "forgottenPassword", component: () => import('pages/public/user/ForgottenPasswordPage.vue'), meta: {layout: PlainLayout}},
|
{path: '/zapomenute-heslo', name: "forgottenPassword", component: () => import('pages/public/user/ForgottenPasswordPage.vue'), meta: {layout: PlainLayout}},
|
||||||
|
{path: '/zapomenute-heslo/:token', name: "resetPassword", component: () => import('pages/public/user/PasswordResetPage.vue'), meta: {layout: PlainLayout}},
|
||||||
|
|
||||||
{path: '', name: "homepage", component: () => import('pages/public/IndexPage.vue'), meta: {layout: PlainLayout}},
|
{path: '', name: "homepage", component: () => import('pages/public/IndexPage.vue'), meta: {layout: PlainLayout}},
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {defineStore} from 'pinia'
|
import {defineStore} from 'pinia'
|
||||||
import {api} from "boot/axios";
|
import {api} from "boot/axios";
|
||||||
import {cookies} from "boot/cookies";
|
import {cookies} from "boot/cookies";
|
||||||
|
import {useFlightsStore} from "stores/Flights";
|
||||||
|
|
||||||
export const useAuthStore = defineStore('Auth', () => {
|
export const useAuthStore = defineStore('Auth', () => {
|
||||||
const login = async (formData) => {
|
const login = async (formData) => {
|
||||||
@@ -12,6 +13,7 @@ export const useAuthStore = defineStore('Auth', () => {
|
|||||||
const logout = () => {
|
const logout = () => {
|
||||||
return api.post("/logout").then(response => {
|
return api.post("/logout").then(response => {
|
||||||
unsetTokens();
|
unsetTokens();
|
||||||
|
useFlightsStore().flights = [];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user