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

refactor: Update get block OLX view to support versions [FC-0062] #35932

Merged
4 changes: 2 additions & 2 deletions openedx/core/djangoapps/content_libraries/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,9 @@ def _delete_library_block(self, block_key, expect_response=200):
""" Delete a specific block from the library """
self._api('delete', URL_LIB_BLOCK.format(block_key=block_key), None, expect_response)

def _get_library_block_olx(self, block_key, expect_response=200):
def _get_library_block_olx(self, block_key, version="draft", expect_response=200):
""" Get the OLX of a specific block in the library """
result = self._api('get', URL_LIB_BLOCK_OLX.format(block_key=block_key), None, expect_response)
result = self._api('get', URL_LIB_BLOCK_OLX.format(block_key=block_key), {"version": version}, expect_response)
if expect_response == 200:
return result["olx"]
return result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,14 @@ def test_library_blocks(self): # pylint: disable=too-many-statements
assert published_block_data['published_by'] == "Bob"
assert published_block_data['has_unpublished_changes'] is False

# Updated OLX and verify draft and published version
published_olx = new_olx
draft_olx = "<problem><p>Not Published OLX</p></problem>"

self._set_library_block_olx(block_id, draft_olx)
assert self._get_library_block_olx(block_id, version='published') == published_olx
assert self._get_library_block_olx(block_id, version='draft') == draft_olx

# fin

def test_library_blocks_studio_view(self):
Expand Down
7 changes: 6 additions & 1 deletion openedx/core/djangoapps/content_libraries/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,8 +713,13 @@ def get(self, request, usage_key_str):
Get the block's OLX
"""
key = LibraryUsageLocatorV2.from_string(usage_key_str)
version = request.query_params.get('version', None)
ChrisChV marked this conversation as resolved.
Show resolved Hide resolved

# Use the default `LatestVersion.AUTO` if `version` is None
version = xblock_api.string_to_version(version)
ChrisChV marked this conversation as resolved.
Show resolved Hide resolved

api.require_permission_for_library_key(key.lib_key, request.user, permissions.CAN_VIEW_THIS_CONTENT_LIBRARY)
xml_str = xblock_api.get_block_draft_olx(key)
xml_str = xblock_api.get_block_olx(key, request.user, version=version)
return Response(LibraryXBlockOlxSerializer({"olx": xml_str}).data)

@convert_exceptions
Expand Down
29 changes: 25 additions & 4 deletions openedx/core/djangoapps/xblock/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
LearningCoreXBlockRuntime,
)
from .data import CheckPerm, LatestVersion
from .rest_api.url_converters import VersionConverter
from .utils import get_secure_token_for_xblock_handler, get_xblock_id_for_anonymous_user

from .runtime.learning_core_runtime import LearningCoreXBlockRuntime
Expand Down Expand Up @@ -208,13 +209,28 @@ def get_component_from_usage_key(usage_key: UsageKeyV2) -> Component:
)


def get_block_draft_olx(usage_key: UsageKeyV2) -> str:
def get_block_olx(
usage_key: UsageKeyV2,
user: UserType,
*,
version: int | LatestVersion = LatestVersion.AUTO
) -> str:
ChrisChV marked this conversation as resolved.
Show resolved Hide resolved
"""
Get the OLX source of the draft version of the given Learning-Core-backed XBlock.
Get the OLX source of the of the given Learning-Core-backed XBlock and a version.
"""
# Inefficient but simple approach. Optimize later if needed.
component = get_component_from_usage_key(usage_key)
component_version = component.versioning.draft
runtime = get_runtime(user=user)
version = runtime.get_auto_latest_version(version)
ChrisChV marked this conversation as resolved.
Show resolved Hide resolved

if version == LatestVersion.DRAFT:
component_version = component.versioning.draft
elif version == LatestVersion.PUBLISHED:
component_version = component.versioning.published
else:
assert isinstance(version, int)
component_version = component.versioning.version_num(version)
if component_version is None:
raise NoSuchUsage(usage_key)

# TODO: we should probably make a method on ComponentVersion that returns
# a content based on the name. Accessing by componentversioncontent__key is
Expand Down Expand Up @@ -307,3 +323,8 @@ def get_handler_url(
# can be called by the XBlock from python as well and in that case we don't
# have access to the request.
return site_root_url + path


def string_to_version(version: str | None) -> LatestVersion | int:
""" Convert from string to LatestVersion or integer version spec """
return VersionConverter().to_python(version)
bradenmacdonald marked this conversation as resolved.
Show resolved Hide resolved
18 changes: 13 additions & 5 deletions openedx/core/djangoapps/xblock/runtime/learning_core_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,7 @@ def get_block(self, usage_key, for_parent=None, *, version: int | LatestVersion
# just get it the easy way.
component = self._get_component_from_usage_key(usage_key)

if version == LatestVersion.AUTO:
if self.authored_data_mode == AuthoredDataMode.DEFAULT_DRAFT:
version = LatestVersion.DRAFT
else:
version = LatestVersion.PUBLISHED
version = self.get_auto_latest_version(version)
if self.authored_data_mode == AuthoredDataMode.STRICTLY_PUBLISHED and version != LatestVersion.PUBLISHED:
raise ValidationError("This runtime only allows accessing the published version of components")
if version == LatestVersion.DRAFT:
Expand Down Expand Up @@ -316,6 +312,18 @@ def save_block(self, block):
)
self.authored_data_store.mark_unchanged(block)

def get_auto_latest_version(self, version: int | LatestVersion) -> int | LatestVersion:
"""
Gets the actual LatesVersion if is `LatestVersion.AUTO`;
ChrisChV marked this conversation as resolved.
Show resolved Hide resolved
otherwise, returns the same value.
"""
if version == LatestVersion.AUTO:
if self.authored_data_mode == AuthoredDataMode.DEFAULT_DRAFT:
return LatestVersion.DRAFT
else:
return LatestVersion.PUBLISHED
return version

def _get_component_from_usage_key(self, usage_key):
"""
Note that Components aren't ever really truly deleted, so this will
Expand Down
Loading