Skip to content

Commit

Permalink
Implement email confirmation
Browse files Browse the repository at this point in the history
  • Loading branch information
mh-malekpour committed Apr 26, 2020
1 parent 6e399a1 commit b6f3cd1
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 6 deletions.
3 changes: 3 additions & 0 deletions templates/users/activate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<b>Welcome! Thanks for signing up. Please follow this link to activate your account:</b>
<p><a href="{{ confirm_url }}">{{ confirm_url }}</a></p>
<b>Cheers!</b>
13 changes: 13 additions & 0 deletions users/email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from flask_mail import Message

from app import app
from extentions import mail


def send_email(to, subject, template):
msg = Message(
subject=subject,
recipients=[to],
html=template
)
mail.send(msg)
21 changes: 21 additions & 0 deletions users/token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from itsdangerous import URLSafeTimedSerializer

from app import app


def generate_confirmation_token(email):
serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])
return serializer.dumps(email, salt=app.config['SECURITY_PASSWORD_SALT'])


def confirm_token(token, expiration=3600):
serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])
try:
email = serializer.loads(
token,
salt=app.config['SECURITY_PASSWORD_SALT'],
max_age=expiration
)
except:
return False
return email
38 changes: 32 additions & 6 deletions users/views.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,64 @@
import datetime

from flask import jsonify, request
from flask import jsonify, render_template, request, url_for
from flask_jwt_extended import (create_access_token, create_refresh_token,
get_jwt_identity, jwt_refresh_token_required,
jwt_required)

from extentions import db
from users import users
from users.email import send_email
from users.forms import ChangePasswordForm, LoginForm, RegisterForm
from users.models import User
from users.token import confirm_token, generate_confirmation_token
from utils.decorators import json_only


@users.route('/signup', methods=['POST'])
def create_user():
def register():
form = RegisterForm()
if not form.validate_on_submit():
return {'errors': form.errors}, 400
new_user = User(form.full_name.data, form.email.data, form.password.data)
db.session.add(new_user)
db.session.commit()
return {'message': 'account created successfully'}, 201
token = generate_confirmation_token(new_user.Email)
subject = "DailyDiet | Please confirm your email"
confirm_url = url_for('users.confirm_email', token=token, _external=True)
html = html = render_template('users/activate.html', confirm_url=confirm_url)
send_email(new_user.Email, subject, html)
return {'msg': 'Account created successfully!'}, 201


@users.route('/confirm/<token>', methods=['GET'])
def confirm_email(token):
try:
email = confirm_token(token)
except:
return {'error': 'The confirmation link is invalid or has expired.'}, 400
user = User.query.filter_by(Email=email).first_or_404()
if user.Confirmed:
return {'msg': 'Account already confirmed. Please login.'}
else:
user.Confirmed = True
user.ConfirmedOn = datetime.datetime.now()
db.session.add(user)
db.session.commit()
return {'msg': 'You have confirmed your account. Thanks!'}


@users.route('/signin', methods=['POST'])
def login():
form = LoginForm()
if not form.validate_on_submit():
return {'errors': form.errors}, 400
email = form.email.data
password = form.password.data
user = User.query.filter(User.Email.ilike(email)).first()
if not user:
return {'error': 'email or password does not match'}, 403
return {'error': 'Email/Password does not match.'}, 403
if not user.check_password(password):
return {'error': 'email or password does not match'}, 403
return {'error': 'Email/Password does not match.'}, 403
access_token = create_access_token(identity=user.Email, fresh=True)
refresh_token = create_refresh_token(identity=user.Email)
return {'access_token': access_token, 'refresh_token': refresh_token}, 200
Expand All @@ -52,7 +78,7 @@ def change_password():
user = User.query.filter(User.Email.ilike(identity)).first()
form = ChangePasswordForm()
if not user.check_password(form.old_password.data):
return {'error': 'old password does not match'}, 403
return {'error': 'Old password does not match.'}, 403
if not form.validate_on_submit():
return {'errors': form.errors}, 400
user.set_password(form.new_password.data)
Expand Down

0 comments on commit b6f3cd1

Please sign in to comment.