diff --git a/openedx/core/djangoapps/content_libraries/tests/test_embed_block.py b/openedx/core/djangoapps/content_libraries/tests/test_embed_block.py index a554e6157e..e9909b7d60 100644 --- a/openedx/core/djangoapps/content_libraries/tests/test_embed_block.py +++ b/openedx/core/djangoapps/content_libraries/tests/test_embed_block.py @@ -219,8 +219,8 @@ class LibrariesEmbedViewTestCase(ContentLibrariesRestApiTest, OpenEdxEventsTestM # show up. html = self._embed_block(block_id, version='published') # This is the pattern we're looking for: - # - assert re.search(r'/library_assets/[0-9a-f-]*/static/deer.jpg', html) + # + assert re.search(r'/library_assets/component_versions/[0-9a-f-]*/static/deer.jpg', html) # Now grab the draft version (4), which is going to once again not have # the asset (because we deleted it). diff --git a/openedx/core/djangoapps/content_libraries/tests/test_static_assets.py b/openedx/core/djangoapps/content_libraries/tests/test_static_assets.py index a5f69f94b1..b903a0ca97 100644 --- a/openedx/core/djangoapps/content_libraries/tests/test_static_assets.py +++ b/openedx/core/djangoapps/content_libraries/tests/test_static_assets.py @@ -123,19 +123,20 @@ class ContentLibrariesComponentVersionAssetTest(ContentLibrariesRestApiTest): block = self._add_block_to_library(library["id"], "html", "html1") self._set_library_block_asset(block["id"], "static/test.svg", SVG_DATA) usage_key = UsageKey.from_string(block["id"]) + self.usage_key = usage_key self.component = get_component_from_usage_key(usage_key) self.draft_component_version = self.component.versioning.draft def test_good_responses(self): get_response = self.client.get( - f"/library_assets/{self.draft_component_version.uuid}/static/test.svg" + f"/library_assets/component_versions/{self.draft_component_version.uuid}/static/test.svg" ) assert get_response.status_code == 200 content = b''.join(chunk for chunk in get_response.streaming_content) assert content == SVG_DATA good_head_response = self.client.head( - f"/library_assets/{self.draft_component_version.uuid}/static/test.svg" + f"/library_assets/component_versions/{self.draft_component_version.uuid}/static/test.svg" ) assert good_head_response.headers == get_response.headers @@ -144,20 +145,20 @@ class ContentLibrariesComponentVersionAssetTest(ContentLibrariesRestApiTest): # Non-existent version... wrong_version_uuid = UUID('11111111-1111-1111-1111-111111111111') response = self.client.get( - f"/library_assets/{wrong_version_uuid}/static/test.svg" + f"/library_assets/component_versions/{wrong_version_uuid}/static/test.svg" ) assert response.status_code == 404 # Non-existent file... response = self.client.get( - f"/library_assets/{self.draft_component_version.uuid}/static/missing.svg" + f"/library_assets/component_versions/{self.draft_component_version.uuid}/static/missing.svg" ) assert response.status_code == 404 # File-like ComponenVersionContent entry that isn't an actually # downloadable file... response = self.client.get( - f"/library_assets/{self.draft_component_version.uuid}/block.xml" + f"/library_assets/component_versions/{self.draft_component_version.uuid}/block.xml" ) assert response.status_code == 404 @@ -165,7 +166,7 @@ class ContentLibrariesComponentVersionAssetTest(ContentLibrariesRestApiTest): """Anonymous users shouldn't get access to library assets.""" self.client.logout() response = self.client.get( - f"/library_assets/{self.draft_component_version.uuid}/static/test.svg" + f"/library_assets/component_versions/{self.draft_component_version.uuid}/static/test.svg" ) assert response.status_code == 403 @@ -181,6 +182,32 @@ class ContentLibrariesComponentVersionAssetTest(ContentLibrariesRestApiTest): ) self.client.login(username="student", password="student-pass") get_response = self.client.get( - f"/library_assets/{self.draft_component_version.uuid}/static/test.svg" + f"/library_assets/component_versions/{self.draft_component_version.uuid}/static/test.svg" ) assert get_response.status_code == 403 + + def test_draft_version(self): + """Get draft version of asset""" + get_response = self.client.get( + f"/library_assets/blocks/{self.usage_key}/static/test.svg" + ) + assert get_response.status_code == 200 + content = b''.join(chunk for chunk in get_response.streaming_content) + assert content == SVG_DATA + + good_head_response = self.client.head( + f"/library_assets/blocks/{self.usage_key}/static/test.svg" + ) + assert good_head_response.headers == get_response.headers + + def test_draft_version_404(self): + """Get draft version of asset""" + get_response = self.client.get( + f"/library_assets/blocks/{self.usage_key}@/static/test.svg" + ) + assert get_response.status_code == 404 + + get_response = self.client.get( + f"/library_assets/blocks/{self.usage_key}/static/test2.svg" + ) + assert get_response.status_code == 404 diff --git a/openedx/core/djangoapps/content_libraries/urls.py b/openedx/core/djangoapps/content_libraries/urls.py index 7806c75500..5bf36162d5 100644 --- a/openedx/core/djangoapps/content_libraries/urls.py +++ b/openedx/core/djangoapps/content_libraries/urls.py @@ -76,9 +76,17 @@ urlpatterns = [ path('pub/jwks/', views.LtiToolJwksView.as_view(), name='lti-pub-jwks'), ])), ])), - path( - 'library_assets//', - views.component_version_asset, - name='library-assets', + path('library_assets/', include([ + path( + 'component_versions//', + views.component_version_asset, + name='library-assets', + ), + path( + 'blocks//', + views.component_draft_asset, + name='library-draft-assets', + ), + ]) ), ] diff --git a/openedx/core/djangoapps/content_libraries/views.py b/openedx/core/djangoapps/content_libraries/views.py index 585b08535d..50b532f25b 100644 --- a/openedx/core/djangoapps/content_libraries/views.py +++ b/openedx/core/djangoapps/content_libraries/views.py @@ -1237,3 +1237,18 @@ def component_version_asset(request, component_version_uuid, asset_path): content.read_file().chunks(), headers=redirect_response.headers, ) + + +@require_safe +def component_draft_asset(request, usage_key, asset_path): + """ + Serves the draft version of static assets associated with a Library Component. + + See `component_version_asset` for more details + """ + try: + component_version_uuid = api.get_component_from_usage_key(usage_key).versioning.draft.uuid + except ObjectDoesNotExist as exc: + raise Http404() from exc + + return component_version_asset(request, component_version_uuid, asset_path) diff --git a/openedx/core/djangoapps/xblock/runtime/learning_core_runtime.py b/openedx/core/djangoapps/xblock/runtime/learning_core_runtime.py index 0942a5a8b3..1d1df738ab 100644 --- a/openedx/core/djangoapps/xblock/runtime/learning_core_runtime.py +++ b/openedx/core/djangoapps/xblock/runtime/learning_core_runtime.py @@ -377,7 +377,7 @@ class LearningCoreXBlockRuntime(XBlockRuntime): then this method will be called with asset_path="test.png" and should return a URL like: - http://studio.local.openedx.io:8001/library_assets/cd31871e-a342-4c3f-ba2f-a661bf630996/static/test.png + http://studio.local.openedx.io:8001/library_assets/component_versions/cd31871e-a342-4c3f-ba2f-a661bf630996/static/test.png If the asset file is not recognized, return None