~muirrum/comortas

930e7cfb92d0a0dbc8317d965e25fa4569920120 — Cara Salter 3 years ago 61d58fc 0.4.0
Implement Flask-Security

Lays foundation to implement better security for views and tournaments
M .gitignore => .gitignore +26 -1
@@ 235,4 235,29 @@ Thumbs.db

# End of https://www.toptal.com/developers/gitignore/api/flask,python,vscode

config.py
\ No newline at end of file
config.py
# Created by https://www.toptal.com/developers/gitignore/api/vim
# Edit at https://www.toptal.com/developers/gitignore?templates=vim

### Vim ###
# Swap
[._]*.s[a-v][a-z]
!*.svg  # comment out if you don't need vector files
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]

# Session
Session.vim
Sessionx.vim

# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~

# End of https://www.toptal.com/developers/gitignore/api/vim

M fllscoring/__init__.py => fllscoring/__init__.py +13 -2
@@ 4,10 4,16 @@ from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate

from flask_security import Security, SQLAlchemyUserDatastore

db = SQLAlchemy()
login_manager = LoginManager()
migrator = Migrate()


security = Security()


def create_app():
    app = Flask(__name__)



@@ 25,11 31,14 @@ def create_app():
    # Init extensions
    db.init_app(app)
    login_manager.init_app(app)
    migrator.init_app(app, db)
    migrator.init_app(app, db) 

    # Configure login manager
    login_manager.login_view = "auth.login"
    login_manager.login_message = "You need to be logged in to view that page"
    from fllscoring.models import Users, Role
    user_datastore = SQLAlchemyUserDatastore(db, Users, Role)
    security.init_app(app, user_datastore)

    # Init blueprints
    import fllscoring.auth


@@ 48,4 57,6 @@ def create_app():
    app.register_blueprint(scoring.bp)


    return app
\ No newline at end of file
    return app



M fllscoring/auth/__init__.py => fllscoring/auth/__init__.py +11 -2
@@ 1,7 1,10 @@
from flask import Blueprint, render_template, redirect, url_for, flash
from flask import Blueprint, render_template, redirect, url_for, flash, current_app
from werkzeug.security import generate_password_hash, check_password_hash

import flask_login
from flask_login import current_user

from flask_principal import identity_changed, Identity, AnonymousIdentity, identity_loaded, RoleNeed, UserNeed

from fllscoring import login_manager, db
from fllscoring.models import Users


@@ 19,6 22,8 @@ def login():
        if user is not None:
            if check_password_hash(user.password_hash, form.password.data):
                flask_login.login_user(user)

                identity_changed.send(current_app._get_current_object(), identity=Identity(user.user_id))
                return redirect(url_for("profile.profile"))
            else:
                flash("Incorrect password")


@@ 35,6 40,7 @@ def register():
        db.session.add(user)
        db.session.commit()
        flask_login.login_user(user)
        identity_changed.send(current_app._get_current_object(), identity=Identity(user.user_id))
        return redirect(url_for('profile.profile'))

    return render_template('auth/register.html', form=form, title="Register")


@@ 42,8 48,11 @@ def register():
@bp.route('/logout')
def logout():
    flask_login.logout_user()
    identity_changed.send(current_app._get_current_object(), AnonymousIdentity())
    return redirect(url_for("meta.home"))

@login_manager.user_loader
def user_loader(user_id):
    return Users.query.filter_by(user_id=user_id).first()
\ No newline at end of file
    return Users.query.filter_by(user_id=user_id).first()



M fllscoring/models.py => fllscoring/models.py +11 -6
@@ 4,24 4,29 @@ from sqlalchemy.ext.mutable import MutableDict

from fllscoring import db

from flask_login import UserMixin
from flask_security import UserMixin, RoleMixin

class Users(db.Model,UserMixin):
    user_id = db.Column(db.Integer, primary_key=True)
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String, nullable=False, unique=True)
    email = db.Column(db.String, nullable=False)
    password_hash = db.Column(db.String, nullable=False)
    is_superadmin = db.Column(db.Boolean, default=False, nullable=False)

    def __repr__(self):
        return f"<User {self.username} ({self.user_id})>"
        return f"<User {self.username} ({self.id})>"

    def get_id(self):
        return self.user_id
        return self.id

class Role(RoleMixin):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, unique=True, nullable=False)
    description = db.Column(db.String)

class Tournaments(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    owner_id = db.Column(db.Integer, ForeignKey("users.user_id"), nullable=False, index=True)
    owner_id = db.Column(db.Integer, ForeignKey("users.id"), nullable=False, index=True)
    tournament_name = db.Column(db.String, nullable=False)

class Team(db.Model):


@@ 38,4 43,4 @@ class MatchScore(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    tournament = db.Column(db.Integer, ForeignKey("tournaments.id", ondelete="CASCADE"))
    team = db.Column(db.Integer, ForeignKey("team.id"))
    score = db.Column(MutableDict().as_mutable(JSONB))
\ No newline at end of file
    score = db.Column(MutableDict().as_mutable(JSONB))

A migrations/versions/621bb8cab38e_flask_security.py => migrations/versions/621bb8cab38e_flask_security.py +32 -0
@@ 0,0 1,32 @@
"""flask-security

Revision ID: 621bb8cab38e
Revises: 616627625894
Create Date: 2021-04-30 09:42:20.535803

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '621bb8cab38e'
down_revision = '616627625894'
branch_labels = None
depends_on = None


def upgrade():
    op.alter_column('users', 'user_id', new_column_name='id')
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint('tournaments_owner_id_fkey', 'tournaments', type_='foreignkey')
    op.create_foreign_key(None, 'tournaments', 'users', ['owner_id'], ['id'])
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('users', 'id', new_column_name='user_id')
    op.drop_constraint(None, 'tournaments', type_='foreignkey')
    op.create_foreign_key('tournaments_owner_id_fkey', 'tournaments', 'users', ['owner_id'], ['user_id'])
    # ### end Alembic commands ###