diff --git a/openedx/core/djangoapps/content/search/tests/test_documents.py b/openedx/core/djangoapps/content/search/tests/test_documents.py index 9394ca254bb2..78ed68039c51 100644 --- a/openedx/core/djangoapps/content/search/tests/test_documents.py +++ b/openedx/core/djangoapps/content/search/tests/test_documents.py @@ -1,6 +1,8 @@ """ Tests for the Studio content search documents (what gets stored in the index) """ +from organizations.models import Organization +from openedx.core.djangoapps.content_tagging import api as tagging_api from openedx.core.djangolib.testing.utils import skip_unless_cms from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase @@ -24,6 +26,8 @@ def setUpClass(cls): cls.store = modulestore() cls.toy_course = ToyCourseFactory.create() # See xmodule/modulestore/tests/sample_courses.py cls.toy_course_key = cls.toy_course.id + # Get references to some blocks in the toy course + cls.html_block_key = cls.toy_course_key.make_usage_key("html", "toyjumpto") # Create a problem in library cls.problem_block = BlockFactory.create( category="problem", @@ -32,11 +36,29 @@ def setUpClass(cls): data="What is a test?", ) + # Create a couple taxonomies and some tags + cls.org = Organization.objects.create(name="edX", short_name="edX") + cls.difficulty_tags = tagging_api.create_taxonomy(name="Difficulty", orgs=[cls.org], allow_multiple=False) + tagging_api.add_tag_to_taxonomy(cls.difficulty_tags, tag="Easy") + tagging_api.add_tag_to_taxonomy(cls.difficulty_tags, tag="Normal") + tagging_api.add_tag_to_taxonomy(cls.difficulty_tags, tag="Difficult") + + cls.subject_tags = tagging_api.create_taxonomy(name="Subject", orgs=[cls.org], allow_multiple=True) + tagging_api.add_tag_to_taxonomy(cls.subject_tags, tag="Linguistics") + tagging_api.add_tag_to_taxonomy(cls.subject_tags, tag="Asian Languages", parent_tag_value="Linguistics") + tagging_api.add_tag_to_taxonomy(cls.subject_tags, tag="Chinese", parent_tag_value="Asian Languages") + tagging_api.add_tag_to_taxonomy(cls.subject_tags, tag="Hypertext") + tagging_api.add_tag_to_taxonomy(cls.subject_tags, tag="Jump Links", parent_tag_value="Hypertext") + + # Tag stuff: + tagging_api.tag_object(cls.problem_block.usage_key, cls.difficulty_tags, tags=["Easy"]) + tagging_api.tag_object(cls.html_block_key, cls.subject_tags, tags=["Chinese", "Jump Links"]) + tagging_api.tag_object(cls.html_block_key, cls.difficulty_tags, tags=["Normal"]) + def test_problem_block(self): """ Test how a problem block gets represented in the search index """ - # block_usage_key = self.toy_course_key.make_usage_key("problem", "test_problem") block = self.store.get_item(self.problem_block.usage_key) doc = searchable_doc_for_course_block(block) assert doc == { @@ -60,4 +82,68 @@ def test_problem_block(self): "capa_content": "What is a test?", "problem_types": ["multiplechoiceresponse"], }, + # See https://blog.meilisearch.com/nested-hierarchical-facets-guide/ + # and https://www.algolia.com/doc/api-reference/widgets/hierarchical-menu/js/ + # For details on why the hierarchical tag data is in this format. + "tags": { + "taxonomy": ["Difficulty"], + "level0": ["Difficulty > Easy"], + }, + } + + def test_html_block(self): + """ + Test how an HTML block gets represented in the search index + """ + block = self.store.get_item(self.html_block_key) + doc = searchable_doc_for_course_block(block) + assert doc == { + "id": "block-v1edxtoy2012_falltypehtmlblocktoyjumpto-b0b4a10", + "type": "course_block", + "block_type": "html", + "usage_key": "block-v1:edX+toy+2012_Fall+type@html+block@toyjumpto", + "block_id": "toyjumpto", + "context_key": "course-v1:edX+toy+2012_Fall", + "org": "edX", + "display_name": "Text", + "breadcrumbs": [ + {"display_name": "Toy Course"}, + {"display_name": "Overview"}, + {"display_name": "Toy Videos"}, + ], + "content": { + "html_content": ( + "This is a link to another page and some Chinese 四節比分和七年前 Some more Chinese 四節比分和七年前 " + ), + }, + "tags": { + "taxonomy": ["Difficulty", "Subject"], + "level0": ["Difficulty > Normal", "Subject > Hypertext", "Subject > Linguistics"], + "level1": ["Subject > Hypertext > Jump Links", "Subject > Linguistics > Asian Languages"], + "level2": ["Subject > Linguistics > Asian Languages > Chinese"], + }, + } + + def test_video_block_untagged(self): + """ + Test how a video block gets represented in the search index. + """ + block_usage_key = self.toy_course_key.make_usage_key("video", "Welcome") + block = self.store.get_item(block_usage_key) + doc = searchable_doc_for_course_block(block) + assert doc == { + "id": "block-v1edxtoy2012_falltypevideoblockwelcome-b47fb14", + "type": "course_block", + "block_type": "video", + "usage_key": "block-v1:edX+toy+2012_Fall+type@video+block@Welcome", + "block_id": "Welcome", + "context_key": "course-v1:edX+toy+2012_Fall", + "org": "edX", + "display_name": "Welcome", + "breadcrumbs": [ + {"display_name": "Toy Course"}, + {"display_name": "Overview"}, + ], + "content": {}, + # This video has no tags. } diff --git a/openedx/core/djangoapps/content_tagging/api.py b/openedx/core/djangoapps/content_tagging/api.py index c167eba3a629..e50d96fe2ce2 100644 --- a/openedx/core/djangoapps/content_tagging/api.py +++ b/openedx/core/djangoapps/content_tagging/api.py @@ -200,6 +200,9 @@ def set_object_tags( # Expose the oel_tagging APIs +add_tag_to_taxonomy = oel_tagging.add_tag_to_taxonomy +update_tag_in_taxonomy = oel_tagging.update_tag_in_taxonomy +delete_tags_from_taxonomy = oel_tagging.delete_tags_from_taxonomy get_taxonomy = oel_tagging.get_taxonomy get_taxonomies = oel_tagging.get_taxonomies get_tags = oel_tagging.get_tags