diff options
| author | stilbruch <stilbruch@protonmail.com> | 2022-03-23 12:30:23 -0500 |
|---|---|---|
| committer | stilbruch <stilbruch@protonmail.com> | 2022-03-23 12:30:23 -0500 |
| commit | c57ebef076438c83a0e408227341398249566ff1 (patch) | |
| tree | d4e943e771a127d285baaee14867f48040f23c8d /app | |
| parent | 43755d0b6d1f65fd65862454be81bd0f5d7ff7dd (diff) | |
| download | Strengthy-c57ebef076438c83a0e408227341398249566ff1.tar.xz Strengthy-c57ebef076438c83a0e408227341398249566ff1.zip | |
User registration and login now works
Diffstat (limited to 'app')
| -rw-r--r-- | app/app.py | 10 | ||||
| -rw-r--r-- | app/database.py | 19 | ||||
| -rw-r--r-- | app/forms.py | 13 | ||||
| -rw-r--r-- | app/login.py | 55 | ||||
| -rw-r--r-- | app/routes.py | 56 | ||||
| -rw-r--r-- | app/tables/user.py | 25 | ||||
| -rw-r--r-- | app/templates/user/login.html | 16 | ||||
| -rw-r--r-- | app/templates/user/register.html | 21 |
8 files changed, 120 insertions, 95 deletions
@@ -1,16 +1,24 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy +from flask_login import LoginManager # Setup app before doing imports app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['SECRET_KEY'] = "super duper secret" # FIXME: do not use in prod -app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://../strenghty.db' +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../strengthy.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False +# Setup flask-login +login_manager = LoginManager(app) +login_manager.init_app(app) + # Setup SQLAlchemy # https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/#a-minimal-application db = SQLAlchemy(app) +# TODO: do in script +import tables.user +db.create_all() # Load routes import routes diff --git a/app/database.py b/app/database.py deleted file mode 100644 index e23aa5d..0000000 --- a/app/database.py +++ /dev/null @@ -1,19 +0,0 @@ -import sqlite3 -from app import app -from flask import g - -# constants -DATABASE_FILE = "../strengthy.db" - -# Called when an "appcontext" is closed, usually a request is finished -@app.teardown_appcontext -def close_db_conn(exception): - db = getattr(g, '_database', None) - if db is not None: - db.close() - -def database_get(): - db = getattr(g, '_database', None) - if db is None: - db = g._database = sqlite3.connect(DATABASE_FILE) - return db diff --git a/app/forms.py b/app/forms.py new file mode 100644 index 0000000..12e4bf8 --- /dev/null +++ b/app/forms.py @@ -0,0 +1,13 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField, BooleanField +from wtforms.validators import DataRequired, Email + +class LoginForm(FlaskForm): + username = StringField("username", validators=[DataRequired()]) + password = PasswordField("password", validators=[DataRequired()]) + #remember_me = BooleanField() + +class RegisterForm(FlaskForm): + username = StringField("username", validators=[DataRequired()]) + password = PasswordField("password", validators=[DataRequired()]) + email = StringField("email", validators=[DataRequired(), Email()]) diff --git a/app/login.py b/app/login.py deleted file mode 100644 index 6d4b4a2..0000000 --- a/app/login.py +++ /dev/null @@ -1,55 +0,0 @@ -from app import app -from database import database_get -from flask_login import LoginManager, UserMixin, current_user -from flask_wtf import FlaskForm -from wtforms import StringField, PasswordField, BooleanField -from wtforms.validators import DataRequired, Email - -# https://python.plainenglish.io/implementing-flask-login-with-hash-password-888731c88a99 - -# Forms classes for flask_wtf -class LoginForm(FlaskForm): - username = StringField("username", validators=[DataRequired()]) - password = PasswordField("password", validators=[DataRequired()]) - remember_me = BooleanField() - -class RegisterForm(FlaskForm): - username = StringField("username", validators=[DataRequired()]) - password = PasswordField("password", validators=[DataRequired()]) - name = StringField("name") - email = StringField("email", validators=[DataRequired(), Email()]) - -# User class for flask_login -class User(UserMixin): - def __init__(self, id, email, password_hash): - self.id = unicode(id) - self.email = email - self.password_hash = password_hash - self.authenticated = False - - def is_authenticated(self): - return self.authenticated - - def is_active(self): - return True - - def is_anonymous(self): - return False - - def get_id(self): - return self.id - -login_manager = LoginManager() -login_manager.init_app(app) - -@login_manager.user_loader -def load_user(uid): - conn = database_get() - curs = conn.cursor() - curs.execute("SELECT * FROM users WHERE id = (?)", [uid]) - row = curs.fetchone() - - if row is None: - return None - else: - return User(int(row[0]), row[1], row[2]) diff --git a/app/routes.py b/app/routes.py index fdf65e3..ca556ad 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,20 +1,56 @@ -from app import app -from database import database_get -from flask import render_template -from login import * +from app import app, db +from flask import render_template, redirect, url_for, flash +from flask_login import login_user +from forms import LoginForm, RegisterForm +from tables.user import User @app.route("/", methods=["GET"]) def index(): return render_template('base/index.html') -@app.route("/login", methods=["GET"]) +@app.route("/home", methods=["GET"]) +def home(): + return render_template('base/home.html') + +@app.route("/login", methods=['GET', 'POST']) def login(): - return render_template('user/login.html') + form = LoginForm() + username = form.username.data + password = form.password.data + + if form.validate_on_submit(): + # Valid submission + user = User.query.filter_by(username=username).first() + + # TODO: show user if login succeeded + if user and user.verify_password(password): + login_user(user) + return redirect(url_for('home')) + else: + flash("invalid login") + return redirect(url_for('register')) -@app.route("/register", methods=["GET"]) + return render_template('user/login.html', form=form) + +@app.route("/register", methods=['GET', 'POST']) def register(): form = RegisterForm() + # Load data from form + username = form.username.data + password = form.password.data + email = form.email.data + + print("register") + + if form.validate_on_submit(): + # Valid submission + user = User.query.filter_by(username=username).first() + if not user: + # No user with this username + user = User(username, password, email) + db.session.add(user) + db.session.commit() - #if form.validate_on_submit(): - # # TODO: make sure username isnt taken somehow - return render_template('user/register.html') + return redirect(url_for('login')) + else: + return render_template('user/register.html', form=form) diff --git a/app/tables/user.py b/app/tables/user.py new file mode 100644 index 0000000..d384fdb --- /dev/null +++ b/app/tables/user.py @@ -0,0 +1,25 @@ +from app import db, login_manager +from flask_login import UserMixin +from werkzeug.security import generate_password_hash, check_password_hash + +@login_manager.user_loader +def get_user(user_id): + return User.query.get(user_id) + +class User(db.Model, UserMixin): + __tablename__ = 'users' + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(80), unique=True, nullable=False) + password = db.Column(db.String(80)) + email = db.Column(db.String(120), unique=True, nullable=False) + + def __init__(self, username, password, email): + self.username = username + self.password = generate_password_hash(password) + self.email = email + + def __repr__(self): + return f'<User {self.username}>' + + def verify_password(self, pwd): + return check_password_hash(self.password, pwd) diff --git a/app/templates/user/login.html b/app/templates/user/login.html index 7a671c1..9aaf33c 100644 --- a/app/templates/user/login.html +++ b/app/templates/user/login.html @@ -3,26 +3,30 @@ {% block content %} <div class="login"> <div class="form"> - <section class="hero is-primary is-fullheight"> + <section class="hero is-primary is-fullheight-with-navbar"> <div class="hero-body"> <div class="container"> <div class="columns is-centered"> <div class="column is-5-tablet is-4-desktop is-3-widescreen"> <h1 class="title is-2">Log in</h1> - <form action="" class="box"> + + <!-- TODO: render errors --> + + <form method="POST" class="box"> + {{ form.csrf_token }} <div class="field"> - <label for="" class="label">Email</label> + <label for="" class="label">Username</label> <div class="control has-icons-left"> - <input type="email" placeholder="e.g. bobsmith@gmail.com" class="input" required> + <input id="username" name="username" type="text" class="input" required> <span class="icon is-small is-left"> - <i class="fa fa-envelope"></i> + <i class="fa fa-user"></i> </span> </div> </div> <div class="field"> <label for="" class="label">Password</label> <div class="control has-icons-left"> - <input type="password" placeholder="*******" class="input" required> + <input id="password" name="password" type="password" placeholder="*******" class="input" required> <span class="icon is-small is-left"> <i class="fa fa-lock"></i> </span> diff --git a/app/templates/user/register.html b/app/templates/user/register.html index dc61204..6341671 100644 --- a/app/templates/user/register.html +++ b/app/templates/user/register.html @@ -3,17 +3,30 @@ {% block content %} <div class="register"> <div class="form"> - <section class="hero is-primary is-fullheight"> + <section class="hero is-primary is-fullheight-with-navbar"> <div class="hero-body"> <div class="container"> <div class="columns is-centered"> <div class="column is-5-tablet is-4-desktop is-3-widescreen"> <h1 class="title is-2">Sign up</h1> - <form action="" class="box"> + + <!-- TODO: render errors --> + + <form method="POST" class="box"> + {{ form.csrf_token }} + <div class="field"> + <label for="" class="label">Username</label> + <div class="control has-icons-left"> + <input id="username" name="username" type="text" placeholder="e.g. gymdude99" class="input" required> + <span class="icon is-small is-left"> + <i class="fa fa-user"></i> + </span> + </div> + </div> <div class="field"> <label for="" class="label">Email</label> <div class="control has-icons-left"> - <input type="email" placeholder="e.g. bobsmith@gmail.com" class="input" required> + <input id="email" name="email" type="email" placeholder="e.g. bobsmith@gmail.com" class="input" required> <span class="icon is-small is-left"> <i class="fa fa-envelope"></i> </span> @@ -22,7 +35,7 @@ <div class="field"> <label for="" class="label">Password</label> <div class="control has-icons-left"> - <input type="password" placeholder="*******" class="input" required> + <input id="password" name="password" type="password" placeholder="*******" class="input" required> <span class="icon is-small is-left"> <i class="fa fa-lock"></i> </span> |
