Skip to content

Commit

Permalink
Merge pull request #40 from openedx/cag/xblock-fix
Browse files Browse the repository at this point in the history
fix: allow to embed dashboards in xblock
  • Loading branch information
bmtcril authored May 1, 2024
2 parents 139f453 + 8841453 commit d9f8cc3
Show file tree
Hide file tree
Showing 10 changed files with 51 additions and 31 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ Unreleased

*

0.7.4 - 2024-04-30
******************

Fixed
=====
* Fixed Superset XBlock and default filters.

0.7.3 - 2024-04-30
******************

Expand Down
2 changes: 1 addition & 1 deletion platform_plugin_aspects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
import os
from pathlib import Path

__version__ = "0.7.3"
__version__ = "0.7.4"

ROOT_DIRECTORY = Path(os.path.dirname(os.path.abspath(__file__)))
2 changes: 1 addition & 1 deletion platform_plugin_aspects/static/html/superset.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ <h2>{{display_name}}</h2>
<p>{{exception}}</p>
{% elif not superset_dashboards %}
<p>Dashboard UUID is not set. Please set the dashboard UUID in the Studio.</p>
{% elif superset_url and superset_guest_token_url %} {% if xblock_id %}
{% elif superset_url %} {% if xblock_id %}
<div class="superset-embedded-container" id="superset-embedded-container-{{xblock_id}}"></div>
{% else %}
<div class="aspects-tabs">
Expand Down
17 changes: 14 additions & 3 deletions platform_plugin_aspects/static/js/embed_dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,22 @@ function getCookie(name) {
}

async function fetchGuestToken() {
const response = await fetch(superset_guest_token_url, {
method: 'GET',
let response;
if (window.from_xblock){
// XBlock handler requires a POST request and a JSON body
body = JSON.stringify({});
method = 'POST';
}else {
body = null;
method = 'GET';
}

response = await fetch(window.superset_guest_token_url, {
method: method,
headers: {
"X-CSRFToken": getCookie("csrftoken"),
}
},
body: body,
});

if (!response.ok) {
Expand Down
8 changes: 5 additions & 3 deletions platform_plugin_aspects/static/js/superset.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
function SupersetXBlock(runtime, element, context) {
const dashboard_uuid = context.dashboard_uuid;
const superset_url = context.superset_url;
const superset_guest_token_url = runtime.handlerUrl(element, 'get_superset_guest_token');
const xblock_id = context.xblock_id
const xblock_id = context.xblock_id;

window.superset_guest_token_url = runtime.handlerUrl(element, 'get_superset_guest_token');
window.from_xblock = true;

function initSuperset(supersetEmbeddedSdk) {
embedDashboard(dashboard_uuid, superset_url, superset_guest_token_url, xblock_id);
embedDashboard(dashboard_uuid, superset_url, xblock_id);
}

if (typeof require === "function") {
Expand Down
1 change: 0 additions & 1 deletion platform_plugin_aspects/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ def test_generate_superset_context(self):

self.assertEqual(len(context["superset_dashboards"]), len(dashboards))
self.assertEqual(context["superset_url"], "http://superset-dummy-url/")
self.assertNotIn("superset_token", context)
self.assertNotIn("exception", context)

@patch("platform_plugin_aspects.utils.SupersetClient")
Expand Down
12 changes: 3 additions & 9 deletions platform_plugin_aspects/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from opaque_keys.edx.keys import CourseKey
from rest_framework.test import APIClient

from ..views import Course, IsCourseStaffInstructor
from ..views import DEFAULT_FILTERS_FORMAT, IsCourseStaffInstructor

COURSE_ID = "course-v1:org+course+run"
User = get_user_model()
Expand Down Expand Up @@ -116,13 +116,7 @@ def test_guest_token_with_course_overview(
mock_model_get.assert_called_once()
mock_generate_guest_token.assert_called_once_with(
user=self.user,
course=Course(
course_id=CourseKey.from_string(COURSE_ID), display_name="Course Title"
),
course=CourseKey.from_string(COURSE_ID),
dashboards=settings.ASPECTS_INSTRUCTOR_DASHBOARDS,
filters=[
"org = 'org'",
"course_name = 'Course Title'",
"course_run = 'run'",
],
filters=DEFAULT_FILTERS_FORMAT,
)
10 changes: 9 additions & 1 deletion platform_plugin_aspects/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ def _(text):
return text


DEFAULT_FILTERS_FORMAT = [
"org = '{course_id.org}'",
"course_key = '{course_id}'",
]


def generate_superset_context(
context,
dashboards,
Expand Down Expand Up @@ -106,7 +112,9 @@ def generate_guest_token(user, course, dashboards, filters) -> str:
superset_username = superset_config.get("username")
superset_password = superset_config.get("password")

formatted_filters = [filter.format(course=course, user=user) for filter in filters]
formatted_filters = [
filter.format(course_id=course, user=user) for filter in filters
]

resources = []

Expand Down
11 changes: 3 additions & 8 deletions platform_plugin_aspects/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response

from .utils import _, generate_guest_token, get_model
from .utils import DEFAULT_FILTERS_FORMAT, _, generate_guest_token, get_model

try:
from openedx.core.lib.api.permissions import (
Expand Down Expand Up @@ -102,7 +102,7 @@ def get_object(self):
# May raise a permission denied
self.check_object_permissions(self.request, course)

return course
return course_key

@method_decorator(cache_page(60 * 5))
def get(self, request, *args, **kwargs):
Expand All @@ -111,11 +111,6 @@ def get(self, request, *args, **kwargs):
"""
course = self.get_object()

built_in_filters = [
f"org = '{course.course_id.org}'",
f"course_name = '{course.display_name}'",
f"course_run = '{course.course_id.run}'",
]
dashboards = settings.ASPECTS_INSTRUCTOR_DASHBOARDS
extra_filters_format = settings.SUPERSET_EXTRA_FILTERS_FORMAT

Expand All @@ -124,7 +119,7 @@ def get(self, request, *args, **kwargs):
user=request.user,
course=course,
dashboards=dashboards,
filters=built_in_filters + extra_filters_format,
filters=DEFAULT_FILTERS_FORMAT + extra_filters_format,
)
except ImproperlyConfigured as exc:
raise APIException() from exc
Expand Down
12 changes: 8 additions & 4 deletions platform_plugin_aspects/xblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@
from xblock.utils.resources import ResourceLoader
from xblock.utils.studio_editable import StudioEditableXBlockMixin

from .utils import _, generate_guest_token, generate_superset_context
from .utils import (
DEFAULT_FILTERS_FORMAT,
_,
generate_guest_token,
generate_superset_context,
)

log = logging.getLogger(__name__)
loader = ResourceLoader(__name__)
Expand Down Expand Up @@ -142,7 +147,6 @@ def student_view(self, context=None):
json_args={
"dashboard_uuid": self.dashboard_uuid,
"superset_url": context.get("superset_url"),
"superset_token": context.get("superset_token"),
"xblock_id": context.get("xblock_id"),
},
)
Expand Down Expand Up @@ -198,9 +202,9 @@ def get_superset_guest_token(
try:
guest_token = generate_guest_token(
user=user,
course=self.runtime.course_id,
course=self.scope_ids.usage_id.context_key,
dashboards=self.dashboards(),
filters=self.filters,
filters=DEFAULT_FILTERS_FORMAT + self.filters,
)
except ImproperlyConfigured as exc:
raise JsonHandlerError(500, str(exc)) from exc
Expand Down

0 comments on commit d9f8cc3

Please sign in to comment.