Commit 4878f6e8 by Don Mitchell

Implement edit info as mixin for split

LMS-11183, LMS-11184
parent 7b52d45a
...@@ -11,11 +11,12 @@ from ..exceptions import ItemNotFoundError ...@@ -11,11 +11,12 @@ from ..exceptions import ItemNotFoundError
from .split_mongo_kvs import SplitMongoKVS from .split_mongo_kvs import SplitMongoKVS
from fs.osfs import OSFS from fs.osfs import OSFS
from .definition_lazy_loader import DefinitionLazyLoader from .definition_lazy_loader import DefinitionLazyLoader
from xmodule.modulestore.edit_info import EditInfoRuntimeMixin
log = logging.getLogger(__name__) 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 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. from, with a backup of calling to the underlying modulestore for more data.
...@@ -89,6 +90,19 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -89,6 +90,19 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
run=course_info.get('run'), run=course_info.get('run'),
branch=course_info.get('branch'), 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) json_data = self.module_data.get(block_id)
if json_data is None: if json_data is None:
# deeper than initial descendant fetch or doesn't exist # deeper than initial descendant fetch or doesn't exist
...@@ -97,9 +111,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -97,9 +111,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
if json_data is None: if json_data is None:
raise ItemNotFoundError(block_id) raise ItemNotFoundError(block_id)
class_ = self.load_block_type(json_data.get('category')) return json_data
new_item = self.xblock_from_json(class_, course_key, block_id, json_data, course_entry_override, **kwargs)
return new_item
# xblock's runtime does not always pass enough contextual information to figure out # 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 # which named container (course x branch) or which parent is requesting an item. Because split allows
...@@ -181,12 +193,8 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -181,12 +193,8 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
) )
edit_info = json_data.get('edit_info', {}) edit_info = json_data.get('edit_info', {})
module.edited_by = edit_info.get('edited_by') module._edited_by = edit_info.get('edited_by')
module.edited_on = edit_info.get('edited_on') 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.previous_version = edit_info.get('previous_version') module.previous_version = edit_info.get('previous_version')
module.update_version = edit_info.get('update_version') module.update_version = edit_info.get('update_version')
module.source_version = edit_info.get('source_version', None) module.source_version = edit_info.get('source_version', None)
...@@ -199,3 +207,79 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -199,3 +207,79 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
self.local_modules[block_locator] = module self.local_modules[block_locator] = module
return 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
...@@ -387,3 +387,11 @@ class DraftVersioningModuleStore(ModuleStoreDraftAndPublished, SplitMongoModuleS ...@@ -387,3 +387,11 @@ class DraftVersioningModuleStore(ModuleStoreDraftAndPublished, SplitMongoModuleS
return self._update_item_from_fields( return self._update_item_from_fields(
user_id, course_key, block_type, block_id, partitioned_fields, None, allow_not_found=True, force=True user_id, course_key, block_type, block_id, partitioned_fields, None, allow_not_found=True, force=True
) )
def compute_published_info_internal(self, xblock):
"""
Get the published branch and find when it was published if it was. Cache the results in the xblock
"""
published_block = self._get_head(xblock, ModuleStoreEnum.BranchName.published)
setattr(xblock, '_published_by', published_block['edit_info']['edited_by'])
setattr(xblock, '_published_on', published_block['edit_info']['edited_on'])
...@@ -13,6 +13,8 @@ from uuid import uuid4 ...@@ -13,6 +13,8 @@ from uuid import uuid4
# before importing the module # before importing the module
# TODO remove this import and the configuration -- xmodule should not depend on django! # TODO remove this import and the configuration -- xmodule should not depend on django!
from django.conf import settings from django.conf import settings
from xmodule.modulestore.edit_info import EditInfoMixin
if not settings.configured: if not settings.configured:
settings.configure() settings.configure()
...@@ -52,6 +54,7 @@ class TestMixedModuleStore(unittest.TestCase): ...@@ -52,6 +54,7 @@ class TestMixedModuleStore(unittest.TestCase):
'default_class': DEFAULT_CLASS, 'default_class': DEFAULT_CLASS,
'fs_root': DATA_DIR, 'fs_root': DATA_DIR,
'render_template': RENDER_TEMPLATE, 'render_template': RENDER_TEMPLATE,
'xblock_mixins': (EditInfoMixin,)
} }
DOC_STORE_CONFIG = { DOC_STORE_CONFIG = {
'host': HOST, 'host': HOST,
......
...@@ -23,6 +23,7 @@ from xmodule.fields import Date, Timedelta ...@@ -23,6 +23,7 @@ from xmodule.fields import Date, Timedelta
from xmodule.modulestore.split_mongo.split import SplitMongoModuleStore from xmodule.modulestore.split_mongo.split import SplitMongoModuleStore
from xmodule.modulestore.tests.test_modulestore import check_has_course_method from xmodule.modulestore.tests.test_modulestore import check_has_course_method
from xmodule.modulestore.tests.mongo_connection import MONGO_PORT_NUM, MONGO_HOST from xmodule.modulestore.tests.mongo_connection import MONGO_PORT_NUM, MONGO_HOST
from xmodule.modulestore.edit_info import EditInfoMixin
BRANCH_NAME_DRAFT = ModuleStoreEnum.BranchName.draft BRANCH_NAME_DRAFT = ModuleStoreEnum.BranchName.draft
...@@ -45,7 +46,7 @@ class SplitModuleTest(unittest.TestCase): ...@@ -45,7 +46,7 @@ class SplitModuleTest(unittest.TestCase):
modulestore_options = { modulestore_options = {
'default_class': 'xmodule.raw_module.RawDescriptor', 'default_class': 'xmodule.raw_module.RawDescriptor',
'fs_root': '', 'fs_root': '',
'xblock_mixins': (InheritanceMixin, XModuleMixin) 'xblock_mixins': (InheritanceMixin, XModuleMixin, EditInfoMixin)
} }
MODULESTORE = { MODULESTORE = {
......
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