Skip to content

Commit 0bd0e6f

Browse files
authored
refactor: Update get block OLX view to support versions [FC-0062] (#35932)
* Deprecate `get_block_draft_olx` * Deprecate get olx view in content libraries * Create `get_block_olx` in xblock API with support of versions * Create get olx view in xblock
1 parent 60aa299 commit 0bd0e6f

File tree

7 files changed

+84
-10
lines changed

7 files changed

+84
-10
lines changed

openedx/core/djangoapps/content_libraries/views.py

+3
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,9 @@ class LibraryBlockOlxView(APIView):
710710
@convert_exceptions
711711
def get(self, request, usage_key_str):
712712
"""
713+
DEPRECATED. Use get_block_olx_view() in xblock REST-API.
714+
Can be removed post-Teak.
715+
713716
Get the block's OLX
714717
"""
715718
key = LibraryUsageLocatorV2.from_string(usage_key_str)

openedx/core/djangoapps/xblock/api.py

+28-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@
3333
LearningCoreXBlockRuntime,
3434
)
3535
from .data import CheckPerm, LatestVersion
36-
from .utils import get_secure_token_for_xblock_handler, get_xblock_id_for_anonymous_user
36+
from .rest_api.url_converters import VersionConverter
37+
from .utils import (
38+
get_secure_token_for_xblock_handler,
39+
get_xblock_id_for_anonymous_user,
40+
get_auto_latest_version,
41+
)
3742

3843
from .runtime.learning_core_runtime import LearningCoreXBlockRuntime
3944

@@ -208,13 +213,26 @@ def get_component_from_usage_key(usage_key: UsageKeyV2) -> Component:
208213
)
209214

210215

211-
def get_block_draft_olx(usage_key: UsageKeyV2) -> str:
216+
def get_block_olx(
217+
usage_key: UsageKeyV2,
218+
*,
219+
version: int | LatestVersion = LatestVersion.AUTO
220+
) -> str:
212221
"""
213-
Get the OLX source of the draft version of the given Learning-Core-backed XBlock.
222+
Get the OLX source of the of the given Learning-Core-backed XBlock and a version.
214223
"""
215-
# Inefficient but simple approach. Optimize later if needed.
216224
component = get_component_from_usage_key(usage_key)
217-
component_version = component.versioning.draft
225+
version = get_auto_latest_version(version)
226+
227+
if version == LatestVersion.DRAFT:
228+
component_version = component.versioning.draft
229+
elif version == LatestVersion.PUBLISHED:
230+
component_version = component.versioning.published
231+
else:
232+
assert isinstance(version, int)
233+
component_version = component.versioning.version_num(version)
234+
if component_version is None:
235+
raise NoSuchUsage(usage_key)
218236

219237
# TODO: we should probably make a method on ComponentVersion that returns
220238
# a content based on the name. Accessing by componentversioncontent__key is
@@ -224,6 +242,11 @@ def get_block_draft_olx(usage_key: UsageKeyV2) -> str:
224242
return content.text
225243

226244

245+
def get_block_draft_olx(usage_key: UsageKeyV2) -> str:
246+
""" DEPRECATED. Use get_block_olx(). Can be removed post-Teak. """
247+
return get_block_olx(usage_key, version=LatestVersion.DRAFT)
248+
249+
227250
def render_block_view(block, view_name, user): # pylint: disable=unused-argument
228251
"""
229252
Get the HTML, JS, and CSS needed to render the given XBlock view.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""
2+
Serializers for the xblock REST API
3+
"""
4+
from rest_framework import serializers
5+
6+
7+
class XBlockOlxSerializer(serializers.Serializer):
8+
"""
9+
Serializer for representing an XBlock's OLX
10+
"""
11+
olx = serializers.CharField()

openedx/core/djangoapps/xblock/rest_api/urls.py

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
path('', views.block_metadata),
2020
# get/post full json fields of an XBlock:
2121
path('fields/', views.BlockFieldsView.as_view()),
22+
# Get the OLX source code of the specified block
23+
path('olx/', views.get_block_olx_view),
2224
# render one of this XBlock's views (e.g. student_view)
2325
path('view/<str:view_name>/', views.render_block_view),
2426
# get the URL needed to call this XBlock's handlers

openedx/core/djangoapps/xblock/rest_api/views.py

+19
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@
3333
get_handler_url as _get_handler_url,
3434
load_block,
3535
render_block_view as _render_block_view,
36+
get_block_olx,
3637
)
3738
from ..utils import validate_secure_token_for_xblock_handler
3839
from .url_converters import VersionConverter
40+
from .serializers import XBlockOlxSerializer
3941

4042
User = get_user_model()
4143

@@ -213,6 +215,23 @@ def xblock_handler(
213215
return response
214216

215217

218+
@api_view(['GET'])
219+
@view_auth_classes(is_authenticated=False)
220+
def get_block_olx_view(
221+
request,
222+
usage_key: UsageKeyV2,
223+
version: LatestVersion | int = LatestVersion.AUTO,
224+
):
225+
"""
226+
Get the OLX (XML serialization) of the specified XBlock
227+
"""
228+
context_impl = get_learning_context_impl(usage_key)
229+
if not context_impl.can_view_block_for_editing(request.user, usage_key):
230+
raise PermissionDenied(f"You don't have permission to access the OLX of component '{usage_key}'.")
231+
olx = get_block_olx(usage_key, version=version)
232+
return Response(XBlockOlxSerializer({"olx": olx}).data)
233+
234+
216235
def cors_allow_xblock_handler(sender, request, **kwargs): # lint-amnesty, pylint: disable=unused-argument
217236
"""
218237
Sandboxed XBlocks need to be able to call XBlock handlers via POST,

openedx/core/djangoapps/xblock/runtime/learning_core_runtime.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from openedx.core.lib.xblock_serializer.api import serialize_modulestore_block_for_learning_core
2525
from openedx.core.lib.xblock_serializer.data import StaticFile
2626
from ..data import AuthoredDataMode, LatestVersion
27+
from ..utils import get_auto_latest_version
2728
from ..learning_context.manager import get_learning_context_impl
2829
from .runtime import XBlockRuntime
2930

@@ -178,11 +179,7 @@ def get_block(self, usage_key, for_parent=None, *, version: int | LatestVersion
178179
# just get it the easy way.
179180
component = self._get_component_from_usage_key(usage_key)
180181

181-
if version == LatestVersion.AUTO:
182-
if self.authored_data_mode == AuthoredDataMode.DEFAULT_DRAFT:
183-
version = LatestVersion.DRAFT
184-
else:
185-
version = LatestVersion.PUBLISHED
182+
version = get_auto_latest_version(version)
186183
if self.authored_data_mode == AuthoredDataMode.STRICTLY_PUBLISHED and version != LatestVersion.PUBLISHED:
187184
raise ValidationError("This runtime only allows accessing the published version of components")
188185
if version == LatestVersion.DRAFT:

openedx/core/djangoapps/xblock/utils.py

+19
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
import crum
1212
from django.conf import settings
1313

14+
from openedx.core.djangoapps.xblock.apps import get_xblock_app_config
15+
16+
from .data import AuthoredDataMode, LatestVersion
17+
1418

1519
def get_secure_token_for_xblock_handler(user_id, block_key_str, time_idx=0):
1620
"""
@@ -167,3 +171,18 @@ def get_xblock_id_for_anonymous_user(user):
167171
return current_request.session["xblock_id_for_anonymous_user"]
168172
else:
169173
raise RuntimeError("Cannot get a user ID for an anonymous user outside of an HTTP request context.")
174+
175+
176+
def get_auto_latest_version(version: int | LatestVersion) -> int | LatestVersion:
177+
"""
178+
Gets the actual LatestVersion if is `LatestVersion.AUTO`;
179+
otherwise, returns the same value.
180+
"""
181+
if version == LatestVersion.AUTO:
182+
authored_data_mode = get_xblock_app_config().get_runtime_params()["authored_data_mode"]
183+
version = (
184+
LatestVersion.DRAFT
185+
if authored_data_mode == AuthoredDataMode.DEFAULT_DRAFT
186+
else LatestVersion.PUBLISHED
187+
)
188+
return version

0 commit comments

Comments
 (0)