Add device account associations

master
esensar 2018-08-24 14:32:31 +02:00
parent 1ae5d1a2b8
commit cb0e61c906
6 changed files with 170 additions and 4 deletions

View File

@ -1,6 +1,7 @@
from marshmallow import Schema, fields from marshmallow import Schema, fields
from webargs.flaskparser import use_args from webargs.flaskparser import use_args
from flasgger import swag_from from flasgger import swag_from
from flask import g
import app.devices as devices import app.devices as devices
from app.api import ProtectedResource from app.api import ProtectedResource
@ -13,6 +14,9 @@ class DeviceSchema(Schema):
class DeviceWrapperSchema(Schema): class DeviceWrapperSchema(Schema):
device = fields.Nested(DeviceSchema, required=True, location='json') device = fields.Nested(DeviceSchema, required=True, location='json')
class DevicesWrapperSchema(Schema):
devices = fields.Nested(DeviceSchema, required=True,
location='json', many=True)
class RecordingsSchema(Schema): class RecordingsSchema(Schema):
recorded_at = fields.DateTime() recorded_at = fields.DateTime()
@ -45,6 +49,12 @@ class DeviceListResource(ProtectedResource):
def post(self, args): def post(self, args):
args = args['device'] args = args['device']
success = devices.create_device( success = devices.create_device(
args['name']) args['name'],
g.current_account.id)
if success: if success:
return '', 201 return '', 201
@swag_from('swagger/get_devices_spec.yaml')
def get(self):
return DevicesWrapperSchema().dump(
{'devices': devices.get_devices(g.current_account.id)}), 200

View File

@ -14,7 +14,7 @@ responses:
schema: schema:
type: object type: object
required: required:
-device - device
properties: properties:
device: device:
$ref: '#/definitions/Device' $ref: '#/definitions/Device'

View File

@ -0,0 +1,18 @@
Gets all associated devices
---
tags:
- Device
parameters:
responses:
200:
description: Success
schema:
type: object
required:
- devices
properties:
devices:
type: array
items:
$ref: '#/definitions/Device'

View File

@ -1,13 +1,13 @@
import sys import sys
from flask import Blueprint from flask import Blueprint
from .models import Device, Recording from .models import Device, Recording, DeviceAssociation
from app import app from app import app
devices_bp = Blueprint('devices', __name__) devices_bp = Blueprint('devices', __name__)
# Public interface # Public interface
def create_device(name, device_type=1): def create_device(name, account_id, device_type=1):
""" """
Tries to create device with given parameters Tries to create device with given parameters
@ -21,6 +21,8 @@ def create_device(name, device_type=1):
""" """
device = Device(name, None, device_type) device = Device(name, None, device_type)
device.save() device.save()
device_association = DeviceAssociation(device.id, account_id)
device_association.save()
def get_device_recordings(device_id): def get_device_recordings(device_id):
@ -56,6 +58,16 @@ def get_device(device_id):
return Device.get(id=device_id) return Device.get(id=device_id)
def get_devices(account_id):
"""
Tries to get all devices associated to account. Raises error on
failure
:returns: List of Devices associated to this account
:rtype: List of Devices
"""
return Device.get_many_for_user(account_id)
def create_recording(device_id, raw_json): def create_recording(device_id, raw_json):
""" """
Tries to create recording with given parameters. Raises error on failure Tries to create recording with given parameters. Raises error on failure

View File

@ -92,6 +92,8 @@ class Device(db.Model):
device_type = db.relationship("DeviceType", foreign_keys=[device_type_id]) device_type = db.relationship("DeviceType", foreign_keys=[device_type_id])
configuration = db.Column(JSON, nullable=True) configuration = db.Column(JSON, nullable=True)
users = db.relationship("DeviceAssociation")
def __init__(self, name, configuration=None, device_type=1): def __init__(self, name, configuration=None, device_type=1):
self.name = name self.name = name
self.configuration = configuration self.configuration = configuration
@ -121,6 +123,13 @@ class Device(db.Model):
""" """
return Device.query.filter_by(**kwargs).all() return Device.query.filter_by(**kwargs).all()
@staticmethod
def get_many_for_user(account_id):
"""
Get many devices which are associated to account
"""
return Device.query.filter(Device.users.any(account_id=account_id)).all()
@staticmethod @staticmethod
def get(**kwargs): def get(**kwargs):
""" """
@ -151,6 +160,58 @@ class Device(db.Model):
self.name, self.device_type_id) self.name, self.device_type_id)
class DeviceAssociation(db.Model):
__tablename__ = 'device_associations'
device_id = db.Column(db.Integer, db.ForeignKey('devices.id'), primary_key=True)
account_id = db.Column(db.Integer, db.ForeignKey('accounts.id'), primary_key=True)
access_level = db.Column(db.Integer, db.ForeignKey('access_levels.id'),
nullable=False)
def __init__(self, device_id, account_id, access_level=1):
self.device_id = device_id
self.account_id = account_id
self.access_level = access_level
def save(self):
"""
Stores this device association to database
This may raise errors
"""
db.session.add(self)
db.session.commit()
@staticmethod
def get_many(**kwargs):
"""
Get many device associations with given filters as a list
Available filters:
* device_id
* account_id
"""
return DeviceAssociation.query.filter_by(**kwargs).all()
@staticmethod
def get_for_user(account_id):
"""
Get many device associations for user with account id passed in
parameter
"""
return get_many(account_id=account_id)
@staticmethod
def get_for_device(device_id):
"""
Get many device associations for device with account id passed in
parameter
"""
return get_many(device_id=device_id)
def __repr__(self):
return '<DeviceAssociation (device_id=%s, accoount_id=%s)>' % (self.device_id, self.account_id)
class DeviceType(db.Model): class DeviceType(db.Model):
__tablename__ = 'device_types' __tablename__ = 'device_types'
@ -162,3 +223,16 @@ class DeviceType(db.Model):
def __repr__(self): def __repr__(self):
return '<DeviceType (name %s)>' % self.name return '<DeviceType (name %s)>' % self.name
class AccessLevel(db.Model):
__tablename__ = 'access_levels'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
def __init__(self, name):
self.name = name
def __repr__(self):
return '<AccessLevel (name %s)>' % self.name

View File

@ -0,0 +1,52 @@
"""empty message
Revision ID: efbd47fca2fd
Revises: 6b444e5e2eef
Create Date: 2018-08-24 14:23:01.904259
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'efbd47fca2fd'
down_revision = '6b444e5e2eef'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('access_levels',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('device_associations',
sa.Column('device_id', sa.Integer(), nullable=False),
sa.Column('account_id', sa.Integer(), nullable=False),
sa.Column('access_level', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['access_level'], ['access_levels.id'], ),
sa.ForeignKeyConstraint(['account_id'], ['accounts.id'], ),
sa.ForeignKeyConstraint(['device_id'], ['devices.id'], ),
sa.PrimaryKeyConstraint('device_id', 'account_id')
)
access_levels_table = sa.Table('access_levels', sa.MetaData(),
sa.Column('id', sa.Integer),
sa.Column('name', sa.String))
op.bulk_insert(access_levels_table,
[
{'id':1, 'name':'FULL'}
]
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('device_associations')
op.drop_table('access_levels')
# ### end Alembic commands ###