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 flask import Blueprint
from .models import Account
from .models import Account, Role
accounts_bp = Blueprint('accounts', __name__)
@ -44,6 +44,44 @@ def update_account_role(account_id, role_id):
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):
"""
Tries to create token for account with given parameters.

View File

@ -122,10 +122,12 @@ class Role(db.Model):
__tablename__ = 'roles'
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.permissions = permissions
def save(self):
"""
@ -147,7 +149,7 @@ class Role(db.Model):
"""
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):
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():
from .resources.account import (AccountResource,
AccountListResource,
AccountRoleResource)
AccountRoleResource,
RoleResource,
RolesResource)
from .resources.token import TokenResource, ValidateTokenResource
from .resources.device import (DeviceResource,
DeviceRecordingResource,
@ -53,6 +55,8 @@ def add_resources():
api.add_resource(AccountResource, '/v1/accounts/<int:account_id>')
api.add_resource(AccountListResource, '/v1/accounts')
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(ValidateTokenResource, '/v1/token/validate')
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')
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):
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')
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):
@use_args(RoleUpdateSchema())
@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 ###