diff --git a/API/user/QueryDashboard.py b/API/user/QueryDashboard.py index ea1f290..d7a2cf0 100644 --- a/API/user/QueryDashboard.py +++ b/API/user/QueryDashboard.py @@ -4,6 +4,8 @@ from FlaskModule import user_api_ns as api from libDashboards.db.models.DashDashboards import DashDashboards +from libDashboards.db.models.DashDashboardSites import DashDashboardSites +from libDashboards.db.models.DashDashboardProjects import DashDashboardProjects from opentera.services.ServiceAccessManager import ServiceAccessManager, current_login_type, LoginType, \ current_user_client from flask_babel import gettext @@ -12,7 +14,8 @@ # Parser definition(s) # GET get_parser = api.parser() -get_parser.add_argument('uuid', type=str, help='Specific dashboard uuid to query information for.') +get_parser.add_argument('id_dashboard', type=int, help='Specific dashboard id to query information for') +get_parser.add_argument('uuid', type=str, help='Specific dashboard uuid to query information for') get_parser.add_argument('id_site', type=int, help='ID of the site to query all dashboards for') get_parser.add_argument('id_project', type=int, help='ID of the project to query all dashboards for') get_parser.add_argument('globals', type=inputs.boolean, help='Query globals dashboards') @@ -24,12 +27,13 @@ 'example)') # POST -post_schema = api.schema_model('criteria', {'properties': DashDashboards.get_json_schema(), 'type': 'object', - 'location': 'json'}) +post_schema = api.schema_model('dashboard', {'properties': DashDashboards.get_json_schema(), 'type': 'object', + 'location': 'json'}) # DELETE delete_parser = api.parser() delete_parser.add_argument('id', type=int, help='ID to delete') +delete_parser.add_argument('uuid', type=int, help='UUID to delete') class QueryDashboard(Resource): @@ -54,50 +58,58 @@ def get(self): request_args = get_parser.parse_args(strict=False) dashboards = [] - if request_args['uuid']: - dashboard = DashDashboards.get_dashboard_by_uuid(request_args['uuid']) + user_info = current_user_client.get_user_info() + accessible_project_ids = [role['id_project'] for role in user_info['projects']] + accessible_site_ids = [role['id_site'] for role in user_info['sites']] + if request_args['uuid'] or request_args['id_dashboard']: + if request_args['uuid']: + dashboard = DashDashboards.get_by_uuid(request_args['uuid']) + else: + dashboard = DashDashboards.get_by_id(request_args['id_dashboard']) if not dashboard: return gettext('Forbidden'), 403 # Explicitely vague for security purpose - if dashboard.id_site: - site_role = current_user_client.get_role_for_site(dashboard.id_site) - if site_role == 'Undefined': + dashboard_sites_ids = DashDashboardSites.get_sites_ids_for_dashboard(dashboard.id_dashboard) + if dashboard_sites_ids: + # Check that we have a match for at least one site + if len(set(accessible_site_ids).intersection(dashboard_sites_ids)) == 0: return gettext('Forbidden'), 403 - if dashboard.id_project: - project_role = current_user_client.get_role_for_project(dashboard.id_project) - if project_role == 'Undefined': + dashboard_proj_ids = DashDashboardProjects.get_projects_ids_for_dashboard(dashboard.id_dashboard) + if dashboard_proj_ids: + # Check that we have a match for at least one project + if len(set(accessible_project_ids).intersection(dashboard_proj_ids)) == 0: return gettext('Forbidden'), 403 - if not dashboard.id_project and not dashboard.id_site: + if not dashboard_proj_ids and not dashboard_sites_ids: # Global dashboard - only for super admins if not current_user_client.user_superadmin: return gettext('Forbidden'), 403 + dashboards = [dashboard] elif request_args['id_site']: - site_role = current_user_client.get_role_for_site(request_args['id_site']) - if site_role == 'Undefined': + if request_args['id_site'] not in accessible_site_ids: return gettext('Forbidden'), 403 - dashboards = DashDashboards.get_dashboards_for_site(request_args['id_site'], - not request_args['all_versions']) + dashboards = DashDashboardSites.get_dashboards_for_site(request_args['id_site'], + enabled_only=request_args['enabled']) elif request_args['id_project']: - project_role = current_user_client.get_role_for_project(request_args['id_project']) - if project_role == 'Undefined': + if request_args['id_project'] not in accessible_project_ids: return gettext('Forbidden'), 403 - dashboards = DashDashboards.get_dashboards_for_project(request_args['id_project'], - not request_args['all_versions']) + dashboards = DashDashboardProjects.get_dashboards_for_project(request_args['id_project'], + enabled_only=request_args['enabled']) elif request_args['globals']: if not current_user_client.user_superadmin: return gettext('Forbidden'), 403 - dashboards = DashDashboards.get_dashboards_globals(not request_args['all_versions']) + dashboards = DashDashboards.get_dashboards_globals() else: return gettext('Must specify at least one id parameter or "globals"') - # Convert to json and return - dashboards_json = [dash.to_json(request_args['list']) for dash in dashboards] + # # Convert to json and return + dashboards_json = [dash.to_json(minimal=request_args['list'], latest=not request_args['all_versions']) + for dash in dashboards] return dashboards_json @api.expect(post_schema) @@ -117,85 +129,102 @@ def post(self): json_dashboard = request.json['dashboard'] - # Check if we have an uuid or an id_dashboard and load infos - updating = ('dashboard_uuid' in json_dashboard or - ('id_dashboard' in json_dashboard and json_dashboard['id_dashboard'] > 0)) - - if updating: - # Load dashboard - dashboard = None - if 'id_dashboard' in json_dashboard and json_dashboard['id_dashboard'] > 0: - dashboard = DashDashboards.get_by_id(json_dashboard['id_dashboard']) - if 'dashboard_uuid' in json_dashboard and dashboard.dashboard_uuid != json_dashboard['dashboard_uuid']: - return gettext('Can\'t change uuid when updating with id'), 400 - if ('dashboard_version' in json_dashboard and - dashboard.dashboard_version != json_dashboard['dashboard_version']): - return gettext('Can\'t change version when updating with it'), 400 - - if 'dashboard_uuid' in json_dashboard: - dashboard = DashDashboards.get_dashboard_by_uuid(json_dashboard['dashboard_uuid'], latest=True) - # Check version - can't update an older version - if 'dashboard_version' in json_dashboard: - if dashboard.dashboard_version > int(json_dashboard['dashboard_version']): - return gettext('Trying to update an older dashboard version - this is not allowed.'), 400 - else: - # Auto increment version - json_dashboard['dashboard_version'] = dashboard.dashboard_version + 1 - - if json_dashboard['dashboard_version'] != dashboard.dashboard_version: - # New version - must create a new dashboard id - pass - - - - if not dashboard: - return gettext('Forbidden'), 403 # Explicitly vague - - # Check access - only admins can change things... - if dashboard.id_site: - site_role = current_user_client.get_role_for_site(dashboard.id_site) - if site_role != 'admin': - return gettext('No access to dashboard to update'), 403 - - if dashboard.id_project: - project_role = current_user_client.get_role_for_project(dashboard.id_project) - if project_role != 'admin': - return gettext('No access to dashboard to update'), 403 - - if not dashboard.id_project and not dashboard.id_site: - if not current_user_client.user_superadmin: - return gettext('No access to dashboard to update'), 403 + pass - # Check access to updated data - if 'id_site' in json_dashboard and json_dashboard['id_site'] != dashboard.id_site: - site_role = current_user_client.get_role_for_site(json_dashboard['id_site']) - if site_role != 'admin': - return gettext('No access to dashboard site'), 403 - - if 'id_project' in json_dashboard and json_dashboard['id_project'] != dashboard.id_project: - project_role = current_user_client.get_role_for_project(json_dashboard['id_project']) - if project_role != 'admin': - return gettext('No access to dashboard project'), 403 - - if ('id_project' not in json_dashboard and 'id_site' not in json_dashboard and - (dashboard.id_site or dashboard.id_project)): - if not current_user_client.user_superadmin: - return gettext('No access to global dashboard'), 403 - - if json_dashboard['id_dashboard'] > 0: - # We have access! Update the dashboard... - try: - DashDashboards.update(json_dashboard['id_dashboard'], json_dashboard) - except exc.SQLAlchemyError as e: - import sys - print(sys.exc_info()) - self.module.logger.log_error(self.module.module_name, - QueryDashboard.__name__, - 'post', 500, 'Database error', str(e)) - return gettext('Database error'), 500 - else: - # New dashboard - pass + # Check if we have an uuid or an id_dashboard and load infos + # updating = ('dashboard_uuid' in json_dashboard or + # ('id_dashboard' in json_dashboard and json_dashboard['id_dashboard'] > 0)) + # + # if updating: + # # Load dashboard + # dashboard = None + # if 'id_dashboard' in json_dashboard and json_dashboard['id_dashboard'] > 0: + # dashboard = DashDashboards.get_by_id(json_dashboard['id_dashboard']) + # if 'dashboard_uuid' in json_dashboard and dashboard.dashboard_uuid != json_dashboard['dashboard_uuid']: + # return gettext('Can\'t change uuid when updating with id'), 400 + # if ('dashboard_version' in json_dashboard and + # dashboard.dashboard_version != json_dashboard['dashboard_version']): + # return gettext('Can\'t change version when updating with it'), 400 + # + # if 'dashboard_uuid' in json_dashboard: + # dashboard = DashDashboards.get_dashboard_by_uuid(json_dashboard['dashboard_uuid'], latest=True) + # # Check version - can't update an older version + # if 'dashboard_version' in json_dashboard: + # if dashboard.dashboard_version > int(json_dashboard['dashboard_version']): + # return gettext('Trying to update an older dashboard version - this is not allowed.'), 400 + # else: + # # Auto increment version + # json_dashboard['dashboard_version'] = dashboard.dashboard_version + 1 + # + # if json_dashboard['dashboard_version'] != dashboard.dashboard_version: + # # New version - must create a new dashboard id + # json_dashboard['id_dashboard'] = 0 + # else: + # json_dashboard['id_dashboard'] = dashboard.id_dashboard + # + # if not dashboard: + # return gettext('Forbidden'), 403 # Explicitly vague + # + # # Check access - only admins can change things... + # if dashboard.id_site: + # site_role = current_user_client.get_role_for_site(dashboard.id_site) + # if site_role != 'admin': + # return gettext('No access to dashboard to update'), 403 + # + # if dashboard.id_project: + # project_role = current_user_client.get_role_for_project(dashboard.id_project) + # if project_role != 'admin': + # return gettext('No access to dashboard to update'), 403 + # + # if not dashboard.id_project and not dashboard.id_site: + # if not current_user_client.user_superadmin: + # return gettext('No access to dashboard to update'), 403 + # + # # Check access to updated data + # if 'id_site' in json_dashboard and json_dashboard['id_site'] != dashboard.id_site: + # site_role = current_user_client.get_role_for_site(json_dashboard['id_site']) + # if site_role != 'admin': + # return gettext('No access to dashboard site'), 403 + # + # if 'id_project' in json_dashboard and json_dashboard['id_project'] != dashboard.id_project: + # project_role = current_user_client.get_role_for_project(json_dashboard['id_project']) + # if project_role != 'admin': + # return gettext('No access to dashboard project'), 403 + # + # if ('id_project' not in json_dashboard and 'id_site' not in json_dashboard and + # (dashboard.id_site or dashboard.id_project)): + # if not current_user_client.user_superadmin: + # return gettext('No access to global dashboard'), 403 + # + # if json_dashboard['id_dashboard'] > 0: + # # Update the dashboard + # try: + # DashDashboards.update(json_dashboard['id_dashboard'], json_dashboard) + # except exc.SQLAlchemyError as e: + # import sys + # print(sys.exc_info()) + # self.module.logger.log_error(self.module.module_name, + # QueryDashboard.__name__, + # 'post', 500, 'Database error', str(e)) + # return gettext('Database error'), 500 + # else: + # # New dashboard + # try: + # new_dashboard = DashDashboards() + # new_dashboard.from_json(json_dashboard) + # DashDashboards.insert(new_dashboard) + # # Update ID for further use + # json_dashboard['id_dashboard'] = new_dashboard.id_dashboard + # + # except exc.SQLAlchemyError as e: + # import sys + # print(sys.exc_info()) + # self.module.logger.log_error(self.module.module_name, + # DashDashboards.__name__, + # 'post', 400, 'Database error', str(e)) + # return gettext('Database error'), 400 + # + # return DashDashboards.get_by_id(json_dashboard['id_dashboard']).to_json() @api.expect(delete_parser, validate=True) @api.doc(description='Delete a dashboard', @@ -207,3 +236,8 @@ def post(self): def delete(self): if current_login_type != LoginType.USER_LOGIN: return gettext('Only users can use this API.'), 403 + + args = delete_parser.parse_args() + + if args['id']: + pass diff --git a/libDashboards/db/DBManager.py b/libDashboards/db/DBManager.py index bdd18d3..a7ac88d 100644 --- a/libDashboards/db/DBManager.py +++ b/libDashboards/db/DBManager.py @@ -34,10 +34,26 @@ def __init__(self, app=flask_app, test: bool = False): def create_defaults(self, test=False): with self.app.app_context(): from libDashboards.db.models.DashDashboards import DashDashboards - if DashDashboards.get_count() == 0: + from libDashboards.db.models.DashDashboardSites import DashDashboardSites + from libDashboards.db.models.DashDashboardProjects import DashDashboardProjects + from libDashboards.db.models.DashDashboardVersions import DashDashboardVersions + + if DashDashboards.get_count() == 0 and test: print("No dashboards - creating defaults") DashDashboards.create_defaults(test) + if DashDashboardVersions.get_count() == 0 and test: + print("No dashboards versions - creating defaults") + DashDashboardVersions.create_defaults(test) + + if DashDashboardSites.get_count() == 0 and test: + print("No dashboards for sites - creating defaults") + DashDashboardSites.create_defaults(test) + + if DashDashboardProjects.get_count() == 0 and test: + print("No dashboards for projects - creating defaults") + DashDashboardProjects.create_defaults(test) + def open(self, db_infos, echo=False): self.db_uri = 'postgresql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % db_infos diff --git a/libDashboards/db/models/DashDashboardProjects.py b/libDashboards/db/models/DashDashboardProjects.py new file mode 100644 index 0000000..f0be263 --- /dev/null +++ b/libDashboards/db/models/DashDashboardProjects.py @@ -0,0 +1,96 @@ +from libDashboards.db.models.BaseModel import BaseModel +from sqlalchemy import Column, Integer, Sequence, Boolean, ForeignKey, String +from sqlalchemy.orm import relationship + + +class DashDashboardProjects(BaseModel): + __tablename__ = 't_dashboards_projects' + id_dashboard_project = Column(Integer, Sequence('id_dashboard_project_sequence'), + primary_key=True, autoincrement=True) + id_project = Column(Integer, nullable=True) + id_dashboard = Column(Integer, ForeignKey('t_dashboards.id_dashboard', ondelete='cascade'), nullable=False) + + dashboard_project_enabled = Column(Boolean, nullable=False, default=True) + dashboard_project_version = Column(Integer, nullable=True) # Use a specific dashboard version for that project + + dashboard_project_dashboard = relationship("DashDashboards", back_populates="dashboard_projects") + + def to_json(self, ignore_fields=None, minimal=False, latest=True): + if ignore_fields is None: + ignore_fields = [] + + ignore_fields.extend(['id_dashboard_project', 'id_project']) + + dashboard_json = super().to_json(ignore_fields=ignore_fields) + + dashboard_json |= self.dashboard_project_dashboard.to_json(minimal=latest, latest=latest) + + # Rename keys to standardize them + dashboard_json['dashboard_enabled'] = dashboard_json.pop('dashboard_project_enabled') + dashboard_json['dashboard_required_version'] = dashboard_json.pop('dashboard_project_version') + + # Get the appropriate dashboard to jsonize + if latest: + dashboard_json['versions'] = [] + if self.dashboard_project_version: + for version in self.dashboard_project_dashboard.dashboard_versions: + if version.dashboard_version == self.dashboard_project_version: + dashboard_json['versions'] = version.to_json(minimal=True) + else: + if len(self.dashboard_project_dashboard.dashboard_versions) > 0: + dashboard_json['versions'] = (self.dashboard_project_dashboard.dashboard_versions[-1]. + to_json(minimal=True)) + + return dashboard_json + + @staticmethod + def get_projects_ids_for_dashboard(dashboard_id: int, enabled_only=True): + query = (DashDashboardProjects.query.with_entities(DashDashboardProjects.id_project) + .filter_by(id_dashboard=dashboard_id)) + if enabled_only: + query = query.filter_by(dashboard_project_enabled=True) + + rows = query.all() + proj_ids = [proj_id[0] for proj_id in rows] + return proj_ids + + @staticmethod + def get_dashboards_for_project(project_id: int, enabled_only=True) -> []: + filters = {'id_project': project_id} + if enabled_only: + filters['dashboard_project_enabled'] = True + + ddp = DashDashboardProjects.query_with_filters(filters) + + return ddp + + @staticmethod + def create_defaults(test=False): + from libDashboards.db.models.DashDashboards import DashDashboards + dashboards = DashDashboards.query.all() + + if test: + ddp = DashDashboardProjects() + ddp.id_project = 1 + ddp.id_dashboard = dashboards[1].id_dashboard + ddp.dashboard_project_enabled = False + ddp.dashboard_project_version = 1 + DashDashboardProjects.insert(ddp) + + ddp = DashDashboardProjects() + ddp.id_project = 1 + ddp.id_dashboard = dashboards[2].id_dashboard + ddp.dashboard_project_enabled = True + DashDashboardProjects.insert(ddp) + + ddp = DashDashboardProjects() + ddp.id_project = 2 + ddp.id_dashboard = dashboards[1].id_dashboard + DashDashboardProjects.insert(ddp) + + ddp = DashDashboardProjects() + ddp.id_project = 2 + ddp.id_dashboard = dashboards[2].id_dashboard + ddp.dashboard_project_enabled = True + ddp.dashboard_project_version = 1 + DashDashboardProjects.insert(ddp) diff --git a/libDashboards/db/models/DashDashboardSites.py b/libDashboards/db/models/DashDashboardSites.py new file mode 100644 index 0000000..5eb265f --- /dev/null +++ b/libDashboards/db/models/DashDashboardSites.py @@ -0,0 +1,82 @@ +from libDashboards.db.models.BaseModel import BaseModel +from sqlalchemy import Column, Integer, Sequence, Boolean, ForeignKey, String +from sqlalchemy.orm import relationship + + +class DashDashboardSites(BaseModel): + __tablename__ = 't_dashboards_sites' + id_dashboard_site = Column(Integer, Sequence('id_dashboard_site_sequence'), primary_key=True, autoincrement=True) + id_site = Column(Integer, nullable=True) + id_dashboard = Column(Integer, ForeignKey('t_dashboards.id_dashboard', ondelete='cascade'), nullable=False) + + dashboard_site_enabled = Column(Boolean, nullable=False, default=True) + dashboard_site_version = Column(Integer, nullable=True) # Force use of a specific dashboard version for that site + + dashboard_site_dashboard = relationship("DashDashboards", back_populates="dashboard_sites") + + def to_json(self, ignore_fields=None, minimal=False, latest=True): + if ignore_fields is None: + ignore_fields = [] + + ignore_fields.extend(['id_dashboard_site', 'id_site']) + + dashboard_json = super().to_json(ignore_fields=ignore_fields) + + dashboard_json |= self.dashboard_site_dashboard.to_json(minimal=latest, latest=latest) + + # Rename keys to standardize them + dashboard_json['dashboard_enabled'] = dashboard_json.pop('dashboard_site_enabled') + dashboard_json['dashboard_required_version'] = dashboard_json.pop('dashboard_site_version') + + # Get the appropriate dashboard to jsonize + if latest: + dashboard_json['versions'] = [] + if self.dashboard_site_version: + for version in self.dashboard_site_dashboard.dashboard_versions: + if version.dashboard_version == self.dashboard_site_version: + dashboard_json['versions'] = version.to_json(minimal=True) + else: + if len(self.dashboard_site_dashboard.dashboard_versions) > 0: + dashboard_json['versions'] = (self.dashboard_site_dashboard.dashboard_versions[-1]. + to_json(minimal=True)) + + return dashboard_json + + @staticmethod + def get_sites_ids_for_dashboard(dashboard_id: int, enabled_only=True): + query = DashDashboardSites.query.with_entities(DashDashboardSites.id_site).filter_by(id_dashboard=dashboard_id) + if enabled_only: + query = query.filter_by(dashboard_site_enabled=True) + + rows = query.all() + site_ids = [site_id[0] for site_id in rows] + return site_ids + + @staticmethod + def get_dashboards_for_site(site_id: int, enabled_only=True) -> []: + filters = {'id_site': site_id} + if enabled_only: + filters['dashboard_site_enabled'] = True + + dds = DashDashboardSites.query_with_filters(filters) + + return dds + + @staticmethod + def create_defaults(test=False): + if test: + from libDashboards.db.models.DashDashboards import DashDashboards + dashboards = DashDashboards.query.all() + + dds = DashDashboardSites() + dds.id_site = 1 + dds.id_dashboard = dashboards[0].id_dashboard + dds.dashboard_site_enabled = True + dds.dashboard_site_version = 1 + DashDashboardSites.insert(dds) + + dds = DashDashboardSites() + dds.id_site = 2 + dds.id_dashboard = dashboards[0].id_dashboard + dds.dashboard_site_enabled = True + DashDashboardSites.insert(dds) diff --git a/libDashboards/db/models/DashDashboardVersions.py b/libDashboards/db/models/DashDashboardVersions.py new file mode 100644 index 0000000..51bb74a --- /dev/null +++ b/libDashboards/db/models/DashDashboardVersions.py @@ -0,0 +1,72 @@ +from libDashboards.db.models.BaseModel import BaseModel +from sqlalchemy import Column, Integer, Sequence, ForeignKey, JSON +from sqlalchemy.orm import relationship + + +class DashDashboardVersions(BaseModel): + __tablename__ = 't_dashboards_versions' + id_dashboard_version = Column(Integer, Sequence('id_dashboard_version_sequence'), + primary_key=True, autoincrement=True) + id_dashboard = Column(Integer, ForeignKey('t_dashboards.id_dashboard', ondelete='cascade'), nullable=False) + + dashboard_definition = Column(JSON, nullable=False) # Dashboard definition string + dashboard_version = Column(Integer, nullable=False) + + dashboard_version_dashboard = relationship("DashDashboards", back_populates="dashboard_versions") + + def to_json(self, ignore_fields=None, minimal=False): + if ignore_fields is None: + ignore_fields = [] + + if minimal: + ignore_fields.extend(['id_dashboard_version', 'id_dashboard']) + + dashboard_json = super().to_json(ignore_fields=ignore_fields) + + return dashboard_json + + @staticmethod + def create_defaults(test=False): + if test: + from libDashboards.db.models.DashDashboards import DashDashboards + dashboards = DashDashboards.query.all() + + # 2 Versions for "site" dashboard + dashboard = DashDashboardVersions() + dashboard.id_dashboard = dashboards[0].id_dashboard + dashboard.dashboard_version = 1 + dashboard.dashboard_definition = '{}' + DashDashboardVersions.insert(dashboard) + + dashboard = DashDashboardVersions() + dashboard.id_dashboard = dashboards[0].id_dashboard + dashboard.dashboard_version = 2 + dashboard.dashboard_definition = '{"widgets": ""}' + DashDashboardVersions.insert(dashboard) + + # 1 version for "project global" dashboard + dashboard = DashDashboardVersions() + dashboard.id_dashboard = dashboards[1].id_dashboard + dashboard.dashboard_version = 1 + dashboard.dashboard_definition = '{}' + DashDashboardVersions.insert(dashboard) + + # 2 version for "alert" dashboard + dashboard = DashDashboardVersions() + dashboard.id_dashboard = dashboards[2].id_dashboard + dashboard.dashboard_version = 1 + dashboard.dashboard_definition = '{}' + DashDashboardVersions.insert(dashboard) + + dashboard = DashDashboardVersions() + dashboard.id_dashboard = dashboards[2].id_dashboard + dashboard.dashboard_version = 2 + dashboard.dashboard_definition = '{"widgets": ""}' + DashDashboardVersions.insert(dashboard) + + # 1 version for "global" dashboard + dashboard = DashDashboardVersions() + dashboard.id_dashboard = dashboards[3].id_dashboard + dashboard.dashboard_version = 1 + dashboard.dashboard_definition = '{}' + DashDashboardVersions.insert(dashboard) diff --git a/libDashboards/db/models/DashDashboards.py b/libDashboards/db/models/DashDashboards.py index cd3b232..74a1597 100644 --- a/libDashboards/db/models/DashDashboards.py +++ b/libDashboards/db/models/DashDashboards.py @@ -1,74 +1,58 @@ from libDashboards.db.models.BaseModel import BaseModel -from sqlalchemy import Column, Integer, Sequence, String, Boolean, func, select -from sqlalchemy.orm import aliased +from sqlalchemy import Column, Integer, Sequence, String, func, select +from sqlalchemy.orm import relationship import uuid class DashDashboards(BaseModel): __tablename__ = 't_dashboards' id_dashboard = Column(Integer, Sequence('id_dashboard_sequence'), primary_key=True, autoincrement=True) - id_site = Column(Integer, nullable=True) - id_project = Column(Integer, nullable=True) dashboard_uuid = Column(String(36), nullable=False) dashboard_name = Column(String, nullable=False) - dashboard_enabled = Column(Boolean, nullable=False, default=True) dashboard_description = Column(String, nullable=True) # Dashboard user-visible description - dashboard_definition = Column(String, nullable=False) # Dashboard definition string - dashboard_version = Column(Integer, nullable=False, default=1) - def to_json(self, ignore_fields=None, minimal=False): + dashboard_versions = relationship("DashDashboardVersions", back_populates="dashboard_version_dashboard", + order_by="DashDashboardVersions.dashboard_version") + dashboard_sites = relationship("DashDashboardSites", back_populates="dashboard_site_dashboard") + dashboard_projects = relationship("DashDashboardProjects", back_populates="dashboard_project_dashboard") + + def to_json(self, ignore_fields=None, minimal=False, latest=True): if ignore_fields is None: ignore_fields = [] - if minimal: - ignore_fields.extend(['asset_definition']) + dashboard_json = super().to_json(ignore_fields=ignore_fields) - asset_json = super().to_json(ignore_fields=ignore_fields) + if not minimal: + if latest: # Only get latest version + dashboard_json['versions'] = [self.dashboard_versions[-1].to_json(minimal=True)] + else: # Append all versions + dashboard_json['versions'] = [version.to_json(minimal=True) for version in self.dashboard_versions] - return asset_json + return dashboard_json @staticmethod - def get_dashboard_by_uuid(dashboard_uuid: str, latest=True): + def get_by_uuid(dashboard_uuid: str): query = DashDashboards.query.filter_by(dashboard_uuid=dashboard_uuid) - if latest: - subquery = select(func.max(DashDashboards.dashboard_version).label("latest_version"), - DashDashboards.dashboard_uuid).group_by(DashDashboards.dashboard_uuid).subquery() - query = (query.filter(DashDashboards.dashboard_version == subquery.c.latest_version). - filter(DashDashboards.dashboard_uuid == subquery.c.dashboard_uuid)) - return query.first() @staticmethod - def get_dashboards_for_site(site_id: int, latest=True) -> []: - query = DashDashboards.query.filter_by(id_site=site_id) - if latest: - subquery = select(func.max(DashDashboards.dashboard_version).label("latest_version"), - DashDashboards.dashboard_uuid).group_by(DashDashboards.dashboard_uuid).subquery() - query = (query.filter(DashDashboards.dashboard_version == subquery.c.latest_version). - filter(DashDashboards.dashboard_uuid == subquery.c.dashboard_uuid)) - return query.all() - - @staticmethod - def get_dashboards_for_project(project_id: int, latest=True) -> []: - query = DashDashboards.query.filter_by(id_project=project_id) - if latest: - subquery = select(func.max(DashDashboards.dashboard_version).label("latest_version"), - DashDashboards.dashboard_uuid).group_by(DashDashboards.dashboard_uuid).subquery() - query = (query.filter(DashDashboards.dashboard_version == subquery.c.latest_version). - filter(DashDashboards.dashboard_uuid == subquery.c.dashboard_uuid)) - return query.all() - - @staticmethod - def get_dashboards_globals(latest=True) -> []: - query = DashDashboards.query.filter_by(id_project=None, id_site=None) - - if latest: - subquery = select(func.max(DashDashboards.dashboard_version).label("latest_version"), - DashDashboards.dashboard_uuid).group_by(DashDashboards.dashboard_uuid).subquery() - query = (query.filter(DashDashboards.dashboard_version == subquery.c.latest_version). - filter(DashDashboards.dashboard_uuid == subquery.c.dashboard_uuid)) - + def get_dashboards_globals() -> []: + from libDashboards.db.models.DashDashboardProjects import DashDashboardProjects + from libDashboards.db.models.DashDashboardSites import DashDashboardSites + query = (DashDashboards.query.join(DashDashboards.dashboard_sites, isouter=True). + join(DashDashboards.dashboard_projects, isouter=True). + filter(DashDashboardProjects.id_project == None). + filter(DashDashboardSites.id_site == None)) + + # query = DashDashboards.query.filter_by(id_project=None, id_site=None) + # + # if latest: + # subquery = select(func.max(DashDashboards.dashboard_version).label("latest_version"), + # DashDashboards.dashboard_uuid).group_by(DashDashboards.dashboard_uuid).subquery() + # query = (query.filter(DashDashboards.dashboard_version == subquery.c.latest_version). + # filter(DashDashboards.dashboard_uuid == subquery.c.dashboard_uuid)) + # return query.all() @classmethod @@ -84,40 +68,26 @@ def create_defaults(test=False): if test: # Create dashboard for site... dashboard = DashDashboards() - dashboard.id_site = 1 - dashboard.dashboard_name = 'Site 1 - Global' + # dashboard.id_site = 1 + dashboard.dashboard_name = 'Site Global' dashboard.dashboard_description = 'Test dashboard for global site overview' - dashboard.dashboard_definition = '{}' DashDashboards.insert(dashboard) # ... for project... dashboard = DashDashboards() - dashboard.id_project = 1 - dashboard.dashboard_name = 'Project 1 - Global' + # dashboard.id_project = 1 + dashboard.dashboard_name = 'Project - Global' dashboard.dashboard_description = 'Test dashboard for global project overview' - dashboard.dashboard_definition = '{}' - DashDashboards.insert(dashboard) - - dashboard = DashDashboards() - dashboard.id_project = 1 - dashboard.dashboard_name = 'Project 1 - Alerts' - dashboard.dashboard_description = 'Test dashboard for project alerts' - dashboard.dashboard_definition = '{}' DashDashboards.insert(dashboard) - uuid = dashboard.dashboard_uuid dashboard = DashDashboards() - dashboard.id_project = 1 - dashboard.dashboard_name = 'Project 1 - Alerts v2' + # dashboard.id_project = 1 + dashboard.dashboard_name = 'Project - Alerts' dashboard.dashboard_description = 'Test dashboard for project alerts' - dashboard.dashboard_definition = '{}' - dashboard.dashboard_version = 2 - dashboard.dashboard_uuid = uuid DashDashboards.insert(dashboard) # ... and globals dashboard = DashDashboards() dashboard.dashboard_name = 'System Dashboard' dashboard.dashboard_description = 'Global system dashboard' - dashboard.dashboard_definition = '{}' DashDashboards.insert(dashboard) diff --git a/libDashboards/db/models/__init__.py b/libDashboards/db/models/__init__.py index 4ae081d..9f5e37e 100644 --- a/libDashboards/db/models/__init__.py +++ b/libDashboards/db/models/__init__.py @@ -1,6 +1,12 @@ from .DashDashboards import DashDashboards +from .DashDashboardProjects import DashDashboardProjects +from .DashDashboardSites import DashDashboardSites +from .DashDashboardVersions import DashDashboardVersions # All exported symbols __all__ = [ - 'DashDashboards' + 'DashDashboards', + 'DashDashboardProjects', + 'DashDashboardSites', + DashDashboardVersions ]