diff --git a/{{cookiecutter.repo_name}}/requirements/prod.txt b/{{cookiecutter.repo_name}}/requirements/prod.txt index c3c2d47..cbb202c 100644 --- a/{{cookiecutter.repo_name}}/requirements/prod.txt +++ b/{{cookiecutter.repo_name}}/requirements/prod.txt @@ -25,4 +25,5 @@ cssmin>=0.1.4 jsmin>=2.0.4 # Auth +Flask-Login>=0.2.7 Flask-Bcrypt>=0.5.2 diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/app.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/app.py index 92c9773..89066d5 100644 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/app.py +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/app.py @@ -5,6 +5,7 @@ from webassets.loaders import PythonLoader from {{ cookiecutter.repo_name }}.settings import ProdConfig from {{cookiecutter.repo_name}}.assets import assets +from {{cookiecutter.repo_name}}.extensions import login_manager from {{cookiecutter.repo_name}}.database import db from {{cookiecutter.repo_name}} import public, user @@ -24,11 +25,13 @@ def create_app(config_object=ProdConfig): def register_extensions(app): db.init_app(app) + login_manager.init_app(app) assets.init_app(app) + return None def register_blueprints(app): # Register blueprints app.register_blueprint(public.views.blueprint) app.register_blueprint(user.views.blueprint) - return app + return None diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/extensions.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/extensions.py index 3cff6d4..73c41bd 100644 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/extensions.py +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/extensions.py @@ -3,3 +3,6 @@ from flask.ext.bcrypt import Bcrypt bcrypt = Bcrypt() + +from flask.ext.login import LoginManager +login_manager = LoginManager() diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/forms.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/forms.py index 977ea53..6553a87 100644 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/forms.py +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/forms.py @@ -1,19 +1,32 @@ from flask_wtf import Form from wtforms import TextField, PasswordField -from wtforms.validators import DataRequired, Email, EqualTo, Length - - -class RegisterForm(Form): - username = TextField('Username', - validators=[DataRequired(), Length(min=3, max=25)]) - email = TextField('Email', - validators=[DataRequired(), Email(), Length(min=6, max=40)]) - password = PasswordField('Password', - validators=[DataRequired(), Length(min=6, max=40)]) - confirm = PasswordField('Verify password', - [DataRequired(), EqualTo('password', message='Passwords must match')]) +from wtforms.validators import DataRequired +from {{cookiecutter.repo_name}}.user.models import User class LoginForm(Form): username = TextField('Username', validators=[DataRequired()]) password = PasswordField('Password', validators=[DataRequired()]) + + def __init__(self, *args, **kwargs): + super(LoginForm, self).__init__(*args, **kwargs) + self.user = None + + def validate(self): + initial_validation = super(LoginForm, self).validate() + if not initial_validation: + return False + + self.user = User.query.filter_by(username=self.username.data).first() + if not self.user: + self.username.errors.append("Unknown username") + return False + + if not self.user.check_password(self.password.data): + self.password.errors.append("Invalid password") + return False + + if not self.user.active: + self.username.errors.append("User not activated") + return False + return True diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/views.py b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/views.py index b291370..bf14a6f 100644 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/views.py +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/public/views.py @@ -2,35 +2,44 @@ '''Public section, including homepage and signup.''' from flask import (Blueprint, request, render_template, flash, url_for, redirect, session) +from flask.ext.login import login_user, login_required, logout_user from sqlalchemy.exc import IntegrityError +from {{cookiecutter.repo_name}}.extensions import login_manager from {{cookiecutter.repo_name}}.user.models import User -from {{cookiecutter.repo_name}}.public.forms import RegisterForm, LoginForm +from {{cookiecutter.repo_name}}.public.forms import LoginForm +from {{cookiecutter.repo_name}}.user.forms import RegisterForm from {{cookiecutter.repo_name}}.utils import flash_errors from {{cookiecutter.repo_name}}.database import db blueprint = Blueprint('public', __name__, static_folder="../static") +@login_manager.user_loader +def load_user(id): + try: + return User.query.get(int(id)) + except Exception: + return None + @blueprint.route("/", methods=["GET", "POST"]) def home(): form = LoginForm(request.form) + # Handle logging in if request.method == 'POST': - u = User.query.filter_by(username=request.form['username']).first() - if u is None or not u.check_password(request.form['password']): - error = 'Invalid username or password.' - flash(error, 'warning') - else: - session['logged_in'] = True - session['username'] = u.username + if form.validate_on_submit(): + login_user(form.user) flash("You are logged in.", 'success') - return redirect(url_for("user.members")) + redirect_url = request.args.get("next") or url_for("user.members") + return redirect(redirect_url) + else: + flash_errors(form) return render_template("public/home.html", form=form) @blueprint.route('/logout/') +@login_required def logout(): - session.pop('logged_in', None) - session.pop('username', None) + logout_user() flash('You are logged out.', 'info') return redirect(url_for('public.home')) @@ -38,7 +47,10 @@ def logout(): def register(): form = RegisterForm(request.form, csrf_enabled=False) if form.validate_on_submit(): - new_user = User(form.username.data, form.email.data, form.password.data) + new_user = User(username=form.username.data, + email=form.email.data, + password=form.password.data, + active=True) try: db.session.add(new_user) db.session.commit() diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/templates/_layouts/nav.html b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/templates/_layouts/nav.html index af4ef11..fb797a9 100644 --- a/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/templates/_layouts/nav.html +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/templates/_layouts/nav.html @@ -20,10 +20,10 @@