Skip to content
Open
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
2 changes: 1 addition & 1 deletion feedback/extensions/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from web_fragments.fragment import Fragment

try:
from cms.djangoapps.contentstore.utils import get_lms_link_for_item
from feedback.utils import get_lms_link_for_item
from lms.djangoapps.courseware.block_render import (get_block_by_usage_id,
load_single_xblock)
from openedx.core.djangoapps.enrollments.data import get_user_enrollments
Expand Down
2 changes: 2 additions & 0 deletions feedback/settings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@
}

SECRET_KEY = 'fake-key'

LMS_ROOT_URL = "https://example.com"
38 changes: 38 additions & 0 deletions feedback/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,44 @@
"""Utilities for feedback app"""

# feedbackblock/feedback/utils.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# feedbackblock/feedback/utils.py

comment is not necessary

from urllib.parse import urlencode, urlparse, urlunparse
from opaque_keys.edx.keys import UsageKey
from django.conf import settings
Comment on lines +4 to +6
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please follow the style guide for imports

Suggested change
from urllib.parse import urlencode, urlparse, urlunparse
from opaque_keys.edx.keys import UsageKey
from django.conf import settings
from urllib.parse import urlencode, urlparse, urlunparse
from django.conf import settings
from opaque_keys.edx.keys import UsageKey



def _(text):
"""Dummy `gettext` replacement to make string extraction tools scrape strings marked for translation"""
return text


def get_lms_link_for_item(location, preview=False):
"""
Returns an LMS link to the course with a jump_to to the provided location.
"""
assert isinstance(location, UsageKey)

try:
# pylint: disable=import-outside-toplevel
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally speaking, it is a bad pattern for plugins to import code from edx-platform, as it creates coupling between something that is supposed to be stable (the plugin) and something that is inherently unstable (edx-platform modules). However, I don't know of any better way to let this block access SiteConfiguration other than adding an new XBlock runtime service, and I don't think a new SiteConfig runtime service is a good idea either given that we want to move away from SiteConfig. So, long story short, this is a bad pattern, but I'm OK with it for this PR given that there's no better way and we need a quick fix for this bug.


except ImportError:
return None

lms_base = SiteConfiguration.get_value_for_org(
location.org,
"LMS_ROOT_URL",
settings.LMS_ROOT_URL
)

if lms_base is None:
return None

query_string = ''
if preview:
query_string = urlencode({'preview': '1'})

url_parts = list(urlparse(lms_base))
url_parts[2] = f'/courses/{location.course_key}/jump_to/{location}'
url_parts[4] = query_string

return urlunparse(url_parts)
62 changes: 62 additions & 0 deletions feedbacktests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from feedback.utils import get_lms_link_for_item
from opaque_keys.edx.keys import UsageKey
from unittest.mock import Mock
import sys
import types
Comment on lines +1 to +5
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import style

Suggested change
from feedback.utils import get_lms_link_for_item
from opaque_keys.edx.keys import UsageKey
from unittest.mock import Mock
import sys
import types
import sys
import types
from unittest.mock import Mock
from opaque_keys.edx.keys import UsageKey
from feedback.utils import get_lms_link_for_item



def test_get_lms_link_importerror(monkeypatch):
location = Mock(spec=UsageKey)
location.org = "edX"
location.course_key = "course-v1:edX+DemoX+2024"
location.__str__ = lambda self=location: "dummy"

if "openedx.core.djangoapps.site_configuration.models" in sys.modules:
del sys.modules["openedx.core.djangoapps.site_configuration.models"]

monkeypatch.setattr("feedback.utils.settings", types.SimpleNamespace(LMS_ROOT_URL="https://example.com"))

result = get_lms_link_for_item(location)
assert result is None

def test_get_lms_link_with_null_lms_base(monkeypatch):
location = Mock(spec=UsageKey)
location.org = "edX"
location.course_key = "dummy"
location.__str__ = lambda self=location: "dummy"

class MockSiteConfiguration:
@staticmethod
def get_value_for_org(org, key, default):
return None # simulate LMS base not set

monkeypatch.setitem(
sys.modules,
"openedx.core.djangoapps.site_configuration.models",
types.SimpleNamespace(SiteConfiguration=MockSiteConfiguration)
)

result = get_lms_link_for_item(location)
assert result is None


def test_get_lms_link_with_preview(monkeypatch):
location = Mock(spec=UsageKey)
location.org = "edX"
location.course_key = "course-v1:edX+DemoX+2024"
location.__str__ = lambda self=location: "dummy"

class MockSiteConfiguration:
@staticmethod
def get_value_for_org(org, key, default):
return "https://fallback.com"

monkeypatch.setitem(
sys.modules,
"openedx.core.djangoapps.site_configuration.models",
types.SimpleNamespace(SiteConfiguration=MockSiteConfiguration)
)

result = get_lms_link_for_item(location, preview=True)
assert result == "https://fallback.com/courses/course-v1:edX+DemoX+2024/jump_to/dummy?preview=1"