Land of Forgotten Passwords
This will add new function to reset user password and some higher magical lore to the software.
This commit is contained in:
parent
30b400005a
commit
0a8b5a5db0
@ -31,4 +31,21 @@ class RegistrationForm(Form):
|
||||
|
||||
def validate_username(self, field):
|
||||
if User.query.filter_by(username=field.data).first():
|
||||
raise ValidationError('Username already in use.')
|
||||
raise ValidationError('Username already in use.')
|
||||
|
||||
class PasswordResetRequestForm(Form):
|
||||
email = StringField('Email', validators=[Required(), Length(1, 64),
|
||||
Email()])
|
||||
submit = SubmitField('Reset Password')
|
||||
|
||||
class PasswordResetForm(Form):
|
||||
email = StringField('Email', validators=[Required(), Length(1, 64),
|
||||
Email()])
|
||||
password = PasswordField('New Password', validators=[
|
||||
Required(), EqualTo('password2', message='Passwords must match')])
|
||||
password2 = PasswordField('Confirm password', validators=[Required()])
|
||||
submit = SubmitField('Reset Password')
|
||||
|
||||
def validate_email(self, field):
|
||||
if User.query.filter_by(email=field.data).first() is None:
|
||||
raise ValidationError('Unknown email address.')
|
@ -6,7 +6,8 @@ from . import auth
|
||||
from .. import db
|
||||
from ..models import User
|
||||
from ..email import send_email
|
||||
from .forms import LoginForm, RegistrationForm
|
||||
from .forms import LoginForm, RegistrationForm, PasswordResetRequestForm, \
|
||||
PasswordResetForm
|
||||
|
||||
@auth.before_app_request
|
||||
def before_request():
|
||||
@ -79,4 +80,38 @@ def resend_confirmation():
|
||||
send_email(current_user.email, 'Confirm Your Account',
|
||||
'auth/email/confirm', user=current_user, token=token)
|
||||
flash('A new confirmation email has been sent to you by email.')
|
||||
return redirect(url_for('main.index'))
|
||||
return redirect(url_for('main.index'))
|
||||
|
||||
# password reset
|
||||
@auth.route('/reset/<token>', methods=['GET', 'POST'])
|
||||
def password_reset(token):
|
||||
if not current_user.is_anonymous:
|
||||
return redirect(url_for('main.index'))
|
||||
form = PasswordResetForm()
|
||||
if form.validate_on_submit():
|
||||
user = User.query.filter_by(email=form.email.data).first()
|
||||
if user is None:
|
||||
return redirect(url_for('main.index'))
|
||||
if user.reset_password(token, form.password.data):
|
||||
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', form=form)
|
||||
|
||||
@auth.route('/reset', methods=['GET', 'POST'])
|
||||
def password_reset_request():
|
||||
if not current_user.is_anonymous:
|
||||
return redirect(url_for('main.index'))
|
||||
form = PasswordResetRequestForm()
|
||||
if form.validate_on_submit():
|
||||
user = User.query.filter_by(email=form.email.data).first()
|
||||
if user:
|
||||
token = user.generate_reset_token()
|
||||
send_email(user.email, 'Reset Your Password',
|
||||
'auth/email/reset_password',
|
||||
user=user, token=token,
|
||||
next=request.args.get('next'))
|
||||
flash('Instruction to reset your password has been '
|
||||
'send to your email address.')
|
||||
return render_template('auth/password_reset_request.html', form=form)
|
@ -51,7 +51,7 @@ class User(UserMixin, db.Model):
|
||||
s = Serializer(current_app.config['SECRET_KEY'], expiration)
|
||||
return s.dumps({'confirm': self.id})
|
||||
|
||||
# confirms uer email by id
|
||||
# confirms user email by id
|
||||
def confirm(self, token):
|
||||
s = Serializer(current_app.config['SECRET_KEY'])
|
||||
try:
|
||||
@ -63,7 +63,24 @@ class User(UserMixin, db.Model):
|
||||
self.confirmed = True
|
||||
db.session.add(self)
|
||||
return True
|
||||
|
||||
|
||||
# generates token for password reset
|
||||
def generate_reset_token(self, expiration=3600):
|
||||
s = Serializer(current_app.config['SECRET_KEY'], expiration)
|
||||
return s.dumps({'reset': self.id})
|
||||
|
||||
def reset_password(self, token, new_password):
|
||||
s = Serializer(current_app.config['SECRET_KEY'])
|
||||
try:
|
||||
data = s.loads(token)
|
||||
except:
|
||||
return False
|
||||
if data.get('reset') != self.id:
|
||||
return False
|
||||
self.password = new_password
|
||||
db.session.add(self)
|
||||
return True
|
||||
|
||||
def __repr__(self):
|
||||
return '<User %r>' % self.username
|
||||
|
||||
|
9
dash/templates/auth/email/reset_password.html
Normal file
9
dash/templates/auth/email/reset_password.html
Normal file
@ -0,0 +1,9 @@
|
||||
<p>Dear {{ user.username }},</p>
|
||||
<p>This message comes from Page of Forgotten Passwords</p>
|
||||
<p>To reset your password <a href="{{ url_for('auth.password_reset', token=token, _external=True) }}">click here</a>.</p>
|
||||
<p>Alternatively, you can paste the following link in your browser's address bar:</p>
|
||||
<p>{{ url_for('auth.password_reset', token=token, _external=True) }}</p>
|
||||
<p>If you have not requested a password reset simply ignore this message.</p>
|
||||
<p>Sincerely,</p>
|
||||
<p>The Unknown Archivists of Page of Forgotten Passwords</p>
|
||||
<p><small>Note: replies to this email address will fall in abyss of unknowns.</small></p>
|
13
dash/templates/auth/email/reset_password.txt
Normal file
13
dash/templates/auth/email/reset_password.txt
Normal file
@ -0,0 +1,13 @@
|
||||
Dear {{ user.username }},
|
||||
|
||||
This message comes from Page of Forgotten Passwords
|
||||
|
||||
To reset your password click on the following link:
|
||||
|
||||
{{ url_for('auth.password_reset', token=token, _external=True) }}
|
||||
|
||||
Sincerely,
|
||||
|
||||
The Unknown Archivists of Page of Forgotten Passwords
|
||||
|
||||
Note: replies to this email address will fall in abyss of unknowns.
|
@ -41,10 +41,15 @@
|
||||
<button type="submit" class="btn btn-primary btn-block btn-flat">Log In</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-left">
|
||||
<p><a href="{{ url_for('auth.password_reset_request') }}">Forgotten Passwords</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-center">
|
||||
<hr />
|
||||
<h4 class="box-title"> If you do not have account?</h4>
|
||||
<a href="{{ url_for('auth.register') }}">
|
||||
<button type="button" class="btn btn-block btn-danger btn-flat">Register Here</button>
|
||||
|
41
dash/templates/auth/password_reset_request.html
Normal file
41
dash/templates/auth/password_reset_request.html
Normal file
@ -0,0 +1,41 @@
|
||||
{% extends "adminlte/base_without_nav.html" %}
|
||||
|
||||
{% block title %}Welcome to Page of Forgotten Passwords{% endblock %}
|
||||
{% block description %}Page of Forgotten Passwords{% endblock %}
|
||||
{% block bodytag %}login-page{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="login-box">
|
||||
<div class="login-logo">
|
||||
<strong>-</strong> stack
|
||||
</div>
|
||||
<div class="login-box-body">
|
||||
<p>Enter your email address:</p>
|
||||
{# Display errors (if there are any). #}
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<ul>
|
||||
{% for message in messages %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{# Render the password reset request form. #}
|
||||
<form method="post">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group has-feedback">
|
||||
<input type="email" name="email" placeholder="Email" required="true" class="form-control">
|
||||
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-xs-offset-0">
|
||||
<button type="submit" class="btn btn-block btn-primary">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
58
dash/templates/auth/reset_password.html
Normal file
58
dash/templates/auth/reset_password.html
Normal file
@ -0,0 +1,58 @@
|
||||
{% extends "adminlte/base_without_nav.html" %}
|
||||
|
||||
{% block title %}Welcome back to Page of Forgotten Passwords{% endblock %}
|
||||
{% block description %}Page of Forgotten Passwords{% endblock %}
|
||||
{% block bodytag %}login-page{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="login-box">
|
||||
<div class="login-logo">
|
||||
<strong>-</strong> stack
|
||||
</div>
|
||||
<div class="login-box-body">
|
||||
<p>Change your password:</p>
|
||||
{# Display errors (if there are any). #}
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<ul>
|
||||
{% for message in messages %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{# Render the password reset request form. #}
|
||||
<form method="post">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group has-feedback">
|
||||
<input type="email" name="email" placeholder="Email" required="true" class="form-control">
|
||||
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
|
||||
{% if form.email.errors %}
|
||||
<span class="text-red">{% for error in form.email.errors %} {{ error }} {% endfor %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<input type="password" name="password" class="form-control" placeholder="Your New Password">
|
||||
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
|
||||
{% if form.password.errors %}
|
||||
<span class="text-red">{% for error in form.password.errors %} {{ error }} {% endfor %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<input type="password" name="password2" class="form-control" placeholder="Retype Your New Password">
|
||||
<span class="glyphicon glyphicon-log-in form-control-feedback"></span>
|
||||
{% if form.password2.errors %}
|
||||
<span class="text-red">{% for error in form.password2.errors %} {{ error }} {% endfor %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-xs-offset-0">
|
||||
<button type="submit" class="btn btn-block btn-primary">Change</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user