|
|
|
|
@@ -11,11 +11,12 @@ from ..exceptions import ItemNotFoundError
|
|
|
|
|
from .split_mongo_kvs import SplitMongoKVS
|
|
|
|
|
from fs.osfs import OSFS
|
|
|
|
|
from .definition_lazy_loader import DefinitionLazyLoader
|
|
|
|
|
from xmodule.modulestore.edit_info import EditInfoRuntimeMixin
|
|
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CachingDescriptorSystem(MakoDescriptorSystem):
|
|
|
|
|
class CachingDescriptorSystem(MakoDescriptorSystem, EditInfoRuntimeMixin):
|
|
|
|
|
"""
|
|
|
|
|
A system that has a cache of a course version's json that it will use to load modules
|
|
|
|
|
from, with a backup of calling to the underlying modulestore for more data.
|
|
|
|
|
@@ -89,6 +90,19 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
|
|
|
|
|
run=course_info.get('run'),
|
|
|
|
|
branch=course_info.get('branch'),
|
|
|
|
|
)
|
|
|
|
|
json_data = self.get_module_data(block_id, course_key)
|
|
|
|
|
|
|
|
|
|
class_ = self.load_block_type(json_data.get('category'))
|
|
|
|
|
new_item = self.xblock_from_json(class_, course_key, block_id, json_data, course_entry_override, **kwargs)
|
|
|
|
|
return new_item
|
|
|
|
|
|
|
|
|
|
def get_module_data(self, block_id, course_key):
|
|
|
|
|
"""
|
|
|
|
|
Get block from module_data adding it to module_data if it's not already there but is in the structure
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
ItemNotFoundError if block is not in the structure
|
|
|
|
|
"""
|
|
|
|
|
json_data = self.module_data.get(block_id)
|
|
|
|
|
if json_data is None:
|
|
|
|
|
# deeper than initial descendant fetch or doesn't exist
|
|
|
|
|
@@ -97,9 +111,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
|
|
|
|
|
if json_data is None:
|
|
|
|
|
raise ItemNotFoundError(block_id)
|
|
|
|
|
|
|
|
|
|
class_ = self.load_block_type(json_data.get('category'))
|
|
|
|
|
new_item = self.xblock_from_json(class_, course_key, block_id, json_data, course_entry_override, **kwargs)
|
|
|
|
|
return new_item
|
|
|
|
|
return json_data
|
|
|
|
|
|
|
|
|
|
# xblock's runtime does not always pass enough contextual information to figure out
|
|
|
|
|
# which named container (course x branch) or which parent is requesting an item. Because split allows
|
|
|
|
|
@@ -181,12 +193,8 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
edit_info = json_data.get('edit_info', {})
|
|
|
|
|
module.edited_by = edit_info.get('edited_by')
|
|
|
|
|
module.edited_on = edit_info.get('edited_on')
|
|
|
|
|
module.subtree_edited_by = None # TODO - addressed with LMS-11183
|
|
|
|
|
module.subtree_edited_on = None # TODO - addressed with LMS-11183
|
|
|
|
|
module.published_by = None # TODO - addressed with LMS-11184
|
|
|
|
|
module.published_date = None # TODO - addressed with LMS-11184
|
|
|
|
|
module._edited_by = edit_info.get('edited_by')
|
|
|
|
|
module._edited_on = edit_info.get('edited_on')
|
|
|
|
|
module.previous_version = edit_info.get('previous_version')
|
|
|
|
|
module.update_version = edit_info.get('update_version')
|
|
|
|
|
module.source_version = edit_info.get('source_version', None)
|
|
|
|
|
@@ -199,3 +207,79 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
|
|
|
|
|
self.local_modules[block_locator] = module
|
|
|
|
|
|
|
|
|
|
return module
|
|
|
|
|
|
|
|
|
|
def get_edited_by(self, xblock):
|
|
|
|
|
"""
|
|
|
|
|
See :meth: cms.lib.xblock.runtime.EditInfoRuntimeMixin.get_edited_by
|
|
|
|
|
"""
|
|
|
|
|
return xblock._edited_by
|
|
|
|
|
|
|
|
|
|
def get_edited_on(self, xblock):
|
|
|
|
|
"""
|
|
|
|
|
See :class: cms.lib.xblock.runtime.EditInfoRuntimeMixin
|
|
|
|
|
"""
|
|
|
|
|
return xblock._edited_on
|
|
|
|
|
|
|
|
|
|
def get_subtree_edited_by(self, xblock):
|
|
|
|
|
"""
|
|
|
|
|
See :class: cms.lib.xblock.runtime.EditInfoRuntimeMixin
|
|
|
|
|
"""
|
|
|
|
|
if not hasattr(xblock, '_subtree_edited_by'):
|
|
|
|
|
json_data = self.module_data[xblock.location.block_id]
|
|
|
|
|
if '_subtree_edited_by' not in json_data.setdefault('edit_info', {}):
|
|
|
|
|
self._compute_subtree_edited_internal(
|
|
|
|
|
xblock.location.block_id, json_data, xblock.location.course_key
|
|
|
|
|
)
|
|
|
|
|
setattr(xblock, '_subtree_edited_by', json_data['edit_info']['_subtree_edited_by'])
|
|
|
|
|
|
|
|
|
|
return getattr(xblock, '_subtree_edited_by')
|
|
|
|
|
|
|
|
|
|
def get_subtree_edited_on(self, xblock):
|
|
|
|
|
"""
|
|
|
|
|
See :class: cms.lib.xblock.runtime.EditInfoRuntimeMixin
|
|
|
|
|
"""
|
|
|
|
|
if not hasattr(xblock, '_subtree_edited_on'):
|
|
|
|
|
json_data = self.module_data[xblock.location.block_id]
|
|
|
|
|
if '_subtree_edited_on' not in json_data.setdefault('edit_info', {}):
|
|
|
|
|
self._compute_subtree_edited_internal(
|
|
|
|
|
xblock.location.block_id, json_data, xblock.location.course_key
|
|
|
|
|
)
|
|
|
|
|
setattr(xblock, '_subtree_edited_on', json_data['edit_info']['_subtree_edited_on'])
|
|
|
|
|
|
|
|
|
|
return getattr(xblock, '_subtree_edited_on')
|
|
|
|
|
|
|
|
|
|
def get_published_by(self, xblock):
|
|
|
|
|
"""
|
|
|
|
|
See :class: cms.lib.xblock.runtime.EditInfoRuntimeMixin
|
|
|
|
|
"""
|
|
|
|
|
if not hasattr(xblock, '_published_by'):
|
|
|
|
|
self.modulestore.compute_published_info_internal(xblock)
|
|
|
|
|
|
|
|
|
|
return getattr(xblock, '_published_by', None)
|
|
|
|
|
|
|
|
|
|
def get_published_on(self, xblock):
|
|
|
|
|
"""
|
|
|
|
|
See :class: cms.lib.xblock.runtime.EditInfoRuntimeMixin
|
|
|
|
|
"""
|
|
|
|
|
if not hasattr(xblock, '_published_on'):
|
|
|
|
|
self.modulestore.compute_published_info_internal(xblock)
|
|
|
|
|
|
|
|
|
|
return getattr(xblock, '_published_on', None)
|
|
|
|
|
|
|
|
|
|
def _compute_subtree_edited_internal(self, block_id, json_data, course_key):
|
|
|
|
|
"""
|
|
|
|
|
Recurse the subtree finding the max edited_on date and its concomitant edited_by. Cache it
|
|
|
|
|
"""
|
|
|
|
|
max_date = json_data['edit_info']['edited_on']
|
|
|
|
|
max_by = json_data['edit_info']['edited_by']
|
|
|
|
|
|
|
|
|
|
for child in json_data.get('fields', {}).get('children', []):
|
|
|
|
|
child_data = self.get_module_data(child, course_key)
|
|
|
|
|
if '_subtree_edited_on' not in json_data.setdefault('edit_info', {}):
|
|
|
|
|
self._compute_subtree_edited_internal(child, child_data)
|
|
|
|
|
if child_data['edit_info']['_subtree_edited_on'] > max_date:
|
|
|
|
|
max_date = child_data['edit_info']['_subtree_edited_on']
|
|
|
|
|
max_by = child_data['edit_info']['_subtree_edited_by']
|
|
|
|
|
|
|
|
|
|
json_data['edit_info']['_subtree_edited_on'] = max_date
|
|
|
|
|
json_data['edit_info']['_subtree_edited_by'] = max_by
|
|
|
|
|
|