From f0274009650574376e1bb4bcb77cd00f28f0201c Mon Sep 17 00:00:00 2001 From: esensar Date: Mon, 15 Oct 2018 19:51:51 +0200 Subject: [PATCH] Add active field to dashboard --- app/api/blueprint.py | 5 ++- app/api/resources/dashboard.py | 39 +++++++++++++--- .../swagger/get_dashboards_spec.yaml | 7 +++ .../resources/swagger/get_devices_spec.yaml | 4 +- .../swagger/update_dashboard_spec.yaml | 1 + app/api/resources/token.py | 2 +- app/dashboards/api.py | 45 ++++++++++++++++--- app/dashboards/models.py | 23 ++++++++++ app/swagger/template.yaml | 3 ++ migrations/versions/4945e4c8fbca_.py | 29 ++++++++++++ runtime.txt | 1 - 11 files changed, 142 insertions(+), 17 deletions(-) create mode 100644 migrations/versions/4945e4c8fbca_.py delete mode 100644 runtime.txt diff --git a/app/api/blueprint.py b/app/api/blueprint.py index 6408d9d..c429367 100644 --- a/app/api/blueprint.py +++ b/app/api/blueprint.py @@ -22,7 +22,8 @@ def add_resources(): DeviceTypeResource, DeviceTypeListResource, DeviceConfigurationResource) - from .resources.dashboard import DashboardResource, DashboardListResource + from .resources.dashboard import (DashboardResource, + DashboardListResource) api.add_resource(AccountResource, '/v1/accounts/') api.add_resource(AccountListResource, '/v1/accounts') @@ -44,9 +45,9 @@ def add_resources(): api.add_resource(DeviceTypeListResource, '/v1/devices/types') api.add_resource(DeviceConfigurationResource, '/v1/devices//configuration') - api.add_resource(DashboardListResource, '/v1/dashboards') api.add_resource(DashboardResource, '/v1/dashboards/') + api.add_resource(DashboardListResource, '/v1/dashboards') add_resources() diff --git a/app/api/resources/dashboard.py b/app/api/resources/dashboard.py index 50a5245..c79376a 100644 --- a/app/api/resources/dashboard.py +++ b/app/api/resources/dashboard.py @@ -1,6 +1,6 @@ -from flask import g +from flask import g, request from flask_restful import abort -from marshmallow import fields +from marshmallow import fields, Schema from webargs.flaskparser import use_args from flasgger import swag_from import app.dashboards.api as dashboard @@ -10,9 +10,14 @@ from app.api.schemas import BaseResourceSchema class DashboardSchema(BaseResourceSchema): id = fields.Integer(dump_only=True) + active = fields.Boolean(required=False) dashboard_data = fields.Raw() +class DashboardIdSchema(Schema): + id = fields.Integer() + + class DashboardResource(ProtectedResource): @swag_from('swagger/get_dashboard_spec.yaml') def get(self, dashboard_id): @@ -29,9 +34,30 @@ class DashboardResource(ProtectedResource): if requested_dashboard.account_id != g.current_account.id: abort(403, message='You are not allowed to access this dashboard', status='error') - success = dashboard.update_dashboard( + if args.get('dashboard_data') is None: + abort(400, message='Missing dashboard_data', status='error') + if args.get('active') is None: + abort(400, message='Missing active', status='error') + success = dashboard.patch_dashboard( + g.current_account.id, dashboard_id, - args['dashboard_data']) + args['dashboard_data'], + args['active']) + if success: + return '', 204 + + @use_args(DashboardSchema(), locations=('json',)) + @swag_from('swagger/update_dashboard_spec.yaml') + def patch(self, args, dashboard_id): + requested_dashboard = dashboard.get_dashboard(dashboard_id) + if requested_dashboard.account_id != g.current_account.id: + abort(403, message='You are not allowed to access this dashboard', + status='error') + success = dashboard.patch_dashboard( + g.current_account.id, + dashboard_id, + args.get('dashboard_data'), + args.get('active')) if success: return '', 204 @@ -57,5 +83,8 @@ class DashboardListResource(ProtectedResource): @swag_from('swagger/get_dashboards_spec.yaml') def get(self): + request_args = request.args return DashboardSchema().dump( - dashboard.get_dashboards(g.current_account.id), many=True), 200 + dashboard.get_dashboards( + g.current_account.id, + request_args.get('active')), many=True), 200 diff --git a/app/api/resources/swagger/get_dashboards_spec.yaml b/app/api/resources/swagger/get_dashboards_spec.yaml index 568605a..f7429bb 100644 --- a/app/api/resources/swagger/get_dashboards_spec.yaml +++ b/app/api/resources/swagger/get_dashboards_spec.yaml @@ -2,6 +2,13 @@ Gets all associated dashboards --- tags: - Dashboard +parameters: + - in: query + name: active + required: false + schema: + type: boolean + description: Filter for whether to display only active dashboard responses: 200: description: Success diff --git a/app/api/resources/swagger/get_devices_spec.yaml b/app/api/resources/swagger/get_devices_spec.yaml index a702f32..09e3cdf 100644 --- a/app/api/resources/swagger/get_devices_spec.yaml +++ b/app/api/resources/swagger/get_devices_spec.yaml @@ -3,14 +3,14 @@ Gets all associated devices tags: - Device parameters: - - in: path + - in: query name: page required: false schema: type: integer minimum: 1 description: requested page - - in: path + - in: query name: per_page required: false schema: diff --git a/app/api/resources/swagger/update_dashboard_spec.yaml b/app/api/resources/swagger/update_dashboard_spec.yaml index 65ac84f..f702179 100644 --- a/app/api/resources/swagger/update_dashboard_spec.yaml +++ b/app/api/resources/swagger/update_dashboard_spec.yaml @@ -1,4 +1,5 @@ Updates a dashboard +Updating active state disables previous active dashboard --- tags: - Dashboard diff --git a/app/api/resources/token.py b/app/api/resources/token.py index 2f9c066..042846a 100644 --- a/app/api/resources/token.py +++ b/app/api/resources/token.py @@ -23,7 +23,7 @@ class TokenResource(Resource): args['password']) if token: return {'status': 'success', 'token': token}, 200 - except ValueError, e: + except ValueError as e: abort(401, message=str(e), status='error') diff --git a/app/dashboards/api.py b/app/dashboards/api.py index 390c80f..6a61997 100644 --- a/app/dashboards/api.py +++ b/app/dashboards/api.py @@ -29,7 +29,8 @@ def get_dashboard(dashboard_id): return Dashboard.get(id=dashboard_id) -def update_dashboard(dashboard_id, dashboard_data): +def patch_dashboard(account_id, dashboard_id, + dashboard_data=None, active=None): """ Tries to update dashboard with given parameters @@ -38,9 +39,12 @@ def update_dashboard(dashboard_id, dashboard_data): :type name: JSON :type dashboard_id: int """ - dashboard = Dashboard.get(id=dashboard_id) - dashboard.dashboard_data = dashboard_data - dashboard.save() + if dashboard_data is not None: + dashboard = Dashboard.get(id=dashboard_id) + dashboard.dashboard_data = dashboard_data + dashboard.save() + if active: + set_active_dashboard(account_id, dashboard_id) def delete_dashboard(dashboard_id): @@ -54,13 +58,42 @@ def delete_dashboard(dashboard_id): dashboard.delete() -def get_dashboards(account_id): +def set_active_dashboard(account_id, dashboard_id): + """ + Tries to set given dashboard as active + + :param dashboard_id: Id of requested dashboard + :type name: int + :param dashboard_id: Id of owner account + :type name: int + """ + Dashboard.deactivate_all_for_user(account_id) + dashboard = Dashboard.get(id=dashboard_id) + dashboard.active = True + dashboard.save() + + +def get_active_dashboard(account_id): + """ + Tries to fetch active dashboard owned by account with given id + + :param account_id: Id of owner account + :type name: int + :returns: active Dashboard object + :rtype: Dashboard + """ + return Dashboard.get(account_id=account_id, active=True) + + +def get_dashboards(account_id, active): """ Tries to fetch dashboards owned by account with given id :param account_id: Id of owner account :type name: int + :param active: Whether to filter active only + :type name: bool :returns: Dashboard list :rtype: List of Dashboard """ - return Dashboard.get_many(account_id=account_id) + return Dashboard.get_many_filtered(account_id=account_id, active=active) diff --git a/app/dashboards/models.py b/app/dashboards/models.py index 90ec9d0..e2370e6 100644 --- a/app/dashboards/models.py +++ b/app/dashboards/models.py @@ -9,6 +9,7 @@ class Dashboard(db.Model): dashboard_data = db.Column(JSON, nullable=False) account_id = db.Column(db.Integer, db.ForeignKey('accounts.id'), primary_key=True) + active = db.Column(db.Boolean, nullable=False, default=False) created_at = db.Column(db.DateTime, nullable=False, default=db.func.current_timestamp()) @@ -74,6 +75,28 @@ class Dashboard(db.Model): """ return Dashboard.query.filter_by(**kwargs).all() + @staticmethod + def get_many_filtered(account_id, active): + """ + Get many dashboard with given filters + + Available filters: + * active + """ + query = Dashboard.query.filter(Dashboard.account_id == account_id) + if active is not None: + query = query.filter(Dashboard.active == active) + return query.all() + + @staticmethod + def deactivate_all_for_user(account_id): + """ + Deactivates all dashboards for this user + """ + db.session.query(Dashboard).filter(account_id == account_id) \ + .update({'active': False}) + db.session.commit() + @staticmethod def get(**kwargs): """ diff --git a/app/swagger/template.yaml b/app/swagger/template.yaml index 8d0e4ae..617d27a 100644 --- a/app/swagger/template.yaml +++ b/app/swagger/template.yaml @@ -224,10 +224,13 @@ definitions: DashboardCreation: type: object required: + - active - dashboard_data properties: dashboard_data: $ref: '#/definitions/dashboarddata' + active: + type: boolean UnauthorizedError: type: object diff --git a/migrations/versions/4945e4c8fbca_.py b/migrations/versions/4945e4c8fbca_.py new file mode 100644 index 0000000..59a989b --- /dev/null +++ b/migrations/versions/4945e4c8fbca_.py @@ -0,0 +1,29 @@ +"""empty message + +Revision ID: 4945e4c8fbca +Revises: ae43d7caad52 +Create Date: 2018-10-10 22:50:41.087670 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '4945e4c8fbca' +down_revision = 'ae43d7caad52' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('dashboards', sa.Column('active', sa.Boolean(), + nullable=False, server_default='False')) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('dashboards', 'active') + # ### end Alembic commands ### diff --git a/runtime.txt b/runtime.txt deleted file mode 100644 index f27f1cc..0000000 --- a/runtime.txt +++ /dev/null @@ -1 +0,0 @@ -python-2.7.15