Override field data within the XBlock runtime
Resolves an issue preventing students in self-paced courses from seeing all available discussion modules. ECOM-3733.
This commit is contained in:
@@ -1160,7 +1160,7 @@ class ModuleStoreReadBase(BulkOperationsMixin, ModuleStoreRead):
|
||||
contentstore=None,
|
||||
doc_store_config=None, # ignore if passed up
|
||||
metadata_inheritance_cache_subsystem=None, request_cache=None,
|
||||
xblock_mixins=(), xblock_select=None, disabled_xblock_types=(), # pylint: disable=bad-continuation
|
||||
xblock_mixins=(), xblock_select=None, xblock_field_data_wrappers=(), disabled_xblock_types=(), # pylint: disable=bad-continuation
|
||||
# temporary parms to enable backward compatibility. remove once all envs migrated
|
||||
db=None, collection=None, host=None, port=None, tz_aware=True, user=None, password=None,
|
||||
# allow lower level init args to pass harmlessly
|
||||
@@ -1177,6 +1177,7 @@ class ModuleStoreReadBase(BulkOperationsMixin, ModuleStoreRead):
|
||||
self.request_cache = request_cache
|
||||
self.xblock_mixins = xblock_mixins
|
||||
self.xblock_select = xblock_select
|
||||
self.xblock_field_data_wrappers = xblock_field_data_wrappers
|
||||
self.disabled_xblock_types = disabled_xblock_types
|
||||
self.contentstore = contentstore
|
||||
|
||||
|
||||
@@ -120,11 +120,25 @@ def load_function(path):
|
||||
"""
|
||||
Load a function by name.
|
||||
|
||||
path is a string of the form "path.to.module.function"
|
||||
returns the imported python object `function` from `path.to.module`
|
||||
Arguments:
|
||||
path: String of the form 'path.to.module.function'. Strings of the form
|
||||
'path.to.module:Class.function' are also valid.
|
||||
|
||||
Returns:
|
||||
The imported object 'function'.
|
||||
"""
|
||||
module_path, _, name = path.rpartition('.')
|
||||
return getattr(import_module(module_path), name)
|
||||
if ':' in path:
|
||||
module_path, _, method_path = path.rpartition(':')
|
||||
module = import_module(module_path)
|
||||
|
||||
class_name, method_name = method_path.split('.')
|
||||
_class = getattr(module, class_name)
|
||||
function = getattr(_class, method_name)
|
||||
else:
|
||||
module_path, _, name = path.rpartition('.')
|
||||
function = getattr(import_module(module_path), name)
|
||||
|
||||
return function
|
||||
|
||||
|
||||
def create_modulestore_instance(
|
||||
@@ -179,12 +193,15 @@ def create_modulestore_instance(
|
||||
else:
|
||||
disabled_xblock_types = ()
|
||||
|
||||
xblock_field_data_wrappers = [load_function(path) for path in settings.XBLOCK_FIELD_DATA_WRAPPERS]
|
||||
|
||||
return class_(
|
||||
contentstore=content_store,
|
||||
metadata_inheritance_cache_subsystem=metadata_inheritance_cache,
|
||||
request_cache=request_cache,
|
||||
xblock_mixins=getattr(settings, 'XBLOCK_MIXINS', ()),
|
||||
xblock_select=getattr(settings, 'XBLOCK_SELECT_FUNCTION', None),
|
||||
xblock_field_data_wrappers=xblock_field_data_wrappers,
|
||||
disabled_xblock_types=disabled_xblock_types,
|
||||
doc_store_config=doc_store_config,
|
||||
i18n_service=i18n_service or ModuleI18nService(),
|
||||
|
||||
@@ -218,6 +218,17 @@ class InheritanceMixin(XBlockMixin):
|
||||
default=False
|
||||
)
|
||||
|
||||
self_paced = Boolean(
|
||||
display_name=_('Self Paced'),
|
||||
help=_(
|
||||
'Set this to "true" to mark this course as self-paced. Self-paced courses do not have '
|
||||
'due dates for assignments, and students can progress through the course at any rate before '
|
||||
'the course ends.'
|
||||
),
|
||||
default=False,
|
||||
scope=Scope.settings
|
||||
)
|
||||
|
||||
|
||||
def compute_inherited_metadata(descriptor):
|
||||
"""Given a descriptor, traverse all of its descendants and do metadata
|
||||
|
||||
@@ -12,27 +12,24 @@ structure:
|
||||
}
|
||||
"""
|
||||
|
||||
import pymongo
|
||||
import sys
|
||||
import logging
|
||||
import copy
|
||||
from datetime import datetime
|
||||
from importlib import import_module
|
||||
import logging
|
||||
import pymongo
|
||||
import re
|
||||
import sys
|
||||
from uuid import uuid4
|
||||
|
||||
from bson.son import SON
|
||||
from datetime import datetime
|
||||
from contracts import contract, new_contract
|
||||
from fs.osfs import OSFS
|
||||
from mongodb_proxy import autoretry_read
|
||||
from opaque_keys.edx.keys import UsageKey, CourseKey, AssetKey
|
||||
from opaque_keys.edx.locations import Location, BlockUsageLocator, SlashSeparatedCourseKey
|
||||
from opaque_keys.edx.locator import CourseLocator, LibraryLocator
|
||||
from path import Path as path
|
||||
from pytz import UTC
|
||||
from contracts import contract, new_contract
|
||||
|
||||
from importlib import import_module
|
||||
from opaque_keys.edx.keys import UsageKey, CourseKey, AssetKey
|
||||
from opaque_keys.edx.locations import Location, BlockUsageLocator
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
from opaque_keys.edx.locator import CourseLocator, LibraryLocator
|
||||
|
||||
from xblock.core import XBlock
|
||||
from xblock.exceptions import InvalidScopeError
|
||||
from xblock.fields import Scope, ScopeIds, Reference, ReferenceList, ReferenceValueDict
|
||||
@@ -54,6 +51,7 @@ from xmodule.modulestore.xml import CourseLocationManager
|
||||
from xmodule.modulestore.store_utilities import DETACHED_XBLOCK_TYPES
|
||||
from xmodule.services import SettingsService
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
new_contract('CourseKey', CourseKey)
|
||||
@@ -318,6 +316,9 @@ class CachingDescriptorSystem(MakoDescriptorSystem, EditInfoRuntimeMixin):
|
||||
).replace(tzinfo=UTC)
|
||||
module._edit_info['published_by'] = raw_metadata.get('published_by')
|
||||
|
||||
for wrapper in self.modulestore.xblock_field_data_wrappers:
|
||||
module._field_data = wrapper(module, module._field_data) # pylint: disable=protected-access
|
||||
|
||||
# decache any computed pending field settings
|
||||
module.save()
|
||||
return module
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from contracts import contract, new_contract
|
||||
from fs.osfs import OSFS
|
||||
from lazy import lazy
|
||||
@@ -7,6 +8,7 @@ from xblock.runtime import KvsFieldData, KeyValueStore
|
||||
from xblock.fields import ScopeIds
|
||||
from xblock.core import XBlock
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, LocalId, CourseLocator, LibraryLocator, DefinitionLocator
|
||||
|
||||
from xmodule.library_tools import LibraryToolsService
|
||||
from xmodule.mako_module import MakoDescriptorSystem
|
||||
from xmodule.error_module import ErrorDescriptor
|
||||
@@ -263,6 +265,10 @@ class CachingDescriptorSystem(MakoDescriptorSystem, EditInfoRuntimeMixin):
|
||||
module.update_version = edit_info.update_version
|
||||
module.source_version = edit_info.source_version
|
||||
module.definition_locator = DefinitionLocator(block_key.type, definition_id)
|
||||
|
||||
for wrapper in self.modulestore.xblock_field_data_wrappers:
|
||||
module._field_data = wrapper(module, module._field_data) # pylint: disable=protected-access
|
||||
|
||||
# decache any pending field settings
|
||||
module.save()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user