diff --git a/openedx/core/djangoapps/content/search/documents.py b/openedx/core/djangoapps/content/search/documents.py index e74bfaac0381..6f9868c0a15b 100644 --- a/openedx/core/djangoapps/content/search/documents.py +++ b/openedx/core/djangoapps/content/search/documents.py @@ -117,7 +117,13 @@ class implementation returns only: # this would be very inefficient. Better to recurse the tree top-down with the parent blocks loaded. log.warning(f"Updating Studio search index for XBlock {block.usage_key} but ancestors weren't cached.") cur_block = cur_block.get_parent() - block_data[Fields.breadcrumbs].insert(0, {"display_name": xblock_api.get_block_display_name(cur_block)}) + block_data[Fields.breadcrumbs].insert( + 0, + { + "display_name": xblock_api.get_block_display_name(cur_block), + "usage_key": str(cur_block.usage_key), + }, + ) try: content_data = block.index_dictionary() # Will be something like: @@ -218,12 +224,13 @@ def searchable_doc_for_library_block(xblock_metadata: lib_api.LibraryXBlockMetad doc = { Fields.id: meili_id_from_opaque_key(xblock_metadata.usage_key), Fields.type: DocType.library_block, + Fields.breadcrumbs: [] } doc.update(_fields_from_block(block)) # Add the breadcrumbs. In v2 libraries, the library itself is not a "parent" of the XBlocks so we add it here: - doc[Fields.breadcrumbs] = [{"display_name": library_name}] + doc[Fields.breadcrumbs] = [{"display_name": library_name, "usage_key": str(xblock_metadata.usage_key.context_key)}] return doc diff --git a/openedx/core/djangoapps/content/search/tests/test_api.py b/openedx/core/djangoapps/content/search/tests/test_api.py index 43e1eb20e68e..46c4ced97892 100644 --- a/openedx/core/djangoapps/content/search/tests/test_api.py +++ b/openedx/core/djangoapps/content/search/tests/test_api.py @@ -63,34 +63,45 @@ def setUp(self): # Create XBlocks self.sequential = self.store.create_child(self.user_id, self.course.location, "sequential", "test_sequential") self.doc_sequential = { - 'id': 'block-v1org1test_coursetest_runtypesequentialblocktest_sequential-f702c144', - 'type': 'course_block', - 'usage_key': 'block-v1:org1+test_course+test_run+type@sequential+block@test_sequential', - 'block_id': 'test_sequential', - 'display_name': 'sequential', - 'block_type': 'sequential', - 'context_key': 'course-v1:org1+test_course+test_run', - 'org': 'org1', - 'breadcrumbs': [{'display_name': 'Test Course'}], - 'content': {}, - 'access_id': course_access.id, + "id": "block-v1org1test_coursetest_runtypesequentialblocktest_sequential-f702c144", + "type": "course_block", + "usage_key": "block-v1:org1+test_course+test_run+type@sequential+block@test_sequential", + "block_id": "test_sequential", + "display_name": "sequential", + "block_type": "sequential", + "context_key": "course-v1:org1+test_course+test_run", + "org": "org1", + "breadcrumbs": [ + { + "display_name": "Test Course", + "usage_key": "block-v1:org1+test_course+test_run+type@course+block@course", + }, + ], + "content": {}, + "access_id": course_access.id, } self.store.create_child(self.user_id, self.sequential.location, "vertical", "test_vertical") self.doc_vertical = { - 'id': 'block-v1org1test_coursetest_runtypeverticalblocktest_vertical-e76a10a4', - 'type': 'course_block', - 'usage_key': 'block-v1:org1+test_course+test_run+type@vertical+block@test_vertical', - 'block_id': 'test_vertical', - 'display_name': 'vertical', - 'block_type': 'vertical', - 'context_key': 'course-v1:org1+test_course+test_run', - 'org': 'org1', - 'breadcrumbs': [ - {'display_name': 'Test Course'}, - {'display_name': 'sequential'} + "id": "block-v1org1test_coursetest_runtypeverticalblocktest_vertical-e76a10a4", + "type": "course_block", + "usage_key": "block-v1:org1+test_course+test_run+type@vertical+block@test_vertical", + "block_id": "test_vertical", + "display_name": "vertical", + "block_type": "vertical", + "context_key": "course-v1:org1+test_course+test_run", + "org": "org1", + "breadcrumbs": [ + { + "display_name": "Test Course", + "usage_key": "block-v1:org1+test_course+test_run+type@course+block@course", + }, + { + "display_name": "sequential", + "usage_key": "block-v1:org1+test_course+test_run+type@sequential+block@test_sequential", + }, ], - 'content': {}, - 'access_id': course_access.id, + "content": {}, + "access_id": course_access.id, } # Create a content library: @@ -111,7 +122,7 @@ def setUp(self): "block_type": "problem", "context_key": "lib:org1:lib", "org": "org1", - "breadcrumbs": [{"display_name": "Library"}], + "breadcrumbs": [{"display_name": "Library", "usage_key": "lib:org1:lib"}], "content": {"problem_types": [], "capa_content": " "}, "type": "library_block", "access_id": lib_access.id, diff --git a/openedx/core/djangoapps/content/search/tests/test_documents.py b/openedx/core/djangoapps/content/search/tests/test_documents.py index 79efda11177b..d9ecd4026520 100644 --- a/openedx/core/djangoapps/content/search/tests/test_documents.py +++ b/openedx/core/djangoapps/content/search/tests/test_documents.py @@ -96,10 +96,22 @@ def test_problem_block(self): "access_id": self.toy_course_access_id, "display_name": "Test Problem", "breadcrumbs": [ - {"display_name": "Toy Course"}, - {"display_name": "chapter"}, - {"display_name": "sequential"}, - {"display_name": "vertical"}, + { + 'display_name': 'Toy Course', + 'usage_key': 'block-v1:edX+toy+2012_Fall+type@course+block@course', + }, + { + 'display_name': 'chapter', + 'usage_key': 'block-v1:edX+toy+2012_Fall+type@chapter+block@vertical_container', + }, + { + 'display_name': 'sequential', + 'usage_key': 'block-v1:edX+toy+2012_Fall+type@sequential+block@vertical_sequential', + }, + { + 'display_name': 'vertical', + 'usage_key': 'block-v1:edX+toy+2012_Fall+type@vertical+block@vertical_test', + }, ], "content": { "capa_content": "What is a test?", @@ -133,9 +145,18 @@ def test_html_block(self): "access_id": self.toy_course_access_id, "display_name": "Text", "breadcrumbs": [ - {"display_name": "Toy Course"}, - {"display_name": "Overview"}, - {"display_name": "Toy Videos"}, + { + 'display_name': 'Toy Course', + 'usage_key': 'block-v1:edX+toy+2012_Fall+type@course+block@course', + }, + { + 'display_name': 'Overview', + 'usage_key': 'block-v1:edX+toy+2012_Fall+type@chapter+block@Overview', + }, + { + "display_name": "Toy Videos", + "usage_key": "block-v1:edX+toy+2012_Fall+type@sequential+block@Toy_Videos", + }, ], "content": { "html_content": ( @@ -168,8 +189,14 @@ def test_video_block_untagged(self): "access_id": self.toy_course_access_id, "display_name": "Welcome", "breadcrumbs": [ - {"display_name": "Toy Course"}, - {"display_name": "Overview"}, + { + 'display_name': 'Toy Course', + 'usage_key': 'block-v1:edX+toy+2012_Fall+type@course+block@course', + }, + { + 'display_name': 'Overview', + 'usage_key': 'block-v1:edX+toy+2012_Fall+type@chapter+block@Overview', + }, ], "content": {}, # This video has no tags. diff --git a/openedx/core/djangoapps/content/search/tests/test_handlers.py b/openedx/core/djangoapps/content/search/tests/test_handlers.py index 1a1134547666..ca866e80af2c 100644 --- a/openedx/core/djangoapps/content/search/tests/test_handlers.py +++ b/openedx/core/djangoapps/content/search/tests/test_handlers.py @@ -72,7 +72,13 @@ def test_create_delete_xblock(self, meilisearch_client): "block_type": "sequential", "context_key": "course-v1:orgA+test_course+test_run", "org": "orgA", - "breadcrumbs": [{"display_name": "Test Course"}], "content": {}, + "breadcrumbs": [ + { + "display_name": "Test Course", + "usage_key": "block-v1:orgA+test_course+test_run+type@course+block@course", + }, + ], + "content": {}, "access_id": course_access.id, } @@ -87,7 +93,16 @@ def test_create_delete_xblock(self, meilisearch_client): "block_type": "vertical", "context_key": "course-v1:orgA+test_course+test_run", "org": "orgA", - "breadcrumbs": [{"display_name": "Test Course"}, {"display_name": "sequential"}], + "breadcrumbs": [ + { + "display_name": "Test Course", + "usage_key": "block-v1:orgA+test_course+test_run+type@course+block@course", + }, + { + "display_name": "sequential", + "usage_key": "block-v1:orgA+test_course+test_run+type@sequential+block@test_sequential", + }, + ], "content": {}, "access_id": course_access.id, } @@ -134,7 +149,7 @@ def test_create_delete_library_block(self, meilisearch_client): "block_type": "problem", "context_key": "lib:orgA:lib_a", "org": "orgA", - "breadcrumbs": [{"display_name": "Library Org A"}], + "breadcrumbs": [{"display_name": "Library Org A", "usage_key": "lib:orgA:lib_a"}], "content": {"problem_types": [], "capa_content": " "}, "access_id": lib_access.id, }