Add Draft module store that is used whenever any item is update in the CAS (but not during import, and not for templates)
This commit is contained in:
@@ -26,4 +26,4 @@ class Command(BaseCommand):
|
||||
print "Importing. Data_dir={data}, course_dirs={courses}".format(
|
||||
data=data_dir,
|
||||
courses=course_dirs)
|
||||
import_from_xml(modulestore(), data_dir, course_dirs, load_error_modules=False)
|
||||
import_from_xml(modulestore('direct'), data_dir, course_dirs, load_error_modules=False)
|
||||
|
||||
@@ -14,17 +14,23 @@ LOGGING = get_logger_config(ENV_ROOT / "log",
|
||||
tracking_filename="tracking.log",
|
||||
debug=True)
|
||||
|
||||
modulestore_options = {
|
||||
'default_class': 'xmodule.raw_module.RawDescriptor',
|
||||
'host': 'localhost',
|
||||
'db': 'xmodule',
|
||||
'collection': 'modulestore',
|
||||
'fs_root': GITHUB_REPO_ROOT,
|
||||
'render_template': 'mitxmako.shortcuts.render_to_string',
|
||||
}
|
||||
|
||||
MODULESTORE = {
|
||||
'default': {
|
||||
'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore',
|
||||
'OPTIONS': modulestore_options
|
||||
},
|
||||
'direct': {
|
||||
'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore',
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.raw_module.RawDescriptor',
|
||||
'host': 'localhost',
|
||||
'db': 'xmodule',
|
||||
'collection': 'modulestore',
|
||||
'fs_root': GITHUB_REPO_ROOT,
|
||||
'render_template': 'mitxmako.shortcuts.render_to_string',
|
||||
}
|
||||
'OPTIONS': modulestore_options
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -345,7 +345,9 @@ class ModuleStore(object):
|
||||
Returns a list containing the top level XModuleDescriptors of the courses
|
||||
in this modulestore.
|
||||
'''
|
||||
raise NotImplementedError
|
||||
# TODO (vshnayder): Why do I have to specify i4x here?
|
||||
course_filter = Location("i4x", category="course")
|
||||
return self.get_items(course_filter)
|
||||
|
||||
def get_parent_locations(self, location):
|
||||
'''Find all locations that are the parents of this location. Needed
|
||||
|
||||
128
common/lib/xmodule/xmodule/modulestore/draft.py
Normal file
128
common/lib/xmodule/xmodule/modulestore/draft.py
Normal file
@@ -0,0 +1,128 @@
|
||||
|
||||
from . import ModuleStoreBase, Location
|
||||
from .exceptions import ItemNotFoundError
|
||||
|
||||
|
||||
class DraftModuleStore(ModuleStoreBase):
|
||||
"""
|
||||
This mixin modifies a modulestore to give it draft semantics.
|
||||
That is, edits made to units are stored to locations that have the revision 'draft',
|
||||
and when reads are made, they first read with revision 'draft', and then fall back
|
||||
to the baseline revision only if 'draft' doesn't exist.
|
||||
|
||||
This module also includes functionality to promote 'draft' modules (and optionally
|
||||
their children) to published modules.
|
||||
"""
|
||||
|
||||
def get_item(self, location, depth=0):
|
||||
"""
|
||||
Returns an XModuleDescriptor instance for the item at location.
|
||||
If location.revision is None, returns the item with the most
|
||||
recent revision
|
||||
|
||||
If any segment of the location is None except revision, raises
|
||||
xmodule.modulestore.exceptions.InsufficientSpecificationError
|
||||
|
||||
If no object is found at that location, raises
|
||||
xmodule.modulestore.exceptions.ItemNotFoundError
|
||||
|
||||
location: Something that can be passed to Location
|
||||
|
||||
depth (int): 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
|
||||
"""
|
||||
try:
|
||||
return super(DraftModuleStore, self).get_item(Location(location)._replace(revision='draft'), depth)
|
||||
except ItemNotFoundError:
|
||||
return super(DraftModuleStore, self).get_item(location, depth)
|
||||
|
||||
def get_instance(self, course_id, location):
|
||||
"""
|
||||
Get an instance of this location, with policy for course_id applied.
|
||||
TODO (vshnayder): this may want to live outside the modulestore eventually
|
||||
"""
|
||||
try:
|
||||
return super(DraftModuleStore, self).get_instance(course_id, Location(location)._replace(revision='draft'))
|
||||
except ItemNotFoundError:
|
||||
return super(DraftModuleStore, self).get_instance(course_id, location)
|
||||
|
||||
def get_items(self, location, 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
|
||||
"""
|
||||
draft_loc = Location(location)._replace(revision='draft')
|
||||
draft_items = super(DraftModuleStore, self).get_items(draft_loc, depth)
|
||||
items = super(DraftModuleStore, self).get_items(location, depth)
|
||||
|
||||
draft_locs_found = set(item.location._replace(revision=None) for item in draft_items)
|
||||
non_draft_items = [
|
||||
item
|
||||
for item in items
|
||||
if (item.location.revision != 'draft'
|
||||
and item.location._replace(revision=None) not in draft_locs_found)
|
||||
]
|
||||
return draft_items + non_draft_items
|
||||
|
||||
def clone_item(self, source, location):
|
||||
"""
|
||||
Clone a new item that is a copy of the item at the location `source`
|
||||
and writes it to `location`
|
||||
"""
|
||||
return super(DraftModuleStore, self).clone_item(source, Location(location)._replace(revision='draft'))
|
||||
|
||||
def update_item(self, location, data):
|
||||
"""
|
||||
Set the data in the item specified by the location to
|
||||
data
|
||||
|
||||
location: Something that can be passed to Location
|
||||
data: A nested dictionary of problem data
|
||||
"""
|
||||
return super(DraftModuleStore, self).update_item(Location(location)._replace(revision='draft'), data)
|
||||
|
||||
def update_children(self, location, children):
|
||||
"""
|
||||
Set the children for the item specified by the location to
|
||||
children
|
||||
|
||||
location: Something that can be passed to Location
|
||||
children: A list of child item identifiers
|
||||
"""
|
||||
return super(DraftModuleStore, self).update_children(Location(location)._replace(revision='draft'), children)
|
||||
|
||||
def update_metadata(self, location, metadata):
|
||||
"""
|
||||
Set the metadata for the item specified by the location to
|
||||
metadata
|
||||
|
||||
location: Something that can be passed to Location
|
||||
metadata: A nested dictionary of module metadata
|
||||
"""
|
||||
return super(DraftModuleStore, self).update_metadata(Location(location)._replace(revision='draft'), metadata)
|
||||
|
||||
def delete_item(self, location):
|
||||
"""
|
||||
Delete an item from this modulestore
|
||||
|
||||
location: Something that can be passed to Location
|
||||
"""
|
||||
return super(DraftModuleStore, self).delete_item(Location(location)._replace(revision='draft'))
|
||||
|
||||
def get_parent_locations(self, location):
|
||||
'''Find all locations that are the parents of this location. Needed
|
||||
for path_to_location().
|
||||
|
||||
returns an iterable of things that can be passed to Location.
|
||||
'''
|
||||
return super(DraftModuleStore, self).get_parent_locations(Location(location)._replace(revision='draft'))
|
||||
@@ -13,6 +13,7 @@ from xmodule.mako_module import MakoDescriptorSystem
|
||||
from xmodule.error_module import ErrorDescriptor
|
||||
|
||||
from . import ModuleStoreBase, Location
|
||||
from .draft import DraftModuleStore
|
||||
from .exceptions import (ItemNotFoundError,
|
||||
DuplicateItemError)
|
||||
|
||||
@@ -341,3 +342,8 @@ class MongoModuleStore(ModuleStoreBase):
|
||||
are loaded on demand, rather than up front
|
||||
"""
|
||||
return {}
|
||||
|
||||
|
||||
# DraftModuleStore is first, because it needs to intercept calls to MongoModuleStore
|
||||
class DraftMongoModuleStore(DraftModuleStore, MongoModuleStore):
|
||||
pass
|
||||
|
||||
@@ -75,6 +75,6 @@ def update_templates():
|
||||
), exc_info=True)
|
||||
continue
|
||||
|
||||
modulestore().update_item(template_location, template.data)
|
||||
modulestore().update_children(template_location, template.children)
|
||||
modulestore().update_metadata(template_location, template.metadata)
|
||||
modulestore('direct').update_item(template_location, template.data)
|
||||
modulestore('direct').update_children(template_location, template.children)
|
||||
modulestore('direct').update_metadata(template_location, template.metadata)
|
||||
|
||||
Reference in New Issue
Block a user