Commit 417fe21d by Calen Pennington

Enable pure XBlocks, but behind a feature flag

[LMS-226]
[LMS-2013]
parent a6a00431
...@@ -5,6 +5,13 @@ These are notable changes in edx-platform. This is a rolling list of changes, ...@@ -5,6 +5,13 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected. the top. Include a label indicating the component affected.
Common: Add feature flags to allow developer use of pure XBlocks
- ALLOW_ALL_ADVANCED_COMPONENTS disables the hard-coded list of advanced
components in Studio, and allows any xblock to be added as an
advanced component in Studio settings
- XBLOCK_SELECT_FUNCTION allows the insertion of a custom function
to limit loading of XBlocks with (including allowing pure xblocks)
Studio: Add sorting by column to the Files & Uploads page. Studio: Add sorting by column to the Files & Uploads page.
See mongo_indexes.md for new indices that should be added. See mongo_indexes.md for new indices that should be added.
......
...@@ -9,7 +9,8 @@ from xmodule.modulestore.locator import CourseLocator, BlockUsageLocator, LocalI ...@@ -9,7 +9,8 @@ from xmodule.modulestore.locator import CourseLocator, BlockUsageLocator, LocalI
from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.html_module import HtmlDescriptor from xmodule.html_module import HtmlDescriptor
from xmodule.modulestore import inheritance from xmodule.modulestore import inheritance
from xmodule.x_module import XModuleDescriptor from xmodule.x_module import prefer_xmodules
from xblock.core import XBlock
class TemplateTests(unittest.TestCase): class TemplateTests(unittest.TestCase):
...@@ -248,9 +249,10 @@ class TemplateTests(unittest.TestCase): ...@@ -248,9 +249,10 @@ class TemplateTests(unittest.TestCase):
- 'definition': - 'definition':
- '_id' (optional): the usage_id of this. Will generate one if not given one. - '_id' (optional): the usage_id of this. Will generate one if not given one.
""" """
class_ = XModuleDescriptor.load_class( class_ = XBlock.load_class(
json_data.get('category', json_data.get('location', {}).get('category')), json_data.get('category', json_data.get('location', {}).get('category')),
default_class default_class,
select=prefer_xmodules
) )
usage_id = json_data.get('_id', None) usage_id = json_data.get('_id', None)
if not '_inherited_settings' in json_data and parent_xblock is not None: if not '_inherited_settings' in json_data and parent_xblock is not None:
......
...@@ -14,13 +14,14 @@ from xmodule.modulestore.django import modulestore ...@@ -14,13 +14,14 @@ from xmodule.modulestore.django import modulestore
from xmodule.util.date_utils import get_default_time_display from xmodule.util.date_utils import get_default_time_display
from xmodule.modulestore.django import loc_mapper from xmodule.modulestore.django import loc_mapper
from xmodule.modulestore.locator import BlockUsageLocator from xmodule.modulestore.locator import BlockUsageLocator
from xmodule.x_module import XModuleDescriptor
from xblock.core import XBlock
from xblock.django.request import webob_to_django_response, django_to_webob_request from xblock.django.request import webob_to_django_response, django_to_webob_request
from xblock.exceptions import NoSuchHandlerError from xblock.exceptions import NoSuchHandlerError
from xblock.fields import Scope from xblock.fields import Scope
from xblock.plugin import PluginMissingError from xblock.plugin import PluginMissingError
from xblock.runtime import Mixologist from xblock.runtime import Mixologist
from xmodule.x_module import prefer_xmodules
from lms.lib.xblock.runtime import unquote_slashes from lms.lib.xblock.runtime import unquote_slashes
...@@ -44,12 +45,18 @@ COMPONENT_TYPES = ['discussion', 'html', 'problem', 'video'] ...@@ -44,12 +45,18 @@ COMPONENT_TYPES = ['discussion', 'html', 'problem', 'video']
OPEN_ENDED_COMPONENT_TYPES = ["combinedopenended", "peergrading"] OPEN_ENDED_COMPONENT_TYPES = ["combinedopenended", "peergrading"]
NOTE_COMPONENT_TYPES = ['notes'] NOTE_COMPONENT_TYPES = ['notes']
ADVANCED_COMPONENT_TYPES = [
'annotatable', if settings.FEATURES.get('ALLOW_ALL_ADVANCED_COMPONENTS'):
'word_cloud', ADVANCED_COMPONENT_TYPES = sorted(set(name for name, class_ in XBlock.load_classes()) - set(COMPONENT_TYPES))
'graphical_slider_tool', else:
'lti',
] + OPEN_ENDED_COMPONENT_TYPES + NOTE_COMPONENT_TYPES ADVANCED_COMPONENT_TYPES = [
'annotatable',
'word_cloud',
'graphical_slider_tool',
'lti',
] + OPEN_ENDED_COMPONENT_TYPES + NOTE_COMPONENT_TYPES
ADVANCED_COMPONENT_CATEGORY = 'advanced' ADVANCED_COMPONENT_CATEGORY = 'advanced'
ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules' ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules'
...@@ -138,7 +145,7 @@ def _load_mixed_class(category): ...@@ -138,7 +145,7 @@ def _load_mixed_class(category):
""" """
Load an XBlock by category name, and apply all defined mixins Load an XBlock by category name, and apply all defined mixins
""" """
component_class = XModuleDescriptor.load_class(category) component_class = XBlock.load_class(category, select=prefer_xmodules)
mixologist = Mixologist(settings.XBLOCK_MIXINS) mixologist = Mixologist(settings.XBLOCK_MIXINS)
return mixologist.mix(component_class) return mixologist.mix(component_class)
......
...@@ -9,10 +9,17 @@ from xmodule_modifiers import wrap_xblock ...@@ -9,10 +9,17 @@ from xmodule_modifiers import wrap_xblock
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.http import HttpResponseBadRequest
from django.views.decorators.http import require_http_methods
from xblock.fields import Scope
from xblock.core import XBlock
from xmodule.modulestore.django import modulestore, loc_mapper from xmodule.modulestore.django import modulestore, loc_mapper
from xmodule.modulestore.inheritance import own_metadata
from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError
from xmodule.modulestore.inheritance import own_metadata
from xmodule.modulestore.locator import BlockUsageLocator
from xmodule.x_module import prefer_xmodules
from util.json_request import expect_json, JsonResponse from util.json_request import expect_json, JsonResponse
from util.string_utils import str_to_bool from util.string_utils import str_to_bool
...@@ -23,12 +30,6 @@ from ..utils import get_modulestore ...@@ -23,12 +30,6 @@ from ..utils import get_modulestore
from .access import has_access from .access import has_access
from .helpers import _xmodule_recurse from .helpers import _xmodule_recurse
from xmodule.x_module import XModuleDescriptor
from django.views.decorators.http import require_http_methods
from xmodule.modulestore.locator import BlockUsageLocator
from student.models import CourseEnrollment
from django.http import HttpResponseBadRequest
from xblock.fields import Scope
from preview import handler_prefix, get_preview_html from preview import handler_prefix, get_preview_html
from edxmako.shortcuts import render_to_response, render_to_string from edxmako.shortcuts import render_to_response, render_to_string
from models.settings.course_grading import CourseGradingModel from models.settings.course_grading import CourseGradingModel
...@@ -260,7 +261,7 @@ def _create_item(request): ...@@ -260,7 +261,7 @@ def _create_item(request):
data = None data = None
template_id = request.json.get('boilerplate') template_id = request.json.get('boilerplate')
if template_id is not None: if template_id is not None:
clz = XModuleDescriptor.load_class(category) clz = XBlock.load_class(category, select=prefer_xmodules)
if clz is not None: if clz is not None:
template = clz.get_template(template_id) template = clz.get_template(template_id)
if template is not None: if template is not None:
......
...@@ -31,7 +31,7 @@ from path import path ...@@ -31,7 +31,7 @@ from path import path
from lms.lib.xblock.mixin import LmsBlockMixin from lms.lib.xblock.mixin import LmsBlockMixin
from cms.lib.xblock.mixin import CmsBlockMixin from cms.lib.xblock.mixin import CmsBlockMixin
from xmodule.modulestore.inheritance import InheritanceMixin from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.x_module import XModuleMixin from xmodule.x_module import XModuleMixin, only_xmodules
from dealer.git import git from dealer.git import git
############################ FEATURE CONFIGURATION ############################# ############################ FEATURE CONFIGURATION #############################
...@@ -62,6 +62,10 @@ FEATURES = { ...@@ -62,6 +62,10 @@ FEATURES = {
# If set to True, new Studio users won't be able to author courses unless # If set to True, new Studio users won't be able to author courses unless
# edX has explicitly added them to the course creator group. # edX has explicitly added them to the course creator group.
'ENABLE_CREATOR_GROUP': False, 'ENABLE_CREATOR_GROUP': False,
# If set to True, Studio won't restrict the set of advanced components
# to just those pre-approved by edX
'ALLOW_ALL_ADVANCED_COMPONENTS': False,
} }
ENABLE_JASMINE = False ENABLE_JASMINE = False
...@@ -178,6 +182,15 @@ MIDDLEWARE_CLASSES = ( ...@@ -178,6 +182,15 @@ MIDDLEWARE_CLASSES = (
# once the responsibility of XBlock creation is moved out of modulestore - cpennington # once the responsibility of XBlock creation is moved out of modulestore - cpennington
XBLOCK_MIXINS = (LmsBlockMixin, CmsBlockMixin, InheritanceMixin, XModuleMixin) XBLOCK_MIXINS = (LmsBlockMixin, CmsBlockMixin, InheritanceMixin, XModuleMixin)
# Only allow XModules in Studio
XBLOCK_SELECT_FUNCTION = only_xmodules
# Use the following lines to allow any xblock in Studio,
# either by uncommenting them here, or adding them to your private.py
# You should also enable the ALLOW_ALL_ADVANCED_COMPONENTS feature flag, so that
# xblocks can be added via advanced settings
# from xmodule.x_module import prefer_xmodules
# XBLOCK_SELECT_FUNCTION = prefer_xmodules
############################ SIGNAL HANDLERS ################################ ############################ SIGNAL HANDLERS ################################
# This is imported to register the exception signal handling that logs exceptions # This is imported to register the exception signal handling that logs exceptions
......
...@@ -430,7 +430,7 @@ class ModuleStoreReadBase(ModuleStoreRead): ...@@ -430,7 +430,7 @@ class ModuleStoreReadBase(ModuleStoreRead):
self, self,
doc_store_config=None, # ignore if passed up doc_store_config=None, # ignore if passed up
metadata_inheritance_cache_subsystem=None, request_cache=None, metadata_inheritance_cache_subsystem=None, request_cache=None,
modulestore_update_signal=None, xblock_mixins=(), modulestore_update_signal=None, xblock_mixins=(), xblock_select=None,
# temporary parms to enable backward compatibility. remove once all envs migrated # temporary parms to enable backward compatibility. remove once all envs migrated
db=None, collection=None, host=None, port=None, tz_aware=True, user=None, password=None db=None, collection=None, host=None, port=None, tz_aware=True, user=None, password=None
): ):
...@@ -442,6 +442,7 @@ class ModuleStoreReadBase(ModuleStoreRead): ...@@ -442,6 +442,7 @@ class ModuleStoreReadBase(ModuleStoreRead):
self.modulestore_update_signal = modulestore_update_signal self.modulestore_update_signal = modulestore_update_signal
self.request_cache = request_cache self.request_cache = request_cache
self.xblock_mixins = xblock_mixins self.xblock_mixins = xblock_mixins
self.xblock_select = xblock_select
def _get_errorlog(self, location): def _get_errorlog(self, location):
""" """
......
...@@ -66,6 +66,7 @@ def create_modulestore_instance(engine, doc_store_config, options): ...@@ -66,6 +66,7 @@ def create_modulestore_instance(engine, doc_store_config, options):
request_cache=request_cache, request_cache=request_cache,
modulestore_update_signal=Signal(providing_args=['modulestore', 'course_id', 'location']), modulestore_update_signal=Signal(providing_args=['modulestore', 'course_id', 'location']),
xblock_mixins=getattr(settings, 'XBLOCK_MIXINS', ()), xblock_mixins=getattr(settings, 'XBLOCK_MIXINS', ()),
xblock_select=getattr(settings, 'XBLOCK_SELECT_FUNCTION', None),
doc_store_config=doc_store_config, doc_store_config=doc_store_config,
**_options **_options
) )
...@@ -83,7 +84,7 @@ def get_default_store_name_for_current_request(): ...@@ -83,7 +84,7 @@ def get_default_store_name_for_current_request():
# get mapping information which is defined in configurations # get mapping information which is defined in configurations
mappings = getattr(settings, 'HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS', None) mappings = getattr(settings, 'HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS', None)
# compare hostname against the regex expressions set of mappings # compare hostname against the regex expressions set of mappings
# which will tell us which store name to use # which will tell us which store name to use
if hostname and mappings: if hostname and mappings:
......
...@@ -25,7 +25,6 @@ from path import path ...@@ -25,7 +25,6 @@ from path import path
from importlib import import_module from importlib import import_module
from xmodule.errortracker import null_error_tracker, exc_info_to_str from xmodule.errortracker import null_error_tracker, exc_info_to_str
from xmodule.mako_module import MakoDescriptorSystem from xmodule.mako_module import MakoDescriptorSystem
from xmodule.x_module import XModuleDescriptor
from xmodule.error_module import ErrorDescriptor from xmodule.error_module import ErrorDescriptor
from xblock.runtime import DbModel from xblock.runtime import DbModel
from xblock.exceptions import InvalidScopeError from xblock.exceptions import InvalidScopeError
...@@ -173,10 +172,8 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -173,10 +172,8 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
# load the module and apply the inherited metadata # load the module and apply the inherited metadata
try: try:
category = json_data['location']['category'] category = json_data['location']['category']
class_ = XModuleDescriptor.load_class( class_ = self.load_block_type(category)
category,
self.default_class
)
definition = json_data.get('definition', {}) definition = json_data.get('definition', {})
metadata = json_data.get('metadata', {}) metadata = json_data.get('metadata', {})
for old_name, new_name in getattr(class_, 'metadata_translations', {}).items(): for old_name, new_name in getattr(class_, 'metadata_translations', {}).items():
...@@ -506,6 +503,7 @@ class MongoModuleStore(ModuleStoreWriteBase): ...@@ -506,6 +503,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
render_template=self.render_template, render_template=self.render_template,
cached_metadata=cached_metadata, cached_metadata=cached_metadata,
mixins=self.xblock_mixins, mixins=self.xblock_mixins,
select=self.xblock_select,
) )
return system.load_item(item['location']) return system.load_item(item['location'])
...@@ -627,8 +625,9 @@ class MongoModuleStore(ModuleStoreWriteBase): ...@@ -627,8 +625,9 @@ class MongoModuleStore(ModuleStoreWriteBase):
render_template=self.render_template, render_template=self.render_template,
cached_metadata={}, cached_metadata={},
mixins=self.xblock_mixins, mixins=self.xblock_mixins,
select=self.xblock_select,
) )
xblock_class = XModuleDescriptor.load_class(location.category, self.default_class) xblock_class = system.load_block_type(location.category)
if definition_data is None: if definition_data is None:
if hasattr(xblock_class, 'data') and xblock_class.data.default is not None: if hasattr(xblock_class, 'data') and xblock_class.data.default is not None:
definition_data = xblock_class.data.default definition_data = xblock_class.data.default
......
import sys import sys
import logging import logging
from xmodule.mako_module import MakoDescriptorSystem from xmodule.mako_module import MakoDescriptorSystem
from xmodule.x_module import XModuleDescriptor
from xmodule.modulestore.locator import BlockUsageLocator, LocalId from xmodule.modulestore.locator import BlockUsageLocator, LocalId
from xmodule.error_module import ErrorDescriptor from xmodule.error_module import ErrorDescriptor
from xmodule.errortracker import exc_info_to_str from xmodule.errortracker import exc_info_to_str
...@@ -62,10 +61,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -62,10 +61,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
if json_data is None: if json_data is None:
raise ItemNotFoundError(block_id) raise ItemNotFoundError(block_id)
class_ = XModuleDescriptor.load_class( class_ = self.load_block_type(json_data.get('category'))
json_data.get('category'),
self.default_class
)
return self.xblock_from_json(class_, block_id, json_data, course_entry_override) return self.xblock_from_json(class_, block_id, json_data, course_entry_override)
# xblock's runtime does not always pass enough contextual information to figure out # xblock's runtime does not always pass enough contextual information to figure out
......
...@@ -42,7 +42,7 @@ Representation: ...@@ -42,7 +42,7 @@ Representation:
*** 'edited_by': user_id whose edit caused this version of the definition, *** 'edited_by': user_id whose edit caused this version of the definition,
*** 'edited_on': datetime of the change causing this version *** 'edited_on': datetime of the change causing this version
*** 'previous_version': the definition_id of the previous version of this definition *** 'previous_version': the definition_id of the previous version of this definition
*** 'original_version': definition_id of the root of the previous version relation on this *** 'original_version': definition_id of the root of the previous version relation on this
definition. Acts as a pseudo-object identifier. definition. Acts as a pseudo-object identifier.
""" """
import threading import threading
...@@ -56,7 +56,7 @@ import copy ...@@ -56,7 +56,7 @@ import copy
from pytz import UTC from pytz import UTC
from xmodule.errortracker import null_error_tracker from xmodule.errortracker import null_error_tracker
from xmodule.x_module import XModuleDescriptor from xmodule.x_module import XModuleDescriptor, prefer_xmodules
from xmodule.modulestore.locator import BlockUsageLocator, DefinitionLocator, CourseLocator, VersionTree, LocalId from xmodule.modulestore.locator import BlockUsageLocator, DefinitionLocator, CourseLocator, VersionTree, LocalId
from xmodule.modulestore.exceptions import InsufficientSpecificationError, VersionConflictError, DuplicateItemError from xmodule.modulestore.exceptions import InsufficientSpecificationError, VersionConflictError, DuplicateItemError
from xmodule.modulestore import inheritance, ModuleStoreWriteBase, Location, SPLIT_MONGO_MODULESTORE_TYPE from xmodule.modulestore import inheritance, ModuleStoreWriteBase, Location, SPLIT_MONGO_MODULESTORE_TYPE
...@@ -68,6 +68,7 @@ from xblock.fields import Scope ...@@ -68,6 +68,7 @@ from xblock.fields import Scope
from xblock.runtime import Mixologist from xblock.runtime import Mixologist
from bson.objectid import ObjectId from bson.objectid import ObjectId
from xmodule.modulestore.split_mongo.mongo_connection import MongoConnection from xmodule.modulestore.split_mongo.mongo_connection import MongoConnection
from xblock.core import XBlock
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
#============================================================================== #==============================================================================
...@@ -184,7 +185,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -184,7 +185,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
error_tracker=self.error_tracker, error_tracker=self.error_tracker,
render_template=self.render_template, render_template=self.render_template,
resources_fs=None, resources_fs=None,
mixins=self.xblock_mixins mixins=self.xblock_mixins,
select=self.xblock_select,
) )
self._add_cache(course_entry['structure']['_id'], system) self._add_cache(course_entry['structure']['_id'], system)
self.cache_items(system, block_ids, depth, lazy) self.cache_items(system, block_ids, depth, lazy)
...@@ -1471,7 +1473,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1471,7 +1473,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
""" """
if fields is None: if fields is None:
return {} return {}
cls = self.mixologist.mix(XModuleDescriptor.load_class(category)) cls = self.mixologist.mix(XBlock.load_class(category, select=prefer_xmodules))
result = collections.defaultdict(dict) result = collections.defaultdict(dict)
for field_name, value in fields.iteritems(): for field_name, value in fields.iteritems():
field = getattr(cls, field_name) field = getattr(cls, field_name)
...@@ -1581,7 +1583,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1581,7 +1583,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
destination_block['edit_info']['edited_by'] = user_id destination_block['edit_info']['edited_by'] = user_id
else: else:
destination_block = self._new_block( destination_block = self._new_block(
user_id, new_block['category'], user_id, new_block['category'],
self._filter_blacklist(copy.copy(new_block['fields']), blacklist), self._filter_blacklist(copy.copy(new_block['fields']), blacklist),
new_block['definition'], new_block['definition'],
new_block['edit_info']['update_version'] new_block['edit_info']['update_version']
......
...@@ -6,7 +6,8 @@ from uuid import uuid4 ...@@ -6,7 +6,8 @@ from uuid import uuid4
from pytz import UTC from pytz import UTC
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.x_module import XModuleDescriptor from xmodule.x_module import prefer_xmodules
from xblock.core import XBlock
class Dummy(object): class Dummy(object):
...@@ -144,7 +145,7 @@ class ItemFactory(XModuleFactory): ...@@ -144,7 +145,7 @@ class ItemFactory(XModuleFactory):
if 'boilerplate' in kwargs: if 'boilerplate' in kwargs:
template_id = kwargs.pop('boilerplate') template_id = kwargs.pop('boilerplate')
clz = XModuleDescriptor.load_class(category) clz = XBlock.load_class(category, select=prefer_xmodules)
template = clz.get_template(template_id) template = clz.get_template(template_id)
assert template is not None assert template is not None
metadata.update(template.get('metadata', {})) metadata.update(template.get('metadata', {}))
......
...@@ -17,7 +17,7 @@ from xmodule.error_module import ErrorDescriptor ...@@ -17,7 +17,7 @@ from xmodule.error_module import ErrorDescriptor
from xmodule.errortracker import make_error_tracker, exc_info_to_str from xmodule.errortracker import make_error_tracker, exc_info_to_str
from xmodule.course_module import CourseDescriptor from xmodule.course_module import CourseDescriptor
from xmodule.mako_module import MakoDescriptorSystem from xmodule.mako_module import MakoDescriptorSystem
from xmodule.x_module import XMLParsingSystem, XModuleDescriptor from xmodule.x_module import XMLParsingSystem, prefer_xmodules
from xmodule.html_module import HtmlDescriptor from xmodule.html_module import HtmlDescriptor
from xblock.core import XBlock from xblock.core import XBlock
...@@ -238,7 +238,7 @@ def create_block_from_xml(xml_data, system, org=None, course=None, default_class ...@@ -238,7 +238,7 @@ def create_block_from_xml(xml_data, system, org=None, course=None, default_class
""" """
node = etree.fromstring(xml_data) node = etree.fromstring(xml_data)
raw_class = XModuleDescriptor.load_class(node.tag, default_class) raw_class = XBlock.load_class(node.tag, default_class, select=prefer_xmodules)
xblock_class = system.mixologist.mix(raw_class) xblock_class = system.mixologist.mix(raw_class)
# leave next line commented out - useful for low-level debugging # leave next line commented out - useful for low-level debugging
...@@ -460,6 +460,7 @@ class XMLModuleStore(ModuleStoreReadBase): ...@@ -460,6 +460,7 @@ class XMLModuleStore(ModuleStoreReadBase):
load_error_modules=self.load_error_modules, load_error_modules=self.load_error_modules,
policy=policy, policy=policy,
mixins=self.xblock_mixins, mixins=self.xblock_mixins,
select=self.xblock_select,
) )
course_descriptor = system.process_xml(etree.tostring(course_data, encoding='unicode')) course_descriptor = system.process_xml(etree.tostring(course_data, encoding='unicode'))
......
...@@ -132,6 +132,7 @@ def import_from_xml( ...@@ -132,6 +132,7 @@ def import_from_xml(
course_dirs=course_dirs, course_dirs=course_dirs,
load_error_modules=load_error_modules, load_error_modules=load_error_modules,
xblock_mixins=store.xblock_mixins, xblock_mixins=store.xblock_mixins,
xblock_select=store.xblock_select,
) )
# NOTE: the XmlModuleStore does not implement get_items() # NOTE: the XmlModuleStore does not implement get_items()
......
...@@ -12,7 +12,7 @@ samples. ...@@ -12,7 +12,7 @@ samples.
import logging import logging
from collections import defaultdict from collections import defaultdict
from .x_module import XModuleDescriptor from xblock.core import XBlock
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -23,7 +23,9 @@ def all_templates(): ...@@ -23,7 +23,9 @@ def all_templates():
""" """
# TODO use memcache to memoize w/ expiration # TODO use memcache to memoize w/ expiration
templates = defaultdict(list) templates = defaultdict(list)
for category, descriptor in XModuleDescriptor.load_classes(): for category, descriptor in XBlock.load_classes():
if not hasattr(descriptor, 'templates'):
continue
templates[category] = descriptor.templates() templates[category] = descriptor.templates()
return templates return templates
...@@ -13,7 +13,7 @@ from xmodule.xml_module import is_pointer_tag ...@@ -13,7 +13,7 @@ from xmodule.xml_module import is_pointer_tag
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.modulestore.xml import ImportSystem, XMLModuleStore from xmodule.modulestore.xml import ImportSystem, XMLModuleStore
from xmodule.modulestore.inheritance import compute_inherited_metadata from xmodule.modulestore.inheritance import compute_inherited_metadata
from xmodule.x_module import XModuleMixin from xmodule.x_module import XModuleMixin, only_xmodules
from xmodule.fields import Date from xmodule.fields import Date
from xmodule.tests import DATA_DIR from xmodule.tests import DATA_DIR
from xmodule.modulestore.inheritance import InheritanceMixin from xmodule.modulestore.inheritance import InheritanceMixin
...@@ -61,7 +61,12 @@ class BaseCourseTestCase(unittest.TestCase): ...@@ -61,7 +61,12 @@ class BaseCourseTestCase(unittest.TestCase):
"""Get a test course by directory name. If there's more than one, error.""" """Get a test course by directory name. If there's more than one, error."""
print("Importing {0}".format(name)) print("Importing {0}".format(name))
modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name], xblock_mixins=(InheritanceMixin,)) modulestore = XMLModuleStore(
DATA_DIR,
course_dirs=[name],
xblock_mixins=(InheritanceMixin,),
xblock_select=only_xmodules,
)
courses = modulestore.get_courses() courses = modulestore.get_courses()
self.assertEquals(len(courses), 1) self.assertEquals(len(courses), 1)
return courses[0] return courses[0]
......
...@@ -25,6 +25,7 @@ class InMemorySystem(XMLParsingSystem, MakoDescriptorSystem): # pylint: disable ...@@ -25,6 +25,7 @@ class InMemorySystem(XMLParsingSystem, MakoDescriptorSystem): # pylint: disable
error_tracker=Mock(), error_tracker=Mock(),
resources_fs=xml_import_data.filesystem, resources_fs=xml_import_data.filesystem,
mixins=xml_import_data.xblock_mixins, mixins=xml_import_data.xblock_mixins,
select=xml_import_data.xblock_select,
render_template=lambda template, context: pprint.pformat((template, context)) render_template=lambda template, context: pprint.pformat((template, context))
) )
......
...@@ -9,6 +9,7 @@ from factory import Factory, lazy_attribute, post_generation, Sequence ...@@ -9,6 +9,7 @@ from factory import Factory, lazy_attribute, post_generation, Sequence
from lxml import etree from lxml import etree
from xmodule.modulestore.inheritance import InheritanceMixin from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.x_module import only_xmodules
class XmlImportData(object): class XmlImportData(object):
...@@ -19,7 +20,7 @@ class XmlImportData(object): ...@@ -19,7 +20,7 @@ class XmlImportData(object):
def __init__(self, xml_node, xml=None, org=None, course=None, def __init__(self, xml_node, xml=None, org=None, course=None,
default_class=None, policy=None, default_class=None, policy=None,
filesystem=None, parent=None, filesystem=None, parent=None,
xblock_mixins=()): xblock_mixins=(), xblock_select=None):
self._xml_node = xml_node self._xml_node = xml_node
self._xml_string = xml self._xml_string = xml
...@@ -28,6 +29,7 @@ class XmlImportData(object): ...@@ -28,6 +29,7 @@ class XmlImportData(object):
self.default_class = default_class self.default_class = default_class
self.filesystem = filesystem self.filesystem = filesystem
self.xblock_mixins = xblock_mixins self.xblock_mixins = xblock_mixins
self.xblock_select = xblock_select
self.parent = parent self.parent = parent
if policy is None: if policy is None:
...@@ -47,7 +49,8 @@ class XmlImportData(object): ...@@ -47,7 +49,8 @@ class XmlImportData(object):
return u"XmlImportData{!r}".format(( return u"XmlImportData{!r}".format((
self._xml_node, self._xml_string, self.org, self._xml_node, self._xml_string, self.org,
self.course, self.default_class, self.policy, self.course, self.default_class, self.policy,
self.filesystem, self.parent, self.xblock_mixins self.filesystem, self.parent, self.xblock_mixins,
self.xblock_select,
)) ))
...@@ -65,6 +68,7 @@ class XmlImportFactory(Factory): ...@@ -65,6 +68,7 @@ class XmlImportFactory(Factory):
filesystem = MemoryFS() filesystem = MemoryFS()
xblock_mixins = (InheritanceMixin,) xblock_mixins = (InheritanceMixin,)
xblock_select = only_xmodules
url_name = Sequence(str) url_name = Sequence(str)
attribs = {} attribs = {}
policy = {} policy = {}
......
...@@ -15,9 +15,10 @@ from xmodule.modulestore.exceptions import ItemNotFoundError, InsufficientSpecif ...@@ -15,9 +15,10 @@ from xmodule.modulestore.exceptions import ItemNotFoundError, InsufficientSpecif
from xblock.core import XBlock from xblock.core import XBlock
from xblock.fields import Scope, Integer, Float, List, XBlockMixin, String from xblock.fields import Scope, Integer, Float, List, XBlockMixin, String
from xmodule.fields import RelativeTime
from xblock.fragment import Fragment from xblock.fragment import Fragment
from xblock.plugin import default_select
from xblock.runtime import Runtime from xblock.runtime import Runtime
from xmodule.fields import RelativeTime
from xmodule.errortracker import exc_info_to_str from xmodule.errortracker import exc_info_to_str
from xmodule.modulestore.locator import BlockUsageLocator from xmodule.modulestore.locator import BlockUsageLocator
...@@ -564,6 +565,22 @@ class ResourceTemplates(object): ...@@ -564,6 +565,22 @@ class ResourceTemplates(object):
return None return None
def prefer_xmodules(identifier, entry_points):
"""Prefer entry_points from the xmodule package"""
from_xmodule = [entry_point for entry_point in entry_points if entry_point.dist.key == 'xmodule']
if from_xmodule:
return default_select(identifier, from_xmodule)
else:
return default_select(identifier, entry_points)
def only_xmodules(identifier, entry_points):
"""Only use entry_points that are supplied by the xmodule package"""
from_xmodule = [entry_point for entry_point in entry_points if entry_point.dist.key == 'xmodule']
return default_select(identifier, from_xmodule)
@XBlock.needs("i18n") @XBlock.needs("i18n")
class XModuleDescriptor(XModuleMixin, HTMLSnippet, ResourceTemplates, XBlock): class XModuleDescriptor(XModuleMixin, HTMLSnippet, ResourceTemplates, XBlock):
""" """
......
...@@ -11,7 +11,9 @@ from django.contrib.auth.models import Group, AnonymousUser ...@@ -11,7 +11,9 @@ from django.contrib.auth.models import Group, AnonymousUser
from xmodule.course_module import CourseDescriptor from xmodule.course_module import CourseDescriptor
from xmodule.error_module import ErrorDescriptor from xmodule.error_module import ErrorDescriptor
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.x_module import XModule, XModuleDescriptor from xmodule.x_module import XModule
from xblock.core import XBlock
from student.models import CourseEnrollmentAllowed from student.models import CourseEnrollmentAllowed
from external_auth.models import ExternalAuthMap from external_auth.models import ExternalAuthMap
...@@ -74,13 +76,13 @@ def has_access(user, obj, action, course_context=None): ...@@ -74,13 +76,13 @@ def has_access(user, obj, action, course_context=None):
if isinstance(obj, ErrorDescriptor): if isinstance(obj, ErrorDescriptor):
return _has_access_error_desc(user, obj, action, course_context) return _has_access_error_desc(user, obj, action, course_context)
# NOTE: any descriptor access checkers need to go above this
if isinstance(obj, XModuleDescriptor):
return _has_access_descriptor(user, obj, action, course_context)
if isinstance(obj, XModule): if isinstance(obj, XModule):
return _has_access_xmodule(user, obj, action, course_context) return _has_access_xmodule(user, obj, action, course_context)
# NOTE: any descriptor access checkers need to go above this
if isinstance(obj, XBlock):
return _has_access_descriptor(user, obj, action, course_context)
if isinstance(obj, Location): if isinstance(obj, Location):
return _has_access_location(user, obj, action, course_context) return _has_access_location(user, obj, action, course_context)
...@@ -338,7 +340,7 @@ def _dispatch(table, action, user, obj): ...@@ -338,7 +340,7 @@ def _dispatch(table, action, user, obj):
debug("%s user %s, object %s, action %s", debug("%s user %s, object %s, action %s",
'ALLOWED' if result else 'DENIED', 'ALLOWED' if result else 'DENIED',
user, user,
obj.location.url() if isinstance(obj, XModuleDescriptor) else str(obj)[:60], obj.location.url() if isinstance(obj, XBlock) else str(obj)[:60],
action) action)
return result return result
......
...@@ -27,6 +27,7 @@ from psychometrics.psychoanalyze import make_psychometrics_data_update_handler ...@@ -27,6 +27,7 @@ from psychometrics.psychoanalyze import make_psychometrics_data_update_handler
from student.models import anonymous_id_for_user, user_by_anonymous_id from student.models import anonymous_id_for_user, user_by_anonymous_id
from util.json_request import JsonResponse from util.json_request import JsonResponse
from util.sandboxing import can_execute_unsafe_code from util.sandboxing import can_execute_unsafe_code
from xblock.core import XBlock
from xblock.fields import Scope from xblock.fields import Scope
from xblock.runtime import DbModel, KeyValueStore from xblock.runtime import DbModel, KeyValueStore
from xblock.exceptions import NoSuchHandlerError from xblock.exceptions import NoSuchHandlerError
...@@ -38,6 +39,7 @@ from xmodule.modulestore.django import modulestore ...@@ -38,6 +39,7 @@ from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule_modifiers import replace_course_urls, replace_jump_to_id_urls, replace_static_urls, add_histogram, wrap_xblock from xmodule_modifiers import replace_course_urls, replace_jump_to_id_urls, replace_static_urls, add_histogram, wrap_xblock
from xmodule.lti_module import LTIModule from xmodule.lti_module import LTIModule
from xmodule.x_module import XModuleDescriptor
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -373,7 +375,9 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours ...@@ -373,7 +375,9 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
# while giving selected modules a per-course anonymized id. # while giving selected modules a per-course anonymized id.
# As we have the time to manually test more modules, we can add to the list # As we have the time to manually test more modules, we can add to the list
# of modules that get the per-course anonymized id. # of modules that get the per-course anonymized id.
if issubclass(getattr(descriptor, 'module_class', None), LTIModule): is_pure_xblock = isinstance(descriptor, XBlock) and not isinstance(descriptor, XModuleDescriptor)
is_lti_module = not is_pure_xblock and issubclass(descriptor.module_class, LTIModule)
if is_pure_xblock or is_lti_module:
anonymous_student_id = anonymous_id_for_user(user, course_id) anonymous_student_id = anonymous_id_for_user(user, course_id)
else: else:
anonymous_student_id = anonymous_id_for_user(user, '') anonymous_student_id = anonymous_id_for_user(user, '')
......
...@@ -34,6 +34,7 @@ class Command(BaseCommand): ...@@ -34,6 +34,7 @@ class Command(BaseCommand):
default_class='xmodule.hidden_module.HiddenDescriptor', default_class='xmodule.hidden_module.HiddenDescriptor',
load_error_modules=True, load_error_modules=True,
xblock_mixins=settings.XBLOCK_MIXINS, xblock_mixins=settings.XBLOCK_MIXINS,
xblock_select=settings.XBLOCK_SELECT_FUNCTION,
) )
export_dir = path(args[0]) export_dir = path(args[0])
......
...@@ -34,7 +34,7 @@ DOC_STORE_CONFIG = { ...@@ -34,7 +34,7 @@ DOC_STORE_CONFIG = {
} }
modulestore_options = { modulestore_options = {
'default_class': 'xmodule.raw_module.RawDescriptor', 'default_class': 'xmodule.hidden_module.HiddenDescriptor',
'fs_root': TEST_ROOT / "data", 'fs_root': TEST_ROOT / "data",
'render_template': 'edxmako.shortcuts.render_to_string', 'render_template': 'edxmako.shortcuts.render_to_string',
} }
......
...@@ -23,7 +23,7 @@ FEATURES['ENABLE_LMS_MIGRATION'] = False ...@@ -23,7 +23,7 @@ FEATURES['ENABLE_LMS_MIGRATION'] = False
META_UNIVERSITIES = {} META_UNIVERSITIES = {}
modulestore_options = { modulestore_options = {
'default_class': 'xmodule.raw_module.RawDescriptor', 'default_class': 'xmodule.hidden_module.HiddenDescriptor',
'fs_root': DATA_DIR, 'fs_root': DATA_DIR,
'render_template': 'edxmako.shortcuts.render_to_string', 'render_template': 'edxmako.shortcuts.render_to_string',
} }
......
...@@ -31,7 +31,7 @@ MODULESTORE = { ...@@ -31,7 +31,7 @@ MODULESTORE = {
'collection': 'modulestore', 'collection': 'modulestore',
}, },
'OPTIONS': { 'OPTIONS': {
'default_class': 'xmodule.raw_module.RawDescriptor', 'default_class': 'xmodule.hidden_module.HiddenDescriptor',
'fs_root': DATA_DIR, 'fs_root': DATA_DIR,
'render_template': 'edxmako.shortcuts.render_to_string', 'render_template': 'edxmako.shortcuts.render_to_string',
} }
......
...@@ -32,7 +32,7 @@ from .discussionsettings import * ...@@ -32,7 +32,7 @@ from .discussionsettings import *
from lms.lib.xblock.mixin import LmsBlockMixin from lms.lib.xblock.mixin import LmsBlockMixin
from xmodule.modulestore.inheritance import InheritanceMixin from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.x_module import XModuleMixin from xmodule.x_module import XModuleMixin, only_xmodules
################################### FEATURES ################################### ################################### FEATURES ###################################
# The display name of the platform to be used in templates/emails/etc. # The display name of the platform to be used in templates/emails/etc.
...@@ -406,6 +406,14 @@ INIT_MODULESTORE_ON_STARTUP = True ...@@ -406,6 +406,14 @@ INIT_MODULESTORE_ON_STARTUP = True
# once the responsibility of XBlock creation is moved out of modulestore - cpennington # once the responsibility of XBlock creation is moved out of modulestore - cpennington
XBLOCK_MIXINS = (LmsBlockMixin, InheritanceMixin, XModuleMixin) XBLOCK_MIXINS = (LmsBlockMixin, InheritanceMixin, XModuleMixin)
# Only allow XModules in the LMS
XBLOCK_SELECT_FUNCTION = only_xmodules
# Use the following lines to allow any xblock in the LMS,
# either by uncommenting them here, or adding them to your private.py
# from xmodule.x_module import prefer_xmodules
# XBLOCK_SELECT_FUNCTION = prefer_xmodules
#################### Python sandbox ############################################ #################### Python sandbox ############################################
CODE_JAIL = { CODE_JAIL = {
......
...@@ -19,7 +19,7 @@ MODULESTORE = { ...@@ -19,7 +19,7 @@ MODULESTORE = {
'collection': 'modulestore', 'collection': 'modulestore',
}, },
'OPTIONS': { 'OPTIONS': {
'default_class': 'xmodule.raw_module.RawDescriptor', 'default_class': 'xmodule.hidden_module.HiddenDescriptor',
'fs_root': GITHUB_REPO_ROOT, 'fs_root': GITHUB_REPO_ROOT,
'render_template': 'edxmako.shortcuts.render_to_string', 'render_template': 'edxmako.shortcuts.render_to_string',
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
-e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk -e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk
# Our libraries: # Our libraries:
-e git+https://github.com/edx/XBlock.git@2a1efc8a413cc140d48f33fa839143ffcbd21d83#egg=XBlock -e git+https://github.com/edx/XBlock.git@cd77808aadd3ea1c2027ca8c0aa5624d8ccccc52#egg=XBlock
-e git+https://github.com/edx/codejail.git@e3d98f9455#egg=codejail -e git+https://github.com/edx/codejail.git@e3d98f9455#egg=codejail
-e git+https://github.com/edx/diff-cover.git@v0.2.6#egg=diff_cover -e git+https://github.com/edx/diff-cover.git@v0.2.6#egg=diff_cover
-e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool -e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool
......
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