Add password reset functionality.

This commit is contained in:
Patrick Jentsch 2019-07-08 15:13:32 +02:00
parent 30e82088b4
commit 49222eeeef
5 changed files with 52 additions and 3 deletions

View File

@ -35,6 +35,13 @@ class RegistrationForm(FlaskForm):
raise ValidationError('Username already in use.') raise ValidationError('Username already in use.')
class PasswordResetForm(FlaskForm):
password = PasswordField('New Password', validators=[
DataRequired(), EqualTo('password2', message='Passwords must match')])
password2 = PasswordField('Confirm password', validators=[DataRequired()])
submit = SubmitField('Reset Password')
class PasswordResetRequestForm(FlaskForm): class PasswordResetRequestForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Length(1, 64), email = StringField('Email', validators=[DataRequired(), Length(1, 64),
Email()]) Email()])

View File

@ -2,7 +2,7 @@ from flask import flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required, login_user, logout_user from flask_login import current_user, login_required, login_user, logout_user
from . import auth from . import auth
from .. import db from .. import db
from .forms import LoginForm, PasswordResetRequestForm, RegistrationForm from .forms import LoginForm, PasswordResetForm, PasswordResetRequestForm, RegistrationForm
from ..email import send_email from ..email import send_email
from ..models import User from ..models import User
@ -64,6 +64,17 @@ def password_reset_request():
title='Password Reset') title='Password Reset')
@auth.route('/reset/<token>') @auth.route('/reset/<token>', methods=['GET', 'POST'])
def password_reset(token): def password_reset(token):
return 'test' if not current_user.is_anonymous:
return redirect(url_for('main.index'))
form = PasswordResetForm()
if form.validate_on_submit():
if User.reset_password(token, form.password.data):
db.session.commit()
flash('Your password has been updated.')
return redirect(url_for('auth.login'))
else:
return redirect(url_for('main.index'))
return render_template('auth/reset_password.html.j2', form=form,
title='Password Reset')

View File

@ -32,6 +32,20 @@ class User(UserMixin, db.Model):
s = Serializer(current_app.config['SECRET_KEY'], expiration) s = Serializer(current_app.config['SECRET_KEY'], expiration)
return s.dumps({'reset': self.id}).decode('utf-8') return s.dumps({'reset': self.id}).decode('utf-8')
@staticmethod
def reset_password(token, new_password):
s = Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token.encode('utf-8'))
except:
return False
user = User.query.get(data.get('reset'))
if user is None:
return False
user.password = new_password
db.session.add(user)
return True
@property @property
def password(self): def password(self):
raise AttributeError('password is not a readable attribute') raise AttributeError('password is not a readable attribute')

View File

@ -7,10 +7,27 @@
<span class="card-title">Reset Your Password</span> <span class="card-title">Reset Your Password</span>
<form method="POST"> <form method="POST">
{{ form.hidden_tag() }} {{ form.hidden_tag() }}
{% if form.email is defined %}
<div class="input-field"> <div class="input-field">
{{ form.email(class='validate', type='email') }} {{ form.email(class='validate', type='email') }}
{{ form.email.label }} {{ form.email.label }}
</div> </div>
{% endif %}
{% if form.password is defined %}
<div class="input-field">
{{ form.password(class='validate', type='password') }}
{{ form.password.label }}
{% for error in form.password.errors %}
<span class="helper-text" style="color:red;">{{ error }}</span>
{% endfor %}
</div>
{% endif %}
{% if form.password2 is defined %}
<div class="input-field">
{{ form.password2(class='validate', type='password') }}
{{ form.password2.label }}
</div>
{% endif %}
<div class="card-action"> <div class="card-action">
{{ form.submit(class='btn right') }} {{ form.submit(class='btn right') }}
</div> </div>

Binary file not shown.