diff --git a/platform_plugin_aspects/extensions/filters.py b/platform_plugin_aspects/extensions/filters.py index 6447406..6b6342f 100644 --- a/platform_plugin_aspects/extensions/filters.py +++ b/platform_plugin_aspects/extensions/filters.py @@ -35,7 +35,7 @@ def run_filter( _ (str): instructor dashboard template name. """ course = context["course"] - dashboard_uuid = settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID + dashboards = settings.ASPECTS_INSTRUCTOR_DASHBOARDS extra_filters_format = settings.SUPERSET_EXTRA_FILTERS_FORMAT filters = ASPECTS_SECURITY_FILTERS_FORMAT + extra_filters_format @@ -45,7 +45,7 @@ def run_filter( context = generate_superset_context( context, user, - dashboard_uuid=dashboard_uuid, + dashboards=dashboards, filters=filters, ) diff --git a/platform_plugin_aspects/settings/common.py b/platform_plugin_aspects/settings/common.py index d76fbb4..e430d59 100644 --- a/platform_plugin_aspects/settings/common.py +++ b/platform_plugin_aspects/settings/common.py @@ -20,7 +20,12 @@ def plugin_settings(settings): "username": "superset", "password": "superset", } - settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID = "1d6bf904-f53f-47fd-b1c9-6cd7e284d286" + settings.ASPECTS_INSTRUCTOR_DASHBOARDS = [ + { + "name": "Instructor Dashboard", + "uuid": "1d6bf904-f53f-47fd-b1c9-6cd7e284d286", + }, + ] settings.SUPERSET_EXTRA_FILTERS_FORMAT = [] settings.EVENT_SINK_CLICKHOUSE_BACKEND_CONFIG = { # URL to a running ClickHouse server's HTTP interface. ex: https://foo.openedx.org:8443/ or diff --git a/platform_plugin_aspects/settings/production.py b/platform_plugin_aspects/settings/production.py index 7e344ef..0b37432 100644 --- a/platform_plugin_aspects/settings/production.py +++ b/platform_plugin_aspects/settings/production.py @@ -11,10 +11,8 @@ def plugin_settings(settings): settings.SUPERSET_CONFIG = getattr(settings, "ENV_TOKENS", {}).get( "SUPERSET_CONFIG", settings.SUPERSET_CONFIG ) - settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID = getattr( - settings, "ENV_TOKENS", {} - ).get( - "ASPECTS_INSTRUCTOR_DASHBOARD_UUID", settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID + settings.ASPECTS_INSTRUCTOR_DASHBOARDS = getattr(settings, "ENV_TOKENS", {}).get( + "ASPECTS_INSTRUCTOR_DASHBOARDS", settings.ASPECTS_INSTRUCTOR_DASHBOARDS ) settings.SUPERSET_EXTRA_FILTERS_FORMAT = getattr(settings, "ENV_TOKENS", {}).get( "SUPERSET_EXTRA_FILTERS_FORMAT", settings.SUPERSET_EXTRA_FILTERS_FORMAT diff --git a/platform_plugin_aspects/settings/tests/test_settings.py b/platform_plugin_aspects/settings/tests/test_settings.py index e821f23..ffc88c7 100644 --- a/platform_plugin_aspects/settings/tests/test_settings.py +++ b/platform_plugin_aspects/settings/tests/test_settings.py @@ -25,7 +25,7 @@ def test_common_settings(self): self.assertNotIn("service_url", settings.SUPERSET_CONFIG) self.assertIn("username", settings.SUPERSET_CONFIG) self.assertIn("password", settings.SUPERSET_CONFIG) - self.assertIsNotNone(settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID) + self.assertIsNotNone(settings.ASPECTS_INSTRUCTOR_DASHBOARDS) self.assertIsNotNone(settings.SUPERSET_EXTRA_FILTERS_FORMAT) for key in ("url", "username", "password", "database", "timeout_secs"): assert key in settings.EVENT_SINK_CLICKHOUSE_BACKEND_CONFIG @@ -46,7 +46,12 @@ def test_production_settings(self): "username": "superset", "password": "superset", }, - "ASPECTS_INSTRUCTOR_DASHBOARD_UUID": "test-settings-dashboard-uuid", + "ASPECTS_INSTRUCTOR_DASHBOARDS": [ + { + "name": "Instructor Dashboard", + "uuid": "test-settings-dashboard-uuid", + } + ], "SUPERSET_EXTRA_FILTERS_FORMAT": [], "EVENT_SINK_CLICKHOUSE_BACKEND_CONFIG": { "url": test_url, @@ -61,8 +66,8 @@ def test_production_settings(self): settings.SUPERSET_CONFIG, settings.ENV_TOKENS["SUPERSET_CONFIG"] ) self.assertEqual( - settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID, - settings.ENV_TOKENS["ASPECTS_INSTRUCTOR_DASHBOARD_UUID"], + settings.ASPECTS_INSTRUCTOR_DASHBOARDS, + settings.ENV_TOKENS["ASPECTS_INSTRUCTOR_DASHBOARDS"], ) self.assertEqual( settings.SUPERSET_EXTRA_FILTERS_FORMAT, diff --git a/platform_plugin_aspects/static/html/superset.html b/platform_plugin_aspects/static/html/superset.html index 6b4837f..c8ec9fe 100644 --- a/platform_plugin_aspects/static/html/superset.html +++ b/platform_plugin_aspects/static/html/superset.html @@ -2,7 +2,7 @@ <script src="https://unpkg.com/@superset-ui/embedded-sdk"></script> -<div class="email-notifier-instructor-wrapper" width="parent"> +<div class="aspects-wrapper" width="parent"> <h2>{{display_name}}</h2> {% if exception %} @@ -10,14 +10,23 @@ <h2>{{display_name}}</h2> <p> {{exception}} </p> - {% elif not dashboard_uuid %} + {% elif not dashboard_uuid and not superset_dashboards %} <p> Dashboard UUID is not set. Please set the dashboard UUID in the Studio. {{dashboard_uuid}} </p> {% elif superset_url and superset_token %} - <div class="superset-embedded-container" id="superset-embedded-container-{{xblock_id}}"></div> + {% if xblock_id %} + <div class="superset-embedded-container" id="superset-embedded-container-{{xblock_id}}"></div> + {% else %} + {% for dashboard in superset_dashboards %} + <div> + <h3>{{dashboard.name}}</h3> + </div> + <div class="superset-embedded-container" id="superset-embedded-container-{{dashboard.uuid}}"></div> + {% endfor %} + {% endif %} <script type="text/javascript"> - window.dashboard_uuid ="{{dashboard_uuid}}"; + window.superset_dashboards = {{superset_dashboards | safe }}; window.superset_url = "{{superset_url}}"; window.superset_token = "{{superset_token}}"; </script> diff --git a/platform_plugin_aspects/static/js/embed_dashboard.js b/platform_plugin_aspects/static/js/embed_dashboard.js index 08c42f7..35b7735 100644 --- a/platform_plugin_aspects/static/js/embed_dashboard.js +++ b/platform_plugin_aspects/static/js/embed_dashboard.js @@ -24,7 +24,11 @@ function embedDashboard(dashboard_uuid, superset_url, superset_token, xblock_id) when the dashboard is loaded */ }); -} -if (window.dashboard_uuid !== undefined) { - embedDashboard(window.dashboard_uuid, window.superset_url, window.superset_token, window.xblock_id); +}; + +if (window.superset_dashboards !== undefined) { + window.superset_dashboards.forEach(function(dashboard) { + console.log(dashboard) + embedDashboard(dashboard.uuid, window.superset_url, window.superset_token, dashboard.uuid); + }); } diff --git a/platform_plugin_aspects/tests/test_utils.py b/platform_plugin_aspects/tests/test_utils.py index 8356757..d14ee05 100644 --- a/platform_plugin_aspects/tests/test_utils.py +++ b/platform_plugin_aspects/tests/test_utils.py @@ -113,17 +113,18 @@ def test_generate_superset_context(self, mock_generate_guest_token): filter_mock = Mock() user_mock = Mock() context = {"course": course_mock} - mock_generate_guest_token.return_value = ("test-token", "test-dashboard-uuid") + dashboards = [{"name": "test", "uuid": "test-dashboard-uuid"}] + mock_generate_guest_token.return_value = ("test-token", dashboards) context = generate_superset_context( context, user_mock, - dashboard_uuid="test-dashboard-uuid", + dashboards=dashboards, filters=[filter_mock], ) self.assertEqual(context["superset_token"], "test-token") - self.assertEqual(context["dashboard_uuid"], "test-dashboard-uuid") + self.assertEqual(context["superset_dashboards"], dashboards) self.assertEqual(context["superset_url"], "http://superset-dummy-url/") self.assertNotIn("exception", context) @@ -143,7 +144,7 @@ def test_generate_superset_context_with_superset_client_exception( context = generate_superset_context( context, user_mock, - dashboard_uuid="test-dashboard-uuid", + dashboards=[{"name": "test", "uuid": "test-dashboard-uuid"}], filters=[filter_mock], ) @@ -175,14 +176,17 @@ def test_generate_superset_context_succesful(self, mock_superset_client): "token": "test-token", } + dashboards = [{"name": "test", "uuid": "test-dashboard-uuid"}] + context = generate_superset_context( context, user_mock, + dashboards=dashboards, filters=[filter_mock], ) self.assertEqual(context["superset_token"], "test-token") - self.assertEqual(context["dashboard_uuid"], "test-settings-dashboard-uuid") + self.assertEqual(context["superset_dashboards"], dashboards) self.assertEqual(context["superset_url"], "http://dummy-superset-url/") def test_generate_superset_context_with_exception(self): @@ -198,7 +202,7 @@ def test_generate_superset_context_with_exception(self): context = generate_superset_context( context, user_mock, - dashboard_uuid="test-dashboard-uuid", + dashboards=[{"name": "test", "uuid": "test-dashboard-uuid"}], filters=[filter_mock], ) diff --git a/platform_plugin_aspects/utils.py b/platform_plugin_aspects/utils.py index edfdd43..1c14094 100644 --- a/platform_plugin_aspects/utils.py +++ b/platform_plugin_aspects/utils.py @@ -28,7 +28,7 @@ def _(text): def generate_superset_context( # pylint: disable=dangerous-default-value context, user, - dashboard_uuid=None, + dashboards, filters=[], ): """ @@ -38,17 +38,17 @@ def generate_superset_context( # pylint: disable=dangerous-default-value context (dict): the context for the instructor dashboard. It must include a course object user (XBlockUser or User): the current user. superset_config (dict): superset config. - dashboard_uuid (str): superset dashboard uuid. + dashboards (list): list of superset dashboard uuid. filters (list): list of filters to apply to the dashboard. """ course = context["course"] superset_config = settings.SUPERSET_CONFIG - superset_token, dashboard_uuid = _generate_guest_token( + superset_token, dashboards = _generate_guest_token( user=user, course=course, superset_config=superset_config, - dashboard_uuid=dashboard_uuid, + dashboards=dashboards, filters=filters, ) @@ -57,21 +57,21 @@ def generate_superset_context( # pylint: disable=dangerous-default-value context.update( { "superset_token": superset_token, - "dashboard_uuid": dashboard_uuid, + "superset_dashboards": dashboards, "superset_url": superset_url, } ) else: context.update( { - "exception": str(dashboard_uuid), + "exception": str(dashboards), } ) return context -def _generate_guest_token(user, course, superset_config, dashboard_uuid, filters): +def _generate_guest_token(user, course, superset_config, dashboards, filters): """ Generate a Superset guest token for the user. @@ -102,16 +102,16 @@ def _generate_guest_token(user, course, superset_config, dashboard_uuid, filters formatted_filters = [filter.format(course=course, user=user) for filter in filters] - if not dashboard_uuid: - dashboard_uuid = settings.ASPECTS_INSTRUCTOR_DASHBOARD_UUID - data = { "user": _superset_user_data(user), - "resources": [{"type": "dashboard", "id": dashboard_uuid}], + "resources": [ + {"type": "dashboard", "id": dashboard["uuid"]} for dashboard in dashboards + ], "rls": [{"clause": filter} for filter in formatted_filters], } try: + logger.info(f"Requesting guest token from Superset, {data}") response = client.session.post( url=f"{superset_internal_host}api/v1/security/guest_token/", json=data, @@ -120,7 +120,7 @@ def _generate_guest_token(user, course, superset_config, dashboard_uuid, filters response.raise_for_status() token = response.json()["token"] - return token, dashboard_uuid + return token, dashboards except Exception as exc: # pylint: disable=broad-except logger.error(exc) return None, exc diff --git a/platform_plugin_aspects/xblock.py b/platform_plugin_aspects/xblock.py index 55006c1..4146513 100644 --- a/platform_plugin_aspects/xblock.py +++ b/platform_plugin_aspects/xblock.py @@ -104,7 +104,7 @@ def student_view(self, context=None): context = generate_superset_context( context=context, user=user, - dashboard_uuid=self.dashboard_uuid, + dashboards=[{"name": self.display_name, "uuid": self.dashboard_uuid}], filters=self.filters, ) context["xblock_id"] = str(self.scope_ids.usage_id.block_id) @@ -125,7 +125,7 @@ def student_view(self, context=None): frag.initialize_js( "SupersetXBlock", json_args={ - "dashboard_uuid": context.get("dashboard_uuid"), + "dashboard_uuid": self.dashboard_uuid, "superset_url": context.get("superset_url"), "superset_token": context.get("superset_token"), "xblock_id": context.get("xblock_id"), diff --git a/test_settings.py b/test_settings.py index f24796d..01e636c 100644 --- a/test_settings.py +++ b/test_settings.py @@ -59,7 +59,12 @@ } ] -ASPECTS_INSTRUCTOR_DASHBOARD_UUID = "test-dashboard-uuid" +ASPECTS_INSTRUCTOR_DASHBOARDS = [ + { + "name": "Instructor Dashboard", + "uuid": "1d6bf904-f53f-47fd-b1c9-6cd7e284d286", + }, +] SUPERSET_EXTRA_FILTERS_FORMAT = []