diff --git a/config.py b/config.py index 33aaae8..d2df949 100644 --- a/config.py +++ b/config.py @@ -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') diff --git a/dash/auth/views.py b/dash/auth/views.py index 52a4abd..aa0910e 100644 --- a/dash/auth/views.py +++ b/dash/auth/views.py @@ -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) \ No newline at end of file + 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/') +@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')) \ No newline at end of file diff --git a/dash/email.py b/dash/email.py index 65c3f47..61579ef 100644 --- a/dash/email.py +++ b/dash/email.py @@ -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 \ No newline at end of file diff --git a/dash/models.py b/dash/models.py index 150be3d..51da1d0 100644 --- a/dash/models.py +++ b/dash/models.py @@ -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 '' % self.username + +@login_manager.user_loader +def load_user(user_id): + return User.query.get(int(user_id)) \ No newline at end of file diff --git a/dash/templates/auth/email/confirm.html b/dash/templates/auth/email/confirm.html new file mode 100644 index 0000000..8714f8e --- /dev/null +++ b/dash/templates/auth/email/confirm.html @@ -0,0 +1,8 @@ +

Dear {{ user.username }},

+

Welcome to - Stack!

+

To confirm your account please click here.

+

Alternatively, you can paste the following link in your browser's address bar:

+

{{ url_for('auth.confirm', token=token, _external=True) }}

+

Sincerely,

+

The - Stack Team

+

Note: replies to this email address are not monitored.

\ No newline at end of file diff --git a/dash/templates/auth/email/confirm.txt b/dash/templates/auth/email/confirm.txt new file mode 100644 index 0000000..b87ef1c --- /dev/null +++ b/dash/templates/auth/email/confirm.txt @@ -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 \ No newline at end of file diff --git a/dash/templates/auth/register.html b/dash/templates/auth/register.html index 6e46ecf..e7230ec 100644 --- a/dash/templates/auth/register.html +++ b/dash/templates/auth/register.html @@ -27,21 +27,21 @@
{{ form.hidden_tag() }}
- + {% if form.email.errors %} {% for error in form.email.errors %} {{ error }} {% endfor %} {% endif %}
- + {% if form.username.errors %} {% for error in form.username.errors %} {{ error }} {% endfor %} {% endif %}
- +
diff --git a/dash/templates/auth/unconfirmed.html b/dash/templates/auth/unconfirmed.html new file mode 100644 index 0000000..88407b3 --- /dev/null +++ b/dash/templates/auth/unconfirmed.html @@ -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 %} + + + +{% endblock %}