Reduce mongo calls on course outline and container pages
This commit is contained in:
@@ -80,7 +80,7 @@ class ModuleStoreDraftAndPublished(BranchSettingMixin):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def has_changes(self, usage_key):
|
||||
def has_changes(self, xblock):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
|
||||
@@ -474,14 +474,14 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
|
||||
store = self._verify_modulestore_support(location.course_key, 'convert_to_draft')
|
||||
return store.convert_to_draft(location, user_id)
|
||||
|
||||
def has_changes(self, usage_key):
|
||||
def has_changes(self, xblock):
|
||||
"""
|
||||
Checks if the given block has unpublished changes
|
||||
:param usage_key: the block to check
|
||||
:param xblock: the block to check
|
||||
:return: True if the draft and published versions differ
|
||||
"""
|
||||
store = self._verify_modulestore_support(usage_key.course_key, 'has_changes')
|
||||
return store.has_changes(usage_key)
|
||||
store = self._verify_modulestore_support(xblock.location.course_key, 'has_changes')
|
||||
return store.has_changes(xblock)
|
||||
|
||||
def _verify_modulestore_support(self, course_key, method):
|
||||
"""
|
||||
|
||||
@@ -297,6 +297,19 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
|
||||
value[key] = self._convert_reference_to_key(subvalue)
|
||||
return jsonfields
|
||||
|
||||
def lookup_item(self, location):
|
||||
"""
|
||||
Returns the JSON payload of the xblock at location.
|
||||
"""
|
||||
|
||||
try:
|
||||
json = self.module_data[location]
|
||||
except KeyError:
|
||||
json = self.modulestore._find_one(location)
|
||||
self.module_data[location] = json
|
||||
|
||||
return json
|
||||
|
||||
|
||||
# The only thing using this w/ wildcards is contentstore.mongo for asset retrieval
|
||||
def location_to_query(location, wildcard=True, tag='i4x'):
|
||||
|
||||
@@ -599,25 +599,19 @@ class DraftModuleStore(MongoModuleStore):
|
||||
_internal([root_usage.to_deprecated_son() for root_usage in root_usages])
|
||||
self.collection.remove({'_id': {'$in': to_be_deleted}}, safe=self.collection.safe)
|
||||
|
||||
def has_changes(self, location):
|
||||
def has_changes(self, xblock):
|
||||
"""
|
||||
Check if the xblock or its children have been changed since the last publish.
|
||||
:param location: location to check
|
||||
:param xblock: xblock to check
|
||||
:return: True if the draft and published versions differ
|
||||
"""
|
||||
|
||||
try:
|
||||
item = self.get_item(location)
|
||||
# defensively check that the parent's child actually exists
|
||||
except ItemNotFoundError:
|
||||
return False
|
||||
|
||||
# don't check children if this block has changes (is not public)
|
||||
if self.compute_publish_state(item) != PublishState.public:
|
||||
if self.compute_publish_state(xblock) != PublishState.public:
|
||||
return True
|
||||
# if this block doesn't have changes, then check its children
|
||||
elif item.has_children:
|
||||
return any([self.has_changes(child) for child in item.children])
|
||||
elif xblock.has_children:
|
||||
return any([self.has_changes(child) for child in xblock.get_children()])
|
||||
# otherwise there are no changes
|
||||
else:
|
||||
return False
|
||||
@@ -799,13 +793,11 @@ class DraftModuleStore(MongoModuleStore):
|
||||
"""
|
||||
if getattr(xblock, 'is_draft', False):
|
||||
published_xblock_location = as_published(xblock.location)
|
||||
published_item = self.collection.find_one(
|
||||
{'_id': published_xblock_location.to_deprecated_son()}
|
||||
)
|
||||
if published_item is None:
|
||||
try:
|
||||
xblock.runtime.lookup_item(published_xblock_location)
|
||||
except ItemNotFoundError:
|
||||
return PublishState.private
|
||||
else:
|
||||
return PublishState.draft
|
||||
return PublishState.draft
|
||||
else:
|
||||
return PublishState.public
|
||||
|
||||
|
||||
@@ -194,16 +194,16 @@ class DraftVersioningModuleStore(ModuleStoreDraftAndPublished, SplitMongoModuleS
|
||||
location = self._map_revision_to_branch(location, revision=revision)
|
||||
return SplitMongoModuleStore.get_parent_location(self, location, **kwargs)
|
||||
|
||||
def has_changes(self, usage_key):
|
||||
def has_changes(self, xblock):
|
||||
"""
|
||||
Checks if the given block has unpublished changes
|
||||
:param usage_key: the block to check
|
||||
:param xblock: the block to check
|
||||
:return: True if the draft and published versions differ
|
||||
"""
|
||||
# TODO for better performance: lookup the courses and get the block entry, don't create the instances
|
||||
draft = self.get_item(usage_key.for_branch(ModuleStoreEnum.BranchName.draft))
|
||||
draft = self.get_item(xblock.location.for_branch(ModuleStoreEnum.BranchName.draft))
|
||||
try:
|
||||
published = self.get_item(usage_key.for_branch(ModuleStoreEnum.BranchName.published))
|
||||
published = self.get_item(xblock.location.for_branch(ModuleStoreEnum.BranchName.published))
|
||||
except ItemNotFoundError:
|
||||
return True
|
||||
|
||||
|
||||
@@ -374,8 +374,8 @@ class TestMixedModuleStore(unittest.TestCase):
|
||||
)
|
||||
|
||||
# Check that neither xblock has changes
|
||||
self.assertFalse(self.store.has_changes(test_course.location))
|
||||
self.assertFalse(self.store.has_changes(chapter.location))
|
||||
self.assertFalse(self.store.has_changes(test_course))
|
||||
self.assertFalse(self.store.has_changes(chapter))
|
||||
|
||||
@ddt.data('draft', 'split')
|
||||
def test_has_changes(self, default_ms):
|
||||
@@ -395,22 +395,22 @@ class TestMixedModuleStore(unittest.TestCase):
|
||||
)
|
||||
|
||||
# Not yet published, so changes are present
|
||||
self.assertTrue(self.store.has_changes(xblock.location))
|
||||
self.assertTrue(self.store.has_changes(xblock))
|
||||
|
||||
# Publish and verify that there are no unpublished changes
|
||||
self.store.publish(xblock.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(xblock.location))
|
||||
newXBlock = self.store.publish(xblock.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(newXBlock))
|
||||
|
||||
# Change the component, then check that there now are changes
|
||||
component = self.store.get_item(xblock.location)
|
||||
component.display_name = 'Changed Display Name'
|
||||
|
||||
component = self.store.update_item(component, self.user_id)
|
||||
self.assertTrue(self.store.has_changes(component.location))
|
||||
self.assertTrue(self.store.has_changes(component))
|
||||
|
||||
# Publish and verify again
|
||||
self.store.publish(component.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component.location))
|
||||
component = self.store.publish(component.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
|
||||
@ddt.data(('draft', 7, 2), ('split', 13, 4))
|
||||
@ddt.unpack
|
||||
@@ -994,7 +994,7 @@ class TestMixedModuleStore(unittest.TestCase):
|
||||
# Draft WITH changes
|
||||
item.display_name = 'new name'
|
||||
item = self.store.update_item(item, self.user_id)
|
||||
self.assertTrue(self.store.has_changes(item.location))
|
||||
self.assertTrue(self.store.has_changes(item))
|
||||
self.assertEquals(self.store.compute_publish_state(item), PublishState.draft)
|
||||
|
||||
@ddt.data('draft', 'split')
|
||||
|
||||
@@ -515,10 +515,10 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
block_id=location.block_id
|
||||
)
|
||||
parent.children += [Location('edX', 'toy', '2012_Fall', 'vertical', 'does_not_exist')]
|
||||
self.draft_store.update_item(parent, self.dummy_user)
|
||||
parent = self.draft_store.update_item(parent, self.dummy_user)
|
||||
|
||||
# Check the parent for changes should return False and not throw an exception
|
||||
self.assertFalse(self.draft_store.has_changes(location))
|
||||
self.assertFalse(self.draft_store.has_changes(parent))
|
||||
|
||||
def _create_test_tree(self, name, user_id=None):
|
||||
"""
|
||||
@@ -569,6 +569,11 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
|
||||
return locations
|
||||
|
||||
def _has_changes(self, location):
|
||||
""" Helper that returns True if location has changes, False otherwise """
|
||||
store = self.draft_store
|
||||
return store.has_changes(store.get_item(location))
|
||||
|
||||
def test_has_changes_ancestors(self):
|
||||
"""
|
||||
Tests that has_changes() returns true on ancestors when a child is changed
|
||||
@@ -577,7 +582,7 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
|
||||
# Verify that there are no unpublished changes
|
||||
for key in locations:
|
||||
self.assertFalse(self.draft_store.has_changes(locations[key]))
|
||||
self.assertFalse(self._has_changes(locations[key]))
|
||||
|
||||
# Change the child
|
||||
child = self.draft_store.get_item(locations['child'])
|
||||
@@ -585,18 +590,18 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
self.draft_store.update_item(child, user_id=self.dummy_user)
|
||||
|
||||
# All ancestors should have changes, but not siblings
|
||||
self.assertTrue(self.draft_store.has_changes(locations['grandparent']))
|
||||
self.assertTrue(self.draft_store.has_changes(locations['parent']))
|
||||
self.assertTrue(self.draft_store.has_changes(locations['child']))
|
||||
self.assertFalse(self.draft_store.has_changes(locations['parent_sibling']))
|
||||
self.assertFalse(self.draft_store.has_changes(locations['child_sibling']))
|
||||
self.assertTrue(self._has_changes(locations['grandparent']))
|
||||
self.assertTrue(self._has_changes(locations['parent']))
|
||||
self.assertTrue(self._has_changes(locations['child']))
|
||||
self.assertFalse(self._has_changes(locations['parent_sibling']))
|
||||
self.assertFalse(self._has_changes(locations['child_sibling']))
|
||||
|
||||
# Publish the unit with changes
|
||||
self.draft_store.publish(locations['parent'], self.dummy_user)
|
||||
|
||||
# Verify that there are no unpublished changes
|
||||
for key in locations:
|
||||
self.assertFalse(self.draft_store.has_changes(locations[key]))
|
||||
self.assertFalse(self._has_changes(locations[key]))
|
||||
|
||||
def test_has_changes_publish_ancestors(self):
|
||||
"""
|
||||
@@ -606,7 +611,7 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
|
||||
# Verify that there are no unpublished changes
|
||||
for key in locations:
|
||||
self.assertFalse(self.draft_store.has_changes(locations[key]))
|
||||
self.assertFalse(self._has_changes(locations[key]))
|
||||
|
||||
# Change both children
|
||||
child = self.draft_store.get_item(locations['child'])
|
||||
@@ -617,22 +622,22 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
self.draft_store.update_item(child_sibling, user_id=self.dummy_user)
|
||||
|
||||
# Verify that ancestors have changes
|
||||
self.assertTrue(self.draft_store.has_changes(locations['grandparent']))
|
||||
self.assertTrue(self.draft_store.has_changes(locations['parent']))
|
||||
self.assertTrue(self._has_changes(locations['grandparent']))
|
||||
self.assertTrue(self._has_changes(locations['parent']))
|
||||
|
||||
# Publish one child
|
||||
self.draft_store.publish(locations['child_sibling'], self.dummy_user)
|
||||
|
||||
# Verify that ancestors still have changes
|
||||
self.assertTrue(self.draft_store.has_changes(locations['grandparent']))
|
||||
self.assertTrue(self.draft_store.has_changes(locations['parent']))
|
||||
self.assertTrue(self._has_changes(locations['grandparent']))
|
||||
self.assertTrue(self._has_changes(locations['parent']))
|
||||
|
||||
# Publish the other child
|
||||
self.draft_store.publish(locations['child'], self.dummy_user)
|
||||
|
||||
# Verify that ancestors now have no changes
|
||||
self.assertFalse(self.draft_store.has_changes(locations['grandparent']))
|
||||
self.assertFalse(self.draft_store.has_changes(locations['parent']))
|
||||
self.assertFalse(self._has_changes(locations['grandparent']))
|
||||
self.assertFalse(self._has_changes(locations['parent']))
|
||||
|
||||
def test_has_changes_add_remove_child(self):
|
||||
"""
|
||||
@@ -642,8 +647,8 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
locations = self._create_test_tree('has_changes_add_remove_child')
|
||||
|
||||
# Test that the ancestors don't have changes
|
||||
self.assertFalse(self.draft_store.has_changes(locations['grandparent']))
|
||||
self.assertFalse(self.draft_store.has_changes(locations['parent']))
|
||||
self.assertFalse(self._has_changes(locations['grandparent']))
|
||||
self.assertFalse(self._has_changes(locations['parent']))
|
||||
|
||||
# Create a new child and attach it to parent
|
||||
new_child_location = Location('edX', 'tree', 'has_changes_add_remove_child', 'vertical', 'new_child')
|
||||
@@ -655,8 +660,8 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
)
|
||||
|
||||
# Verify that the ancestors now have changes
|
||||
self.assertTrue(self.draft_store.has_changes(locations['grandparent']))
|
||||
self.assertTrue(self.draft_store.has_changes(locations['parent']))
|
||||
self.assertTrue(self._has_changes(locations['grandparent']))
|
||||
self.assertTrue(self._has_changes(locations['parent']))
|
||||
|
||||
# Remove the child from the parent
|
||||
parent = self.draft_store.get_item(locations['parent'])
|
||||
@@ -664,8 +669,8 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
self.draft_store.update_item(parent, user_id=self.dummy_user)
|
||||
|
||||
# Verify that ancestors now have no changes
|
||||
self.assertFalse(self.draft_store.has_changes(locations['grandparent']))
|
||||
self.assertFalse(self.draft_store.has_changes(locations['parent']))
|
||||
self.assertFalse(self._has_changes(locations['grandparent']))
|
||||
self.assertFalse(self._has_changes(locations['parent']))
|
||||
|
||||
def test_has_changes_non_direct_only_children(self):
|
||||
"""
|
||||
@@ -689,16 +694,16 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
self.draft_store.publish(parent_location, self.dummy_user)
|
||||
|
||||
# Verify that there are no changes
|
||||
self.assertFalse(self.draft_store.has_changes(parent_location))
|
||||
self.assertFalse(self.draft_store.has_changes(child_location))
|
||||
self.assertFalse(self._has_changes(parent_location))
|
||||
self.assertFalse(self._has_changes(child_location))
|
||||
|
||||
# Change the child
|
||||
child.display_name = 'Changed Display Name'
|
||||
self.draft_store.update_item(child, user_id=self.dummy_user)
|
||||
|
||||
# Verify that both parent and child have changes
|
||||
self.assertTrue(self.draft_store.has_changes(parent_location))
|
||||
self.assertTrue(self.draft_store.has_changes(child_location))
|
||||
self.assertTrue(self._has_changes(parent_location))
|
||||
self.assertTrue(self._has_changes(child_location))
|
||||
|
||||
def test_update_edit_info_ancestors(self):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user