diff --git a/openedx_learning/apps/authoring/components/api.py b/openedx_learning/apps/authoring/components/api.py index 22750d9d..f4e5fdfe 100644 --- a/openedx_learning/apps/authoring/components/api.py +++ b/openedx_learning/apps/authoring/components/api.py @@ -12,6 +12,7 @@ """ from __future__ import annotations +import mimetypes from datetime import datetime, timezone from enum import StrEnum, auto from logging import getLogger @@ -129,7 +130,7 @@ def create_component_version( def create_next_component_version( component_pk: int, /, - content_to_replace: dict[str, int | None], + content_to_replace: dict[str, int | None | bytes], created: datetime, title: str | None = None, created_by: int | None = None, @@ -191,6 +192,20 @@ def create_next_component_version( # content represented by our key from the next version. Otherwise, # we add our key->content_pk mapping to the next version. if content_pk is not None: + if isinstance(content_pk, bytes): + file_path, file_content = key, content_pk + media_type_str, _encoding = mimetypes.guess_type(file_path) + # We use "application/octet-stream" as a generic fallback media type, per + # RFC 2046: https://datatracker.ietf.org/doc/html/rfc2046 + media_type_str = media_type_str or "application/octet-stream" + media_type = contents_api.get_or_create_media_type(media_type_str) + content = contents_api.get_or_create_file_content( + component.publishable_entity.learning_package.id, + media_type.id, + data=file_content, + created=created, + ) + content_pk = content.pk ComponentVersionContent.objects.create( content_id=content_pk, component_version=component_version, diff --git a/openedx_learning/apps/authoring/components/management/commands/add_assets_to_component.py b/openedx_learning/apps/authoring/components/management/commands/add_assets_to_component.py index 3b37eda1..6e4f1aef 100644 --- a/openedx_learning/apps/authoring/components/management/commands/add_assets_to_component.py +++ b/openedx_learning/apps/authoring/components/management/commands/add_assets_to_component.py @@ -4,14 +4,12 @@ This is mostly meant to be a debugging tool to let us to easily load some test asset data into the system. """ -import mimetypes import pathlib from datetime import datetime, timezone from django.core.management.base import BaseCommand from ....components.api import create_component_version_content -from ....contents.api import get_or_create_file_content, get_or_create_media_type from ....publishing.api import get_learning_package_by_key from ...api import create_next_component_version, get_component_by_key @@ -70,7 +68,7 @@ def handle(self, *args, **options): created = datetime.now(tz=timezone.utc) keys_to_remove = set() - local_keys_to_content = {} + local_keys_to_raw_content = {} for file_mapping in file_mappings: local_key, file_path = file_mapping.split(":", 1) @@ -80,22 +78,14 @@ def handle(self, *args, **options): keys_to_remove.add(local_key) continue - media_type_str, _encoding = mimetypes.guess_type(file_path) - media_type = get_or_create_media_type(media_type_str) - content = get_or_create_file_content( - learning_package.id, - media_type.id, - data=pathlib.Path(file_path).read_bytes(), - created=created, - ) - local_keys_to_content[local_key] = content.id + local_keys_to_raw_content[local_key] = pathlib.Path(file_path).read_bytes() next_version = create_next_component_version( component.pk, content_to_replace={local_key: None for local_key in keys_to_remove}, created=created, ) - for local_key, content_id in sorted(local_keys_to_content.items()): + for local_key, content_id in sorted(local_keys_to_raw_content.items()): create_component_version_content( next_version.pk, content_id, diff --git a/tests/openedx_learning/apps/authoring/components/test_api.py b/tests/openedx_learning/apps/authoring/components/test_api.py index 9cb761da..7a9537b1 100644 --- a/tests/openedx_learning/apps/authoring/components/test_api.py +++ b/tests/openedx_learning/apps/authoring/components/test_api.py @@ -442,13 +442,14 @@ def test_multiple_versions(self): content_to_replace={ "hello.txt": hello_content.pk, "goodbye.txt": goodbye_content.pk, + "raw.txt": b'raw content', }, created=self.now, ) assert version_1.version_num == 1 assert version_1.title == "Problem Version 1" version_1_contents = list(version_1.contents.all()) - assert len(version_1_contents) == 2 + assert len(version_1_contents) == 3 assert ( hello_content == version_1.contents @@ -472,7 +473,7 @@ def test_multiple_versions(self): created=self.now, ) assert version_2.version_num == 2 - assert version_2.contents.count() == 3 + assert version_2.contents.count() == 4 assert ( blank_content == version_2.contents @@ -503,7 +504,7 @@ def test_multiple_versions(self): created=self.now, ) assert version_3.version_num == 3 - assert version_3.contents.count() == 1 + assert version_3.contents.count() == 2 assert ( hello_content == version_3.contents