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 ###