diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4d117a9c73..04c8a5baae 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -43,6 +43,13 @@ history of background tasks for a given problem and student.
Blades: Small UX fix on capa multiple-choice problems. Make labels only
as wide as the text to reduce accidental choice selections.
+Studio:
+- use xblock field defaults to initialize all new instances' fields and
+only use templates as override samples.
+- create new instances via in memory create_xmodule and related methods rather
+than cloning a db record.
+- have an explicit method for making a draft copy as distinct from making a new module.
+
Studio: Remove XML from the video component editor. All settings are
moved to be edited as metadata.
diff --git a/README.md b/README.md
index e533459c8b..2208fe1cad 100644
--- a/README.md
+++ b/README.md
@@ -239,7 +239,6 @@ CMS templates. Fortunately, `rake` will do all of this for you! Just run:
$ rake django-admin[syncdb]
$ rake django-admin[migrate]
- $ rake cms:update_templates
If you are running these commands using the [`zsh`](http://www.zsh.org/) shell,
zsh will assume that you are doing
diff --git a/cms/djangoapps/contentstore/course_info_model.py b/cms/djangoapps/contentstore/course_info_model.py
index ada3873992..7e1e6470ff 100644
--- a/cms/djangoapps/contentstore/course_info_model.py
+++ b/cms/djangoapps/contentstore/course_info_model.py
@@ -20,8 +20,8 @@ def get_course_updates(location):
try:
course_updates = modulestore('direct').get_item(location)
except ItemNotFoundError:
- template = Location(['i4x', 'edx', "templates", 'course_info', "Empty"])
- course_updates = modulestore('direct').clone_item(template, Location(location))
+ modulestore('direct').create_and_save_xmodule(location)
+ course_updates = modulestore('direct').get_item(location)
# current db rep: {"_id" : locationjson, "definition" : { "data" : "
@@ -181,7 +183,7 @@
diff --git a/cms/templates/unit.html b/cms/templates/unit.html
index ce4f239ab1..300d631421 100644
--- a/cms/templates/unit.html
+++ b/cms/templates/unit.html
@@ -59,8 +59,8 @@
% if type == 'advanced' or len(templates) > 1:
% else:
- % for __, location, __ in templates:
-
+ % for __, category, __, __ in templates:
+
% endfor
% endif
@@ -74,49 +74,60 @@
% if len(templates) > 1 or type == 'advanced':
% if type == "problem":
-
-
- % endif
-
-
- % for name, location, has_markdown in templates:
- % if has_markdown or type != "problem":
- -
-
- ${name}
-
-
- % endif
-
- %endfor
+
- % if type == "problem":
-
-
- % for name, location, has_markdown in templates:
- % if not has_markdown:
- -
-
- ${name}
-
-
- % endif
- % endfor
-
-
-
- % endif
-
${_("Cancel")}
-
- % endif
+ % endif
+
+
+ % for name, category, has_markdown, boilerplate_name in sorted(templates):
+ % if has_markdown or type != "problem":
+ % if boilerplate_name is None:
+ -
+
+ ${name}
+
+
+
+ % else:
+ -
+
+ ${name}
+
+
+ % endif
+ % endif
+
+ %endfor
+
+
+ % if type == "problem":
+
+
+ % for name, category, has_markdown, boilerplate_name in sorted(templates):
+ % if not has_markdown:
+ -
+
+ ${name}
+
+
+ % endif
+ % endfor
+
+
+
+ % endif
+ Cancel
+
+ % endif
% endfor
diff --git a/cms/templates/widgets/units.html b/cms/templates/widgets/units.html
index 5ac05e79eb..62c1fb62d7 100644
--- a/cms/templates/widgets/units.html
+++ b/cms/templates/widgets/units.html
@@ -34,7 +34,7 @@ This def will enumerate through a passed in subsection and list all of the units
% endfor
-
+
New Unit
diff --git a/cms/urls.py b/cms/urls.py
index 6db07dc2ed..711742d89f 100644
--- a/cms/urls.py
+++ b/cms/urls.py
@@ -17,7 +17,7 @@ urlpatterns = ('', # nopep8
url(r'^preview_component/(?P
.*?)$', 'contentstore.views.preview_component', name='preview_component'),
url(r'^save_item$', 'contentstore.views.save_item', name='save_item'),
url(r'^delete_item$', 'contentstore.views.delete_item', name='delete_item'),
- url(r'^clone_item$', 'contentstore.views.clone_item', name='clone_item'),
+ url(r'^create_item$', 'contentstore.views.create_item', name='create_item'),
url(r'^create_draft$', 'contentstore.views.create_draft', name='create_draft'),
url(r'^publish_draft$', 'contentstore.views.publish_draft', name='publish_draft'),
url(r'^unpublish_unit$', 'contentstore.views.unpublish_unit', name='unpublish_unit'),
diff --git a/common/djangoapps/terrain/course_helpers.py b/common/djangoapps/terrain/course_helpers.py
index 27bf95099d..c62b1a1e79 100644
--- a/common/djangoapps/terrain/course_helpers.py
+++ b/common/djangoapps/terrain/course_helpers.py
@@ -12,7 +12,6 @@ from django.contrib.sessions.middleware import SessionMiddleware
from student.models import CourseEnrollment
from xmodule.modulestore.django import modulestore
from xmodule.contentstore.django import contentstore
-from xmodule.templates import update_templates
from urllib import quote_plus
@@ -84,5 +83,4 @@ def clear_courses():
# from the bash shell to drop it:
# $ mongo test_xmodule --eval "db.dropDatabase()"
modulestore().collection.drop()
- update_templates(modulestore('direct'))
contentstore().fs_files.drop()
diff --git a/common/djangoapps/tests.py b/common/djangoapps/tests.py
index 8e78ee7f37..4a61a106d4 100644
--- a/common/djangoapps/tests.py
+++ b/common/djangoapps/tests.py
@@ -23,15 +23,15 @@ class TestXmoduleModfiers(ModuleStoreTestCase):
number='313', display_name='histogram test')
section = ItemFactory.create(
parent_location=course.location, display_name='chapter hist',
- template='i4x://edx/templates/chapter/Empty')
+ category='chapter')
problem = ItemFactory.create(
parent_location=section.location, display_name='problem hist 1',
- template='i4x://edx/templates/problem/Blank_Common_Problem')
+ category='problem')
problem.has_score = False # don't trip trying to retrieve db data
late_problem = ItemFactory.create(
parent_location=section.location, display_name='problem hist 2',
- template='i4x://edx/templates/problem/Blank_Common_Problem')
+ category='problem')
late_problem.lms.start = datetime.datetime.now(UTC) + datetime.timedelta(days=32)
late_problem.has_score = False
diff --git a/common/lib/xmodule/xmodule/abtest_module.py b/common/lib/xmodule/xmodule/abtest_module.py
index 2e61076e94..53f080eb3a 100644
--- a/common/lib/xmodule/xmodule/abtest_module.py
+++ b/common/lib/xmodule/xmodule/abtest_module.py
@@ -80,8 +80,6 @@ class ABTestModule(ABTestFields, XModule):
class ABTestDescriptor(ABTestFields, RawDescriptor, XmlDescriptor):
module_class = ABTestModule
- template_dir_name = "abtest"
-
@classmethod
def definition_from_xml(cls, xml_object, system):
"""
diff --git a/common/lib/xmodule/xmodule/annotatable_module.py b/common/lib/xmodule/xmodule/annotatable_module.py
index 8b1bbc71d3..f80e3e488e 100644
--- a/common/lib/xmodule/xmodule/annotatable_module.py
+++ b/common/lib/xmodule/xmodule/annotatable_module.py
@@ -150,5 +150,4 @@ class AnnotatableModule(AnnotatableFields, XModule):
class AnnotatableDescriptor(AnnotatableFields, RawDescriptor):
module_class = AnnotatableModule
- template_dir_name = "annotatable"
mako_template = "widgets/raw-edit.html"
diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py
index 13f00bb77e..60103a2126 100644
--- a/common/lib/xmodule/xmodule/combined_open_ended_module.py
+++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py
@@ -290,7 +290,6 @@ class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor):
has_score = True
always_recalculate_grades = True
- template_dir_name = "combinedopenended"
#Specify whether or not to pass in S3 interface
needs_s3_interface = True
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index ceadee1c15..d4aac5b0ae 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -366,8 +366,6 @@ class CourseFields(object):
class CourseDescriptor(CourseFields, SequenceDescriptor):
module_class = SequenceModule
- template_dir_name = 'course'
-
def __init__(self, *args, **kwargs):
"""
Expects the same arguments as XModuleDescriptor.__init__
diff --git a/common/lib/xmodule/xmodule/error_module.py b/common/lib/xmodule/xmodule/error_module.py
index a37081c447..db1f998187 100644
--- a/common/lib/xmodule/xmodule/error_module.py
+++ b/common/lib/xmodule/xmodule/error_module.py
@@ -96,6 +96,7 @@ class ErrorDescriptor(ErrorFields, JSONEditingDescriptor):
'contents': contents,
'display_name': 'Error: ' + location.name,
'location': location,
+ 'category': 'error'
}
return cls(
system,
@@ -109,12 +110,12 @@ class ErrorDescriptor(ErrorFields, JSONEditingDescriptor):
}
@classmethod
- def from_json(cls, json_data, system, error_msg='Error not available'):
+ def from_json(cls, json_data, system, location, error_msg='Error not available'):
return cls._construct(
system,
- json.dumps(json_data, indent=4),
+ json.dumps(json_data, skipkeys=False, indent=4),
error_msg,
- location=Location(json_data['location']),
+ location=location
)
@classmethod
diff --git a/common/lib/xmodule/xmodule/foldit_module.py b/common/lib/xmodule/xmodule/foldit_module.py
index fdab14b58d..c4e9e2d35c 100644
--- a/common/lib/xmodule/xmodule/foldit_module.py
+++ b/common/lib/xmodule/xmodule/foldit_module.py
@@ -184,7 +184,6 @@ class FolditDescriptor(FolditFields, XmlDescriptor, EditingDescriptor):
filename_extension = "xml"
has_score = True
- template_dir_name = "foldit"
js = {'coffee': [resource_string(__name__, 'js/src/html/edit.coffee')]}
js_module_name = "HTMLEditingDescriptor"
diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py
index e101d90b4c..5a4930ff95 100644
--- a/common/lib/xmodule/xmodule/gst_module.py
+++ b/common/lib/xmodule/xmodule/gst_module.py
@@ -141,7 +141,6 @@ class GraphicalSliderToolModule(GraphicalSliderToolFields, XModule):
class GraphicalSliderToolDescriptor(GraphicalSliderToolFields, MakoModuleDescriptor, XmlDescriptor):
module_class = GraphicalSliderToolModule
- template_dir_name = 'graphical_slider_tool'
@classmethod
def definition_from_xml(cls, xml_object, system):
diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py
index 9ff2e4d9a8..2c7c9e0b01 100644
--- a/common/lib/xmodule/xmodule/html_module.py
+++ b/common/lib/xmodule/xmodule/html_module.py
@@ -234,7 +234,7 @@ class StaticTabDescriptor(StaticTabFields, HtmlDescriptor):
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
in order to be able to create new ones
"""
- template_dir_name = "statictab"
+ template_dir_name = None
module_class = StaticTabModule
@@ -261,5 +261,5 @@ class CourseInfoDescriptor(CourseInfoFields, HtmlDescriptor):
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
in order to be able to create new ones
"""
- template_dir_name = "courseinfo"
+ template_dir_name = None
module_class = CourseInfoModule
diff --git a/common/lib/xmodule/xmodule/js/spec/combinedopenended/edit_spec.coffee b/common/lib/xmodule/xmodule/js/spec/combinedopenended/edit_spec.coffee
index aa077da450..d859a59dda 100644
--- a/common/lib/xmodule/xmodule/js/spec/combinedopenended/edit_spec.coffee
+++ b/common/lib/xmodule/xmodule/js/spec/combinedopenended/edit_spec.coffee
@@ -11,13 +11,13 @@ describe 'OpenEndedMarkdownEditingDescriptor', ->
@descriptor = new OpenEndedMarkdownEditingDescriptor($('.combinedopenended-editor'))
@descriptor.createXMLEditor('replace with markdown')
saveResult = @descriptor.save()
- expect(saveResult.metadata.markdown).toEqual(null)
+ expect(saveResult.nullout).toEqual(['markdown'])
expect(saveResult.data).toEqual('replace with markdown')
it 'saves xml from the xml editor', ->
loadFixtures 'combinedopenended-without-markdown.html'
@descriptor = new OpenEndedMarkdownEditingDescriptor($('.combinedopenended-editor'))
saveResult = @descriptor.save()
- expect(saveResult.metadata.markdown).toEqual(null)
+ expect(saveResult.nullout).toEqual(['markdown'])
expect(saveResult.data).toEqual('xml only')
describe 'insertPrompt', ->
diff --git a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee
index 5161e658e7..1df9587037 100644
--- a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee
+++ b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee
@@ -11,13 +11,13 @@ describe 'MarkdownEditingDescriptor', ->
@descriptor = new MarkdownEditingDescriptor($('.problem-editor'))
@descriptor.createXMLEditor('replace with markdown')
saveResult = @descriptor.save()
- expect(saveResult.metadata.markdown).toEqual(null)
+ expect(saveResult.nullout).toEqual(['markdown'])
expect(saveResult.data).toEqual('replace with markdown')
it 'saves xml from the xml editor', ->
loadFixtures 'problem-without-markdown.html'
@descriptor = new MarkdownEditingDescriptor($('.problem-editor'))
saveResult = @descriptor.save()
- expect(saveResult.metadata.markdown).toEqual(null)
+ expect(saveResult.nullout).toEqual(['markdown'])
expect(saveResult.data).toEqual('xml only')
describe 'insertMultipleChoice', ->
diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee
index 1b7f9bb4fb..4cdd571c65 100644
--- a/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee
+++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee
@@ -153,8 +153,7 @@ Write a persuasive essay to a newspaper reflecting your vies on censorship in li
else
{
data: @xml_editor.getValue()
- metadata:
- markdown: null
+ nullout: ['markdown']
}
@insertRubric: (selectedText) ->
diff --git a/common/lib/xmodule/xmodule/js/src/problem/edit.coffee b/common/lib/xmodule/xmodule/js/src/problem/edit.coffee
index b723f230e9..bd2871eb61 100644
--- a/common/lib/xmodule/xmodule/js/src/problem/edit.coffee
+++ b/common/lib/xmodule/xmodule/js/src/problem/edit.coffee
@@ -123,9 +123,8 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
}
else
{
- data: @xml_editor.getValue()
- metadata:
- markdown: null
+ data: @xml_editor.getValue()
+ nullout: ['markdown']
}
@insertMultipleChoice: (selectedText) ->
diff --git a/common/lib/xmodule/xmodule/modulestore/__init__.py b/common/lib/xmodule/xmodule/modulestore/__init__.py
index 2fa12e2e90..eb721dfc99 100644
--- a/common/lib/xmodule/xmodule/modulestore/__init__.py
+++ b/common/lib/xmodule/xmodule/modulestore/__init__.py
@@ -310,14 +310,7 @@ class ModuleStore(object):
"""
raise NotImplementedError
- 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`
- """
- raise NotImplementedError
-
- def update_item(self, location, data):
+ def update_item(self, location, data, allow_not_found=False):
"""
Set the data in the item specified by the location to
data
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo/base.py b/common/lib/xmodule/xmodule/modulestore/mongo/base.py
index f56393d75e..0b1c601a2f 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo/base.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo/base.py
@@ -33,7 +33,7 @@ from xblock.runtime import DbModel, KeyValueStore, InvalidScopeError
from xblock.core import Scope
from xmodule.modulestore import ModuleStoreBase, Location, namedtuple_to_son
-from xmodule.modulestore.exceptions import ItemNotFoundError, DuplicateItemError
+from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore.inheritance import own_metadata, INHERITABLE_METADATA, inherit_metadata
log = logging.getLogger(__name__)
@@ -62,11 +62,12 @@ class MongoKeyValueStore(KeyValueStore):
A KeyValueStore that maps keyed data access to one of the 3 data areas
known to the MongoModuleStore (data, children, and metadata)
"""
- def __init__(self, data, children, metadata, location):
+ def __init__(self, data, children, metadata, location, category):
self._data = data
self._children = children
self._metadata = metadata
self._location = location
+ self._category = category
def get(self, key):
if key.scope == Scope.children:
@@ -78,6 +79,8 @@ class MongoKeyValueStore(KeyValueStore):
elif key.scope == Scope.content:
if key.field_name == 'location':
return self._location
+ elif key.field_name == 'category':
+ return self._category
elif key.field_name == 'data' and not isinstance(self._data, dict):
return self._data
else:
@@ -93,6 +96,8 @@ class MongoKeyValueStore(KeyValueStore):
elif key.scope == Scope.content:
if key.field_name == 'location':
self._location = value
+ elif key.field_name == 'category':
+ self._category = value
elif key.field_name == 'data' and not isinstance(self._data, dict):
self._data = value
else:
@@ -109,6 +114,8 @@ class MongoKeyValueStore(KeyValueStore):
elif key.scope == Scope.content:
if key.field_name == 'location':
self._location = Location(None)
+ elif key.field_name == 'category':
+ self._category = None
elif key.field_name == 'data' and not isinstance(self._data, dict):
self._data = None
else:
@@ -123,7 +130,10 @@ class MongoKeyValueStore(KeyValueStore):
return key.field_name in self._metadata
elif key.scope == Scope.content:
if key.field_name == 'location':
+ # WHY TRUE? if it's been deleted should it be False?
return True
+ elif key.field_name == 'category':
+ return self._category is not None
elif key.field_name == 'data' and not isinstance(self._data, dict):
return True
else:
@@ -185,8 +195,9 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
else:
# load the module and apply the inherited metadata
try:
+ category = json_data['location']['category']
class_ = XModuleDescriptor.load_class(
- json_data['location']['category'],
+ category,
self.default_class
)
definition = json_data.get('definition', {})
@@ -201,9 +212,12 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
definition.get('children', []),
metadata,
location,
+ category
)
model_data = DbModel(kvs, class_, None, MongoUsage(self.course_id, location))
+ model_data['category'] = category
+ model_data['location'] = location
module = class_(self, model_data)
if self.cached_metadata is not None:
# parent container pointers don't differentiate between draft and non-draft
@@ -217,6 +231,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
return ErrorDescriptor.from_json(
json_data,
self,
+ json_data['location'],
error_msg=exc_info_to_str(sys.exc_info())
)
@@ -582,51 +597,97 @@ class MongoModuleStore(ModuleStoreBase):
modules = self._load_items(list(items), depth)
return modules
- def clone_item(self, source, location):
+ def create_xmodule(self, location, definition_data=None, metadata=None, system=None):
"""
- Clone a new item that is a copy of the item at the location `source`
- and writes it to `location`
+ Create the new xmodule but don't save it. Returns the new module.
+
+ :param location: a Location--must have a category
+ :param definition_data: can be empty. The initial definition_data for the kvs
+ :param metadata: can be empty, the initial metadata for the kvs
+ :param system: if you already have an xmodule from the course, the xmodule.system value
"""
- item = None
- try:
- source_item = self.collection.find_one(location_to_query(source))
-
- # allow for some programmatically generated substitutions in metadata, e.g. Discussion_id's should be auto-generated
- for key in source_item['metadata'].keys():
- if source_item['metadata'][key] == '$$GUID$$':
- source_item['metadata'][key] = uuid4().hex
-
- source_item['_id'] = Location(location).dict()
- self.collection.insert(
- source_item,
- # Must include this to avoid the django debug toolbar (which defines the deprecated "safe=False")
- # from overriding our default value set in the init method.
- safe=self.collection.safe
+ if not isinstance(location, Location):
+ location = Location(location)
+ # differs from split mongo in that I believe most of this logic should be above the persistence
+ # layer but added it here to enable quick conversion. I'll need to reconcile these.
+ if metadata is None:
+ metadata = {}
+ if system is None:
+ system = CachingDescriptorSystem(
+ self,
+ {},
+ self.default_class,
+ None,
+ self.error_tracker,
+ self.render_template,
+ {}
)
- item = self._load_items([source_item])[0]
+ xblock_class = XModuleDescriptor.load_class(location.category, self.default_class)
+ if definition_data is None:
+ if hasattr(xblock_class, 'data') and getattr(xblock_class, 'data').default is not None:
+ definition_data = getattr(xblock_class, 'data').default
+ else:
+ definition_data = {}
+ dbmodel = self._create_new_model_data(location.category, location, definition_data, metadata)
+ xmodule = xblock_class(system, dbmodel)
+ # force inherited fields w/ defaults to take the defaults so the children can inherit
+ for attr in INHERITABLE_METADATA:
+ if hasattr(xmodule, attr):
+ xmodule._model_data[attr] = getattr(xmodule, attr)
+ return xmodule
- # VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so
- # if we add one then we need to also add it to the policy information (i.e. metadata)
- # we should remove this once we can break this reference from the course to static tabs
- if location.category == 'static_tab':
- course = self.get_course_for_item(item.location)
- existing_tabs = course.tabs or []
- existing_tabs.append({
- 'type': 'static_tab',
- 'name': item.display_name,
- 'url_slug': item.location.name
- })
- course.tabs = existing_tabs
- self.update_metadata(course.location, course._model_data._kvs._metadata)
-
- except pymongo.errors.DuplicateKeyError:
- raise DuplicateItemError(location)
+ def save_xmodule(self, xmodule):
+ """
+ Save the given xmodule (will either create or update based on whether id already exists).
+ Pulls out the data definition v metadata v children locally but saves it all.
+ :param xmodule:
+ """
+ # split mongo's persist_dag is more general and useful.
+ self.collection.save({
+ '_id': xmodule.location.dict(),
+ 'metadata': own_metadata(xmodule),
+ 'definition': {
+ 'data': xmodule.xblock_kvs._data,
+ 'children': xmodule.children if xmodule.has_children else []
+ }
+ })
# recompute (and update) the metadata inheritance tree which is cached
- self.refresh_cached_metadata_inheritance_tree(Location(location))
- self.fire_updated_modulestore_signal(get_course_id_no_run(Location(location)), Location(location))
+ self.refresh_cached_metadata_inheritance_tree(xmodule.location)
+ self.fire_updated_modulestore_signal(get_course_id_no_run(xmodule.location), xmodule.location)
- return item
+ def create_and_save_xmodule(self, location, definition_data=None, metadata=None, system=None):
+ """
+ Create the new xmodule and save it. Does not return the new module because if the caller
+ will insert it as a child, it's inherited metadata will completely change. The difference
+ between this and just doing create_xmodule and save_xmodule is this ensures static_tabs get
+ pointed to by the course.
+
+ :param location: a Location--must have a category
+ :param definition_data: can be empty. The initial definition_data for the kvs
+ :param metadata: can be empty, the initial metadata for the kvs
+ :param system: if you already have an xmodule from the course, the xmodule.system value
+ """
+ # differs from split mongo in that I believe most of this logic should be above the persistence
+ # layer but added it here to enable quick conversion. I'll need to reconcile these.
+ new_object = self.create_xmodule(location, definition_data, metadata, system)
+ location = new_object.location
+ self.save_xmodule(new_object)
+
+ # VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so
+ # if we add one then we need to also add it to the policy information (i.e. metadata)
+ # we should remove this once we can break this reference from the course to static tabs
+ # TODO move this special casing to app tier (similar to attaching new element to parent)
+ if location.category == 'static_tab':
+ course = self.get_course_for_item(location)
+ existing_tabs = course.tabs or []
+ existing_tabs.append({
+ 'type': 'static_tab',
+ 'name': new_object.display_name,
+ 'url_slug': new_object.location.name
+ })
+ course.tabs = existing_tabs
+ self.update_metadata(course.location, course.xblock_kvs._metadata)
def fire_updated_modulestore_signal(self, course_id, location):
"""
@@ -683,7 +744,7 @@ class MongoModuleStore(ModuleStoreBase):
if result['n'] == 0:
raise ItemNotFoundError(location)
- def update_item(self, location, data):
+ def update_item(self, location, data, allow_not_found=False):
"""
Set the data in the item specified by the location to
data
@@ -691,8 +752,11 @@ class MongoModuleStore(ModuleStoreBase):
location: Something that can be passed to Location
data: A nested dictionary of problem data
"""
-
- self._update_single_item(location, {'definition.data': data})
+ try:
+ self._update_single_item(location, {'definition.data': data})
+ except ItemNotFoundError:
+ if not allow_not_found:
+ raise
def update_children(self, location, children):
"""
@@ -775,3 +839,24 @@ class MongoModuleStore(ModuleStoreBase):
are loaded on demand, rather than up front
"""
return {}
+
+ def _create_new_model_data(self, category, location, definition_data, metadata):
+ """
+ To instantiate a new xmodule which will be saved latter, set up the dbModel and kvs
+ """
+ kvs = MongoKeyValueStore(
+ definition_data,
+ [],
+ metadata,
+ location,
+ category
+ )
+
+ class_ = XModuleDescriptor.load_class(
+ category,
+ self.default_class
+ )
+ model_data = DbModel(kvs, class_, None, MongoUsage(None, location))
+ model_data['category'] = category
+ model_data['location'] = location
+ return model_data
diff --git a/common/lib/xmodule/xmodule/modulestore/mongo/draft.py b/common/lib/xmodule/xmodule/modulestore/mongo/draft.py
index f34c3a53f9..d289e03739 100644
--- a/common/lib/xmodule/xmodule/modulestore/mongo/draft.py
+++ b/common/lib/xmodule/xmodule/modulestore/mongo/draft.py
@@ -8,11 +8,12 @@ and otherwise returns i4x://org/course/cat/name).
from datetime import datetime
-from xmodule.modulestore import Location, namedtuple_to_son
-from xmodule.modulestore.exceptions import ItemNotFoundError
-from xmodule.modulestore.inheritance import own_metadata
from xmodule.exceptions import InvalidVersionError
-from xmodule.modulestore.mongo.base import MongoModuleStore
+from xmodule.modulestore import Location, namedtuple_to_son
+from xmodule.modulestore.exceptions import ItemNotFoundError, DuplicateItemError
+from xmodule.modulestore.inheritance import own_metadata
+from xmodule.modulestore.mongo.base import location_to_query, get_course_id_no_run, MongoModuleStore
+import pymongo
from pytz import UTC
DRAFT = 'draft'
@@ -92,6 +93,21 @@ class DraftModuleStore(MongoModuleStore):
except ItemNotFoundError:
return wrap_draft(super(DraftModuleStore, self).get_instance(course_id, location, depth=depth))
+ def create_xmodule(self, location, definition_data=None, metadata=None, system=None):
+ """
+ Create the new xmodule but don't save it. Returns the new module with a draft locator
+
+ :param location: a Location--must have a category
+ :param definition_data: can be empty. The initial definition_data for the kvs
+ :param metadata: can be empty, the initial metadata for the kvs
+ :param system: if you already have an xmodule from the course, the xmodule.system value
+ """
+ draft_loc = as_draft(location)
+ if draft_loc.category in DIRECT_ONLY_CATEGORIES:
+ raise InvalidVersionError(location)
+ return super(DraftModuleStore, self).create_xmodule(draft_loc, definition_data, metadata, system)
+
+
def get_items(self, location, course_id=None, depth=0):
"""
Returns a list of XModuleDescriptor instances for the items
@@ -119,14 +135,26 @@ class DraftModuleStore(MongoModuleStore):
]
return [wrap_draft(item) for item in draft_items + non_draft_items]
- def clone_item(self, source, location):
+ def convert_to_draft(self, source_location):
"""
- Clone a new item that is a copy of the item at the location `source`
- and writes it to `location`
+ Create a copy of the source and mark its revision as draft.
+
+ :param source: the location of the source (its revision must be None)
"""
- if Location(location).category in DIRECT_ONLY_CATEGORIES:
- raise InvalidVersionError(location)
- return wrap_draft(super(DraftModuleStore, self).clone_item(source, as_draft(location)))
+ original = self.collection.find_one(location_to_query(source_location))
+ draft_location = as_draft(source_location)
+ if draft_location.category in DIRECT_ONLY_CATEGORIES:
+ raise InvalidVersionError(source_location)
+ original['_id'] = draft_location.dict()
+ try:
+ self.collection.insert(original)
+ except pymongo.errors.DuplicateKeyError:
+ raise DuplicateItemError(original['_id'])
+
+ self.refresh_cached_metadata_inheritance_tree(draft_location)
+ self.fire_updated_modulestore_signal(get_course_id_no_run(draft_location), draft_location)
+
+ return self._load_items([original])[0]
def update_item(self, location, data, allow_not_found=False):
"""
@@ -140,7 +168,7 @@ class DraftModuleStore(MongoModuleStore):
try:
draft_item = self.get_item(location)
if not getattr(draft_item, 'is_draft', False):
- self.clone_item(location, draft_loc)
+ self.convert_to_draft(location)
except ItemNotFoundError, e:
if not allow_not_found:
raise e
@@ -158,7 +186,7 @@ class DraftModuleStore(MongoModuleStore):
draft_loc = as_draft(location)
draft_item = self.get_item(location)
if not getattr(draft_item, 'is_draft', False):
- self.clone_item(location, draft_loc)
+ self.convert_to_draft(location)
return super(DraftModuleStore, self).update_children(draft_loc, children)
@@ -174,7 +202,7 @@ class DraftModuleStore(MongoModuleStore):
draft_item = self.get_item(location)
if not getattr(draft_item, 'is_draft', False):
- self.clone_item(location, draft_loc)
+ self.convert_to_draft(location)
if 'is_draft' in metadata:
del metadata['is_draft']
@@ -218,9 +246,7 @@ class DraftModuleStore(MongoModuleStore):
"""
Turn the published version into a draft, removing the published version
"""
- if Location(location).category in DIRECT_ONLY_CATEGORIES:
- raise InvalidVersionError(location)
- super(DraftModuleStore, self).clone_item(location, as_draft(location))
+ self.convert_to_draft(location)
super(DraftModuleStore, self).delete_item(location)
def _query_children_for_cache_children(self, items):
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
index c32d0bca4c..564aac141d 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
@@ -5,7 +5,6 @@ from django.test import TestCase
from django.conf import settings
import xmodule.modulestore.django
-from xmodule.templates import update_templates
from unittest.util import safe_repr
@@ -110,22 +109,6 @@ class ModuleStoreTestCase(TestCase):
modulestore.collection.remove(query)
modulestore.collection.drop()
- @staticmethod
- def load_templates_if_necessary():
- """
- Load templates into the direct modulestore only if they do not already exist.
- We need the templates, because they are copied to create
- XModules such as sections and problems.
- """
- modulestore = xmodule.modulestore.django.modulestore('direct')
-
- # Count the number of templates
- query = {"_id.course": "templates"}
- num_templates = modulestore.collection.find(query).count()
-
- if num_templates < 1:
- update_templates(modulestore)
-
@classmethod
def setUpClass(cls):
"""
@@ -169,9 +152,6 @@ class ModuleStoreTestCase(TestCase):
# Flush anything that is not a template
ModuleStoreTestCase.flush_mongo_except_templates()
- # Check that we have templates loaded; if not, load them
- ModuleStoreTestCase.load_templates_if_necessary()
-
# Call superclass implementation
super(ModuleStoreTestCase, self)._pre_setup()
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/factories.py b/common/lib/xmodule/xmodule/modulestore/tests/factories.py
index 457a88482a..9a0c87ff97 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/factories.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/factories.py
@@ -1,15 +1,13 @@
-from factory import Factory, lazy_attribute_sequence, lazy_attribute
-from uuid import uuid4
import datetime
+from factory import Factory, LazyAttributeSequence
+from uuid import uuid4
+from pytz import UTC
+
from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore
-from xmodule.modulestore.inheritance import own_metadata
-from xmodule.x_module import ModuleSystem
-from mitxmako.shortcuts import render_to_string
-from xblock.runtime import InvalidScopeError
-from pytz import UTC
-
+from xmodule.course_module import CourseDescriptor
+from xblock.core import Scope
class XModuleCourseFactory(Factory):
"""
@@ -21,9 +19,8 @@ class XModuleCourseFactory(Factory):
@classmethod
def _create(cls, target_class, **kwargs):
- template = Location('i4x', 'edx', 'templates', 'course', 'Empty')
org = kwargs.pop('org', None)
- number = kwargs.pop('number', None)
+ number = kwargs.pop('number', kwargs.pop('course', None))
display_name = kwargs.pop('display_name', None)
location = Location('i4x', org, number, 'course', Location.clean(display_name))
@@ -33,7 +30,7 @@ class XModuleCourseFactory(Factory):
store = modulestore()
# Write the data to the mongo datastore
- new_course = store.clone_item(template, location)
+ new_course = store.create_xmodule(location)
# This metadata code was copied from cms/djangoapps/contentstore/views.py
if display_name is not None:
@@ -56,13 +53,7 @@ class XModuleCourseFactory(Factory):
setattr(new_course, k, v)
# Update the data in the mongo datastore
- store.update_metadata(new_course.location, own_metadata(new_course))
- store.update_item(new_course.location, new_course._model_data._kvs._data)
-
- # update_item updates the the course as it exists in the modulestore, but doesn't
- # update the instance we are working with, so have to refetch the course after updating it.
- new_course = store.get_instance(new_course.id, new_course.location)
-
+ store.save_xmodule(new_course)
return new_course
@@ -73,7 +64,6 @@ class Course:
class CourseFactory(XModuleCourseFactory):
FACTORY_FOR = Course
- template = 'i4x://edx/templates/course/Empty'
org = 'MITx'
number = '999'
display_name = 'Robot Super Course'
@@ -86,18 +76,14 @@ class XModuleItemFactory(Factory):
ABSTRACT_FACTORY = True
- display_name = None
+ parent_location = 'i4x://MITx/999/course/Robot_Super_Course'
+ category = 'problem'
+ display_name = LazyAttributeSequence(lambda o, n: "{} {}".format(o.category, n))
- @lazy_attribute
- def category(attr):
- template = Location(attr.template)
- return template.category
-
- @lazy_attribute
- def location(attr):
- parent = Location(attr.parent_location)
- dest_name = attr.display_name.replace(" ", "_") if attr.display_name is not None else uuid4().hex
- return parent._replace(category=attr.category, name=dest_name)
+ @staticmethod
+ def location(parent, category, display_name):
+ dest_name = display_name.replace(" ", "_") if display_name is not None else uuid4().hex
+ return Location(parent).replace(category=category, name=dest_name)
@classmethod
def _create(cls, target_class, **kwargs):
@@ -107,8 +93,7 @@ class XModuleItemFactory(Factory):
*parent_location* (required): the location of the parent module
(e.g. the parent course or section)
- *template* (required): the template to create the item from
- (e.g. i4x://templates/section/Empty)
+ category: the category of the resulting item.
*data* (optional): the data for the item
(e.g. XML problem definition for a problem item)
@@ -121,41 +106,32 @@ class XModuleItemFactory(Factory):
"""
DETACHED_CATEGORIES = ['about', 'static_tab', 'course_info']
-
+ # catch any old style users before they get into trouble
+ assert not 'template' in kwargs
parent_location = Location(kwargs.get('parent_location'))
- template = Location(kwargs.get('template'))
data = kwargs.get('data')
+ category = kwargs.get('category')
display_name = kwargs.get('display_name')
metadata = kwargs.get('metadata', {})
+ location = kwargs.get('location', XModuleItemFactory.location(parent_location, category, display_name))
+ assert location != parent_location
store = modulestore('direct')
# This code was based off that in cms/djangoapps/contentstore/views.py
parent = store.get_item(parent_location)
- new_item = store.clone_item(template, kwargs.get('location'))
-
# replace the display name with an optional parameter passed in from the caller
if display_name is not None:
- new_item.display_name = display_name
+ metadata['display_name'] = display_name
+ # note that location comes from above lazy_attribute
+ store.create_and_save_xmodule(location, metadata=metadata, definition_data=data)
- # Add additional metadata or override current metadata
- item_metadata = own_metadata(new_item)
- item_metadata.update(metadata)
- store.update_metadata(new_item.location.url(), item_metadata)
+ if location.category not in DETACHED_CATEGORIES:
+ parent.children.append(location.url())
+ store.update_children(parent_location, parent.children)
- # replace the data with the optional *data* parameter
- if data is not None:
- store.update_item(new_item.location, data)
-
- if new_item.location.category not in DETACHED_CATEGORIES:
- store.update_children(parent_location, parent.children + [new_item.location.url()])
-
- # update_children updates the the item as it exists in the modulestore, but doesn't
- # update the instance we are working with, so have to refetch the item after updating it.
- new_item = store.get_item(new_item.location)
-
- return new_item
+ return store.get_item(location)
class Item:
@@ -164,40 +140,4 @@ class Item:
class ItemFactory(XModuleItemFactory):
FACTORY_FOR = Item
-
- parent_location = 'i4x://MITx/999/course/Robot_Super_Course'
- template = 'i4x://edx/templates/chapter/Empty'
-
- @lazy_attribute_sequence
- def display_name(attr, n):
- return "{} {}".format(attr.category.title(), n)
-
-
-def get_test_xmodule_for_descriptor(descriptor):
- """
- Attempts to create an xmodule which responds usually correctly from the descriptor. Not guaranteed.
-
- :param descriptor:
- """
- module_sys = ModuleSystem(
- ajax_url='',
- track_function=None,
- get_module=None,
- render_template=render_to_string,
- replace_urls=None,
- xblock_model_data=_test_xblock_model_data_accessor(descriptor)
- )
- return descriptor.xmodule(module_sys)
-
-
-def _test_xblock_model_data_accessor(descriptor):
- simple_map = {}
- for field in descriptor.fields:
- try:
- simple_map[field.name] = getattr(descriptor, field.name)
- except InvalidScopeError:
- simple_map[field.name] = field.default
- for field in descriptor.module_class.fields:
- if field.name not in simple_map:
- simple_map[field.name] = field.default
- return lambda o: simple_map
+ category = 'chapter'
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
index 44e69fb0ed..c149724cc7 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mongo.py
@@ -9,7 +9,6 @@ from xblock.runtime import KeyValueStore, InvalidScopeError
from xmodule.modulestore import Location
from xmodule.modulestore.mongo import MongoModuleStore, MongoKeyValueStore
from xmodule.modulestore.xml_importer import import_from_xml
-from xmodule.templates import update_templates
from .test_modulestore import check_path_to_location
from . import DATA_DIR
@@ -51,7 +50,6 @@ class TestMongoModuleStore(object):
# Explicitly list the courses to load (don't want the big one)
courses = ['toy', 'simple']
import_from_xml(store, DATA_DIR, courses)
- update_templates(store)
return store
@staticmethod
@@ -126,7 +124,7 @@ class TestMongoKeyValueStore(object):
self.location = Location('i4x://org/course/category/name@version')
self.children = ['i4x://org/course/child/a', 'i4x://org/course/child/b']
self.metadata = {'meta': 'meta_val'}
- self.kvs = MongoKeyValueStore(self.data, self.children, self.metadata, self.location)
+ self.kvs = MongoKeyValueStore(self.data, self.children, self.metadata, self.location, 'category')
def _check_read(self, key, expected_value):
assert_equals(expected_value, self.kvs.get(key))
diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py
index 26c8b9bfca..012740ff9a 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml.py
@@ -463,7 +463,10 @@ class XMLModuleStore(ModuleStoreBase):
# tabs are referenced in policy.json through a 'slug' which is just the filename without the .html suffix
slug = os.path.splitext(os.path.basename(filepath))[0]
loc = Location('i4x', course_descriptor.location.org, course_descriptor.location.course, category, slug)
- module = HtmlDescriptor(system, {'data': html, 'location': loc})
+ module = HtmlDescriptor(
+ system,
+ {'data': html, 'location': loc, 'category': category}
+ )
# VS[compat]:
# Hack because we need to pull in the 'display_name' for static tabs (because we need to edit them)
# from the course policy
diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py
index 1fe62035e6..60eb9dc749 100644
--- a/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py
+++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py
@@ -810,7 +810,6 @@ class CombinedOpenEndedV1Descriptor():
filename_extension = "xml"
has_score = True
- template_dir_name = "combinedopenended"
def __init__(self, system):
self.system = system
diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py
index 0f0851fbf7..8d8a85f788 100644
--- a/common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py
+++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py
@@ -730,7 +730,6 @@ class OpenEndedDescriptor():
filename_extension = "xml"
has_score = True
- template_dir_name = "openended"
def __init__(self, system):
self.system = system
diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py
index a5498289e2..1262e1f68f 100644
--- a/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py
+++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py
@@ -287,7 +287,6 @@ class SelfAssessmentDescriptor():
filename_extension = "xml"
has_score = True
- template_dir_name = "selfassessment"
def __init__(self, system):
self.system = system
diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py
index c88a2e1b38..03003ed1e5 100644
--- a/common/lib/xmodule/xmodule/peer_grading_module.py
+++ b/common/lib/xmodule/xmodule/peer_grading_module.py
@@ -613,7 +613,6 @@ class PeerGradingDescriptor(PeerGradingFields, RawDescriptor):
has_score = True
always_recalculate_grades = True
- template_dir_name = "peer_grading"
#Specify whether or not to pass in open ended interface
needs_open_ended_interface = True
diff --git a/common/lib/xmodule/xmodule/poll_module.py b/common/lib/xmodule/xmodule/poll_module.py
index ca12f239ab..8e7407752a 100644
--- a/common/lib/xmodule/xmodule/poll_module.py
+++ b/common/lib/xmodule/xmodule/poll_module.py
@@ -140,7 +140,6 @@ class PollDescriptor(PollFields, MakoModuleDescriptor, XmlDescriptor):
_child_tag_name = 'answer'
module_class = PollModule
- template_dir_name = 'poll'
@classmethod
def definition_from_xml(cls, xml_object, system):
diff --git a/common/lib/xmodule/xmodule/templates.py b/common/lib/xmodule/xmodule/templates.py
index 6479b3df24..8e350bb618 100644
--- a/common/lib/xmodule/xmodule/templates.py
+++ b/common/lib/xmodule/xmodule/templates.py
@@ -1,34 +1,18 @@
"""
-This module handles loading xmodule templates from disk into the modulestore.
-These templates are used by the CMS to provide baseline content that
-can be cloned when adding new modules to a course.
+This module handles loading xmodule templates
+These templates are used by the CMS to provide content that overrides xmodule defaults for
+samples.
-`Template`s are defined in x_module. They contain 3 attributes:
- metadata: A dictionary with the template metadata. This should contain
- any values for fields
- * with scope Scope.settings
- * that have values different than the field defaults
- * and that are to be editable in Studio
- data: A JSON value that defines the template content. This should be a dictionary
- containing values for fields
- * with scope Scope.content
- * that have values different than the field defaults
- * and that are to be editable in Studio
- or, if the module uses a single Scope.content String field named `data`, this
- should be a string containing the contents of that field
- children: A list of Location urls that define the template children
-
-Templates are defined on XModuleDescriptor types, in the template attribute.
+``Template``s are defined in x_module. They contain 2 attributes:
+ :metadata: A dictionary with the template metadata
+ :data: A JSON value that defines the template content
"""
-
+# should this move to cms since it's really only for module crud?
import logging
-from fs.memoryfs import MemoryFS
from collections import defaultdict
from .x_module import XModuleDescriptor
-from .mako_module import MakoDescriptorSystem
-from .modulestore import Location
log = logging.getLogger(__name__)
@@ -37,73 +21,9 @@ def all_templates():
"""
Returns all templates for enabled modules, grouped by descriptor type
"""
-
+ # TODO use memcache to memoize w/ expiration
templates = defaultdict(list)
for category, descriptor in XModuleDescriptor.load_classes():
templates[category] = descriptor.templates()
return templates
-
-
-class TemplateTestSystem(MakoDescriptorSystem):
- """
- This system exists to help verify that XModuleDescriptors can be instantiated
- from their defined templates before we load the templates into the modulestore.
- """
- def __init__(self):
- super(TemplateTestSystem, self).__init__(
- lambda *a, **k: None,
- MemoryFS(),
- lambda msg: None,
- render_template=lambda *a, **k: None,
- )
-
-
-def update_templates(modulestore):
- """
- Updates the set of templates in the modulestore with all templates currently
- available from the installed plugins
- """
-
- # cdodge: build up a list of all existing templates. This will be used to determine which
- # templates have been removed from disk - and thus we need to remove from the DB
- templates_to_delete = modulestore.get_items(['i4x', 'edx', 'templates', None, None, None])
-
- for category, templates in all_templates().items():
- for template in templates:
- if 'display_name' not in template.metadata:
- log.warning('No display_name specified in template {0}, skipping'.format(template))
- continue
-
- template_location = Location('i4x', 'edx', 'templates', category, Location.clean_for_url_name(template.metadata['display_name']))
-
- try:
- json_data = {
- 'definition': {
- 'data': template.data,
- 'children': template.children
- },
- 'metadata': template.metadata
- }
- json_data['location'] = template_location.dict()
-
- XModuleDescriptor.load_from_json(json_data, TemplateTestSystem())
- except:
- log.warning('Unable to instantiate {cat} from template {template}, skipping'.format(
- cat=category,
- template=template
- ), 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)
-
- # remove template from list of templates to delete
- templates_to_delete = [t for t in templates_to_delete if t.location != template_location]
-
- # now remove all templates which appear to have removed from disk
- if len(templates_to_delete) > 0:
- logging.debug('deleting dangling templates = {0}'.format(templates_to_delete))
- for template in templates_to_delete:
- modulestore.delete_item(template.location)
diff --git a/common/lib/xmodule/xmodule/templates/about/empty.yaml b/common/lib/xmodule/xmodule/templates/about/empty.yaml
deleted file mode 100644
index 0967ef424b..0000000000
--- a/common/lib/xmodule/xmodule/templates/about/empty.yaml
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/common/lib/xmodule/xmodule/templates/annotatable/default.yaml b/common/lib/xmodule/xmodule/templates/annotatable/default.yaml
deleted file mode 100644
index 0967ef424b..0000000000
--- a/common/lib/xmodule/xmodule/templates/annotatable/default.yaml
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml b/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml
deleted file mode 100644
index 0967ef424b..0000000000
--- a/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/common/lib/xmodule/xmodule/templates/course/empty.yaml b/common/lib/xmodule/xmodule/templates/course/empty.yaml
deleted file mode 100644
index 0967ef424b..0000000000
--- a/common/lib/xmodule/xmodule/templates/course/empty.yaml
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/common/lib/xmodule/xmodule/templates/courseinfo/empty.yaml b/common/lib/xmodule/xmodule/templates/courseinfo/empty.yaml
deleted file mode 100644
index 0967ef424b..0000000000
--- a/common/lib/xmodule/xmodule/templates/courseinfo/empty.yaml
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/common/lib/xmodule/xmodule/templates/default/empty.yaml b/common/lib/xmodule/xmodule/templates/default/empty.yaml
deleted file mode 100644
index 0967ef424b..0000000000
--- a/common/lib/xmodule/xmodule/templates/default/empty.yaml
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/common/lib/xmodule/xmodule/templates/discussion/default.yaml b/common/lib/xmodule/xmodule/templates/discussion/default.yaml
deleted file mode 100644
index 0967ef424b..0000000000
--- a/common/lib/xmodule/xmodule/templates/discussion/default.yaml
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/common/lib/xmodule/xmodule/templates/html/announcement.yaml b/common/lib/xmodule/xmodule/templates/html/announcement.yaml
index 30a8ccb41e..c0ecc61524 100644
--- a/common/lib/xmodule/xmodule/templates/html/announcement.yaml
+++ b/common/lib/xmodule/xmodule/templates/html/announcement.yaml
@@ -21,4 +21,3 @@ data: |
-children: []
diff --git a/common/lib/xmodule/xmodule/templates/html/empty.yaml b/common/lib/xmodule/xmodule/templates/html/empty.yaml
deleted file mode 100644
index 0967ef424b..0000000000
--- a/common/lib/xmodule/xmodule/templates/html/empty.yaml
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/common/lib/xmodule/xmodule/templates/html/everything.yaml b/common/lib/xmodule/xmodule/templates/html/everything.yaml
deleted file mode 100644
index 348ce64fa1..0000000000
--- a/common/lib/xmodule/xmodule/templates/html/everything.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
----
-metadata:
- display_name: Announcement
-
-data: |
- Heading of document
- First subheading
- This is a paragraph. It will take care of line breaks for you.
HTML only parses the location
-
- of tags for inserting line breaks into your doc, not
- line
- breaks
- you
- add
- yourself.
-
- Links
- You can refer to other parts of the internet with a link, to other parts of your course by prepending your link with /course/
- Now a list:
-
- - An item
- - Another item
- - And yet another
-
- This list has an ordering
-
- - An item
- - Another item
- - Yet another item
-
- Note, we have a lot of standard edX styles, so please try to avoid any custom styling, and make sure that you make a note of any custom styling that you do yourself so that we can incorporate it into
- tools that other people can use.
-children: []
diff --git a/common/lib/xmodule/xmodule/templates/html/latex_html.yaml b/common/lib/xmodule/xmodule/templates/html/latex_html.yaml
index ba5c4b5c06..2db7e98c65 100644
--- a/common/lib/xmodule/xmodule/templates/html/latex_html.yaml
+++ b/common/lib/xmodule/xmodule/templates/html/latex_html.yaml
@@ -19,4 +19,3 @@ data: |
It is very convenient to write complex equations in LaTeX.