get_courses_for_wiki return course_keys across all modulestores [LMS-2914]

This commit is contained in:
Sarina Canelake
2014-07-16 14:06:42 -04:00
parent 6074e0b117
commit d0449cdff2
11 changed files with 114 additions and 50 deletions

View File

@@ -286,6 +286,15 @@ class ModuleStoreRead(object):
"""
pass
@abstractmethod
def get_courses_for_wiki(self, wiki_slug):
"""
Return the list of courses which use this wiki_slug
:param wiki_slug: the course wiki root slug
:return: list of course keys
"""
pass
@abstractmethod
def compute_publish_state(self, xblock):
"""

View File

@@ -414,7 +414,7 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
"""
Return the list of courses which use this wiki_slug
:param wiki_slug: the course wiki root slug
:return: list of course locations
:return: list of course keys
"""
courses = []
for modulestore in self.modulestores:

View File

@@ -60,6 +60,10 @@ BLOCK_TYPES_WITH_CHILDREN = list(set(
name for name, class_ in XBlock.load_classes() if getattr(class_, 'has_children', False)
))
# Allow us to call _from_deprecated_(son|string) throughout the file
# pylint: disable=protected-access
class MongoRevisionKey(object):
"""
Key Revision constants to use for Location and Usage Keys in the Mongo modulestore
@@ -1252,14 +1256,17 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
"""
Return the list of courses which use this wiki_slug
:param wiki_slug: the course wiki root slug
:return: list of course locations
:return: list of course keys
"""
courses = self.collection.find(
{'_id.category': 'course', 'definition.data.wiki_slug': wiki_slug},
{'_id': True}
)
# the course's run == its name. It's the only xblock for which that's necessarily true.
return [Location._from_deprecated_son(course['_id'], course['_id']['name']) for course in courses]
return [
Location._from_deprecated_son(course['_id'], course['_id']['name']).course_key
for course in courses
]
def _create_new_field_data(self, _category, _location, definition_data, metadata):
"""

View File

@@ -108,8 +108,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
SCHEMA_VERSION = 1
reference_type = Locator
# a list of field name to store in course index search_targets. Note, this will
# only record one value per key. If the draft and published disagree, the last one set wins.
# a list of field names to store in course index search_targets. Note, this will
# only record one value per key. If branches disagree, the last one set wins.
# It won't recompute the value on operations such as update_course_index (e.g., to revert to a prev
# version) but those functions will have an optional arg for setting these.
SEARCH_TARGET_DICT = ['wiki_slug']
@@ -997,6 +997,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
master_branch: the tag (key) for the version name in the dict which is the DRAFT version. Not the actual
version guid, but what to call it.
search_targets: a dict of search key and value. For example, wiki_slug. Add any fields whose edits
should change the search targets to SplitMongoModuleStore.SEARCH_TARGET dict
versions_dict: the starting version ids where the keys are the tags such as DRAFT and PUBLISHED
and the values are structure guids. If provided, the new course will reuse this version (unless you also
provide any fields overrides, see above). if not provided, will create a mostly empty course
@@ -1887,13 +1890,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
"""
Find all the courses which cached that they have the given field with the given value.
Returns: list of course_keys
Returns: list of branch-agnostic course_keys
"""
entries = self.db_connection.find_matching_course_indexes(
{'search_targets.{}'.format(field_name): field_value}
)
return [
CourseLocator(entry['org'], entry['course'], entry['run']) # which branch? TODO
CourseLocator(entry['org'], entry['course'], entry['run']) # Branch agnostic
for entry in entries
]
@@ -1901,7 +1904,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
"""
Return the list of courses which use this wiki_slug
:param wiki_slug: the course wiki root slug
:return: list of course locations
:return: list of course keys
"""
return self.find_courses_by_search_target('wiki_slug', wiki_slug)

View File

@@ -648,18 +648,21 @@ class TestMixedModuleStore(unittest.TestCase):
"""
self.initdb(default_ms)
# Test XML wikis
course_locations = self.store.get_courses_for_wiki('toy')
self.assertEqual(len(course_locations), 1)
self.assertIn(self.course_locations[self.XML_COURSEID1], course_locations)
wiki_courses = self.store.get_courses_for_wiki('toy')
self.assertEqual(len(wiki_courses), 1)
self.assertIn(self.course_locations[self.XML_COURSEID1].course_key, wiki_courses)
course_locations = self.store.get_courses_for_wiki('simple')
self.assertEqual(len(course_locations), 1)
self.assertIn(self.course_locations[self.XML_COURSEID2], course_locations)
wiki_courses = self.store.get_courses_for_wiki('simple')
self.assertEqual(len(wiki_courses), 1)
self.assertIn(self.course_locations[self.XML_COURSEID2].course_key, wiki_courses)
# Test Mongo wiki
course_locations = self.store.get_courses_for_wiki('999')
self.assertEqual(len(course_locations), 1)
self.assertIn(self.course_locations[self.MONGO_COURSEID], course_locations)
wiki_courses = self.store.get_courses_for_wiki('999')
self.assertEqual(len(wiki_courses), 1)
self.assertIn(
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None), # Branch agnostic
wiki_courses
)
self.assertEqual(len(self.store.get_courses_for_wiki('edX.simple.2012_Fall')), 0)
self.assertEqual(len(self.store.get_courses_for_wiki('no_such_wiki')), 0)
@@ -744,7 +747,6 @@ class TestMixedModuleStore(unittest.TestCase):
self.assertTrue(self.store.has_changes(item.location))
self.assertEquals(self.store.compute_publish_state(item), PublishState.draft)
@ddt.data('draft', 'split')
def test_get_courses_for_wiki_shared(self, default_ms):
"""
@@ -753,8 +755,11 @@ class TestMixedModuleStore(unittest.TestCase):
self.initdb(default_ms)
# verify initial state - initially, we should have a wiki for the Mongo course
course_locations = self.store.get_courses_for_wiki('999')
self.assertEqual([self.course_locations[self.MONGO_COURSEID]], course_locations)
wiki_courses = self.store.get_courses_for_wiki('999')
self.assertIn(
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None), # Branch agnostic
wiki_courses
)
# set Mongo course to share the wiki with simple course
mongo_course = self.store.get_course(self.course_locations[self.MONGO_COURSEID].course_key)
@@ -762,23 +767,40 @@ class TestMixedModuleStore(unittest.TestCase):
self.store.update_item(mongo_course, self.user_id)
# now mongo_course should not be retrievable with old wiki_slug
course_locations = self.store.get_courses_for_wiki('999')
self.assertEqual(len(course_locations), 0)
wiki_courses = self.store.get_courses_for_wiki('999')
self.assertEqual(len(wiki_courses), 0)
# but there should be two courses with wiki_slug 'simple'
course_locations = self.store.get_courses_for_wiki('simple')
self.assertEqual(len(course_locations), 2)
for cid in [self.MONGO_COURSEID, self.XML_COURSEID2]:
self.assertIn(self.course_locations[cid], course_locations)
wiki_courses = self.store.get_courses_for_wiki('simple')
self.assertEqual(len(wiki_courses), 2)
self.assertIn(
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None),
wiki_courses
)
self.assertIn(self.course_locations[self.XML_COURSEID2].course_key, wiki_courses)
# configure mongo course to use unique wiki_slug.
mongo_course = self.store.get_course(self.course_locations[self.MONGO_COURSEID].course_key)
mongo_course.wiki_slug = 'MITx.999.2013_Spring'
self.store.update_item(mongo_course, self.user_id)
# it should be retrievable with its new wiki_slug
course_locations = self.store.get_courses_for_wiki('MITx.999.2013_Spring')
self.assertEqual(len(course_locations), 1)
self.assertIn(self.course_locations[self.MONGO_COURSEID], course_locations)
wiki_courses = self.store.get_courses_for_wiki('MITx.999.2013_Spring')
self.assertEqual(len(wiki_courses), 1)
self.assertIn(
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None),
wiki_courses
)
# and NOT retriveable with its old wiki_slug
wiki_courses = self.store.get_courses_for_wiki('simple')
self.assertEqual(len(wiki_courses), 1)
self.assertNotIn(
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None),
wiki_courses
)
self.assertIn(
self.course_locations[self.XML_COURSEID2].course_key,
wiki_courses
)
#=============================================================================================================

View File

@@ -351,7 +351,7 @@ class TestMongoModuleStore(unittest.TestCase):
for course_number in self.courses:
course_locations = self.draft_store.get_courses_for_wiki(course_number)
assert_equals(len(course_locations), 1)
assert_equals(Location('edX', course_number, '2012_Fall', 'course', '2012_Fall'), course_locations[0])
assert_equals(SlashSeparatedCourseKey('edX', course_number, '2012_Fall'), course_locations[0])
course_locations = self.draft_store.get_courses_for_wiki('no_such_wiki')
assert_equals(len(course_locations), 0)
@@ -369,7 +369,7 @@ class TestMongoModuleStore(unittest.TestCase):
course_locations = self.draft_store.get_courses_for_wiki('simple')
assert_equals(len(course_locations), 2)
for course_number in ['toy', 'simple']:
assert_in(Location('edX', course_number, '2012_Fall', 'course', '2012_Fall'), course_locations)
assert_in(SlashSeparatedCourseKey('edX', course_number, '2012_Fall'), course_locations)
# configure simple course to use unique wiki_slug.
simple_course = self.draft_store.get_course(SlashSeparatedCourseKey('edX', 'simple', '2012_Fall'))
@@ -378,7 +378,7 @@ class TestMongoModuleStore(unittest.TestCase):
# it should be retrievable with its new wiki_slug
course_locations = self.draft_store.get_courses_for_wiki('edX.simple.2012_Fall')
assert_equals(len(course_locations), 1)
assert_in(Location('edX', 'simple', '2012_Fall', 'course', '2012_Fall'), course_locations)
assert_in(SlashSeparatedCourseKey('edX', 'simple', '2012_Fall'), course_locations)
@Plugin.register_temp_plugin(ReferenceTestXBlock, 'ref_test')
def test_reference_converters(self):

View File

@@ -1395,10 +1395,12 @@ class TestCourseCreation(SplitModuleTest):
self.assertEqual(index_info['edited_by'], 'create_user')
# check structure info
structure_info = modulestore().get_course_history_info(new_locator)
# TODO uncomment these lines once bulk updater implemented; right now, these will not
# pass because create_course calls update_item resulting in two versions. Bulk updater will fix this.
# TODO LMS-11098 "Implement bulk_write in Split"
# Right now, these assertions will not pass because create_course calls update_item,
# resulting in two versions. Bulk updater will fix this.
# self.assertEqual(structure_info['original_version'], index_info['versions'][BRANCH_NAME_DRAFT])
# self.assertIsNone(structure_info['previous_version'])
self.assertEqual(structure_info['edited_by'], 'create_user')
# check the returned course object
self.assertIsInstance(new_course, CourseDescriptor)

View File

@@ -81,7 +81,7 @@ class TestXMLModuleStore(unittest.TestCase):
for course in store.get_courses():
course_locations = store.get_courses_for_wiki(course.wiki_slug)
self.assertEqual(len(course_locations), 1)
self.assertIn(course.location, course_locations)
self.assertIn(course.location.course_key, course_locations)
course_locations = store.get_courses_for_wiki('no_such_wiki')
self.assertEqual(len(course_locations), 0)
@@ -96,7 +96,7 @@ class TestXMLModuleStore(unittest.TestCase):
course_locations = store.get_courses_for_wiki('simple')
self.assertEqual(len(course_locations), 2)
for course_number in ['toy', 'simple']:
self.assertIn(Location('edX', course_number, '2012_Fall', 'course', '2012_Fall'), course_locations)
self.assertIn(SlashSeparatedCourseKey('edX', course_number, '2012_Fall'), course_locations)
def test_has_course(self):
"""

View File

@@ -815,7 +815,7 @@ class XMLModuleStore(ModuleStoreReadBase):
:return: list of course locations
"""
courses = self.get_courses()
return [course.location for course in courses if (course.wiki_slug == wiki_slug)]
return [course.location.course_key for course in courses if (course.wiki_slug == wiki_slug)]
def heartbeat(self):
"""