-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: new view & API calls to serve content library assets (#35639)
This commit adds a new view to serve static assets for content libraries, along with Content Library API calls to add, delete, and get metadata about these assets. These assets come from Learning Core and should ONLY BE ACCESSED FROM STUDIO. Users must have read access to the library in order to see an asset in that library. This also re-implements video transcript support for content libraries and re-enables some previously disabled tests around it.
- Loading branch information
Showing
7 changed files
with
394 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,16 @@ | ||
""" | ||
Tests for static asset files in Learning-Core-based Content Libraries | ||
""" | ||
from unittest import skip | ||
from uuid import UUID | ||
|
||
from opaque_keys.edx.keys import UsageKey | ||
|
||
from common.djangoapps.student.tests.factories import UserFactory | ||
from openedx.core.djangoapps.content_libraries.tests.base import ( | ||
ContentLibrariesRestApiTest, | ||
) | ||
from openedx.core.djangoapps.xblock.api import get_component_from_usage_key | ||
from openedx.core.djangolib.testing.utils import skip_unless_cms | ||
|
||
# Binary data representing an SVG image file | ||
SVG_DATA = """<svg xmlns="http://www.w3.org/2000/svg" height="30" width="100"> | ||
|
@@ -23,15 +28,10 @@ | |
""" | ||
|
||
|
||
@skip("Assets are being reimplemented in Learning Core. Disable until that's ready.") | ||
@skip_unless_cms | ||
class ContentLibrariesStaticAssetsTest(ContentLibrariesRestApiTest): | ||
""" | ||
Tests for static asset files in Learning-Core-based Content Libraries | ||
WARNING: every test should have a unique library slug, because even though | ||
the django/mysql database gets reset for each test case, the lookup between | ||
library slug and bundle UUID does not because it's assumed to be immutable | ||
and cached forever. | ||
""" | ||
|
||
def test_asset_filenames(self): | ||
|
@@ -79,7 +79,7 @@ def test_video_transcripts(self): | |
/> | ||
""") | ||
# Upload the transcript file | ||
self._set_library_block_asset(block_id, "3_yD_cEKoCk-en.srt", TRANSCRIPT_DATA) | ||
self._set_library_block_asset(block_id, "static/3_yD_cEKoCk-en.srt", TRANSCRIPT_DATA) | ||
|
||
transcript_handler_url = self._get_block_handler_url(block_id, "transcript") | ||
|
||
|
@@ -108,3 +108,79 @@ def check_download(): | |
self._commit_library_changes(library["id"]) | ||
check_sjson() | ||
check_download() | ||
|
||
|
||
@skip_unless_cms | ||
class ContentLibrariesComponentVersionAssetTest(ContentLibrariesRestApiTest): | ||
""" | ||
Tests for the view that actually delivers the Library asset in Studio. | ||
""" | ||
|
||
def setUp(self): | ||
super().setUp() | ||
|
||
library = self._create_library(slug="asset-lib2", title="Static Assets Test Library") | ||
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.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" | ||
) | ||
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" | ||
) | ||
assert good_head_response.headers == get_response.headers | ||
|
||
def test_missing(self): | ||
"""Test asset requests that should 404.""" | ||
# 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" | ||
) | ||
assert response.status_code == 404 | ||
|
||
# Non-existent file... | ||
response = self.client.get( | ||
f"/library_assets/{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" | ||
) | ||
assert response.status_code == 404 | ||
|
||
def test_anonymous_user(self): | ||
"""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" | ||
) | ||
assert response.status_code == 403 | ||
|
||
def test_unauthorized_user(self): | ||
"""User who is not a Content Library staff should not have access.""" | ||
self.client.logout() | ||
student = UserFactory.create( | ||
username="student", | ||
email="[email protected]", | ||
password="student-pass", | ||
is_staff=False, | ||
is_superuser=False, | ||
) | ||
self.client.login(username="student", password="student-pass") | ||
get_response = self.client.get( | ||
f"/library_assets/{self.draft_component_version.uuid}/static/test.svg" | ||
) | ||
assert get_response.status_code == 403 |
Oops, something went wrong.