diff --git a/app/auth/forms.py b/app/auth/forms.py index 3a71b095..d23e4e2d 100644 --- a/app/auth/forms.py +++ b/app/auth/forms.py @@ -35,6 +35,13 @@ class RegistrationForm(FlaskForm): 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): email = StringField('Email', validators=[DataRequired(), Length(1, 64), Email()]) diff --git a/app/auth/views.py b/app/auth/views.py index 04afc1e6..5ecb5713 100644 --- a/app/auth/views.py +++ b/app/auth/views.py @@ -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 . import auth from .. import db -from .forms import LoginForm, PasswordResetRequestForm, RegistrationForm +from .forms import LoginForm, PasswordResetForm, PasswordResetRequestForm, RegistrationForm from ..email import send_email from ..models import User @@ -64,6 +64,17 @@ def password_reset_request(): title='Password Reset') -@auth.route('/reset/') +@auth.route('/reset/', methods=['GET', 'POST']) 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') diff --git a/app/models.py b/app/models.py index d7d33b85..1a34dd64 100644 --- a/app/models.py +++ b/app/models.py @@ -32,6 +32,20 @@ class User(UserMixin, db.Model): s = Serializer(current_app.config['SECRET_KEY'], expiration) 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 def password(self): raise AttributeError('password is not a readable attribute') diff --git a/app/templates/auth/reset_password.html.j2 b/app/templates/auth/reset_password.html.j2 index bb9cfe74..e545e464 100644 --- a/app/templates/auth/reset_password.html.j2 +++ b/app/templates/auth/reset_password.html.j2 @@ -7,10 +7,27 @@ Reset Your Password
{{ form.hidden_tag() }} + {% if form.email is defined %}
{{ form.email(class='validate', type='email') }} {{ form.email.label }}
+ {% endif %} + {% if form.password is defined %} +
+ {{ form.password(class='validate', type='password') }} + {{ form.password.label }} + {% for error in form.password.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + {% if form.password2 is defined %} +
+ {{ form.password2(class='validate', type='password') }} + {{ form.password2.label }} +
+ {% endif %}
{{ form.submit(class='btn right') }}
diff --git a/data_dev.sqlite b/data_dev.sqlite index 75d6c154..2f7bde00 100644 Binary files a/data_dev.sqlite and b/data_dev.sqlite differ