Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: allow to embed dashboards in xblock #40

Merged
merged 4 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading