See #187: Front logic for password reset
This commit is contained in:
parent
22f0b1a2d8
commit
3b9024129d
|
@ -0,0 +1,12 @@
|
|||
{% load i18n %}{% autoescape off %}
|
||||
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
|
||||
|
||||
{% trans "Please go to the following page and choose a new password:" %}
|
||||
{{ funkwhale_url }}/auth/password/reset/confirm?uid={{ uid }}&token={{ token }}
|
||||
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
|
||||
|
||||
{% trans "Thanks for using our site!" %}
|
||||
|
||||
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
|
||||
|
||||
{% endautoescape %}
|
|
@ -12,9 +12,15 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="field">
|
||||
<i18next tag="label" path="Username or email"/>
|
||||
<label>
|
||||
{{ $t('Username or email') }} |
|
||||
<router-link :to="{path: '/signup'}">
|
||||
{{ $t('Create an account') }}
|
||||
</router-link>
|
||||
</label>
|
||||
<input
|
||||
ref="username"
|
||||
tabindex="1"
|
||||
required
|
||||
type="text"
|
||||
autofocus
|
||||
|
@ -23,18 +29,16 @@
|
|||
>
|
||||
</div>
|
||||
<div class="field">
|
||||
<i18next tag="label" path="Password"/>
|
||||
<input
|
||||
required
|
||||
type="password"
|
||||
placeholder="Enter your password"
|
||||
v-model="credentials.password"
|
||||
>
|
||||
<label>
|
||||
{{ $t('Password') }} |
|
||||
<router-link :to="{name: 'auth.password-reset', query: {email: credentials.username}}">
|
||||
{{ $t('Reset your password') }}
|
||||
</router-link>
|
||||
</label>
|
||||
<password-input :index="2" required v-model="credentials.password" />
|
||||
|
||||
</div>
|
||||
<button :class="['ui', {'loading': isLoading}, 'button']" type="submit"><i18next path="Login"/></button>
|
||||
<router-link class="ui right floated basic button" :to="{path: '/signup'}">
|
||||
<i18next path="Create an account"/>
|
||||
</router-link>
|
||||
<button tabindex="3" :class="['ui', {'loading': isLoading}, 'right', 'floated', 'green', 'button']" type="submit"><i18next path="Login"/></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -42,12 +46,15 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import PasswordInput from '@/components/forms/PasswordInput'
|
||||
|
||||
export default {
|
||||
name: 'login',
|
||||
props: {
|
||||
next: {type: String, default: '/'}
|
||||
},
|
||||
components: {
|
||||
PasswordInput
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// We need to initialize the component with any
|
||||
|
|
|
@ -9,6 +9,8 @@ import Signup from '@/components/auth/Signup'
|
|||
import Profile from '@/components/auth/Profile'
|
||||
import Settings from '@/components/auth/Settings'
|
||||
import Logout from '@/components/auth/Logout'
|
||||
import PasswordReset from '@/views/auth/PasswordReset'
|
||||
import PasswordResetConfirm from '@/views/auth/PasswordResetConfirm'
|
||||
import Library from '@/components/library/Library'
|
||||
import LibraryHome from '@/components/library/Home'
|
||||
import LibraryArtist from '@/components/library/Artist'
|
||||
|
@ -59,6 +61,23 @@ export default new Router({
|
|||
component: Login,
|
||||
props: (route) => ({ next: route.query.next || '/library' })
|
||||
},
|
||||
{
|
||||
path: '/auth/password/reset',
|
||||
name: 'auth.password-reset',
|
||||
component: PasswordReset,
|
||||
props: (route) => ({
|
||||
defaultEmail: route.query.email
|
||||
})
|
||||
},
|
||||
{
|
||||
path: '/auth/password/reset/confirm',
|
||||
name: 'auth.password-reset-confirm',
|
||||
component: PasswordResetConfirm,
|
||||
props: (route) => ({
|
||||
defaultUid: route.query.uid,
|
||||
defaultToken: route.query.token
|
||||
})
|
||||
},
|
||||
{
|
||||
path: '/signup',
|
||||
name: 'signup',
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div class="main pusher" v-title="$t('Reset your password')">
|
||||
<div class="ui vertical stripe segment">
|
||||
<div class="ui small text container">
|
||||
<h2>{{ $t('Reset your password') }}</h2>
|
||||
<form class="ui form" @submit.prevent="submit()">
|
||||
<div v-if="errors.length > 0" class="ui negative message">
|
||||
<div class="header">{{ $('Error while asking for a password reset') }}</div>
|
||||
<ul class="list">
|
||||
<li v-for="error in errors">{{ error }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>{{ $t('Use this form to request a password reset. We will send an email to the given address with instructions to reset your password.') }}</p>
|
||||
<div class="field">
|
||||
<label>{{ $t('Account\'s email') }}</label>
|
||||
<input
|
||||
required
|
||||
ref="email"
|
||||
type="email"
|
||||
autofocus
|
||||
:placeholder="$t('Input the email address binded to your account')"
|
||||
v-model="email">
|
||||
</div>
|
||||
<router-link :to="{path: '/login'}">
|
||||
{{ $t('Back to login') }}
|
||||
</router-link>
|
||||
<button :class="['ui', {'loading': isLoading}, 'right', 'floated', 'green', 'button']" type="submit">
|
||||
{{ $t('Ask for a password reset') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
props: ['defaultEmail'],
|
||||
data () {
|
||||
return {
|
||||
email: this.defaultEmail,
|
||||
isLoading: false,
|
||||
errors: []
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$refs.email.focus()
|
||||
},
|
||||
methods: {
|
||||
submit () {
|
||||
let self = this
|
||||
self.isLoading = true
|
||||
self.errors = []
|
||||
let payload = {
|
||||
email: this.email
|
||||
}
|
||||
return axios.post('auth/password/reset/', payload).then(response => {
|
||||
self.isLoading = false
|
||||
self.$router.push({
|
||||
name: 'auth.password-reset-confirm'
|
||||
})
|
||||
}, error => {
|
||||
self.errors = error.backendErrors
|
||||
self.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<div class="main pusher" v-title="$t('Change your password')">
|
||||
<div class="ui vertical stripe segment">
|
||||
<div class="ui small text container">
|
||||
<h2>{{ $t('Change your password') }}</h2>
|
||||
<form v-if="!success" class="ui form" @submit.prevent="submit()">
|
||||
<div v-if="errors.length > 0" class="ui negative message">
|
||||
<div class="header">{{ $('Error while changing your password') }}</div>
|
||||
<ul class="list">
|
||||
<li v-for="error in errors">{{ error }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<template v-if="token && uid">
|
||||
<div class="field">
|
||||
<label>{{ $t('New password') }}</label>
|
||||
<password-input v-model="newPassword" />
|
||||
</div>
|
||||
<router-link :to="{path: '/login'}">
|
||||
{{ $t('Back to login') }}
|
||||
</router-link>
|
||||
<button :class="['ui', {'loading': isLoading}, 'right', 'floated', 'green', 'button']" type="submit">
|
||||
{{ $t('Update your password') }}</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>{{ $t('If the email address provided in the previous step is valid and binded to a user account, you should receive an email with reset instructions in the next couple of minutes.') }}</p>
|
||||
</template>
|
||||
</form>
|
||||
<div v-else class="ui positive message">
|
||||
<div class="header">{{ $t('Password updated successfully') }}</div>
|
||||
<p>{{ $t('Your password has been updated successfully.') }}</p>
|
||||
<router-link :to="{name: 'login'}">
|
||||
{{ $t('Proceed to login') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import PasswordInput from '@/components/forms/PasswordInput'
|
||||
|
||||
export default {
|
||||
props: ['defaultToken', 'defaultUid'],
|
||||
components: {
|
||||
PasswordInput
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
newPassword: '',
|
||||
isLoading: false,
|
||||
errors: [],
|
||||
token: this.defaultToken,
|
||||
uid: this.defaultUid,
|
||||
success: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit () {
|
||||
let self = this
|
||||
self.isLoading = true
|
||||
self.errors = []
|
||||
let payload = {
|
||||
uid: this.uid,
|
||||
token: this.token,
|
||||
new_password1: this.newPassword,
|
||||
new_password2: this.newPassword
|
||||
}
|
||||
return axios.post('auth/password/reset/confirm/', payload).then(response => {
|
||||
self.isLoading = false
|
||||
self.success = true
|
||||
}, error => {
|
||||
self.errors = error.backendErrors
|
||||
self.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
Loading…
Reference in New Issue