Skip to content

Commit 11bab7d

Browse files
authored
refactor!: use LibraryCollectionLocator and LibraryContainerLocator [FC-0083] (#36476)
efactors the content_libraries.api to use LibraryCollectionLocator and LibraryContainerLocator keys, instead of passing separate LibraryUsageKeyV2 keys along with the collection/container locators. Renames misleading uses of collection_usage_key to collection_locator, including in the content_libraries.api and content.search.api method names and parameters. This change impacts Developers, but should not affect end users. This refactoring seems reasonable to do without going through deprecation, given the minimal use of these APIs.
1 parent dc4144e commit 11bab7d

18 files changed

Lines changed: 176 additions & 146 deletions

File tree

openedx/core/djangoapps/content/search/api.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
from meilisearch.errors import MeilisearchApiError, MeilisearchError
1919
from meilisearch.models.task import TaskInfo
2020
from opaque_keys.edx.keys import UsageKey, OpaqueKey
21-
from opaque_keys.edx.locator import LibraryContainerLocator, LibraryLocatorV2, LibraryCollectionLocator
21+
from opaque_keys.edx.locator import (
22+
LibraryCollectionLocator,
23+
LibraryContainerLocator,
24+
LibraryLocatorV2,
25+
)
2226
from openedx_learning.api import authoring as authoring_api
2327
from common.djangoapps.student.roles import GlobalStaff
2428
from rest_framework.request import Request
@@ -461,8 +465,9 @@ def index_collection_batch(batch, num_done, library_key) -> int:
461465
docs = []
462466
for collection in batch:
463467
try:
464-
doc = searchable_doc_for_collection(library_key, collection.key, collection=collection)
465-
doc.update(searchable_doc_tags_for_collection(library_key, collection.key))
468+
collection_key = lib_api.library_collection_locator(library_key, collection.key)
469+
doc = searchable_doc_for_collection(collection_key, collection=collection)
470+
doc.update(searchable_doc_tags_for_collection(collection_key))
466471
docs.append(doc)
467472
except Exception as err: # pylint: disable=broad-except
468473
status_cb(f"Error indexing collection {collection}: {err}")
@@ -702,13 +707,13 @@ def _get_document_from_index(document_id: str) -> dict:
702707
return document
703708

704709

705-
def upsert_library_collection_index_doc(library_key: LibraryLocatorV2, collection_key: str) -> None:
710+
def upsert_library_collection_index_doc(collection_key: LibraryCollectionLocator) -> None:
706711
"""
707712
Creates, updates, or deletes the document for the given Library Collection in the search index.
708713
709714
If the Collection is not found or disabled (i.e. soft-deleted), then delete it from the search index.
710715
"""
711-
doc = searchable_doc_for_collection(library_key, collection_key)
716+
doc = searchable_doc_for_collection(collection_key)
712717
update_components = False
713718

714719
# Soft-deleted/disabled collections are removed from the index
@@ -738,21 +743,24 @@ def upsert_library_collection_index_doc(library_key: LibraryLocatorV2, collectio
738743
if update_components:
739744
from .tasks import update_library_components_collections as update_task
740745

741-
update_task.delay(str(library_key), collection_key)
746+
update_task.delay(str(collection_key))
742747

743748

744749
def update_library_components_collections(
745-
library_key: LibraryLocatorV2,
746-
collection_key: str,
750+
collection_key: LibraryCollectionLocator,
747751
batch_size: int = 1000,
748752
) -> None:
749753
"""
750754
Updates the "collections" field for all components associated with a given Library Collection.
751755
752756
Because there may be a lot of components, we send these updates to Meilisearch in batches.
753757
"""
758+
library_key = collection_key.library_key
754759
library = lib_api.get_library(library_key)
755-
components = authoring_api.get_collection_components(library.learning_package_id, collection_key)
760+
components = authoring_api.get_collection_components(
761+
library.learning_package_id,
762+
collection_key.collection_id,
763+
)
756764

757765
paginator = Paginator(components, batch_size)
758766
for page in paginator.page_range:
@@ -828,12 +836,12 @@ def upsert_block_collections_index_docs(usage_key: UsageKey):
828836
_update_index_docs([doc])
829837

830838

831-
def upsert_collection_tags_index_docs(collection_usage_key: LibraryCollectionLocator):
839+
def upsert_collection_tags_index_docs(collection_key: LibraryCollectionLocator):
832840
"""
833841
Updates the tags data in documents for the given library collection
834842
"""
835843

836-
doc = searchable_doc_tags_for_collection(collection_usage_key.library_key, collection_usage_key.collection_id)
844+
doc = searchable_doc_tags_for_collection(collection_key)
837845
_update_index_docs([doc])
838846

839847

openedx/core/djangoapps/content/search/documents.py

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from django.core.exceptions import ObjectDoesNotExist
1010
from django.utils.text import slugify
1111
from opaque_keys.edx.keys import LearningContextKey, UsageKey, OpaqueKey
12-
from opaque_keys.edx.locator import LibraryContainerLocator, LibraryLocatorV2
12+
from opaque_keys.edx.locator import LibraryCollectionLocator, LibraryContainerLocator
1313
from openedx_learning.api import authoring as authoring_api
1414
from openedx_learning.api.authoring_models import Collection
1515
from rest_framework.exceptions import NotFound
@@ -450,19 +450,14 @@ def searchable_doc_collections(usage_key: UsageKey) -> dict:
450450

451451

452452
def searchable_doc_tags_for_collection(
453-
library_key: LibraryLocatorV2,
454-
collection_key: str,
453+
collection_key: LibraryCollectionLocator
455454
) -> dict:
456455
"""
457456
Generate a dictionary document suitable for ingestion into a search engine
458457
like Meilisearch or Elasticsearch, with the tags data for the given library collection.
459458
"""
460-
collection_usage_key = lib_api.get_library_collection_usage_key(
461-
library_key,
462-
collection_key,
463-
)
464-
doc = searchable_doc_for_key(collection_usage_key)
465-
doc.update(_tags_for_content_object(collection_usage_key))
459+
doc = searchable_doc_for_key(collection_key)
460+
doc.update(_tags_for_content_object(collection_key))
466461

467462
return doc
468463

@@ -484,8 +479,7 @@ def searchable_doc_for_course_block(block) -> dict:
484479

485480

486481
def searchable_doc_for_collection(
487-
library_key: LibraryLocatorV2,
488-
collection_key: str,
482+
collection_key: LibraryCollectionLocator,
489483
*,
490484
# Optionally provide the collection if we've already fetched one
491485
collection: Collection | None = None,
@@ -498,21 +492,16 @@ def searchable_doc_for_collection(
498492
If no collection is found for the given library_key + collection_key, the returned document will contain only basic
499493
information derived from the collection usage key, and no Fields.type value will be included in the returned dict.
500494
"""
501-
collection_usage_key = lib_api.get_library_collection_usage_key(
502-
library_key,
503-
collection_key,
504-
)
505-
506-
doc = searchable_doc_for_key(collection_usage_key)
495+
doc = searchable_doc_for_key(collection_key)
507496

508497
try:
509-
collection = collection or lib_api.get_library_collection_from_usage_key(collection_usage_key)
498+
collection = collection or lib_api.get_library_collection_from_locator(collection_key)
510499
except lib_api.ContentLibraryCollectionNotFound:
511500
# Collection not found, so we can only return the base doc
512501
pass
513502

514503
if collection:
515-
assert collection.key == collection_key
504+
assert collection.key == collection_key.collection_id
516505

517506
draft_num_children = authoring_api.filter_publishable_entities(
518507
collection.entities,
@@ -524,9 +513,9 @@ def searchable_doc_for_collection(
524513
).count()
525514

526515
doc.update({
527-
Fields.context_key: str(library_key),
528-
Fields.org: str(library_key.org),
529-
Fields.usage_key: str(collection_usage_key),
516+
Fields.context_key: str(collection_key.library_key),
517+
Fields.org: str(collection_key.org),
518+
Fields.usage_key: str(collection_key),
530519
Fields.block_id: collection.key,
531520
Fields.type: DocType.collection,
532521
Fields.display_name: collection.title,
@@ -537,7 +526,7 @@ def searchable_doc_for_collection(
537526
Fields.published: {
538527
Fields.published_num_children: published_num_children,
539528
},
540-
Fields.access_id: _meili_access_id_from_context_key(library_key),
529+
Fields.access_id: _meili_access_id_from_context_key(collection_key.library_key),
541530
Fields.breadcrumbs: [{"display_name": collection.learning_package.title}],
542531
})
543532

openedx/core/djangoapps/content/search/handlers.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -187,16 +187,14 @@ def library_collection_updated_handler(**kwargs) -> None:
187187

188188
if library_collection.background:
189189
update_library_collection_index_doc.delay(
190-
str(library_collection.library_key),
191-
library_collection.collection_key,
190+
str(library_collection.collection_key),
192191
)
193192
else:
194193
# Update collection index synchronously to make sure that search index is updated before
195194
# the frontend invalidates/refetches index.
196195
# See content_library_updated_handler for more details.
197196
update_library_collection_index_doc.apply(args=[
198-
str(library_collection.library_key),
199-
library_collection.collection_key,
197+
str(library_collection.collection_key),
200198
])
201199

202200

@@ -252,16 +250,14 @@ def library_container_updated_handler(**kwargs) -> None:
252250

253251
if library_container.background:
254252
update_library_container_index_doc.delay(
255-
str(library_container.library_key),
256-
library_container.container_key,
253+
str(library_container.container_key),
257254
)
258255
else:
259256
# Update container index synchronously to make sure that search index is updated before
260257
# the frontend invalidates/refetches index.
261258
# See content_library_updated_handler for more details.
262259
update_library_container_index_doc.apply(args=[
263-
str(library_container.library_key),
264-
library_container.container_key,
260+
str(library_container.container_key),
265261
])
266262

267263

openedx/core/djangoapps/content/search/tasks.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from meilisearch.errors import MeilisearchError
1313
from opaque_keys.edx.keys import UsageKey
1414
from opaque_keys.edx.locator import (
15+
LibraryCollectionLocator,
1516
LibraryContainerLocator,
1617
LibraryLocatorV2,
1718
LibraryUsageLocatorV2,
@@ -92,38 +93,40 @@ def update_content_library_index_docs(library_key_str: str) -> None:
9293

9394
@shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError))
9495
@set_code_owner_attribute
95-
def update_library_collection_index_doc(library_key_str: str, collection_key: str) -> None:
96+
def update_library_collection_index_doc(collection_key_str: str) -> None:
9697
"""
9798
Celery task to update the content index document for a library collection
9899
"""
99-
library_key = LibraryLocatorV2.from_string(library_key_str)
100+
collection_key = LibraryCollectionLocator.from_string(collection_key_str)
101+
library_key = collection_key.library_key
100102

101103
log.info("Updating content index documents for collection %s in library%s", collection_key, library_key)
102104

103-
api.upsert_library_collection_index_doc(library_key, collection_key)
105+
api.upsert_library_collection_index_doc(collection_key)
104106

105107

106108
@shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError))
107109
@set_code_owner_attribute
108-
def update_library_components_collections(library_key_str: str, collection_key: str) -> None:
110+
def update_library_components_collections(collection_key_str: str) -> None:
109111
"""
110112
Celery task to update the "collections" field for components in the given content library collection.
111113
"""
112-
library_key = LibraryLocatorV2.from_string(library_key_str)
114+
collection_key = LibraryCollectionLocator.from_string(collection_key_str)
115+
library_key = collection_key.library_key
113116

114117
log.info("Updating document.collections for library %s collection %s components", library_key, collection_key)
115118

116-
api.update_library_components_collections(library_key, collection_key)
119+
api.update_library_components_collections(collection_key)
117120

118121

119122
@shared_task(base=LoggedTask, autoretry_for=(MeilisearchError, ConnectionError))
120123
@set_code_owner_attribute
121-
def update_library_container_index_doc(library_key_str: str, container_key_str: str) -> None:
124+
def update_library_container_index_doc(container_key_str: str) -> None:
122125
"""
123126
Celery task to update the content index document for a library container
124127
"""
125-
library_key = LibraryLocatorV2.from_string(library_key_str)
126128
container_key = LibraryContainerLocator.from_string(container_key_str)
129+
library_key = container_key.library_key
127130

128131
log.info("Updating content index documents for container %s in library%s", container_key, library_key)
129132

openedx/core/djangoapps/content/search/tests/test_api.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from datetime import datetime, timezone
99
from unittest.mock import MagicMock, Mock, call, patch
1010
from opaque_keys.edx.keys import UsageKey
11+
from opaque_keys.edx.locator import LibraryCollectionLocator
1112

1213
import ddt
1314
import pytest
@@ -188,11 +189,13 @@ def setUp(self):
188189
created_by=None,
189190
description="my collection description"
190191
)
191-
self.collection_usage_key = "lib-collection:org1:lib:MYCOL"
192+
self.collection_key = LibraryCollectionLocator.from_string(
193+
"lib-collection:org1:lib:MYCOL",
194+
)
192195
self.collection_dict = {
193196
"id": "lib-collectionorg1libmycol-5b647617",
194197
"block_id": self.collection.key,
195-
"usage_key": self.collection_usage_key,
198+
"usage_key": str(self.collection_key),
196199
"type": "collection",
197200
"display_name": "my_collection",
198201
"description": "my collection description",
@@ -737,8 +740,8 @@ def test_delete_all_drafts(self, mock_meilisearch):
737740
@override_settings(MEILISEARCH_ENABLED=True)
738741
def test_index_tags_in_collections(self, mock_meilisearch):
739742
# Tag collection
740-
tagging_api.tag_object(self.collection_usage_key, self.taxonomyA, ["one", "two"])
741-
tagging_api.tag_object(self.collection_usage_key, self.taxonomyB, ["three", "four"])
743+
tagging_api.tag_object(str(self.collection_key), self.taxonomyA, ["one", "two"])
744+
tagging_api.tag_object(str(self.collection_key), self.taxonomyB, ["three", "four"])
742745

743746
# Build expected docs with tags at each stage
744747
doc_collection_with_tags1 = {

openedx/core/djangoapps/content/search/tests/test_documents.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from datetime import datetime, timezone
66

77
from freezegun import freeze_time
8+
from opaque_keys.edx.locator import LibraryCollectionLocator, LibraryContainerLocator
89
from openedx_learning.api import authoring as authoring_api
910
from organizations.models import Organization
1011

@@ -81,7 +82,9 @@ def setUpClass(cls):
8182
created_by=None,
8283
description="my toy collection description"
8384
)
84-
cls.collection_usage_key = "lib-collection:edX:2012_Fall:TOY_COLLECTION"
85+
cls.collection_key = LibraryCollectionLocator.from_string(
86+
"lib-collection:edX:2012_Fall:TOY_COLLECTION",
87+
)
8588
cls.library_block = library_api.create_library_block(
8689
cls.library.key,
8790
"html",
@@ -94,7 +97,9 @@ def setUpClass(cls):
9497
title="A Unit in the Search Index",
9598
user_id=None,
9699
)
97-
cls.container_usage_key = "lct:edX:2012_Fall:unit:unit1"
100+
cls.container_key = LibraryContainerLocator.from_string(
101+
"lct:edX:2012_Fall:unit:unit1",
102+
)
98103

99104
# Add the problem block to the collection
100105
library_api.update_library_collection_components(
@@ -123,8 +128,8 @@ def setUpClass(cls):
123128
tagging_api.tag_object(str(cls.html_block_key), cls.subject_tags, tags=["Chinese", "Jump Links"])
124129
tagging_api.tag_object(str(cls.html_block_key), cls.difficulty_tags, tags=["Normal"])
125130
tagging_api.tag_object(str(cls.library_block.usage_key), cls.difficulty_tags, tags=["Normal"])
126-
tagging_api.tag_object(cls.collection_usage_key, cls.difficulty_tags, tags=["Normal"])
127-
tagging_api.tag_object(cls.container_usage_key, cls.difficulty_tags, tags=["Normal"])
131+
tagging_api.tag_object(str(cls.collection_key), cls.difficulty_tags, tags=["Normal"])
132+
tagging_api.tag_object(str(cls.container_key), cls.difficulty_tags, tags=["Normal"])
128133

129134
@property
130135
def toy_course_access_id(self):
@@ -451,13 +456,13 @@ def test_html_published_library_block(self):
451456
assert doc["publish_status"] == "modified"
452457

453458
def test_collection_with_library(self):
454-
doc = searchable_doc_for_collection(self.library.key, self.collection.key)
455-
doc.update(searchable_doc_tags_for_collection(self.library.key, self.collection.key))
459+
doc = searchable_doc_for_collection(self.collection_key)
460+
doc.update(searchable_doc_tags_for_collection(self.collection_key))
456461

457462
assert doc == {
458463
"id": "lib-collectionedx2012_falltoy_collection-d1d907a4",
459464
"block_id": self.collection.key,
460-
"usage_key": self.collection_usage_key,
465+
"usage_key": str(self.collection_key),
461466
"type": "collection",
462467
"org": "edX",
463468
"display_name": "Toy Collection",
@@ -480,13 +485,13 @@ def test_collection_with_library(self):
480485
def test_collection_with_published_library(self):
481486
library_api.publish_changes(self.library.key)
482487

483-
doc = searchable_doc_for_collection(self.library.key, self.collection.key)
484-
doc.update(searchable_doc_tags_for_collection(self.library.key, self.collection.key))
488+
doc = searchable_doc_for_collection(self.collection_key)
489+
doc.update(searchable_doc_tags_for_collection(self.collection_key))
485490

486491
assert doc == {
487492
"id": "lib-collectionedx2012_falltoy_collection-d1d907a4",
488493
"block_id": self.collection.key,
489-
"usage_key": self.collection_usage_key,
494+
"usage_key": str(self.collection_key),
490495
"type": "collection",
491496
"org": "edX",
492497
"display_name": "Toy Collection",

0 commit comments

Comments
 (0)