From a97a23471027cd5953f2fc77d51a271dd6d647d1 Mon Sep 17 00:00:00 2001 From: "waleed.mujahid" Date: Wed, 4 Mar 2026 21:36:59 +0500 Subject: [PATCH 1/2] fix: create SearchAccess on library creation for course creator search access When a course creator creates a new library, the SearchAccess record must exist immediately so their JWT token can include the library's access_id. Without this, course creators cannot see newly added components in search results until the page is refreshed. This issue doesn't affect superusers who bypass access_id filtering. --- openedx/core/djangoapps/content/search/handlers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openedx/core/djangoapps/content/search/handlers.py b/openedx/core/djangoapps/content/search/handlers.py index 38dac3153596..fe5ddecdbf9f 100644 --- a/openedx/core/djangoapps/content/search/handlers.py +++ b/openedx/core/djangoapps/content/search/handlers.py @@ -192,7 +192,7 @@ def library_block_deleted(**kwargs) -> None: @only_if_meilisearch_enabled def content_library_created_handler(**kwargs) -> None: """ - Create the index for the content library + Create the index and SearchAccess for the content library """ content_library_data = kwargs.get("content_library", None) if not content_library_data or not isinstance(content_library_data, ContentLibraryData): # pragma: no cover @@ -200,6 +200,10 @@ def content_library_created_handler(**kwargs) -> None: return library_key = content_library_data.library_key + # Create SearchAccess record immediately so course creators can search this library + # right after creation. Without this, the JWT token won't include the new library's + # access_id until it's added by the document indexing process or the page is refreshed. + SearchAccess.objects.get_or_create(context_key=library_key) update_content_library_index_docs.apply(args=[str(library_key), True]) From 5d6fc06110183620f5bafb8701428ac236a9fc29 Mon Sep 17 00:00:00 2001 From: "waleed.mujahid" Date: Wed, 4 Mar 2026 21:53:35 +0500 Subject: [PATCH 2/2] test: verify SearchAccess is created automatically on library creation --- .../content/search/tests/test_handlers.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/openedx/core/djangoapps/content/search/tests/test_handlers.py b/openedx/core/djangoapps/content/search/tests/test_handlers.py index 7ccbec687e98..17f5962f90dd 100644 --- a/openedx/core/djangoapps/content/search/tests/test_handlers.py +++ b/openedx/core/djangoapps/content/search/tests/test_handlers.py @@ -138,6 +138,23 @@ def test_create_delete_xblock(self, meilisearch_client): "block-v1orgatest_coursetest_runtypeverticalblocktest_vertical-011f143b" ) + def test_library_creation_creates_search_access(self, meilisearch_client): + """ + Test that creating a library automatically creates a SearchAccess record. + This is required for course creators to search library content immediately after creation. + """ + # Create a library + library = library_api.create_library( + org=self.orgA, + slug="test_lib", + title="Test Library", + description="Test library for SearchAccess creation", + ) + + assert SearchAccess.objects.filter(context_key=library.key).exists() + search_access = SearchAccess.objects.get(context_key=library.key) + assert search_access.context_key == library.key + def test_create_delete_library_block(self, meilisearch_client): # Create library library = library_api.create_library( @@ -146,7 +163,7 @@ def test_create_delete_library_block(self, meilisearch_client): title="Library Org A", description="This is a library from Org A", ) - lib_access, _ = SearchAccess.objects.get_or_create(context_key=library.key) + lib_access = SearchAccess.objects.get(context_key=library.key) # Populate it with a problem, freezing the date so we can verify created date serializes correctly. created_date = datetime(2023, 4, 5, 6, 7, 8, tzinfo=timezone.utc)