Commit fa95d323 by Jonathan Piacenti

Tested version handling, modified modulestore when it didn't work.

parent ce19c769
...@@ -747,6 +747,9 @@ class TestOverrides(LibraryTestCase): ...@@ -747,6 +747,9 @@ class TestOverrides(LibraryTestCase):
publish_item=False, publish_item=False,
) )
# Refresh library now that we've added something.
self.library = modulestore().get_library(self.lib_key)
# Also create a course: # Also create a course:
with modulestore().default_store(ModuleStoreEnum.Type.split): with modulestore().default_store(ModuleStoreEnum.Type.split):
self.course = CourseFactory.create() self.course = CourseFactory.create()
...@@ -862,6 +865,42 @@ class TestOverrides(LibraryTestCase): ...@@ -862,6 +865,42 @@ class TestOverrides(LibraryTestCase):
self.assertEqual(self.problem_in_course.weight, new_weight) self.assertEqual(self.problem_in_course.weight, new_weight)
self.assertEqual(self.problem_in_course.data, new_data_value) self.assertEqual(self.problem_in_course.data, new_data_value)
def test_duplicated_version(self):
"""
Test that if a library is updated, and the content block is duplicated,
the new block will use the old library version and not the new one.
"""
self.assertEqual(len(self.library.children), 1)
self.assertEqual(len(self.lc_block.children), 1)
# Create an additional problem block in the library:
self.problem = ItemFactory.create(
category="problem",
parent_location=self.library.location,
user_id=self.user.id,
publish_item=False,
)
# Refresh our reference to the library
store = modulestore()
self.library = store.get_library(self.lib_key)
# Refresh our reference to the block
self.lc_block = store.get_item(self.lc_block.location)
# The library has changed...
self.assertEqual(len(self.library.children), 2)
# But the block hasn't.
self.assertEqual(len(self.lc_block.children), 1)
duplicate = store.get_item(
_duplicate_item(self.course.location, self.lc_block.location, self.user)
)
self.assertEqual(len(duplicate.children), 1)
self.assertTrue(self.lc_block.source_library_version)
self.assertEqual(self.lc_block.source_library_version, duplicate.source_library_version)
class TestIncompatibleModuleStore(LibraryTestCase): class TestIncompatibleModuleStore(LibraryTestCase):
""" """
......
...@@ -612,7 +612,7 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, user, display_ ...@@ -612,7 +612,7 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, user, display_
store.update_item(dest_module, user.id) store.update_item(dest_module, user.id)
# pylint: disable=protected-access # pylint: disable=protected-access
if ('detached' not in source_item.runtime.load_block_type(category)._class_tags): if 'detached' not in source_item.runtime.load_block_type(category)._class_tags:
parent = store.get_item(parent_usage_key) parent = store.get_item(parent_usage_key)
# If source was already a child of the parent, add duplicate immediately afterward. # If source was already a child of the parent, add duplicate immediately afterward.
# Otherwise, add child to end. # Otherwise, add child to end.
......
...@@ -16,7 +16,7 @@ class LibraryToolsService(object): ...@@ -16,7 +16,7 @@ class LibraryToolsService(object):
def __init__(self, modulestore): def __init__(self, modulestore):
self.store = modulestore self.store = modulestore
def _get_library(self, library_key): def _get_library(self, library_key, version=None):
""" """
Given a library key like "library-v1:ProblemX+PR0B", return the Given a library key like "library-v1:ProblemX+PR0B", return the
'library' XBlock with meta-information about the library. 'library' XBlock with meta-information about the library.
...@@ -28,8 +28,18 @@ class LibraryToolsService(object): ...@@ -28,8 +28,18 @@ class LibraryToolsService(object):
if not isinstance(library_key, LibraryLocator): if not isinstance(library_key, LibraryLocator):
library_key = LibraryLocator.from_string(library_key) library_key = LibraryLocator.from_string(library_key)
assert library_key.version_guid is None
if version:
library_key = library_key.for_version(version)
try: try:
return self.store.get_library(library_key, remove_version=False, remove_branch=False) library = self.store.get_library(
library_key, remove_version=False, remove_branch=False, head_validation=False
)
if version:
assert library_key.version_guid == library.location.version_guid
return library
except ItemNotFoundError: except ItemNotFoundError:
return None return None
...@@ -123,8 +133,8 @@ class LibraryToolsService(object): ...@@ -123,8 +133,8 @@ class LibraryToolsService(object):
return return
source_blocks = [] source_blocks = []
library_key = dest_block.source_library_key.for_version(version) library_key = dest_block.source_library_key
library = self._get_library(library_key) library = self._get_library(library_key, version=version)
if library is None: if library is None:
raise ValueError("Requested library not found.") raise ValueError("Requested library not found.")
if user_perms and not user_perms.can_read(library_key): if user_perms and not user_perms.can_read(library_key):
......
...@@ -790,7 +790,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase): ...@@ -790,7 +790,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
else: else:
self.request_cache.data['course_cache'] = {} self.request_cache.data['course_cache'] = {}
def _lookup_course(self, course_key): def _lookup_course(self, course_key, head_validation=True):
""" """
Decode the locator into the right series of db access. Does not Decode the locator into the right series of db access. Does not
return the CourseDescriptor! It returns the actual db json from return the CourseDescriptor! It returns the actual db json from
...@@ -799,11 +799,12 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase): ...@@ -799,11 +799,12 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
Semantics: if course id and branch given, then it will get that branch. If Semantics: if course id and branch given, then it will get that branch. If
also give a version_guid, it will see if the current head of that branch == that guid. If not also give a version_guid, it will see if the current head of that branch == that guid. If not
it raises VersionConflictError (the version now differs from what it was when you got your it raises VersionConflictError (the version now differs from what it was when you got your
reference) reference) unless you specify head_validation = False, in which case it will return the
revision (if specified) by the course_key.
:param course_key: any subclass of CourseLocator :param course_key: any subclass of CourseLocator
""" """
if course_key.org and course_key.course and course_key.run: if head_validation and course_key.org and course_key.course and course_key.run:
if course_key.branch is None: if course_key.branch is None:
raise InsufficientSpecificationError(course_key) raise InsufficientSpecificationError(course_key)
...@@ -937,11 +938,11 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase): ...@@ -937,11 +938,11 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
""" """
return CourseLocator(org, course, run) return CourseLocator(org, course, run)
def _get_structure(self, structure_id, depth, **kwargs): def _get_structure(self, structure_id, depth, head_validation=True, **kwargs):
""" """
Gets Course or Library by locator Gets Course or Library by locator
""" """
structure_entry = self._lookup_course(structure_id) structure_entry = self._lookup_course(structure_id, head_validation=head_validation)
root = structure_entry.structure['root'] root = structure_entry.structure['root']
result = self._load_items(structure_entry, [root], depth, **kwargs) result = self._load_items(structure_entry, [root], depth, **kwargs)
return result[0] return result[0]
...@@ -955,14 +956,14 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase): ...@@ -955,14 +956,14 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
raise ItemNotFoundError(course_id) raise ItemNotFoundError(course_id)
return self._get_structure(course_id, depth, **kwargs) return self._get_structure(course_id, depth, **kwargs)
def get_library(self, library_id, depth=0, **kwargs): def get_library(self, library_id, depth=0, head_validation=True, **kwargs):
""" """
Gets the 'library' root block for the library identified by the locator Gets the 'library' root block for the library identified by the locator
""" """
if not isinstance(library_id, LibraryLocator): if not isinstance(library_id, LibraryLocator):
# The supplied CourseKey is of the wrong type, so it can't possibly be stored in this modulestore. # The supplied CourseKey is of the wrong type, so it can't possibly be stored in this modulestore.
raise ItemNotFoundError(library_id) raise ItemNotFoundError(library_id)
return self._get_structure(library_id, depth, **kwargs) return self._get_structure(library_id, depth, head_validation=head_validation, **kwargs)
def has_course(self, course_id, ignore_case=False, **kwargs): def has_course(self, course_id, ignore_case=False, **kwargs):
""" """
......
...@@ -58,7 +58,11 @@ class DraftVersioningModuleStore(SplitMongoModuleStore, ModuleStoreDraftAndPubli ...@@ -58,7 +58,11 @@ class DraftVersioningModuleStore(SplitMongoModuleStore, ModuleStoreDraftAndPubli
course_id = self._map_revision_to_branch(course_id) course_id = self._map_revision_to_branch(course_id)
return super(DraftVersioningModuleStore, self).get_course(course_id, depth=depth, **kwargs) return super(DraftVersioningModuleStore, self).get_course(course_id, depth=depth, **kwargs)
def get_library(self, library_id, depth=0, **kwargs): def get_library(self, library_id, depth=0, head_validation=True, **kwargs):
if not head_validation and library_id.version_guid:
return SplitMongoModuleStore.get_library(
self, library_id, depth=depth, head_validation=head_validation, **kwargs
)
library_id = self._map_revision_to_branch(library_id) library_id = self._map_revision_to_branch(library_id)
return super(DraftVersioningModuleStore, self).get_library(library_id, depth=depth, **kwargs) return super(DraftVersioningModuleStore, self).get_library(library_id, depth=depth, **kwargs)
......
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