Skip to content

Commit

Permalink
Add login management
Browse files Browse the repository at this point in the history
  • Loading branch information
Jackson Chadfield committed Jul 31, 2019
1 parent 3d7223d commit 547181f
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 16 deletions.
11 changes: 9 additions & 2 deletions OpenLearn/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from flask import Flask, render_template

from OpenLearn import extensions, database
from OpenLearn import extensions, database, commands
from . import views
from . import settings

Expand All @@ -31,6 +31,13 @@ def create_app():
def register_extensions(app):
"""Register Flask extensions."""
extensions.db.init_app(app)
extensions.bcrypt.init_app(app)
extensions.login_manager.init_app(app)

# Flask Login
@extensions.login_manager.user_loader
def load_user(user_id):
return database.User.query.get(int(user_id))


def register_blueprints(app):
Expand Down Expand Up @@ -75,7 +82,7 @@ def shell_context():

def register_commands(app):
"""Register Click commands."""
pass
app.cli.add_command(commands.rebuild_database)


def configure_logger(app):
Expand Down
22 changes: 19 additions & 3 deletions OpenLearn/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
from decimal import Decimal
from typing import Union, List

from flask_login import UserMixin
from sqlalchemy import func

from .extensions import db
from .extensions import db, bcrypt

# Alias common SQLAlchemy names
Column = db.Column
Expand All @@ -35,15 +36,30 @@ def type(self):
}[self]


class User(db.Model):
class User(db.Model, UserMixin):
id: MInteger = db.Column(db.Integer, primary_key=True)
username: MString = db.Column(db.String(25), unique=True, nullable=False)
password = db.Column(db.Binary(60), nullable=False)
__password = db.Column("password", db.Binary(60), nullable=False)

quizzes: List["Quiz"] = relationship("Quiz", back_populates="owner")

created_on: MDateTime = db.Column(db.DateTime(timezone=True), nullable=False, server_default=func.now())

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

@property
def password(self):
return self.__password

@password.setter
def password(self, value):
pw_hash = bcrypt.generate_password_hash(value)
self.__password = pw_hash

def check_password(self, candidate) -> bool:
return bcrypt.check_password_hash(self.__password, candidate)


class Quiz(db.Model):
id: MInteger = db.Column(db.Integer, primary_key=True)
Expand Down
4 changes: 4 additions & 0 deletions OpenLearn/extensions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# -*- coding: utf-8 -*-

from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
16 changes: 12 additions & 4 deletions OpenLearn/views/public/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
Blueprint,
current_app,
render_template,
abort, redirect)
abort, redirect, url_for)
from flask_login import login_user

from OpenLearn.database import User
from OpenLearn.extensions import db
from .forms import RegisterForm, LoginForm

blueprint = Blueprint("public", __name__, static_folder="../../static", template_folder="../../templates/public")
Expand All @@ -24,17 +27,22 @@ def index():
return render_template("index.html")


@blueprint.route("/sign-in")
@blueprint.route("/login")
def sign_in():
form = LoginForm()
if form.validate_on_submit():
return redirect("/success")
login_user(form.user)
return redirect(url_for("teacher.dashboard"))
return render_template("sign-in.html", form=form)


@blueprint.route("/register", methods=["GET", "POST"])
def register():
form = RegisterForm()
if form.validate_on_submit():
return redirect("/success")
user = User(username=form.username.data, password=form.password.data)
db.session.add(user)
db.session.commit()
login_user(user)
return redirect(url_for("teacher.dashboard"))
return render_template("register.html", form=form)
22 changes: 22 additions & 0 deletions OpenLearn/views/public/forms.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# -*- coding: utf-8 -*-
from typing import Optional

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import Length, EqualTo, InputRequired

from OpenLearn.database import User


class LoginForm(FlaskForm):
username = StringField("Username", validators=[
Expand All @@ -13,6 +17,24 @@ class LoginForm(FlaskForm):
InputRequired(message="You must enter your username")
])

def __init__(self, *args, **kwargs):
"""Create instance."""
super().__init__(*args, **kwargs)
self.user: Optional[User] = None

def validate(self):
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

return True



class RegisterForm(FlaskForm):
username = StringField("Username", validators=[
Expand Down
21 changes: 14 additions & 7 deletions OpenLearn/views/teacher/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
"""The controller for all views related to teachers"""
from flask import (
Blueprint,
current_app,
flash,
redirect,
render_template,
request,
url_for,
)
redirect, url_for)
from flask_login import login_required, logout_user

blueprint = Blueprint("teacher", __name__, static_folder="../static", template_folder="../templates/teacher")


@blueprint.route("/dashboard")
@login_required
def dashboard():
return "You are logged in"


@blueprint.route("/logout")
def logout():
logout_user()
return redirect(url_for("public.sign_in"))

0 comments on commit 547181f

Please sign in to comment.