Commit a39dfbb2 by Gregory Martin Committed by GitHub

Merge pull request #15127 from edx/yro_refactorCMSsignalhandling

Refactor CMS Signal Handling
parents 95add48b b4f265ad
"""
Contentstore Application Configuration
Above-modulestore level signal handlers are connected here.
"""
from django.apps import AppConfig
class ContentstoreConfig(AppConfig):
"""
Application Configuration for Grades.
"""
name = u'contentstore'
def ready(self):
"""
Connect handlers to signals.
"""
# Can't import models at module level in AppConfigs, and models get
# included from the signal handlers
from .signals import handlers # pylint: disable=unused-variable
...@@ -4,7 +4,7 @@ import logging ...@@ -4,7 +4,7 @@ import logging
from datetime import datetime from datetime import datetime
from pytz import UTC from pytz import UTC
from django.dispatch import receiver, Signal from django.dispatch import receiver
from xmodule.modulestore.django import modulestore, SignalHandler from xmodule.modulestore.django import modulestore, SignalHandler
from contentstore.courseware_index import CoursewareSearchIndexer, LibrarySearchIndexer from contentstore.courseware_index import CoursewareSearchIndexer, LibrarySearchIndexer
...@@ -17,17 +17,6 @@ from util.module_utils import yield_dynamic_descriptor_descendants ...@@ -17,17 +17,6 @@ from util.module_utils import yield_dynamic_descriptor_descendants
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# Signal that indicates that a course grading policy has been updated.
# This signal is generated when a grading policy change occurs within
# modulestore for either course or subsection changes.
GRADING_POLICY_CHANGED = Signal(
providing_args=[
'user_id', # Integer User ID
'course_id', # Unicode string representing the course
]
)
@receiver(SignalHandler.course_published) @receiver(SignalHandler.course_published)
def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument
""" """
...@@ -50,10 +39,9 @@ def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable= ...@@ -50,10 +39,9 @@ def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=
# Finally call into the course search subsystem # Finally call into the course search subsystem
# to kick off an indexing action # to kick off an indexing action
if CoursewareSearchIndexer.indexing_is_enabled(): if CoursewareSearchIndexer.indexing_is_enabled():
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded # 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 from contentstore.tasks import update_search_index
update_search_index.delay(unicode(course_key), datetime.now(UTC).isoformat()) update_search_index.delay(unicode(course_key), datetime.now(UTC).isoformat())
...@@ -66,7 +54,7 @@ def listen_for_library_update(sender, library_key, **kwargs): # pylint: disable ...@@ -66,7 +54,7 @@ def listen_for_library_update(sender, library_key, **kwargs): # pylint: disable
if LibrarySearchIndexer.indexing_is_enabled(): if LibrarySearchIndexer.indexing_is_enabled():
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded # 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 from contentstore.tasks import update_library_index
update_library_index.delay(unicode(library_key), datetime.now(UTC).isoformat()) update_library_index.delay(unicode(library_key), datetime.now(UTC).isoformat())
......
"""
Contentstore signals
"""
from django.dispatch import Signal
# Signal that indicates that a course grading policy has been updated.
# This signal is generated when a grading policy change occurs within
# modulestore for either course or subsection changes.
GRADING_POLICY_CHANGED = Signal(
providing_args=[
'user_id', # Integer User ID
'course_id', # Unicode string representing the course
]
)
""" will register signal handlers, moved out of __init__.py to ensure correct loading order post Django 1.7 """
from . import signals # pylint: disable=unused-import
...@@ -44,7 +44,7 @@ from contentstore.courseware_index import ( ...@@ -44,7 +44,7 @@ from contentstore.courseware_index import (
SearchIndexingError, SearchIndexingError,
CourseAboutSearchIndexer, CourseAboutSearchIndexer,
) )
from contentstore.signals import listen_for_course_publish, listen_for_library_update from contentstore.signals.handlers import listen_for_course_publish, listen_for_library_update
from contentstore.utils import reverse_course_url, reverse_usage_url from contentstore.utils import reverse_course_url, reverse_usage_url
from contentstore.tests.utils import CourseTestCase from contentstore.tests.utils import CourseTestCase
......
""" """
Unit tests for the gating feature in Studio Unit tests for the gating feature in Studio
""" """
from contentstore.signals import handle_item_deleted from contentstore.signals.handlers import handle_item_deleted
from milestones.tests.utils import MilestonesTestCaseMixin from milestones.tests.utils import MilestonesTestCaseMixin
from mock import patch from mock import patch
from openedx.core.lib.gating import api as gating_api from openedx.core.lib.gating import api as gating_api
...@@ -42,16 +42,16 @@ class TestHandleItemDeleted(ModuleStoreTestCase, MilestonesTestCaseMixin): ...@@ -42,16 +42,16 @@ class TestHandleItemDeleted(ModuleStoreTestCase, MilestonesTestCaseMixin):
gating_api.add_prerequisite(self.course.id, self.open_seq.location) gating_api.add_prerequisite(self.course.id, self.open_seq.location)
gating_api.set_required_content(self.course.id, self.gated_seq.location, self.open_seq.location, 100) gating_api.set_required_content(self.course.id, self.gated_seq.location, self.open_seq.location, 100)
@patch('contentstore.signals.gating_api.set_required_content') @patch('contentstore.signals.handlers.gating_api.set_required_content')
@patch('contentstore.signals.gating_api.remove_prerequisite') @patch('contentstore.signals.handlers.gating_api.remove_prerequisite')
def test_chapter_deleted(self, mock_remove_prereq, mock_set_required): def test_chapter_deleted(self, mock_remove_prereq, mock_set_required):
""" Test gating milestone data is cleanup up when course content item is deleted """ """ Test gating milestone data is cleanup up when course content item is deleted """
handle_item_deleted(usage_key=self.chapter.location, user_id=0) handle_item_deleted(usage_key=self.chapter.location, user_id=0)
mock_remove_prereq.assert_called_with(self.open_seq.location) mock_remove_prereq.assert_called_with(self.open_seq.location)
mock_set_required.assert_called_with(self.open_seq.location.course_key, self.open_seq.location, None, None) mock_set_required.assert_called_with(self.open_seq.location.course_key, self.open_seq.location, None, None)
@patch('contentstore.signals.gating_api.set_required_content') @patch('contentstore.signals.handlers.gating_api.set_required_content')
@patch('contentstore.signals.gating_api.remove_prerequisite') @patch('contentstore.signals.handlers.gating_api.remove_prerequisite')
def test_sequential_deleted(self, mock_remove_prereq, mock_set_required): def test_sequential_deleted(self, mock_remove_prereq, mock_set_required):
""" Test gating milestone data is cleanup up when course content item is deleted """ """ Test gating milestone data is cleanup up when course content item is deleted """
handle_item_deleted(usage_key=self.open_seq.location, user_id=0) handle_item_deleted(usage_key=self.open_seq.location, user_id=0)
......
...@@ -9,7 +9,7 @@ from pytz import UTC ...@@ -9,7 +9,7 @@ from pytz import UTC
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from contentstore.signals import listen_for_course_publish from contentstore.signals.handlers import listen_for_course_publish
from edx_proctoring.api import ( from edx_proctoring.api import (
get_all_exams_for_course, get_all_exams_for_course,
......
...@@ -128,8 +128,8 @@ class TestSubsectionGating(CourseTestCase): ...@@ -128,8 +128,8 @@ class TestSubsectionGating(CourseTestCase):
self.assertEqual(resp['prereq_min_score'], 100) self.assertEqual(resp['prereq_min_score'], 100)
self.assertEqual(resp['visibility_state'], VisibilityState.gated) self.assertEqual(resp['visibility_state'], VisibilityState.gated)
@patch('contentstore.signals.gating_api.set_required_content') @patch('contentstore.signals.handlers.gating_api.set_required_content')
@patch('contentstore.signals.gating_api.remove_prerequisite') @patch('contentstore.signals.handlers.gating_api.remove_prerequisite')
def test_delete_item_signal_handler_called(self, mock_remove_prereq, mock_set_required): def test_delete_item_signal_handler_called(self, mock_remove_prereq, mock_set_required):
seq3 = ItemFactory.create( seq3 = ItemFactory.create(
parent_location=self.chapter.location, parent_location=self.chapter.location,
......
...@@ -868,7 +868,8 @@ INSTALLED_APPS = ( ...@@ -868,7 +868,8 @@ INSTALLED_APPS = (
'django_nose', 'django_nose',
# For CMS # For CMS
'contentstore', 'contentstore.apps.ContentstoreConfig',
'openedx.core.djangoapps.contentserver', 'openedx.core.djangoapps.contentserver',
'course_creators', 'course_creators',
'openedx.core.djangoapps.external_auth', 'openedx.core.djangoapps.external_auth',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment