Add role management routes

master
esensar 2018-09-23 01:22:19 +02:00
parent 3b09857dbc
commit 562e2653c9
5 changed files with 143 additions and 6 deletions

View File

@ -1,6 +1,6 @@
from app.core import bcrypt from app.core import bcrypt
from flask import Blueprint from flask import Blueprint
from .models import Account from .models import Account, Role
accounts_bp = Blueprint('accounts', __name__) accounts_bp = Blueprint('accounts', __name__)
@ -44,6 +44,44 @@ def update_account_role(account_id, role_id):
acc.save() acc.save()
def create_role(display_name, permissions):
"""
Tries to create role
:param display_name: Name of role - display only
:param permissions: List of strings - permissions that this role has
:type display_name: String
:type permissions: List of String
:returns: True if role is successfully created
:rtype: Boolean
:raises: ValueError if role already exists
"""
role = Role(display_name, permissions)
role.save()
def get_role(role_id):
"""
Tries to get role
:param role_id: Id of role
:type role_id: int
:returns: Role if found
:rtype: Role
"""
return Role.get(role_id)
def get_all_roles():
"""
Gets all roles
:returns: Role list if found
:rtype: List of Roles
"""
return Role.get_all()
def create_token(username, password): def create_token(username, password):
""" """
Tries to create token for account with given parameters. Tries to create token for account with given parameters.

View File

@ -122,10 +122,12 @@ class Role(db.Model):
__tablename__ = 'roles' __tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
display_name = db.Column(db.String) display_name = db.Column(db.String, unique=True)
permissions = db.Column(db.ARRAY(db.String))
def __init__(self, name): def __init__(self, name, permissions):
self.display_name = str(name) self.display_name = str(name)
self.permissions = permissions
def save(self): def save(self):
""" """
@ -147,7 +149,7 @@ class Role(db.Model):
""" """
Get role with id = roleId Get role with id = roleId
""" """
return Role.query.filter_by(id=roleId) return Role.query.filter_by(id=roleId).first_or_404()
def __repr__(self): def __repr__(self):
return '<Role %s>' % self.display_name return '<Role %s (%s)>' % self.display_name, self.permissions

View File

@ -40,7 +40,9 @@ class ProtectedResource(Resource):
def add_resources(): def add_resources():
from .resources.account import (AccountResource, from .resources.account import (AccountResource,
AccountListResource, AccountListResource,
AccountRoleResource) AccountRoleResource,
RoleResource,
RolesResource)
from .resources.token import TokenResource, ValidateTokenResource from .resources.token import TokenResource, ValidateTokenResource
from .resources.device import (DeviceResource, from .resources.device import (DeviceResource,
DeviceRecordingResource, DeviceRecordingResource,
@ -53,6 +55,8 @@ def add_resources():
api.add_resource(AccountResource, '/v1/accounts/<int:account_id>') api.add_resource(AccountResource, '/v1/accounts/<int:account_id>')
api.add_resource(AccountListResource, '/v1/accounts') api.add_resource(AccountListResource, '/v1/accounts')
api.add_resource(AccountRoleResource, '/v1/accounts/<int:account_id>/role') api.add_resource(AccountRoleResource, '/v1/accounts/<int:account_id>/role')
api.add_resource(RoleResource, '/v1/roles/<int:role_id>')
api.add_resource(RolesResource, '/v1/roles')
api.add_resource(TokenResource, '/v1/token') api.add_resource(TokenResource, '/v1/token')
api.add_resource(ValidateTokenResource, '/v1/token/validate') api.add_resource(ValidateTokenResource, '/v1/token/validate')
api.add_resource(DeviceResource, '/v1/devices/<int:device_id>') api.add_resource(DeviceResource, '/v1/devices/<int:device_id>')

View File

@ -17,6 +17,32 @@ class RoleUpdateSchema(Schema):
role_id = fields.Integer(required=True, load_only=True, location='json') role_id = fields.Integer(required=True, load_only=True, location='json')
class RoleSchema(Schema):
role_id = fields.Integer(required=True, location='json')
display_name = fields.String(required=True, location='json')
permissions = fields.List(fields.String, required=True,
location='json', many=True)
class RoleWrapperSchema(Schema):
role = fields.Nested(RoleSchema, required=True, location='json')
class RolesWrapperSchema(Schema):
roles = fields.Nested(RoleSchema, required=True,
location='json', many=True)
class RoleCreationSchema(Schema):
display_name = fields.String(required=True, location='json')
permissions = fields.List(fields.String, required=True,
location='json', many=True)
class RoleCreationWrapperSchema(Schema):
role = fields.Nested(RoleCreationSchema, required=True, location='json')
class UserWrapperSchema(Schema): class UserWrapperSchema(Schema):
user = fields.Nested(UserSchema, required=True, location='json') user = fields.Nested(UserSchema, required=True, location='json')
@ -29,6 +55,29 @@ class AccountResource(ProtectedResource):
abort(403, message='You can only get your own account', status='error') abort(403, message='You can only get your own account', status='error')
class RoleResource(ProtectedResource):
@swag_from('swagger/get_role_spec.yaml')
def get(self, role_id):
return RoleWrapperSchema().dump(
{'role': accounts.get_role(role_id)}), 200
class RolesResource(ProtectedResource):
@use_args(RoleCreationWrapperSchema())
@swag_from('swagger/create_role_spec.yaml')
def post(self, args):
args = args['role']
success = accounts.create_role(args['display_name'],
args['permissions'])
if success:
return '', 201
@swag_from('swagger/get_roles_spec.yaml')
def get(self):
return RolesWrapperSchema().dump(
{'roles': accounts.get_all_roles()}), 200
class AccountRoleResource(ProtectedResource): class AccountRoleResource(ProtectedResource):
@use_args(RoleUpdateSchema()) @use_args(RoleUpdateSchema())
@swag_from('swagger/update_account_role_spec.yaml') @swag_from('swagger/update_account_role_spec.yaml')

View File

@ -0,0 +1,44 @@
"""empty message
Revision ID: 55611f1868bd
Revises: 5aa58dcd7a2c
Create Date: 2018-09-23 00:56:34.193022
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '55611f1868bd'
down_revision = '5aa58dcd7a2c'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('roles', sa.Column('permissions', sa.ARRAY(sa.String()), nullable=True))
op.create_unique_constraint(None, 'roles', ['display_name'])
role = sa.table('roles', sa.column('id', sa.Integer),
sa.column('permissions', sa.ARRAY(sa.String)))
op.execute(role.update().where(role.c.id == op.inline_literal(1)).
values({'permissions':
['CREATE_DEVICE_TYPE', 'ASSIGN_ROLE',
'CREATE_DEVICE', 'CREATE_DASHBOARD',
'READ_DEVICE_TYPES', 'READ_ROLES']})
)
op.execute(role.update().where(role.c.id == op.inline_literal(2)).
values({'permissions':
['CREATE_DEVICE', 'CREATE_DASHBOARD',
'READ_DEVICE_TYPES', 'READ_ROLES']})
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'roles', type_='unique')
op.drop_column('roles', 'permissions')
# ### end Alembic commands ###