Skip to content

Commit

Permalink
Refs #1. Reworked Dashboard database structure and API.
Browse files Browse the repository at this point in the history
  • Loading branch information
SBriere committed Feb 15, 2024
1 parent a234a8d commit b44a3b6
Show file tree
Hide file tree
Showing 7 changed files with 447 additions and 171 deletions.
236 changes: 135 additions & 101 deletions API/user/QueryDashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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')
Expand All @@ -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):
Expand All @@ -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)
Expand All @@ -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',
Expand All @@ -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
18 changes: 17 additions & 1 deletion libDashboards/db/DBManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading

0 comments on commit b44a3b6

Please sign in to comment.