Email confirmation system added
User confirmation based on email
This commit is contained in:
parent
c8c5d627bd
commit
669eeaabad
@ -14,8 +14,8 @@ class Config:
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
DEBUG = True
|
||||
MAIL_SERVER = 'smtp.googlemail.com'
|
||||
MAIL_PORT = 587
|
||||
MAIL_SERVER = 'localhost'
|
||||
MAIL_PORT = 25
|
||||
MAIL_USE_TLS = True
|
||||
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
|
||||
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
|
||||
|
@ -8,6 +8,19 @@ from ..models import User
|
||||
from ..email import send_email
|
||||
from .forms import LoginForm, RegistrationForm
|
||||
|
||||
@auth.before_app_request
|
||||
def before_request():
|
||||
if current_user.is_authenticated \
|
||||
and not current_user.confirmed \
|
||||
and request.endpoint[:5] != 'auth.' \
|
||||
and request.endpoint != 'static':
|
||||
return redirect(url_for('auth.unconfirmed'))
|
||||
|
||||
@auth.route('/unconfirmed')
|
||||
def unconfirmed():
|
||||
if current_user.is_anonymous or current_user.confirmed:
|
||||
return redirect(url_for('main.index'))
|
||||
return render_template('auth/unconfirmed.html')
|
||||
|
||||
@auth.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
@ -26,7 +39,7 @@ def logout():
|
||||
logout_user()
|
||||
flash('You have been logged out.')
|
||||
return redirect(url_for('main.index'))
|
||||
|
||||
|
||||
@auth.route('/register', methods=['GET', 'POST'])
|
||||
def register():
|
||||
form = RegistrationForm()
|
||||
@ -38,6 +51,32 @@ def register():
|
||||
avatar="/static/img/user2-160x160.jpg",
|
||||
created_at=datetime.datetime.now())
|
||||
db.session.add(user)
|
||||
flash('You can now login.')
|
||||
return redirect(url_for('auth.login'))
|
||||
return render_template('auth/register.html', form=form)
|
||||
db.session.commit()
|
||||
token = user.generate_confirmation_token()
|
||||
send_email(user.email, 'Confirm Your Account',
|
||||
'auth/email/confirm', user=user, token=token)
|
||||
flash('A confirmation email has been sent to you by email.')
|
||||
return redirect(url_for('main.index'))
|
||||
return render_template('auth/register.html', form=form)
|
||||
|
||||
# user email confirmation function
|
||||
@auth.route('/confirm/<token>')
|
||||
@login_required
|
||||
def confirm(token):
|
||||
if current_user.confirmed:
|
||||
return redirect(url_for('main.index'))
|
||||
if current_user.confirm(token):
|
||||
flash('You have confirmed your account. Thanks!')
|
||||
else:
|
||||
flash('The confirmation link is invalid or has expired.')
|
||||
return redirect(url_for('main.index'))
|
||||
|
||||
# resend confirmation email
|
||||
@auth.route('/confirm')
|
||||
@login_required
|
||||
def resend_confirmation():
|
||||
token = current_user.generate_confirmation_token()
|
||||
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'))
|
@ -4,17 +4,17 @@ from flask_mail import Message
|
||||
from . import mail
|
||||
|
||||
|
||||
def send_async_email(app, msg):
|
||||
with app.app_context():
|
||||
def send_async_email(dash, msg):
|
||||
with dash.app_context():
|
||||
mail.send(msg)
|
||||
|
||||
|
||||
def send_email(to, subject, template, **kwargs):
|
||||
app = current_app._get_current_object()
|
||||
msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
|
||||
sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
|
||||
dash = current_app._get_current_object()
|
||||
msg = Message(dash.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
|
||||
sender=dash.config['FLASKY_MAIL_SENDER'], recipients=[to])
|
||||
msg.body = render_template(template + '.txt', **kwargs)
|
||||
msg.html = render_template(template + '.html', **kwargs)
|
||||
thr = Thread(target=send_async_email, args=[app, msg])
|
||||
thr = Thread(target=send_async_email, args=[dash, msg])
|
||||
thr.start()
|
||||
return thr
|
@ -10,9 +10,6 @@ from flask_login import UserMixin
|
||||
from . import db
|
||||
from . import login_manager
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
return User.query.get(int(user_id))
|
||||
|
||||
class Role(db.Model):
|
||||
__tablename__ = 'roles'
|
||||
@ -49,11 +46,12 @@ class User(UserMixin, db.Model):
|
||||
def verify_password(self, password):
|
||||
return check_password_hash(self.password_hash, password)
|
||||
|
||||
# user email confirmation
|
||||
# generates confirmation token for user email confirmation
|
||||
def generate_confirmation_token(self, expiration=3600):
|
||||
s = Serializer(current_app.config['SECRET_KEY'], expiration)
|
||||
return s.dumps({'confirm': self.id})
|
||||
|
||||
|
||||
# confirms uer email by id
|
||||
def confirm(self, token):
|
||||
s = Serializer(current_app.config['SECRET_KEY'])
|
||||
try:
|
||||
@ -68,3 +66,7 @@ class User(UserMixin, db.Model):
|
||||
|
||||
def __repr__(self):
|
||||
return '<User %r>' % self.username
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
return User.query.get(int(user_id))
|
8
dash/templates/auth/email/confirm.html
Normal file
8
dash/templates/auth/email/confirm.html
Normal file
@ -0,0 +1,8 @@
|
||||
<p>Dear {{ user.username }},</p>
|
||||
<p>Welcome to <b>- Stack</b>!</p>
|
||||
<p>To confirm your account please <a href="{{ url_for('auth.confirm', 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.confirm', token=token, _external=True) }}</p>
|
||||
<p>Sincerely,</p>
|
||||
<p>The - Stack Team</p>
|
||||
<p><small>Note: replies to this email address are not monitored.</small></p>
|
11
dash/templates/auth/email/confirm.txt
Normal file
11
dash/templates/auth/email/confirm.txt
Normal file
@ -0,0 +1,11 @@
|
||||
Dear {{ user.username }},
|
||||
|
||||
Welcome to - Stack!
|
||||
|
||||
To confirm your account please click on the following link:
|
||||
|
||||
{{ url_for('auth.confirm', token=token, _external=True) }}
|
||||
|
||||
Sincerely,
|
||||
|
||||
The - Stack Team
|
@ -27,21 +27,21 @@
|
||||
<form action="{{ url_for('auth.register') }}" method="post" name="register">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group has-feedback">
|
||||
<input type="email" name="email" class="form-control" placeholder="Email">
|
||||
<input type="email" name="email" class="form-control" placeholder="Email" value="{{ request.form['email'] }}">
|
||||
<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="text" name="username" class="form-control" placeholder="User name">
|
||||
<input type="text" name="username" class="form-control" placeholder="User name" value="{{ request.form['username'] }}">
|
||||
<span class="glyphicon glyphicon-user form-control-feedback"></span>
|
||||
{% if form.username.errors %}
|
||||
<span class="text-red">{% for error in form.username.errors %} {{ error }} {% endfor %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<input type="text" name="full_name" class="form-control" placeholder="Full name">
|
||||
<input type="text" name="full_name" class="form-control" placeholder="Full name" value="{{ request.form['full_name'] }}">
|
||||
<span class="glyphicon glyphicon-user form-control-feedback"></span>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
|
35
dash/templates/auth/unconfirmed.html
Normal file
35
dash/templates/auth/unconfirmed.html
Normal file
@ -0,0 +1,35 @@
|
||||
{% extends "adminlte/base_without_nav.html" %}
|
||||
|
||||
{% block title %}Confirm Account{% endblock %}
|
||||
{% block description %}You have not confirmed your account!{% 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">
|
||||
{# 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 %}
|
||||
<h3>Hello {{ current_user.username }}</h3>
|
||||
<h4>You have not confirmed your account yet!</h4>
|
||||
<p>Before accessing this page, you need to confirm your account.
|
||||
Please check your email inbox and click on confirmation link.</p>
|
||||
<p>If you have not received confirmation email:</p>
|
||||
<a href="{{ url_for('auth.resend_confirmation') }}">
|
||||
<button type="button" class="btn btn-primary">Re-Send Confirmation</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user