Commit 75f8b7c9 by Calen Pennington

Add Draft module store that is used whenever any item is update in the CAS (but…

Add Draft module store that is used whenever any item is update in the CAS (but not during import, and not for templates)
parent 6079c571
......@@ -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
......
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)
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