diff --git a/common/djangoapps/xblock_django/models.py b/common/djangoapps/xblock_django/models.py index fb175754e9..5a2442d5c9 100644 --- a/common/djangoapps/xblock_django/models.py +++ b/common/djangoapps/xblock_django/models.py @@ -41,16 +41,6 @@ class XBlockDisableConfig(ConfigurationModel): return block_type in config.disabled_blocks.split() - @classmethod - def disabled_block_types(cls): - """ Return list of disabled xblock types. """ - - config = cls.current() - if not config.enabled: - return () - - return config.disabled_blocks.split() - @classmethod def disabled_create_block_types(cls): """ Return list of deprecated XBlock types. Merges types in settings file and field. """ diff --git a/common/lib/xmodule/xmodule/modulestore/django.py b/common/lib/xmodule/xmodule/modulestore/django.py index ed98300265..798b5e110e 100644 --- a/common/lib/xmodule/xmodule/modulestore/django.py +++ b/common/lib/xmodule/xmodule/modulestore/django.py @@ -19,6 +19,7 @@ from django.conf import settings if not settings.configured: settings.configure() +from django.db.models.signals import post_save from django.core.cache import caches, InvalidCacheBackendError import django.dispatch import django.utils @@ -49,9 +50,11 @@ except ImportError: HAS_USER_SERVICE = False try: - from xblock_django.models import XBlockDisableConfig + from xblock_django.api import disabled_xblocks + from xblock_django.models import XBlockConfiguration except ImportError: - XBlockDisableConfig = None + disabled_xblocks = None + XBlockConfiguration = None log = logging.getLogger(__name__) ASSET_IGNORE_REGEX = getattr(settings, "ASSET_IGNORE_REGEX", r"(^\._.*$)|(^\.DS_Store$)|(^.*~$)") @@ -188,8 +191,8 @@ def create_modulestore_instance( if 'read_preference' in doc_store_config: doc_store_config['read_preference'] = getattr(ReadPreference, doc_store_config['read_preference']) - if XBlockDisableConfig and settings.FEATURES.get('ENABLE_DISABLING_XBLOCK_TYPES', False): - disabled_xblock_types = XBlockDisableConfig.disabled_block_types() + if disabled_xblocks: + disabled_xblock_types = [block.name for block in disabled_xblocks()] else: disabled_xblock_types = () @@ -252,6 +255,17 @@ def clear_existing_modulestores(): _MIXED_MODULESTORE = None +if XBlockConfiguration and disabled_xblocks: + @django.dispatch.receiver(post_save, sender=XBlockConfiguration) + def reset_disabled_xblocks(sender, instance, **kwargs): # pylint: disable=unused-argument + """ + If XBlockConfiguation and disabled_xblocks are available, register a signal handler + to update disabled_xblocks on model changes. + """ + disabled_xblock_types = [block.name for block in disabled_xblocks()] + modulestore().disabled_xblock_types = disabled_xblock_types + + class ModuleI18nService(object): """ Implement the XBlock runtime "i18n" service. diff --git a/common/lib/xmodule/xmodule/modulestore/mixed.py b/common/lib/xmodule/xmodule/modulestore/mixed.py index 0f726bbaf0..1c7e799338 100644 --- a/common/lib/xmodule/xmodule/modulestore/mixed.py +++ b/common/lib/xmodule/xmodule/modulestore/mixed.py @@ -185,6 +185,25 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase): self.mappings[course_key] = store self.modulestores.append(store) + @property + def disabled_xblock_types(self): + """ + Returns the list of disabled xblock types. + """ + return None if not hasattr(self, "_disabled_xblock_types") else self._disabled_xblock_types + + @disabled_xblock_types.setter + def disabled_xblock_types(self, value): + """ + Sets the list of disabled xblock types, and propagates down + to child modulestores if available. + """ + self._disabled_xblock_types = value # pylint: disable=attribute-defined-outside-init + + if hasattr(self, 'modulestores'): + for store in self.modulestores: + store.disabled_xblock_types = value + def _clean_locator_for_mapping(self, locator): """ In order for mapping to work, the locator must be minimal--no version, no branch-- diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py index 4c9b4ec742..552297aa1e 100644 --- a/lms/djangoapps/courseware/tests/test_module_render.py +++ b/lms/djangoapps/courseware/tests/test_module_render.py @@ -59,6 +59,7 @@ from openedx.core.djangoapps.credit.api import ( set_credit_requirements, set_credit_requirement_status ) +from xblock_django.models import XBlockConfiguration from edx_proctoring.api import ( create_exam, @@ -2232,7 +2233,22 @@ class TestDisabledXBlockTypes(ModuleStoreTestCase): def test_get_item(self, default_ms): with self.store.default_store(default_ms): course = CourseFactory() - for block_type in ('video',): - item = ItemFactory(category=block_type, parent=course) - item = self.store.get_item(item.scope_ids.usage_id) - self.assertEqual(item.__class__.__name__, 'RawDescriptorWithMixins') + self._verify_descriptor('video', course, 'RawDescriptorWithMixins') + + @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) + def test_dynamic_updates(self, default_ms): + """Tests that the list of disabled xblocks can dynamically update.""" + with self.store.default_store(default_ms): + course = CourseFactory() + self._verify_descriptor('problem', course, 'CapaDescriptorWithMixins') + XBlockConfiguration(name='problem', enabled=False).save() + self._verify_descriptor('problem', course, 'RawDescriptorWithMixins') + + def _verify_descriptor(self, category, course, descriptor): + """ + Helper method that gets an item with the specified category from the + modulestore and verifies that it has the expected descriptor name. + """ + item = ItemFactory(category=category, parent=course) + item = self.store.get_item(item.scope_ids.usage_id) + self.assertEqual(item.__class__.__name__, descriptor) diff --git a/lms/envs/common.py b/lms/envs/common.py index b8be3cea7b..1f41b06593 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -340,9 +340,6 @@ FEATURES = { # Enable OpenBadge support. See the BADGR_* settings later in this file. 'ENABLE_OPENBADGES': False, - # The block types to disable need to be specified in "x block disable config" in django admin. - 'ENABLE_DISABLING_XBLOCK_TYPES': True, - # Enable LTI Provider feature. 'ENABLE_LTI_PROVIDER': False,