diff --git a/cms/djangoapps/contentstore/courseware_index.py b/cms/djangoapps/contentstore/courseware_index.py index ab522f44ca7b3a731c46be93b11fb1ee305ddf67..3a28ee90fbf96d563032dce445cdc3ba0401a84f 100644 --- a/cms/djangoapps/contentstore/courseware_index.py +++ b/cms/djangoapps/contentstore/courseware_index.py @@ -10,9 +10,6 @@ from eventtracking import tracker from xmodule.modulestore import ModuleStoreEnum from search.search_engine_base import SearchEngine -from opaque_keys.edx.locator import CourseLocator, LibraryLocator - - # REINDEX_AGE is the default amount of time that we look back for changes # that might have happened. If we are provided with a time at which the # indexing is triggered, then we know it is safe to only index items @@ -23,13 +20,6 @@ REINDEX_AGE = timedelta(0, 60) # 60 seconds log = logging.getLogger('edx.modulestore') -def indexing_is_enabled(): - """ - Checks to see if the indexing feature is enabled - """ - return settings.FEATURES.get('ENABLE_COURSEWARE_INDEX', False) - - class SearchIndexingError(Exception): """ Indicates some error(s) occured during indexing """ @@ -45,12 +35,20 @@ class SearchIndexBase(object): INDEX_NAME = None DOCUMENT_TYPE = None + ENABLE_INDEXING_KEY = None INDEX_EVENT = { 'name': None, 'category': None } + @classmethod + def indexing_is_enabled(cls): + """ + Checks to see if the indexing feature is enabled + """ + return settings.FEATURES.get(cls.ENABLE_INDEXING_KEY, False) + @classmethod def _fetch_top_level(self, modulestore, structure_key): """ Fetch the item from the modulestore location """ @@ -220,6 +218,7 @@ class SearchIndexBase(object): class CoursewareSearchIndexer(SearchIndexBase): INDEX_NAME = "courseware_index" DOCUMENT_TYPE = "courseware_content" + ENABLE_INDEXING_KEY = 'ENABLE_COURSEWARE_INDEX' INDEX_EVENT = { 'name': 'edx.course.index.reindexed', @@ -247,6 +246,7 @@ class CoursewareSearchIndexer(SearchIndexBase): class LibrarySearchIndexer(SearchIndexBase): INDEX_NAME = "library_index" DOCUMENT_TYPE = "library_content" + ENABLE_INDEXING_KEY = 'ENABLE_LIBRARY_INDEX' INDEX_EVENT = { 'name': 'edx.library.index.reindexed', diff --git a/cms/djangoapps/contentstore/signals.py b/cms/djangoapps/contentstore/signals.py index df21a57ccd587ba7cbb31d6d0aa7cc52c31521b6..27e9bda4fea6d692e2ed8e80e840993701067fa8 100644 --- a/cms/djangoapps/contentstore/signals.py +++ b/cms/djangoapps/contentstore/signals.py @@ -5,7 +5,7 @@ from pytz import UTC from django.dispatch import receiver from xmodule.modulestore.django import SignalHandler -from contentstore.courseware_index import indexing_is_enabled +from contentstore.courseware_index import CoursewareSearchIndexer, LibrarySearchIndexer @receiver(SignalHandler.course_published) @@ -15,5 +15,16 @@ def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable= """ # import here, because signal is registered at startup, but items in tasks are not yet able to be loaded from .tasks import update_search_index - if indexing_is_enabled(): + if CoursewareSearchIndexer.indexing_is_enabled(): update_search_index.delay(unicode(course_key), datetime.now(UTC).isoformat()) + + +@receiver(SignalHandler.library_updated) +def listen_for_course_publish(sender, library_key, **kwargs): # pylint: disable=unused-argument + """ + Receives signal and kicks off celery task to update search index + """ + # import here, because signal is registered at startup, but items in tasks are not yet able to be loaded + from .tasks import update_library_index + if LibrarySearchIndexer.indexing_is_enabled(): + update_library_index.delay(unicode(library_key), datetime.now(UTC).isoformat()) diff --git a/cms/djangoapps/contentstore/tasks.py b/cms/djangoapps/contentstore/tasks.py index cebf5aee73cc468d623a5eb29d97a4aca2dbccec..9b1942df1eae8a4adc0e46df6a0cb9f34ab69ee3 100644 --- a/cms/djangoapps/contentstore/tasks.py +++ b/cms/djangoapps/contentstore/tasks.py @@ -10,7 +10,7 @@ from pytz import UTC from django.contrib.auth.models import User -from contentstore.courseware_index import CoursewareSearchIndexer, SearchIndexingError +from contentstore.courseware_index import CoursewareSearchIndexer, LibrarySearchIndexer, SearchIndexingError from contentstore.utils import initialize_permissions from course_action_state.models import CourseRerunState from opaque_keys.edx.keys import CourseKey @@ -98,3 +98,15 @@ def update_search_index(course_id, triggered_time_isoformat): LOGGER.error('Search indexing error for complete course %s - %s', course_id, unicode(exc)) else: LOGGER.debug('Search indexing successful for complete course %s', course_id) + +@task() +def update_library_index(library_id, triggered_time): + """ Updates course search index. """ + try: + library_key = CourseKey.from_string(library_id) + LibrarySearchIndexed.indexindex_course(modulestore(), library_key, triggered_at=triggered_time) + + except SearchIndexingError as exc: + LOGGER.error('Search indexing error for library %s - %s', library_id, unicode(exc)) + else: + LOGGER.debug('Search indexing successful for library %s', library_id) \ No newline at end of file diff --git a/cms/envs/aws.py b/cms/envs/aws.py index e78bae1c4110c7f0ebaf9aeab40dece67e4ebd07..3eb5dc99b8ff205149d081bf98de17d27d4809ce 100644 --- a/cms/envs/aws.py +++ b/cms/envs/aws.py @@ -328,7 +328,7 @@ API_DATE_FORMAT = ENV_TOKENS.get('API_DATE_FORMAT', API_DATE_FORMAT) # Example: {'CN': 'http://api.xuetangx.com/edx/video?s3_url='} VIDEO_CDN_URL = ENV_TOKENS.get('VIDEO_CDN_URL', {}) -if FEATURES['ENABLE_COURSEWARE_INDEX']: +if FEATURES['ENABLE_COURSEWARE_INDEX'] or FEATURES['ENABLE_LIBRARY_INDEX']: # Use ElasticSearch for the search engine SEARCH_ENGINE = "search.elastic.ElasticSearchEngine" diff --git a/cms/envs/bok_choy.py b/cms/envs/bok_choy.py index eb5e32193b9af9bef4c5eb67bf689e3b0097935e..0f0cdb85cb89a2d42cea3312944096ea3dcc205b 100644 --- a/cms/envs/bok_choy.py +++ b/cms/envs/bok_choy.py @@ -78,6 +78,7 @@ YOUTUBE['TEST_URL'] = "127.0.0.1:{0}/test_youtube/".format(YOUTUBE_PORT) YOUTUBE['TEXT_API']['url'] = "127.0.0.1:{0}/test_transcripts_youtube/".format(YOUTUBE_PORT) FEATURES['ENABLE_COURSEWARE_INDEX'] = True +FEATURES['ENABLE_LIBRARY_INDEX'] = True SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine" # Path at which to store the mock index MOCK_SEARCH_BACKING_FILE = ( diff --git a/cms/envs/common.py b/cms/envs/common.py index f3278b0a8b9186590cb564b3c4d833fb807179e4..4654aef5b7e53237cc29d9b05cdffabbdd69dfa2 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -140,6 +140,9 @@ FEATURES = { # Enable the courseware search functionality 'ENABLE_COURSEWARE_INDEX': False, + # Enable content libraries search functionality + 'ENABLE_LIBRARY_INDEX': False, + # Enable course reruns, which will always use the split modulestore 'ALLOW_COURSE_RERUNS': True, diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py index 533b88bcc799642f21e52c8c1e58158c9876934e..3aa7f47b00080ad7d473be28dd914fbd0b1ca62b 100644 --- a/cms/envs/devstack.py +++ b/cms/envs/devstack.py @@ -80,6 +80,7 @@ FEATURES['ENTRANCE_EXAMS'] = True ################################ SEARCH INDEX ################################ FEATURES['ENABLE_COURSEWARE_INDEX'] = True +FEATURES['ENABLE_LIBRARY_INDEX'] = True SEARCH_ENGINE = "search.elastic.ElasticSearchEngine" ############################################################################### diff --git a/cms/envs/test.py b/cms/envs/test.py index 87b03469b42f401bc56eed63564d03c9fb921bc5..ddc48208b451d32b0bd75657e515d95efa7777de 100644 --- a/cms/envs/test.py +++ b/cms/envs/test.py @@ -267,6 +267,7 @@ VIDEO_CDN_URL = { # Courseware Search Index FEATURES['ENABLE_COURSEWARE_INDEX'] = True +FEATURES['ENABLE_LIBRARY_INDEX'] = True SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine" # Dummy secret key for dev/test diff --git a/common/lib/xmodule/xmodule/modulestore/django.py b/common/lib/xmodule/xmodule/modulestore/django.py index a6bdb6ce75af6954e26f8d044d43ec45e44c5896..a8c73d7f3df20c43a9bd9a0856c925b002105aca 100644 --- a/common/lib/xmodule/xmodule/modulestore/django.py +++ b/common/lib/xmodule/xmodule/modulestore/django.py @@ -80,9 +80,11 @@ class SignalHandler(object): """ course_published = django.dispatch.Signal(providing_args=["course_key"]) + library_updated = django.dispatch.Signal(providing_args=["library_key"]) _mapping = { - "course_published": course_published + "course_published": course_published, + "library_updated": library_updated } def __init__(self, modulestore_class):