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
	
	 Eliot Berriot
						Eliot Berriot