Skip to content

Commit f7229c2

Browse files
committed
refactor!: move "contents" applet to "media" (0.35.0)
BREAKING CHANGE for openedx-platform, as API function signatures and model relations in openedx_content have changed: - get_content -> get_media - get_content_info_headers -> get_media_info_headers - get_or_create_text_content -> get_or_create_text_media - get_or_create_file_content -> get_or_create_file_media - create_component_version_media -> create_component_version_media - look_up_component_version_content -> look_up_component_version_media - Content -> Media - ComponentVersionContent -> ComponentVersionMedia - ComponentVersion.contents -> ComponentVersion.media The rationale for this change is that we use the term "content" as a generic way to talk about all kinds of things: components, units, courses, etc. We've also recently refactored so that the entire app is called openedx_content. Changing our terminology to refer to raw data blobs as "media" helps to reduce confusion. Updates version to 0.35.0.
1 parent 6bdab16 commit f7229c2

File tree

25 files changed

+434
-380
lines changed

25 files changed

+434
-380
lines changed

.importlinter

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ layers=
5050
# has no child elements.
5151
openedx_content.applets.components
5252

53-
# The "contents" applet stores the simplest pieces of binary and text data,
53+
# The "media" applet stores the simplest pieces of binary and text data,
5454
# without versioning information. These belong to a single Learning Package.
55-
openedx_content.applets.contents
55+
openedx_content.applets.media
5656

5757
# The "collections" applet stores arbitrary groupings of PublishableEntities.
5858
# Its only dependency should be the publishing app.

olx_importer/management/commands/load_components.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,15 @@ def create_content(self, static_local_path, now, component_version):
114114
logger.warning(f' Static reference not found: "{real_path}"')
115115
return # Might as well bail if we can't find the file.
116116

117-
content = content_api.get_or_create_file_content(
117+
media = content_api.get_or_create_file_media(
118118
self.learning_package.id,
119119
data=data_bytes,
120120
mime_type=mime_type,
121121
created=now,
122122
)
123-
content_api.create_component_version_content(
123+
content_api.create_component_version_media(
124124
component_version,
125-
content.id,
125+
media.id,
126126
key=key,
127127
)
128128

@@ -163,14 +163,14 @@ def import_block_type(self, block_type_name, now): # , publish_log_entry):
163163

164164
# Create the Content entry for the raw data...
165165
text = xml_file_path.read_text('utf-8')
166-
text_content, _created = content_api.get_or_create_text_content(
166+
text_content, _created = content_api.get_or_create_text_media(
167167
self.learning_package.id,
168168
text=text,
169169
mime_type=f"application/vnd.openedx.xblock.v1.{block_type_name}+xml",
170170
created=now,
171171
)
172172
# Add the OLX source text to the ComponentVersion
173-
content_api.create_component_version_content(
173+
content_api.create_component_version_media(
174174
component_version,
175175
text_content.pk,
176176
key="block.xml",

src/openedx_content/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .applets.backup_restore.admin import *
77
from .applets.collections.admin import *
88
from .applets.components.admin import *
9-
from .applets.contents.admin import *
9+
from .applets.media.admin import *
1010
from .applets.publishing.admin import *
1111
from .applets.sections.admin import *
1212
from .applets.subsections.admin import *

src/openedx_content/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from .applets.backup_restore.api import *
1414
from .applets.collections.api import *
1515
from .applets.components.api import *
16-
from .applets.contents.api import *
16+
from .applets.media.api import *
1717
from .applets.publishing.api import *
1818
from .applets.sections.api import *
1919
from .applets.subsections.api import *

src/openedx_content/applets/backup_restore/zipper.py

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@
2222
Collection,
2323
ComponentType,
2424
ComponentVersion,
25-
ComponentVersionContent,
26-
Content,
25+
ComponentVersionMedia,
2726
LearningPackage,
27+
Media,
2828
PublishableEntity,
2929
PublishableEntityVersion,
3030
)
3131

3232
from ..collections import api as collections_api
3333
from ..components import api as components_api
34-
from ..contents import api as contents_api
34+
from ..media import api as media_api
3535
from ..publishing import api as publishing_api
3636
from ..sections import api as sections_api
3737
from ..subsections import api as subsections_api
@@ -191,14 +191,14 @@ def get_publishable_entities(self) -> QuerySet[PublishableEntity]:
191191
# especially with large libraries (up to 100K items),
192192
# which is too large for this type of prefetch.
193193
Prefetch(
194-
"draft__version__componentversion__componentversioncontent_set",
195-
queryset=ComponentVersionContent.objects.select_related("content"),
196-
to_attr="prefetched_contents",
194+
"draft__version__componentversion__componentversionmedia_set",
195+
queryset=ComponentVersionMedia.objects.select_related("media"),
196+
to_attr="prefetched_media",
197197
),
198198
Prefetch(
199-
"published__version__componentversion__componentversioncontent_set",
200-
queryset=ComponentVersionContent.objects.select_related("content"),
201-
to_attr="prefetched_contents",
199+
"published__version__componentversion__componentversionmedia_set",
200+
queryset=ComponentVersionMedia.objects.select_related("media"),
201+
to_attr="prefetched_media",
202202
),
203203
)
204204
.order_by("key")
@@ -372,29 +372,29 @@ def create_zip(self, path: str) -> None:
372372
# ------ COMPONENT STATIC CONTENT -------------
373373
component_version: ComponentVersion = version.componentversion
374374

375-
# Get content data associated with this version
376-
contents: QuerySet[
377-
ComponentVersionContent
378-
] = component_version.prefetched_contents # type: ignore[attr-defined]
375+
# Get media data associated with this version
376+
prefetched_media: QuerySet[
377+
ComponentVersionMedia
378+
] = component_version.prefetched_media # type: ignore[attr-defined]
379379

380-
for component_version_content in contents:
381-
content: Content = component_version_content.content
380+
for component_version_media in prefetched_media:
381+
media: Media = component_version_media.media
382382

383-
# Important: The component_version_content.key contains implicitly
383+
# Important: The component_version_media.key contains implicitly
384384
# the file name and the file extension
385-
file_path = version_folder / component_version_content.key
385+
file_path = version_folder / component_version_media.key
386386

387-
if content.has_file and content.path:
387+
if media.has_file and media.path:
388388
# If has_file, we pull it from the file system
389-
with content.read_file() as f:
389+
with media.read_file() as f:
390390
file_data = f.read()
391-
elif not content.has_file and content.text:
392-
# Otherwise, we use the text content as the file data
393-
file_data = content.text
391+
elif not media.has_file and media.text:
392+
# Otherwise, we use the text media as the file data
393+
file_data = media.text
394394
else:
395-
# If no file and no text, we skip this content
395+
# If no file and no text, we skip this media
396396
continue
397-
self.add_file_to_zip(zipf, file_path, file_data, timestamp=content.created)
397+
self.add_file_to_zip(zipf, file_path, file_data, timestamp=media.created)
398398

399399
# ------ COLLECTION SERIALIZATION -------------
400400
collections = self.get_collections()
@@ -792,13 +792,13 @@ def _save_components(self, learning_package, components, component_static_files)
792792
for valid_published in components.get("components_published", []):
793793
entity_key = valid_published.pop("entity_key")
794794
version_num = valid_published["version_num"] # Should exist, validated earlier
795-
content_to_replace = self._resolve_static_files(version_num, entity_key, component_static_files)
795+
media_to_replace = self._resolve_static_files(version_num, entity_key, component_static_files)
796796
self.all_published_entities_versions.add(
797797
(entity_key, version_num)
798798
) # Track published version
799799
components_api.create_next_component_version(
800800
self.components_map_by_key[entity_key].publishable_entity.id,
801-
content_to_replace=content_to_replace,
801+
media_to_replace=media_to_replace,
802802
force_version_num=valid_published.pop("version_num", None),
803803
created_by=self.user_id,
804804
**valid_published
@@ -876,14 +876,14 @@ def _save_draft_versions(self, components, containers, component_static_files):
876876
version_num = valid_draft["version_num"] # Should exist, validated earlier
877877
if self._is_version_already_exists(entity_key, version_num):
878878
continue
879-
content_to_replace = self._resolve_static_files(version_num, entity_key, component_static_files)
879+
media_to_replace = self._resolve_static_files(version_num, entity_key, component_static_files)
880880
components_api.create_next_component_version(
881881
self.components_map_by_key[entity_key].publishable_entity.id,
882-
content_to_replace=content_to_replace,
882+
media_to_replace=media_to_replace,
883883
force_version_num=valid_draft.pop("version_num", None),
884-
# Drafts can diverge from published, so we allow ignoring previous content
884+
# Drafts can diverge from published, so we allow ignoring previous media
885885
# Use case: published v1 had files A, B; draft v2 only has file A
886-
ignore_previous_content=True,
886+
ignore_previous_media=True,
887887
created_by=self.user_id,
888888
**valid_draft
889889
)
@@ -970,7 +970,7 @@ def _resolve_static_files(
970970
entity_key: str,
971971
static_files_map: dict[str, List[str]]
972972
) -> dict[str, bytes | int]:
973-
"""Resolve static file paths into their binary content."""
973+
"""Resolve static file paths into their binary media content."""
974974
resolved_files: dict[str, bytes | int] = {}
975975

976976
static_file_key = f"{entity_key}:v{num_version}" # e.g., "xblock.v1:html:my_component_123456:v1"
@@ -979,21 +979,21 @@ def _resolve_static_files(
979979
for static_file in static_files:
980980
local_key = static_file.split(f"v{num_version}/")[-1]
981981
with self.zipf.open(static_file, "r") as f:
982-
content_bytes = f.read()
982+
media_bytes = f.read()
983983
if local_key == "block.xml":
984984
# Special handling for block.xml to ensure
985-
# storing the value as a content instance
985+
# storing the value as a media instance
986986
if not self.learning_package_id:
987987
raise ValueError("learning_package_id must be set before resolving static files.")
988-
text_content = contents_api.get_or_create_text_content(
988+
text_media = media_api.get_or_create_text_media(
989989
self.learning_package_id,
990-
contents_api.get_or_create_media_type(f"application/vnd.openedx.xblock.v1.{block_type}+xml").id,
991-
text=content_bytes.decode("utf-8"),
990+
media_api.get_or_create_media_type(f"application/vnd.openedx.xblock.v1.{block_type}+xml").id,
991+
text=media_bytes.decode("utf-8"),
992992
created=self.utc_now,
993993
)
994-
resolved_files[local_key] = text_content.id
994+
resolved_files[local_key] = text_media.id
995995
else:
996-
resolved_files[local_key] = content_bytes
996+
resolved_files[local_key] = media_bytes
997997
return resolved_files
998998

999999
def _resolve_children(self, entity_data: dict[str, Any], lookup_map: dict[str, Any]) -> list[Any]:

src/openedx_content/applets/components/admin.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from openedx_django_lib.admin_utils import ReadOnlyModelAdmin
1313

14-
from .models import Component, ComponentVersion, ComponentVersionContent
14+
from .models import Component, ComponentVersion, ComponentVersionMedia
1515

1616

1717
class ComponentVersionInline(admin.TabularInline):
@@ -54,14 +54,14 @@ class ContentInline(admin.TabularInline):
5454
"""
5555
Django admin configuration for Content
5656
"""
57-
model = ComponentVersion.contents.through
57+
model = ComponentVersion.media.through
5858

5959
def get_queryset(self, request):
6060
queryset = super().get_queryset(request)
6161
return queryset.select_related(
62-
"content",
63-
"content__learning_package",
64-
"content__media_type",
62+
"media",
63+
"media__learning_package",
64+
"media__media_type",
6565
"component_version",
6666
"component_version__publishable_entity_version",
6767
"component_version__component",
@@ -74,22 +74,22 @@ def get_queryset(self, request):
7474
"rendered_data",
7575
]
7676
readonly_fields = [
77-
"content",
77+
"media",
7878
"key",
7979
"format_size",
8080
"rendered_data",
8181
]
8282
extra = 0
8383

84-
def has_file(self, cvc_obj):
85-
return cvc_obj.content.has_file
84+
def has_file(self, cvm_obj):
85+
return cvm_obj.media.has_file
8686

87-
def rendered_data(self, cvc_obj):
88-
return content_preview(cvc_obj)
87+
def rendered_data(self, cvm_obj):
88+
return media_preview(cvm_obj)
8989

9090
@admin.display(description="Size")
91-
def format_size(self, cvc_obj):
92-
return filesizeformat(cvc_obj.content.size)
91+
def format_size(self, cvm_obj):
92+
return filesizeformat(cvm_obj.media.size)
9393

9494

9595
@admin.register(ComponentVersion)
@@ -103,7 +103,7 @@ class ComponentVersionAdmin(ReadOnlyModelAdmin):
103103
"title",
104104
"version_num",
105105
"created",
106-
"contents",
106+
"media",
107107
]
108108
fields = [
109109
"component",
@@ -134,26 +134,26 @@ def format_text_for_admin_display(text: str) -> SafeText:
134134
)
135135

136136

137-
def content_preview(cvc_obj: ComponentVersionContent) -> SafeText:
137+
def media_preview(cvm_obj: ComponentVersionMedia) -> SafeText:
138138
"""
139-
Get the HTML to display a preview of the given ComponentVersionContent
139+
Get the HTML to display a preview of the given ComponentVersionMedia
140140
"""
141-
content_obj = cvc_obj.content
141+
media_obj = cvm_obj.media
142142

143-
if content_obj.media_type.type == "image":
143+
if media_obj.media_type.type == "image":
144144
# This base64 encoding looks really goofy and is bad for performance,
145145
# but image previews in the admin are extremely useful, and this lets us
146146
# have them without creating a separate view in Open edX Core. (Keep in
147147
# mind that these assets are private, so they cannot be accessed via the
148148
# MEDIA_URL like most Django uploaded assets.)
149-
data = content_obj.read_file().read()
149+
data = media_obj.read_file().read()
150150
return format_html(
151151
'<img src="data:{};base64, {}" style="max-width: 100%;" /><br><pre>{}</pre>',
152-
content_obj.mime_type,
152+
media_obj.mime_type,
153153
base64.encodebytes(data).decode('utf8'),
154-
content_obj.os_path(),
154+
media_obj.os_path(),
155155
)
156156

157157
return format_text_for_admin_display(
158-
content_obj.text or ""
158+
media_obj.text or ""
159159
)

0 commit comments

Comments
 (0)