diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py b/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py index a155ceb235a4..48b9189e9cdc 100644 --- a/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py +++ b/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py @@ -274,7 +274,7 @@ def setUp(self): collection_key = "test-collection" content_api.create_collection( learning_package_id=learning_package.id, - key=collection_key, + collection_code=collection_key, title="Test Collection", created_by=self.user.id, ) diff --git a/cms/djangoapps/modulestore_migrator/api/read_api.py b/cms/djangoapps/modulestore_migrator/api/read_api.py index c418223b4db7..4d860fe31ec3 100644 --- a/cms/djangoapps/modulestore_migrator/api/read_api.py +++ b/cms/djangoapps/modulestore_migrator/api/read_api.py @@ -180,7 +180,7 @@ def _migration(m: models.ModulestoreMigration) -> ModulestoreMigration: source_key=m.source.key, target_key=LibraryLocatorV2.from_string(m.target.key), target_title=m.target.title, - target_collection_slug=(m.target_collection.key if m.target_collection else None), + target_collection_slug=(m.target_collection.collection_code if m.target_collection else None), target_collection_title=(m.target_collection.title if m.target_collection else None), is_failed=m.is_failed, task_uuid=m.task_status.uuid, diff --git a/cms/djangoapps/modulestore_migrator/tasks.py b/cms/djangoapps/modulestore_migrator/tasks.py index 6e821775440f..5c1b93497c6b 100644 --- a/cms/djangoapps/modulestore_migrator/tasks.py +++ b/cms/djangoapps/modulestore_migrator/tasks.py @@ -409,7 +409,7 @@ def _populate_collection(user_id: int, migration: models.ModulestoreMigration) - if block_target_pks: content_api.add_to_collection( learning_package_id=migration.target.pk, - key=migration.target_collection.key, + collection_code=migration.target_collection.collection_code, entities_qset=PublishableEntity.objects.filter(id__in=block_target_pks), created_by=user_id, ) diff --git a/cms/djangoapps/modulestore_migrator/tests/test_api.py b/cms/djangoapps/modulestore_migrator/tests/test_api.py index ba7135ad87e1..5d9ce0eaffe5 100644 --- a/cms/djangoapps/modulestore_migrator/tests/test_api.py +++ b/cms/djangoapps/modulestore_migrator/tests/test_api.py @@ -232,7 +232,7 @@ def test_start_migration_to_library_with_collection(self): collection_key = "test-collection" content_api.create_collection( learning_package_id=self.learning_package.id, - key=collection_key, + collection_code=collection_key, title="Test Collection", created_by=user.id, ) @@ -249,7 +249,7 @@ def test_start_migration_to_library_with_collection(self): ) modulestoremigration = ModulestoreMigration.objects.get() - assert modulestoremigration.target_collection.key == collection_key + assert modulestoremigration.target_collection.collection_code == collection_key def test_start_migration_to_library_with_strategy_skip(self): """ @@ -487,19 +487,19 @@ def test_migration_api_for_various_scenarios(self): # Lib 2 has Collection C content_api.create_collection( learning_package_id=self.learning_package.id, - key="test-collection-1a", + collection_code="test-collection-1a", title="Test Collection A in Lib 1", created_by=user.id, ) content_api.create_collection( learning_package_id=self.learning_package.id, - key="test-collection-1b", + collection_code="test-collection-1b", title="Test Collection B in Lib 1", created_by=user.id, ) content_api.create_collection( learning_package_id=self.learning_package_2.id, - key="test-collection-2c", + collection_code="test-collection-2c", title="Test Collection C in Lib 2", created_by=user.id, ) diff --git a/openedx/core/djangoapps/content/search/api.py b/openedx/core/djangoapps/content/search/api.py index d997b28ed1cb..138b2bca71d1 100644 --- a/openedx/core/djangoapps/content/search/api.py +++ b/openedx/core/djangoapps/content/search/api.py @@ -503,7 +503,7 @@ def index_collection_batch(batch, num_done, library_key) -> int: docs = [] for collection in batch: try: - collection_key = lib_api.library_collection_locator(library_key, collection.key) + collection_key = lib_api.library_collection_locator(library_key, collection.collection_code) doc = searchable_doc_for_collection(collection_key, collection=collection) doc.update(searchable_doc_tags(collection_key)) docs.append(doc) @@ -898,7 +898,7 @@ def upsert_content_library_index_docs(library_key: LibraryLocatorV2, full_index: docs.append(doc) for collection in lib_api.get_library_collections(library_key): - collection_key = lib_api.library_collection_locator(library_key, collection.key) + collection_key = lib_api.library_collection_locator(library_key, collection.collection_code) doc = searchable_doc_for_collection(collection_key, collection=collection) docs.append(doc) diff --git a/openedx/core/djangoapps/content/search/documents.py b/openedx/core/djangoapps/content/search/documents.py index 11408f2e6f43..58bea6d32c5a 100644 --- a/openedx/core/djangoapps/content/search/documents.py +++ b/openedx/core/djangoapps/content/search/documents.py @@ -543,7 +543,7 @@ def searchable_doc_for_collection( pass if collection: - assert collection.key == collection_key.collection_id + assert collection.collection_code == collection_key.collection_id draft_num_children = content_api.filter_publishable_entities( collection.entities, @@ -558,7 +558,7 @@ def searchable_doc_for_collection( Fields.context_key: str(collection_key.context_key), Fields.org: str(collection_key.org), Fields.usage_key: str(collection_key), - Fields.block_id: collection.key, + Fields.block_id: collection.collection_code, Fields.type: DocType.collection, Fields.display_name: collection.title, Fields.description: collection.description, diff --git a/openedx/core/djangoapps/content/search/tests/test_api.py b/openedx/core/djangoapps/content/search/tests/test_api.py index 27a8201330f7..87de1cfb1552 100644 --- a/openedx/core/djangoapps/content/search/tests/test_api.py +++ b/openedx/core/djangoapps/content/search/tests/test_api.py @@ -194,7 +194,7 @@ def setUp(self) -> None: with freeze_time(self.created_date): self.collection = content_api.create_collection( learning_package_id=self.learning_package.id, - key="MYCOL", + collection_code="MYCOL", title="my_collection", created_by=None, description="my collection description" @@ -204,7 +204,7 @@ def setUp(self) -> None: ) self.collection_dict = { "id": "lib-collectionorg1libmycol-5b647617", - "block_id": self.collection.key, + "block_id": self.collection.collection_code, "usage_key": str(self.collection_key), "type": "collection", "display_name": "my_collection", @@ -711,7 +711,7 @@ def test_index_library_block_and_collections(self, mock_meilisearch) -> None: for collection in (collection2, collection1): library_api.update_library_collection_items( self.library.key, - collection_key=collection.key, + collection_key=collection.collection_code, opaque_keys=[ self.problem1.usage_key, ], @@ -893,7 +893,7 @@ def test_delete_collection(self, mock_meilisearch) -> None: with freeze_time(updated_date): library_api.update_library_collection_items( self.library.key, - collection_key=self.collection.key, + collection_key=self.collection.collection_code, opaque_keys=[ self.problem1.usage_key, self.unit.container_key @@ -907,14 +907,14 @@ def test_delete_collection(self, mock_meilisearch) -> None: "id": self.doc_problem1["id"], "collections": { "display_name": [self.collection.title], - "key": [self.collection.key], + "key": [self.collection.collection_code], }, } doc_unit_with_collection = { "id": self.unit_dict["id"], "collections": { "display_name": [self.collection.title], - "key": [self.collection.key], + "key": [self.collection.collection_code], }, } @@ -933,7 +933,7 @@ def test_delete_collection(self, mock_meilisearch) -> None: # Soft-delete the collection content_api.delete_collection( self.collection.learning_package_id, - self.collection.key, + self.collection.collection_code, ) doc_problem_without_collection = { @@ -968,7 +968,7 @@ def test_delete_collection(self, mock_meilisearch) -> None: with freeze_time(restored_date): content_api.restore_collection( self.collection.learning_package_id, - self.collection.key, + self.collection.collection_code, ) doc_collection = copy.deepcopy(self.collection_dict) @@ -990,7 +990,7 @@ def test_delete_collection(self, mock_meilisearch) -> None: # Hard-delete the collection content_api.delete_collection( self.collection.learning_package_id, - self.collection.key, + self.collection.collection_code, hard_delete=True, ) diff --git a/openedx/core/djangoapps/content/search/tests/test_documents.py b/openedx/core/djangoapps/content/search/tests/test_documents.py index bd155a3b3b8f..954b994f6fd5 100644 --- a/openedx/core/djangoapps/content/search/tests/test_documents.py +++ b/openedx/core/djangoapps/content/search/tests/test_documents.py @@ -492,7 +492,7 @@ def test_collection_with_library(self): assert doc == { "id": "lib-collectionedx2012_falltoy_collection-d1d907a4", - "block_id": self.collection.key, + "block_id": self.collection.collection_code, "usage_key": str(self.collection_key), "type": "collection", "org": "edX", @@ -521,7 +521,7 @@ def test_collection_with_published_library(self): assert doc == { "id": "lib-collectionedx2012_falltoy_collection-d1d907a4", - "block_id": self.collection.key, + "block_id": self.collection.collection_code, "usage_key": str(self.collection_key), "type": "collection", "org": "edX", diff --git a/openedx/core/djangoapps/content_libraries/api/block_metadata.py b/openedx/core/djangoapps/content_libraries/api/block_metadata.py index f117d2762949..90f483ab1531 100644 --- a/openedx/core/djangoapps/content_libraries/api/block_metadata.py +++ b/openedx/core/djangoapps/content_libraries/api/block_metadata.py @@ -2,13 +2,18 @@ Content libraries data classes related to XBlocks/Components. """ from __future__ import annotations + +import typing as t from dataclasses import dataclass from django.utils.translation import gettext as _ from opaque_keys.edx.locator import LibraryUsageLocatorV2 +from openedx_content.models_api import Component + from .libraries import ( library_component_usage_key, PublishableItem, + CollectionMetadata, ) # The public API is only the following symbols: @@ -26,7 +31,9 @@ class LibraryXBlockMetadata(PublishableItem): usage_key: LibraryUsageLocatorV2 @classmethod - def from_component(cls, library_key, component, associated_collections=None): + def from_component( + cls, library_key, component: Component, associated_collections: list[CollectionMetadata] | None = None + ) -> t.Self: """ Construct a LibraryXBlockMetadata from a Component object. """ diff --git a/openedx/core/djangoapps/content_libraries/api/blocks.py b/openedx/core/djangoapps/content_libraries/api/blocks.py index 3bae77f3c1cc..fa144666cf65 100644 --- a/openedx/core/djangoapps/content_libraries/api/blocks.py +++ b/openedx/core/djangoapps/content_libraries/api/blocks.py @@ -729,7 +729,7 @@ def delete_library_block( library_collection=LibraryCollectionData( collection_key=library_collection_locator( library_key=library_key, - collection_key=collection.key, + collection_key=collection.collection_code, ), background=True, ) @@ -795,7 +795,7 @@ def restore_library_block(usage_key: LibraryUsageLocatorV2, user_id: int | None library_collection=LibraryCollectionData( collection_key=library_collection_locator( library_key=library_key, - collection_key=collection.key, + collection_key=collection.collection_code, ), background=True, ) diff --git a/openedx/core/djangoapps/content_libraries/api/collections.py b/openedx/core/djangoapps/content_libraries/api/collections.py index ad441c01dace..efb470ea7b26 100644 --- a/openedx/core/djangoapps/content_libraries/api/collections.py +++ b/openedx/core/djangoapps/content_libraries/api/collections.py @@ -54,7 +54,7 @@ def create_library_collection( try: collection = content_api.create_collection( learning_package_id=content_library.learning_package_id, - key=collection_key, + collection_code=collection_key, title=title, description=description, created_by=created_by, @@ -86,7 +86,7 @@ def update_library_collection( try: collection = content_api.update_collection( learning_package_id=content_library.learning_package_id, - key=collection_key, + collection_code=collection_key, title=title, description=description, ) @@ -232,7 +232,7 @@ def set_library_item_collections( library_collection=LibraryCollectionData( collection_key=library_collection_locator( library_key=library_key, - collection_key=collection.key, + collection_key=collection.collection_code, ), background=True, ) diff --git a/openedx/core/djangoapps/content_libraries/api/container_metadata.py b/openedx/core/djangoapps/content_libraries/api/container_metadata.py index b0b84a43108a..1ad4a46905c2 100644 --- a/openedx/core/djangoapps/content_libraries/api/container_metadata.py +++ b/openedx/core/djangoapps/content_libraries/api/container_metadata.py @@ -4,6 +4,7 @@ from __future__ import annotations +import typing as t from dataclasses import dataclass, field as dataclass_field from enum import Enum from django.db.models import QuerySet @@ -25,7 +26,7 @@ from ..models import ContentLibrary from .exceptions import ContentLibraryBlockNotFound, ContentLibraryContainerNotFound -from .libraries import PublishableItem, library_component_usage_key +from .libraries import PublishableItem, library_component_usage_key, CollectionMetadata # The public API is only the following symbols: __all__ = [ @@ -73,7 +74,9 @@ class ContainerMetadata(PublishableItem): container_pk: int @classmethod - def from_container(cls, library_key, container: Container, associated_collections=None): + def from_container( + cls, library_key, container: Container, associated_collections: list[CollectionMetadata] | None = None + ) -> t.Self: """ Construct a ContainerMetadata object from a Container object. """ diff --git a/openedx/core/djangoapps/content_libraries/api/containers.py b/openedx/core/djangoapps/content_libraries/api/containers.py index 907f614f7466..2d83ce9ac5c5 100644 --- a/openedx/core/djangoapps/content_libraries/api/containers.py +++ b/openedx/core/djangoapps/content_libraries/api/containers.py @@ -79,7 +79,7 @@ def get_container( associated_collections = content_api.get_entity_collections( container.publishable_entity.learning_package_id, container_key.container_id, - ).values("key", "title") + ).values("collection_code", "title") else: associated_collections = None container_meta = ContainerMetadata.from_container( @@ -235,7 +235,7 @@ def delete_container( library_collection=LibraryCollectionData( collection_key=library_collection_locator( library_key=library_key, - collection_key=collection.key, + collection_key=collection.collection_code, ), background=True, ) @@ -319,7 +319,7 @@ def restore_container(container_key: LibraryContainerLocator) -> None: library_collection=LibraryCollectionData( collection_key=library_collection_locator( library_key=library_key, - collection_key=collection.key, + collection_key=collection.collection_code, ), ) ) diff --git a/openedx/core/djangoapps/content_libraries/api/libraries.py b/openedx/core/djangoapps/content_libraries/api/libraries.py index fce2ce5ec4f6..c27a760f3c33 100644 --- a/openedx/core/djangoapps/content_libraries/api/libraries.py +++ b/openedx/core/djangoapps/content_libraries/api/libraries.py @@ -180,7 +180,7 @@ class CollectionMetadata: """ Class to represent collection metadata in a content library. """ - key: str + collection_code: str title: str diff --git a/openedx/core/djangoapps/content_libraries/rest_api/collections.py b/openedx/core/djangoapps/content_libraries/rest_api/collections.py index 85f082138411..1563a47a851d 100644 --- a/openedx/core/djangoapps/content_libraries/rest_api/collections.py +++ b/openedx/core/djangoapps/content_libraries/rest_api/collections.py @@ -34,7 +34,7 @@ class LibraryCollectionsView(ModelViewSet): """ serializer_class = ContentLibraryCollectionSerializer - lookup_field = 'key' + lookup_field = 'collection_code' def __init__(self, *args, **kwargs) -> None: """ @@ -154,7 +154,7 @@ def partial_update(self, request: RestRequest, *args, **kwargs) -> Response: request.user, authz_permissions.EDIT_LIBRARY_COLLECTION ) - collection_key = kwargs["key"] + collection_key = kwargs["collection_code"] update_serializer = ContentLibraryCollectionUpdateSerializer( data=request.data, partial=True @@ -185,7 +185,7 @@ def destroy(self, request: RestRequest, *args, **kwargs) -> Response: assert collection.learning_package_id content_api.delete_collection( collection.learning_package_id, - collection.key, + collection.collection_code, hard_delete=False, ) return Response(None, status=HTTP_204_NO_CONTENT) @@ -203,7 +203,7 @@ def restore(self, request: RestRequest, *args, **kwargs) -> Response: authz_permissions.EDIT_LIBRARY_COLLECTION ) assert content_library.learning_package_id - collection_key = kwargs["key"] + collection_key = kwargs["collection_code"] content_api.restore_collection( content_library.learning_package_id, collection_key, @@ -224,7 +224,7 @@ def update_items(self, request: RestRequest, *args, **kwargs) -> Response: request.user, authz_permissions.EDIT_LIBRARY_COLLECTION ) - collection_key = kwargs["key"] + collection_key = kwargs["collection_code"] serializer = ContentLibraryItemKeysSerializer(data=request.data) serializer.is_valid(raise_exception=True) diff --git a/openedx/core/djangoapps/content_libraries/rest_api/serializers.py b/openedx/core/djangoapps/content_libraries/rest_api/serializers.py index b7c7124fde08..d74c512b69f6 100644 --- a/openedx/core/djangoapps/content_libraries/rest_api/serializers.py +++ b/openedx/core/djangoapps/content_libraries/rest_api/serializers.py @@ -132,7 +132,8 @@ class CollectionMetadataSerializer(serializers.Serializer): """ Serializer for CollectionMetadata """ - key = serializers.CharField() + collection_code = serializers.CharField() + key = serializers.CharField(source="collection_code") # back-compat title = serializers.CharField() diff --git a/openedx/core/djangoapps/content_libraries/tasks.py b/openedx/core/djangoapps/content_libraries/tasks.py index a28bf1e861dd..c5e8bc684f58 100644 --- a/openedx/core/djangoapps/content_libraries/tasks.py +++ b/openedx/core/djangoapps/content_libraries/tasks.py @@ -259,7 +259,7 @@ def send_events_after_revert(draft_change_log_id: int, library_key_str: str) -> ): collection_key = api.library_collection_locator( library_key=library_key, - collection_key=parent_collection.key, + collection_key=parent_collection.collection_code, ) affected_collection_keys.add(collection_key) diff --git a/openedx/core/djangoapps/content_libraries/tests/test_api.py b/openedx/core/djangoapps/content_libraries/tests/test_api.py index 1fe394b21b7a..eeb47228ead2 100644 --- a/openedx/core/djangoapps/content_libraries/tests/test_api.py +++ b/openedx/core/djangoapps/content_libraries/tests/test_api.py @@ -342,7 +342,7 @@ def test_create_library_collection(self) -> None: description="Description for Collection 4", created_by=self.user.id, ) - assert collection.key == "COL4" + assert collection.collection_code == "COL4" assert collection.title == "Collection 4" assert collection.description == "Description for Collection 4" assert collection.created_by == self.user diff --git a/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py b/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py index aba221dac821..a89a31a7db91 100644 --- a/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py +++ b/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py @@ -1930,8 +1930,8 @@ def test_collection_permissions(self): self.lib_id, title=f"Temp Collection {user.username}", expect_response=status.HTTP_200_OK) - collection_id = collection_data["key"] - collection_key = LibraryCollectionLocator(lib_key=library_key, collection_id=collection_id) + collection_code = collection_data["key"] + collection_key = LibraryCollectionLocator(lib_key=library_key, collection_id=collection_code) # Update collection self._update_collection(collection_key, title="Updated Collection", expect_response=status.HTTP_200_OK) self._add_items_to_collection( @@ -1945,8 +1945,8 @@ def test_collection_permissions(self): self.lib_id, title="New Temp Collection", expect_response=status.HTTP_200_OK) - collection_id = collection_data["key"] - collection_key = LibraryCollectionLocator(lib_key=library_key, collection_id=collection_id) + collection_code = collection_data["key"] + collection_key = LibraryCollectionLocator(lib_key=library_key, collection_id=collection_code) for user in self._all_users_excluding(self.library_collection_editors): with self.as_user(user): diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index e89bbb77d151..e11505eb07f2 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -829,7 +829,7 @@ openedx-calc==5.0.0 # via # -r requirements/edx/kernel.in # xblocks-contrib -openedx-core==0.38.0 +git+https://github.com/openedx/openedx-core.git@kdmccormick/collection-code#egg=openedx-core # via # -c requirements/constraints.txt # -r requirements/edx/kernel.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 4a9a2d55f155..bfa2e1cba65e 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -1382,7 +1382,7 @@ openedx-calc==5.0.0 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # xblocks-contrib -openedx-core==0.38.0 +git+https://github.com/openedx/openedx-core.git@kdmccormick/collection-code#egg=openedx-core # via # -c requirements/constraints.txt # -r requirements/edx/doc.txt diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index 659b862df2da..6ccd1344e515 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -1007,7 +1007,7 @@ openedx-calc==5.0.0 # via # -r requirements/edx/base.txt # xblocks-contrib -openedx-core==0.38.0 +git+https://github.com/openedx/openedx-core.git@kdmccormick/collection-code#egg=openedx-core # via # -c requirements/constraints.txt # -r requirements/edx/base.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 5fa000d059f7..13c58a7725bb 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -1056,7 +1056,7 @@ openedx-calc==5.0.0 # via # -r requirements/edx/base.txt # xblocks-contrib -openedx-core==0.38.0 +git+https://github.com/openedx/openedx-core.git@kdmccormick/collection-code#egg=openedx-core # via # -c requirements/constraints.txt # -r requirements/edx/base.txt