From 551cc3f5a7980ba2cb870745432a98005e8ef2e5 Mon Sep 17 00:00:00 2001 From: kelepirci Date: Sat, 6 Aug 2016 22:25:30 +0300 Subject: [PATCH] User role system implimented New user role system implimented. With new system User, Reseller and Administrator roles are created. Also new permission for user and reseller defined with hex decimal system. --- config.py | 6 +-- dash/email.py | 4 +- dash/models.py | 80 ++++++++++++++++++++++++++-- migrations/versions/c751862fad43_.py | 30 +++++++++++ 4 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 migrations/versions/c751862fad43_.py diff --git a/config.py b/config.py index d2df949..ff36ab7 100644 --- a/config.py +++ b/config.py @@ -4,9 +4,9 @@ basedir = os.path.abspath(os.path.dirname(__file__)) class Config: SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string' SQLALCHEMY_COMMIT_ON_TEARDOWN = True - FLASKY_MAIL_SUBJECT_PREFIX = '[dash-stack]' - FLASKY_MAIL_SENDER = 'dash-stack Admin ' - FLASKY_ADMIN = os.environ.get('DASH_STACK_ADMIN') + DASH_MAIL_SUBJECT_PREFIX = '[dash-stack]' + DASH_MAIL_SENDER = 'dash-stack Admin ' + DASH_ADMIN = "ozkasgarli@gmail.com" @staticmethod def init_app(dash): diff --git a/dash/email.py b/dash/email.py index 61579ef..9a35b8c 100644 --- a/dash/email.py +++ b/dash/email.py @@ -11,8 +11,8 @@ def send_async_email(dash, msg): def send_email(to, subject, template, **kwargs): dash = current_app._get_current_object() - msg = Message(dash.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject, - sender=dash.config['FLASKY_MAIL_SENDER'], recipients=[to]) + msg = Message(dash.config['DASH_MAIL_SUBJECT_PREFIX'] + ' ' + subject, + sender=dash.config['DASH_MAIL_SENDER'], recipients=[to]) msg.body = render_template(template + '.txt', **kwargs) msg.html = render_template(template + '.html', **kwargs) thr = Thread(target=send_async_email, args=[dash, msg]) diff --git a/dash/models.py b/dash/models.py index cd34292..294262b 100644 --- a/dash/models.py +++ b/dash/models.py @@ -10,14 +10,77 @@ from flask_login import UserMixin from . import db from . import login_manager +# user roles +class Permission: + ## user permissions + # instance management + LAUNCH_INSTANCE = 0x1A + REMOVE_INSTANCE = 0x2A + MANAGE_INSTANCE = 0x3A + LIST_INSTANCE = 0x4A + + ## reseller permissions + # Users Management + CREATE_USER = 0x1B + MANAGE_USER = 0x2B + DELETE_USER = 0x3B + LIST_USER = 0x4B + SUSPEND_USER = 0x5B + UNSUSPEND_USER = 0x6B + + # Tenant Management + CREATE_TENANT = 0x7B + MANAGE_TENANT = 0x8B + DELETE_TENANT = 0x9B + LIST_TENANT = 0xB1 + SUSPEND_TENANT = 0xB2 + UNSUSPEND_TENANT = 0xB3 + MODIFY_TENANT_QUOTA = 0xB4 + + # administrator permissions class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(64), unique=True) + name = db.Column(db.String(128), unique=True) + default = db.Column(db.Boolean, default=False, index=True) + permissions = db.Column(db.Integer) users = db.relationship('User', backref='role', lazy='dynamic') - + + # creates roles and permissions in db + @staticmethod + def insert_roles(): + roles = { + 'User': (Permission.LAUNCH_INSTANCE | + Permission.REMOVE_INSTANCE | + Permission.MANAGE_INSTANCE | + Permission.LIST_INSTANCE, True), + 'Reseller': (Permission.CREATE_USER | + Permission.MANAGE_USER | + Permission.DELETE_USER | + Permission.LIST_USER | + Permission.SUSPEND_USER | + Permission.UNSUSPEND_USER | + # tenant management + Permission.CREATE_TENANT | + Permission.MANAGE_TENANT | + Permission.DELETE_TENANT | + Permission.LIST_TENANT | + Permission.SUSPEND_TENANT | + Permission.UNSUSPEND_TENANT | + Permission.MODIFY_TENANT_QUOTA, False), + 'Administrator': (0xff, False) + } + for r in roles: + role = Role.query.filter_by(name=r).first() + if role is None: + role = Role(name=r) + role.permissions = roles[r][0] + role.default = roles[r][1] + db.session.add(role) + db.session.commit() + def __repr__(self): return '' % self.name @@ -34,7 +97,7 @@ class User(UserMixin, db.Model): created_at = db.Column(db.DateTime) role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) confirmed = db.Column(db.Boolean, default=False) - + @property def password(self): raise AttributeError('password is not a readable attribute') @@ -102,7 +165,16 @@ class User(UserMixin, db.Model): self.email = new_email db.session.add(self) return True - + + # Role assignment + def __init__(self, **kwargs): + super(User, self).__init__(**kwargs) + if self.role is None: + if self.email == current_app.config['DASH_ADMIN']: + self.role = Role.query.filter_by(permissions=0xff).first() + if self.role is None: + self.role = Role.query.filter_by(default=True).first() + def __repr__(self): return '' % self.username diff --git a/migrations/versions/c751862fad43_.py b/migrations/versions/c751862fad43_.py new file mode 100644 index 0000000..6533069 --- /dev/null +++ b/migrations/versions/c751862fad43_.py @@ -0,0 +1,30 @@ +"""empty message + +Revision ID: c751862fad43 +Revises: 9643649cdb9c +Create Date: 2016-08-06 20:06:07.900854 + +""" + +# revision identifiers, used by Alembic. +revision = 'c751862fad43' +down_revision = '9643649cdb9c' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.add_column('roles', sa.Column('default', sa.Boolean(), nullable=True)) + op.add_column('roles', sa.Column('permissions', sa.Integer(), nullable=True)) + op.create_index(op.f('ix_roles_default'), 'roles', ['default'], unique=False) + ### end Alembic commands ### + + +def downgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_roles_default'), table_name='roles') + op.drop_column('roles', 'permissions') + op.drop_column('roles', 'default') + ### end Alembic commands ###