flask-login-example/app.py

245 lines
7.0 KiB
Python
Raw Normal View History

2017-05-17 20:16:30 +02:00
from os import getenv
from flask import Flask, redirect, url_for, render_template, flash, session
from functools import wraps
from forms import LoginForm, SignupForm, EmailResetPasswordForm, ResetPasswordForm
from models import db, User
from flask_mail import Mail, Message
2017-05-18 18:25:54 +02:00
from uuid import uuid4
from crypt import crypt, mksalt, METHOD_SHA512
2017-05-17 20:16:30 +02:00
# CONFIGURATIONS
# Flask
app = Flask(__name__)
app.config['SECRET_KEY'] = getenv('SECRET_KEY')
app.config['DEBUG'] = bool(getenv('DEBUG'))
# Database
app.config['SQLALCHEMY_DATABASE_URI'] = getenv('SQLALCHEMY_DATABASE_URI')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
# Email
app.config['MAIL_SERVER'] = getenv('MAIL_SERVER')
app.config['MAIL_USERNAME'] = getenv('MAIL_USERNAME')
app.config['MAIL_PASSWORD'] = getenv('MAIL_PASSWORD')
mail = Mail(app)
# END CONFIGURATIONS
# DECORATIONS
def login_required(f):
# Decoration: check login in session
@wraps(f)
def decorated_function(*args, **kwargs):
if 'user' not in session:
session.clear()
return redirect(url_for('index'))
return f(*args, **kwargs)
return decorated_function
# END DECORATIONS
# VIEWS
@app.route('/')
def index():
'''
Index page
'''
return redirect(url_for('login'))
@app.route('/signup', methods=('GET', 'POST'))
def signup():
'''
Signup page
'''
form = SignupForm()
if form.validate_on_submit():
2017-05-18 18:25:54 +02:00
if not User.query.filter_by(email=form.email.data).all():
2017-05-17 20:16:30 +02:00
my_user = User()
form.populate_obj(my_user)
2017-05-18 18:25:54 +02:00
# Encrypt password
my_user.password = crypt(
form.password.data, mksalt(METHOD_SHA512)
)
2017-05-17 20:16:30 +02:00
db.session.add(my_user)
# Prepare the account activation email
msg = Message(
'Activate account',
sender='no-repy@' + getenv('DOMAIN'),
recipients=[my_user.email]
)
2017-05-18 18:25:54 +02:00
link = 'http://' + getenv('DOMAIN') + url_for('activate_account', token=my_user.token)
2017-05-17 20:16:30 +02:00
msg.body = render_template(
'emails/activate.txt', username=my_user.username,
2017-05-18 18:25:54 +02:00
token=link
2017-05-17 20:16:30 +02:00
)
msg.html = render_template(
'emails/activate.html',
username=my_user.username,
2017-05-18 18:25:54 +02:00
token=link
2017-05-17 20:16:30 +02:00
)
try:
# Save new User
db.session.commit()
# Send confirmation email
mail.send(msg)
# Informamos al usuario
flash('Account created successfully.', 'success')
flash('We have sent you a confirmation email.', 'warning')
return redirect(url_for('login'))
except:
db.session.rollback()
flash(
'''We're sorry, an internal error has occurred.
Please, try again.''',
'danger'
)
else:
flash('Email exists.', 'danger')
return render_template('web/signup.html', form=form)
@app.route('/activate/<token>')
def activate_account(token):
'''
Activate account
'''
# Obtenemos el usuario que tenga ese token
my_user = User.query.filter_by(token=token).first()
if my_user:
# Lo activamos
my_user.is_active = True
db.session.add(my_user)
db.session.commit()
# Mostramos mensaje
flash('Your account has been activated.', 'success')
return redirect(url_for('login'))
@app.route('/forgot_password/new', methods=('GET', 'POST'))
def forgot_password():
'''
Page lost password
'''
form = EmailResetPasswordForm()
if form.validate_on_submit():
# Check if the email is in the database
my_user = User.query.filter_by(email=form.email.data).first()
if my_user:
# Generate new token
2017-05-18 18:25:54 +02:00
token = str(uuid4()).replace('-', '')
2017-05-17 20:16:30 +02:00
# Update user token
my_user.token = token
db.session.add(my_user)
db.session.commit()
# Send email with token
2017-05-18 18:25:54 +02:00
link = 'http://' + getenv('DOMAIN') + url_for(
'update_password',
email=my_user.email, token=token
)
2017-05-17 20:16:30 +02:00
msg = Message(
'Recover password',
sender='no-repy@' + getenv('DOMAIN'),
recipients=[form.email.data]
)
msg.body = render_template(
'emails/forgot_password.txt', username=my_user.username,
2017-05-18 18:25:54 +02:00
token=link
2017-05-17 20:16:30 +02:00
)
msg.html = render_template(
'emails/forgot_password.html',
username=my_user.username,
2017-05-18 18:25:54 +02:00
token=link
2017-05-17 20:16:30 +02:00
)
mail.send(msg)
flash('''
We have sent an email to change your password.
Please check your Spam folder if not found.
''', 'success')
return redirect(url_for('login'))
else:
flash('Email is not registered.', 'danger')
return render_template('web/forgot_password.html', form=form)
@app.route('/forgot_password/update/<email>/<token>', methods=('GET', 'POST'))
def update_password(email, token):
'''
Page update password
'''
form = ResetPasswordForm()
# Check that the user is valid
my_user = User.query.filter_by(email=email, token=token).first()
if my_user:
if form.validate_on_submit():
# Encrypt password
2017-05-18 18:25:54 +02:00
my_user.password = crypt(
form.password.data, mksalt(METHOD_SHA512)
2017-05-17 20:16:30 +02:00
)
# Update password
db.session.add(my_user)
db.session.commit()
flash('Your password has been updated successfully.', 'success')
return redirect(url_for('login'))
else:
return redirect(url_for('index'))
return render_template('web/update_password.html', form=form, email=email)
@app.route('/login', methods=('GET', 'POST'))
def login():
'''
Page login
'''
form = LoginForm()
if form.validate_on_submit():
# Validate email and password
email = form.email.data
2017-05-18 18:25:54 +02:00
password = crypt(
form.password.data, mksalt(METHOD_SHA512)
)
2017-05-17 20:16:30 +02:00
my_user = User.query.filter_by(email=email, password=password).first()
if my_user:
# Login de usuario
session['user'] = my_user.id
return redirect(url_for('dashboard'))
else:
flash('Your email or password is not valid.', 'danger')
return render_template('web/login.html', form=form)
@app.route('/logout')
@login_required
def logout():
'''
Page logout
'''
# Clear sessions
session.clear()
return redirect(url_for('index'))
@app.route('/dashboard')
@login_required
def dashboard():
'''
Page dashboard.
Protected area. Only accessible with login.
'''
return render_template('web/dashboard.html')
# END VIEWS
# MAIN
if __name__ == "__main__":
app.run()
# END MAIN