Files
edx-platform/common/lib/xmodule/xmodule/modulestore/mixed.py
Calen Pennington 8201b1412e Use XBlock 0.3
2013-09-06 09:45:59 -04:00

151 lines
5.8 KiB
Python

"""
MixedModuleStore allows for aggregation between multiple modulestores.
In this way, courses can be served up both - say - XMLModuleStore or MongoModuleStore
IMPORTANT: This modulestore only supports READONLY applications, e.g. LMS
"""
from . import ModuleStoreBase
from xmodule.modulestore.django import create_modulestore_instance
import logging
log = logging.getLogger(__name__)
class MixedModuleStore(ModuleStoreBase):
"""
ModuleStore that can be backed by either XML or Mongo
"""
def __init__(self, mappings, stores, **kwargs):
"""
Initialize a MixedModuleStore. Here we look into our passed in kwargs which should be a
collection of other modulestore configuration informations
"""
super(MixedModuleStore, self).__init__(**kwargs)
self.modulestores = {}
self.mappings = mappings
if 'default' not in stores:
raise Exception('Missing a default modulestore in the MixedModuleStore __init__ method.')
for key, store in stores.items():
self.modulestores[key] = create_modulestore_instance(store['ENGINE'],
store['OPTIONS'])
def _get_modulestore_for_courseid(self, course_id):
"""
For a given course_id, look in the mapping table and see if it has been pinned
to a particular modulestore
"""
mapping = self.mappings.get(course_id, 'default')
return self.modulestores[mapping]
def has_item(self, course_id, location):
return self._get_modulestore_for_courseid(course_id).has_item(course_id, location)
def get_item(self, location, depth=0):
"""
This method is explicitly not implemented as we need a course_id to disambiguate
We should be able to fix this when the data-model rearchitecting is done
"""
raise NotImplementedError
def get_instance(self, course_id, location, depth=0):
return self._get_modulestore_for_courseid(course_id).get_instance(course_id, location, depth)
def get_items(self, location, course_id=None, depth=0):
"""
Returns a list of XModuleDescriptor instances for the items
that match location. Any element of location that is None is treated
as a wildcard that matches any value
location: Something that can be passed to Location
depth: An argument that some module stores may use to prefetch
descendents of the queried modules for more efficient results later
in the request. The depth is counted in the number of calls to
get_children() to cache. None indicates to cache all descendents
"""
if not course_id:
raise Exception("Must pass in a course_id when calling get_items() with MixedModuleStore")
return self._get_modulestore_for_courseid(course_id).get_items(location, course_id, depth)
def update_item(self, location, data, allow_not_found=False):
"""
MixedModuleStore is for read-only (aka LMS)
"""
raise NotImplementedError
def update_children(self, location, children):
"""
MixedModuleStore is for read-only (aka LMS)
"""
raise NotImplementedError
def update_metadata(self, location, metadata):
"""
MixedModuleStore is for read-only (aka LMS)
"""
raise NotImplementedError
def delete_item(self, location):
"""
MixedModuleStore is for read-only (aka LMS)
"""
raise NotImplementedError
def get_courses(self):
'''
Returns a list containing the top level XModuleDescriptors of the courses
in this modulestore.
'''
courses = []
for key in self.modulestores:
store_courses = self.modulestores[key].get_courses()
# If the store has not been labeled as 'default' then we should
# only surface courses that have a mapping entry, for example the XMLModuleStore will
# slurp up anything that is on disk, however, we don't want to surface those to
# consumers *unless* there is an explicit mapping in the configuration
if key != 'default':
for course in store_courses:
# make sure that the courseId is mapped to the store in question
if key == self.mappings.get(course.location.course_id, 'default'):
courses = courses + ([course])
else:
# if we're the 'default' store provider, then we surface all courses hosted in
# that store provider
courses = courses + (store_courses)
return courses
def get_course(self, course_id):
"""
returns the course module associated with the course_id
"""
return self._get_modulestore_for_courseid(course_id).get_course(course_id)
def get_parent_locations(self, location, course_id):
"""
returns the parent locations for a given lcoation and course_id
"""
return self._get_modulestore_for_courseid(course_id).get_parent_locations(location, course_id)
def get_modulestore_type(self, course_id):
"""
Returns a type which identifies which modulestore is servicing the given
course_id. The return can be either "xml" (for XML based courses) or "mongo" for MongoDB backed courses
"""
return self._get_modulestore_for_courseid(course_id).get_modulestore_type(course_id)
def get_errored_courses(self):
"""
Return a dictionary of course_dir -> [(msg, exception_str)], for each
course_dir where course loading failed.
"""
errs = {}
for store in self.modulestores.values():
errs.update(store.get_errored_courses())
return errs