diff --git a/app/auth/forms.py b/app/auth/forms.py index 3a71b0950ad43cd302b8a43a40a4ec3e1feadf9b..d23e4e2d2436ab39b997e667a2b6d912133f77e4 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 f4c921b5879daca69fc882520ad73d1a09d18b1b..e4595f3761dda0150f074327c284604a96b44b37 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 @@ -81,6 +81,17 @@ def password_reset_request(): title='Password Reset') -@auth.route('/reset/<token>') +@auth.route('/reset/<token>', 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 45a2a6336f848aebd8e15aec87c18ff364ccecda..d8d18d0883541c674835a70d08ff794b341f6839 100644 --- a/app/models.py +++ b/app/models.py @@ -47,6 +47,20 @@ class User(UserMixin, db.Model): db.session.add(self) return True + @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 bb9cfe74f1aa8cc673cf9683428a6924e277d5b1..e545e464e45ff7383928e7dc3a2cb141c87a7b51 100644 --- a/app/templates/auth/reset_password.html.j2 +++ b/app/templates/auth/reset_password.html.j2 @@ -7,10 +7,27 @@ <span class="card-title">Reset Your Password</span> <form method="POST"> {{ form.hidden_tag() }} + {% if form.email is defined %} <div class="input-field"> {{ form.email(class='validate', type='email') }} {{ form.email.label }} </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"> {{ form.submit(class='btn right') }} </div>