1717from meilisearch import Client as MeilisearchClient
1818from meilisearch .errors import MeilisearchApiError , MeilisearchError
1919from meilisearch .models .task import TaskInfo
20- from opaque_keys .edx .keys import UsageKey , OpaqueKey
20+ from opaque_keys import OpaqueKey
21+ from opaque_keys .edx .keys import UsageKey
2122from opaque_keys .edx .locator import (
2223 LibraryCollectionLocator ,
2324 LibraryContainerLocator ,
2425 LibraryLocatorV2 ,
2526)
2627from openedx_learning .api import authoring as authoring_api
27- from common .djangoapps .student .roles import GlobalStaff
2828from rest_framework .request import Request
29+
2930from common .djangoapps .student .role_helpers import get_course_roles
31+ from common .djangoapps .student .roles import GlobalStaff
3032from openedx .core .djangoapps .content .course_overviews .models import CourseOverview
31- from openedx .core .djangoapps .content .search .models import get_access_ids_for_request , IncrementalIndexCompleted
3233from openedx .core .djangoapps .content .search .index_config import (
3334 INDEX_DISTINCT_ATTRIBUTE ,
3435 INDEX_FILTERABLE_ATTRIBUTES ,
35- INDEX_SEARCHABLE_ATTRIBUTES ,
36- INDEX_SORTABLE_ATTRIBUTES ,
3736 INDEX_RANKING_RULES ,
37+ INDEX_SEARCHABLE_ATTRIBUTES ,
38+ INDEX_SORTABLE_ATTRIBUTES
3839)
40+ from openedx .core .djangoapps .content .search .models import IncrementalIndexCompleted , get_access_ids_for_request
3941from openedx .core .djangoapps .content_libraries import api as lib_api
4042from xmodule .modulestore .django import modulestore
4143
4244from .documents import (
4345 Fields ,
4446 meili_id_from_opaque_key ,
45- searchable_doc_for_course_block ,
47+ searchable_doc_collections ,
4648 searchable_doc_for_collection ,
4749 searchable_doc_for_container ,
50+ searchable_doc_for_course_block ,
4851 searchable_doc_for_library_block ,
4952 searchable_doc_for_key ,
50- searchable_doc_collections ,
5153 searchable_doc_tags ,
5254 searchable_doc_tags_for_collection ,
5355)
@@ -492,6 +494,7 @@ def index_container_batch(batch, num_done, library_key) -> int:
492494 )
493495 doc = searchable_doc_for_container (container_key )
494496 doc .update (searchable_doc_tags (container_key ))
497+ doc .update (searchable_doc_collections (container_key ))
495498 docs .append (doc )
496499 except Exception as err : # pylint: disable=broad-except
497500 status_cb (f"Error indexing container { container .key } : { err } " )
@@ -722,7 +725,7 @@ def upsert_library_collection_index_doc(collection_key: LibraryCollectionLocator
722725
723726 _delete_index_doc (doc [Fields .id ])
724727
725- update_components = True
728+ update_items = True
726729
727730 # Hard-deleted collections are also deleted from the index,
728731 # but their components are automatically updated as part of the deletion process, so we don't have to.
@@ -735,15 +738,17 @@ def upsert_library_collection_index_doc(collection_key: LibraryCollectionLocator
735738 else :
736739 already_indexed = _get_document_from_index (doc [Fields .id ])
737740 if not already_indexed :
738- update_components = True
741+ update_items = True
739742
740743 _update_index_docs ([doc ])
741744
742745 # Asynchronously update the collection's components "collections" field
743- if update_components :
744- from .tasks import update_library_components_collections as update_task
746+ if update_items :
747+ from .tasks import update_library_components_collections as update_components_task
748+ from .tasks import update_library_containers_collections as update_containers_task
745749
746- update_task .delay (str (collection_key ))
750+ update_components_task .delay (str (collection_key ))
751+ update_containers_task .delay (str (collection_key ))
747752
748753
749754def update_library_components_collections (
@@ -781,6 +786,41 @@ def update_library_components_collections(
781786 _update_index_docs (docs )
782787
783788
789+ def update_library_containers_collections (
790+ collection_key : LibraryCollectionLocator ,
791+ batch_size : int = 1000 ,
792+ ) -> None :
793+ """
794+ Updates the "collections" field for all containers associated with a given Library Collection.
795+
796+ Because there may be a lot of containers, we send these updates to Meilisearch in batches.
797+ """
798+ library_key = collection_key .library_key
799+ library = lib_api .get_library (library_key )
800+ containers = authoring_api .get_collection_containers (
801+ library .learning_package_id ,
802+ collection_key .collection_id ,
803+ )
804+
805+ paginator = Paginator (containers , batch_size )
806+ for page in paginator .page_range :
807+ docs = []
808+
809+ for container in paginator .page (page ).object_list :
810+ container_key = lib_api .library_container_locator (
811+ library_key ,
812+ container ,
813+ )
814+ doc = searchable_doc_collections (container_key )
815+ docs .append (doc )
816+
817+ log .info (
818+ f"Updating document.collections for library { library_key } containers"
819+ f" page { page } / { paginator .num_pages } "
820+ )
821+ _update_index_docs (docs )
822+
823+
784824def upsert_library_container_index_doc (container_key : LibraryContainerLocator ) -> None :
785825 """
786826 Creates, updates, or deletes the document for the given Library Container in the search index.
@@ -827,12 +867,12 @@ def upsert_content_object_tags_index_doc(key: OpaqueKey):
827867 _update_index_docs ([doc ])
828868
829869
830- def upsert_block_collections_index_docs ( usage_key : UsageKey ):
870+ def upsert_item_collections_index_docs ( opaque_key : OpaqueKey ):
831871 """
832- Updates the collections data in documents for the given Course/Library block
872+ Updates the collections data in documents for the given Course/Library block, or Container
833873 """
834- doc = {Fields .id : meili_id_from_opaque_key (usage_key )}
835- doc .update (searchable_doc_collections (usage_key ))
874+ doc = {Fields .id : meili_id_from_opaque_key (opaque_key )}
875+ doc .update (searchable_doc_collections (opaque_key ))
836876 _update_index_docs ([doc ])
837877
838878
0 commit comments