"""Update Elasticsearch indices each time a page is modified.""" from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.db import transaction from richie.apps.courses.models import Category, Course, Organization from richie.apps.search.index_manager import richie_bulk from richie.apps.search.indexers import ES_INDICES def update_course(instance, _language): """ Update Elasticsearch indices when a course was modified and published: - update the course document in the Elasticsearch courses index. Returns None if the page was related to a course and the Elasticsearch update is done. Raises ObjectDoesNotExist if the page instance is not related to a course. """ course = Course.objects.get(draft_extension__extended_object=instance) richie_bulk([ES_INDICES.courses.get_es_document_for_course(course)]) def update_course_run(instance, _language): """ Update Elasticsearch indices when a course run was modified and published: - update the course document in the Elasticsearch courses index for the parent course of this course run. Returns None if the page was related to a course run and the Elasticsearch update is done. Raises ObjectDoesNotExist if the page instance is not related to a course run. """ course = instance.courserun.get_course().public_extension richie_bulk([ES_INDICES.courses.get_es_document_for_course(course)]) def update_organization(instance, language): """ Update Elasticsearch indices when an organization was modified and published: - update the organization document in the Elasticsearch organizations index for the organization and its direct parent (because the parent ID may change from Parent to Leaf), - update the course documents in the Elasticsearch courses index for all courses linked to this organization. Returns None if the page was related to an organization and the Elasticsearch update is done. Raises ObjectDoesNotExist if the page instance is not related to an organization. """ organization = Organization.objects.get(draft_extension__extended_object=instance) actions = [ ES_INDICES.courses.get_es_document_for_course(course) for course in organization.get_courses(language) ] actions.append( ES_INDICES.organizations.get_es_document_for_organization(organization) ) # Update the organization's parent only if it exists try: parent = organization.extended_object.get_parent_page().organization except AttributeError: pass else: actions.append( ES_INDICES.organizations.get_es_document_for_organization(parent) ) richie_bulk(actions) def update_category(instance, language): """ Update Elasticsearch indices when a category was modified and published: - update the category document in the Elasticsearch categories index for the category and its direct parent (because the parent ID may change from Parent to Leaf), - update the course documents in the Elasticsearch courses index for all courses linked to this category. Returns None if the page was related to a category and the Elasticsearch update is done. Raises ObjectDoesNotExist if the page instance is not related to a category. """ category = Category.objects.get(draft_extension__extended_object=instance) actions = [ ES_INDICES.courses.get_es_document_for_course(course) for course in category.get_courses(language) ] actions.append(ES_INDICES.categories.get_es_document_for_category(category)) # Update the category's parent only if it exists try: parent = category.extended_object.get_parent_page().category except AttributeError: pass else: actions.append(ES_INDICES.categories.get_es_document_for_category(parent)) richie_bulk(actions) def update_page_extension(instance, language): """ Try updating each type of page extension one-by-one until one works (because we don't know to which type of page extension this page is related). """ for method in [ update_course, update_course_run, update_category, update_organization, ]: try: # The method should raise an ObjectDoesNotExist exception if the page extension # linked to this instance is of another type. method(instance, language) except ObjectDoesNotExist: continue else: return # pylint: disable=unused-argument def on_page_publish(sender, instance, language, **kwargs): """ Trigger update of the Elasticsearch indices impacted by the modification of the instance only once the database transaction is successful. """ if getattr(settings, "RICHIE_KEEP_SEARCH_UPDATED", True): transaction.on_commit(lambda: update_page_extension(instance, language))