diff --git a/cms/__init__.py b/cms/__init__.py index e8dccbbf60..8b13789179 100644 --- a/cms/__init__.py +++ b/cms/__init__.py @@ -1,3 +1 @@ -from xmodule.templates import update_templates -update_templates() diff --git a/cms/djangoapps/contentstore/__init__.py b/cms/djangoapps/contentstore/__init__.py index e69de29bb2..e8dccbbf60 100644 --- a/cms/djangoapps/contentstore/__init__.py +++ b/cms/djangoapps/contentstore/__init__.py @@ -0,0 +1,3 @@ +from xmodule.templates import update_templates + +update_templates() diff --git a/cms/envs/dev.py b/cms/envs/dev.py index 19b4dec8b2..fc2a5a5684 100644 --- a/cms/envs/dev.py +++ b/cms/envs/dev.py @@ -14,7 +14,6 @@ LOGGING = get_logger_config(ENV_ROOT / "log", tracking_filename="tracking.log", debug=True) - MODULESTORE = { 'default': { 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore', diff --git a/common/lib/xmodule/xmodule/abtest_module.py b/common/lib/xmodule/xmodule/abtest_module.py index 8fd4810946..505295a637 100644 --- a/common/lib/xmodule/xmodule/abtest_module.py +++ b/common/lib/xmodule/xmodule/abtest_module.py @@ -62,6 +62,8 @@ class ABTestModule(XModule): class ABTestDescriptor(RawDescriptor, XmlDescriptor): module_class = ABTestModule +# template_dir_name = "abtest" + def __init__(self, system, definition=None, **kwargs): """ definition is a dictionary with the following layout: diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py index ffd4d3c583..798febfc1d 100644 --- a/common/lib/xmodule/xmodule/html_module.py +++ b/common/lib/xmodule/xmodule/html_module.py @@ -34,10 +34,6 @@ class HtmlDescriptor(XmlDescriptor, EditingDescriptor): module_class = HtmlModule filename_extension = "xml" - templates = [ - Template('Empty', '', []) - ] - # VS[compat] TODO (cpennington): Delete this method once all fall 2012 course # are being edited in the cms @classmethod diff --git a/common/lib/xmodule/xmodule/templates.py b/common/lib/xmodule/xmodule/templates.py index c193d0efac..9eebc01182 100644 --- a/common/lib/xmodule/xmodule/templates.py +++ b/common/lib/xmodule/xmodule/templates.py @@ -1,8 +1,14 @@ +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 from .modulestore.django import modulestore +log = logging.getLogger(__name__) + def all_templates(): """ @@ -11,11 +17,21 @@ def all_templates(): templates = defaultdict(list) for category, descriptor in XModuleDescriptor.load_classes(): - templates[category] = descriptor.templates + templates[category] = descriptor.templates() return templates +class TemplateTestSystem(MakoDescriptorSystem): + def __init__(self): + super(TemplateTestSystem, self).__init__( + lambda *a, **k: None, + MemoryFS(), + lambda msg: None, + render_template=lambda *a, **k: None, + ) + + def update_templates(): """ Updates the set of templates in the modulestore with all templates currently @@ -24,7 +40,23 @@ def update_templates(): for category, templates in all_templates().items(): for template in templates: - template_location = Location('i4x', 'edx', 'templates', category, Location.clean_for_url_name(template.name)) + 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 = template._asdict() + 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, {'display_name': template.name}) + modulestore().update_metadata(template_location, template.metadata) diff --git a/common/lib/xmodule/xmodule/templates/default/empty.json b/common/lib/xmodule/xmodule/templates/default/empty.json new file mode 100644 index 0000000000..be5d368dbc --- /dev/null +++ b/common/lib/xmodule/xmodule/templates/default/empty.json @@ -0,0 +1,5 @@ +{ + "metadata": { "display_name": "Empty" }, + "data": "", + "children": [] +} diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 6b33211530..d2ecbe49b9 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -1,6 +1,8 @@ import logging import pkg_resources import sys +import json +import os from fs.errors import ResourceNotFoundError from functools import partial @@ -8,6 +10,7 @@ from lxml import etree from lxml.etree import XMLSyntaxError from pprint import pprint from collections import namedtuple +from pkg_resources import resource_listdir, resource_string, resource_isdir from xmodule.errortracker import exc_info_to_str from xmodule.modulestore import Location @@ -326,10 +329,41 @@ def policy_key(location): return '{cat}/{name}'.format(cat=location.category, name=location.name) -Template = namedtuple("Template", "name data children") +Template = namedtuple("Template", "metadata data children") -class XModuleDescriptor(Plugin, HTMLSnippet): + + +class ResourceTemplates(object): + @classmethod + def templates(cls): + """ + Returns a list of Template objects that describe possible templates that can be used + to create a module of this type. + If no templates are provided, there will be no way to create a module of + this type + + Expects a class attribute template_dir_name that defines the directory + inside the 'templates' resource directory to pull templates from + """ + templates = [] + dirname = os.path.join('templates', cls.template_dir_name) + if not resource_isdir(__name__, dirname): + log.warning("No resource directory {dir} found when loading {cls_name} templates".format( + dir=dirname, + cls_name=cls.__name__, + )) + return [] + + for template_file in resource_listdir(__name__, dirname): + template_content = resource_string(__name__, os.path.join(dirname, template_file)) + template = json.loads(template_content) + templates.append(Template(**template)) + + return templates + + +class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates): """ An XModuleDescriptor is a specification for an element of a course. This could be a problem, an organizational element (a group of content), or a @@ -369,10 +403,8 @@ class XModuleDescriptor(Plugin, HTMLSnippet): equality_attributes = ('definition', 'metadata', 'location', 'shared_state_key', '_inherited_metadata') - # A list of Template objects that describe possible templates that can be used - # to create a module of this type. - # If no templates are provided, there will be no way to create a module of this type - templates = [] + # Name of resource directory to load templates from + template_dir_name = "default" # ============================= STRUCTURAL MANIPULATION =================== def __init__(self,