Enable pure XBlocks, but behind a feature flag
[LMS-226] [LMS-2013]
This commit is contained in:
@@ -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
|
||||
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.
|
||||
See mongo_indexes.md for new indices that should be added.
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ from xmodule.modulestore.locator import CourseLocator, BlockUsageLocator, LocalI
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from xmodule.html_module import HtmlDescriptor
|
||||
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):
|
||||
@@ -248,9 +249,10 @@ class TemplateTests(unittest.TestCase):
|
||||
- 'definition':
|
||||
- '_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')),
|
||||
default_class
|
||||
default_class,
|
||||
select=prefer_xmodules
|
||||
)
|
||||
usage_id = json_data.get('_id', None)
|
||||
if not '_inherited_settings' in json_data and parent_xblock is not None:
|
||||
|
||||
@@ -14,13 +14,14 @@ from xmodule.modulestore.django import modulestore
|
||||
from xmodule.util.date_utils import get_default_time_display
|
||||
from xmodule.modulestore.django import loc_mapper
|
||||
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.exceptions import NoSuchHandlerError
|
||||
from xblock.fields import Scope
|
||||
from xblock.plugin import PluginMissingError
|
||||
from xblock.runtime import Mixologist
|
||||
from xmodule.x_module import prefer_xmodules
|
||||
|
||||
from lms.lib.xblock.runtime import unquote_slashes
|
||||
|
||||
@@ -44,12 +45,18 @@ COMPONENT_TYPES = ['discussion', 'html', 'problem', 'video']
|
||||
|
||||
OPEN_ENDED_COMPONENT_TYPES = ["combinedopenended", "peergrading"]
|
||||
NOTE_COMPONENT_TYPES = ['notes']
|
||||
ADVANCED_COMPONENT_TYPES = [
|
||||
'annotatable',
|
||||
'word_cloud',
|
||||
'graphical_slider_tool',
|
||||
'lti',
|
||||
] + OPEN_ENDED_COMPONENT_TYPES + NOTE_COMPONENT_TYPES
|
||||
|
||||
if settings.FEATURES.get('ALLOW_ALL_ADVANCED_COMPONENTS'):
|
||||
ADVANCED_COMPONENT_TYPES = sorted(set(name for name, class_ in XBlock.load_classes()) - set(COMPONENT_TYPES))
|
||||
else:
|
||||
|
||||
ADVANCED_COMPONENT_TYPES = [
|
||||
'annotatable',
|
||||
'word_cloud',
|
||||
'graphical_slider_tool',
|
||||
'lti',
|
||||
] + OPEN_ENDED_COMPONENT_TYPES + NOTE_COMPONENT_TYPES
|
||||
|
||||
ADVANCED_COMPONENT_CATEGORY = 'advanced'
|
||||
ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules'
|
||||
|
||||
@@ -138,7 +145,7 @@ def _load_mixed_class(category):
|
||||
"""
|
||||
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)
|
||||
return mixologist.mix(component_class)
|
||||
|
||||
|
||||
@@ -9,10 +9,17 @@ from xmodule_modifiers import wrap_xblock
|
||||
|
||||
from django.core.exceptions import PermissionDenied
|
||||
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.inheritance import own_metadata
|
||||
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.string_utils import str_to_bool
|
||||
@@ -23,12 +30,6 @@ from ..utils import get_modulestore
|
||||
|
||||
from .access import has_access
|
||||
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 edxmako.shortcuts import render_to_response, render_to_string
|
||||
from models.settings.course_grading import CourseGradingModel
|
||||
@@ -260,7 +261,7 @@ def _create_item(request):
|
||||
data = None
|
||||
template_id = request.json.get('boilerplate')
|
||||
if template_id is not None:
|
||||
clz = XModuleDescriptor.load_class(category)
|
||||
clz = XBlock.load_class(category, select=prefer_xmodules)
|
||||
if clz is not None:
|
||||
template = clz.get_template(template_id)
|
||||
if template is not None:
|
||||
|
||||
@@ -31,7 +31,7 @@ from path import path
|
||||
from lms.lib.xblock.mixin import LmsBlockMixin
|
||||
from cms.lib.xblock.mixin import CmsBlockMixin
|
||||
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
|
||||
|
||||
############################ FEATURE CONFIGURATION #############################
|
||||
@@ -62,6 +62,10 @@ FEATURES = {
|
||||
# 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.
|
||||
'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
|
||||
|
||||
@@ -178,6 +182,15 @@ MIDDLEWARE_CLASSES = (
|
||||
# once the responsibility of XBlock creation is moved out of modulestore - cpennington
|
||||
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 ################################
|
||||
# This is imported to register the exception signal handling that logs exceptions
|
||||
|
||||
@@ -430,7 +430,7 @@ class ModuleStoreReadBase(ModuleStoreRead):
|
||||
self,
|
||||
doc_store_config=None, # ignore if passed up
|
||||
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
|
||||
db=None, collection=None, host=None, port=None, tz_aware=True, user=None, password=None
|
||||
):
|
||||
@@ -442,6 +442,7 @@ class ModuleStoreReadBase(ModuleStoreRead):
|
||||
self.modulestore_update_signal = modulestore_update_signal
|
||||
self.request_cache = request_cache
|
||||
self.xblock_mixins = xblock_mixins
|
||||
self.xblock_select = xblock_select
|
||||
|
||||
def _get_errorlog(self, location):
|
||||
"""
|
||||
|
||||
@@ -66,6 +66,7 @@ def create_modulestore_instance(engine, doc_store_config, options):
|
||||
request_cache=request_cache,
|
||||
modulestore_update_signal=Signal(providing_args=['modulestore', 'course_id', 'location']),
|
||||
xblock_mixins=getattr(settings, 'XBLOCK_MIXINS', ()),
|
||||
xblock_select=getattr(settings, 'XBLOCK_SELECT_FUNCTION', None),
|
||||
doc_store_config=doc_store_config,
|
||||
**_options
|
||||
)
|
||||
@@ -83,7 +84,7 @@ def get_default_store_name_for_current_request():
|
||||
|
||||
# get mapping information which is defined in configurations
|
||||
mappings = getattr(settings, 'HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS', None)
|
||||
|
||||
|
||||
# compare hostname against the regex expressions set of mappings
|
||||
# which will tell us which store name to use
|
||||
if hostname and mappings:
|
||||
|
||||
@@ -25,7 +25,6 @@ from path import path
|
||||
from importlib import import_module
|
||||
from xmodule.errortracker import null_error_tracker, exc_info_to_str
|
||||
from xmodule.mako_module import MakoDescriptorSystem
|
||||
from xmodule.x_module import XModuleDescriptor
|
||||
from xmodule.error_module import ErrorDescriptor
|
||||
from xblock.runtime import DbModel
|
||||
from xblock.exceptions import InvalidScopeError
|
||||
@@ -173,10 +172,8 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
|
||||
# load the module and apply the inherited metadata
|
||||
try:
|
||||
category = json_data['location']['category']
|
||||
class_ = XModuleDescriptor.load_class(
|
||||
category,
|
||||
self.default_class
|
||||
)
|
||||
class_ = self.load_block_type(category)
|
||||
|
||||
definition = json_data.get('definition', {})
|
||||
metadata = json_data.get('metadata', {})
|
||||
for old_name, new_name in getattr(class_, 'metadata_translations', {}).items():
|
||||
@@ -506,6 +503,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
render_template=self.render_template,
|
||||
cached_metadata=cached_metadata,
|
||||
mixins=self.xblock_mixins,
|
||||
select=self.xblock_select,
|
||||
)
|
||||
return system.load_item(item['location'])
|
||||
|
||||
@@ -627,8 +625,9 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
render_template=self.render_template,
|
||||
cached_metadata={},
|
||||
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 hasattr(xblock_class, 'data') and xblock_class.data.default is not None:
|
||||
definition_data = xblock_class.data.default
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import sys
|
||||
import logging
|
||||
from xmodule.mako_module import MakoDescriptorSystem
|
||||
from xmodule.x_module import XModuleDescriptor
|
||||
from xmodule.modulestore.locator import BlockUsageLocator, LocalId
|
||||
from xmodule.error_module import ErrorDescriptor
|
||||
from xmodule.errortracker import exc_info_to_str
|
||||
@@ -62,10 +61,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
|
||||
if json_data is None:
|
||||
raise ItemNotFoundError(block_id)
|
||||
|
||||
class_ = XModuleDescriptor.load_class(
|
||||
json_data.get('category'),
|
||||
self.default_class
|
||||
)
|
||||
class_ = self.load_block_type(json_data.get('category'))
|
||||
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
|
||||
|
||||
@@ -42,7 +42,7 @@ Representation:
|
||||
*** 'edited_by': user_id whose edit caused this version of the definition,
|
||||
*** 'edited_on': datetime of the change causing this version
|
||||
*** '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.
|
||||
"""
|
||||
import threading
|
||||
@@ -56,7 +56,7 @@ import copy
|
||||
from pytz import UTC
|
||||
|
||||
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.exceptions import InsufficientSpecificationError, VersionConflictError, DuplicateItemError
|
||||
from xmodule.modulestore import inheritance, ModuleStoreWriteBase, Location, SPLIT_MONGO_MODULESTORE_TYPE
|
||||
@@ -68,6 +68,7 @@ from xblock.fields import Scope
|
||||
from xblock.runtime import Mixologist
|
||||
from bson.objectid import ObjectId
|
||||
from xmodule.modulestore.split_mongo.mongo_connection import MongoConnection
|
||||
from xblock.core import XBlock
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
#==============================================================================
|
||||
@@ -184,7 +185,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
error_tracker=self.error_tracker,
|
||||
render_template=self.render_template,
|
||||
resources_fs=None,
|
||||
mixins=self.xblock_mixins
|
||||
mixins=self.xblock_mixins,
|
||||
select=self.xblock_select,
|
||||
)
|
||||
self._add_cache(course_entry['structure']['_id'], system)
|
||||
self.cache_items(system, block_ids, depth, lazy)
|
||||
@@ -1471,7 +1473,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
"""
|
||||
if fields is None:
|
||||
return {}
|
||||
cls = self.mixologist.mix(XModuleDescriptor.load_class(category))
|
||||
cls = self.mixologist.mix(XBlock.load_class(category, select=prefer_xmodules))
|
||||
result = collections.defaultdict(dict)
|
||||
for field_name, value in fields.iteritems():
|
||||
field = getattr(cls, field_name)
|
||||
@@ -1581,7 +1583,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
destination_block['edit_info']['edited_by'] = user_id
|
||||
else:
|
||||
destination_block = self._new_block(
|
||||
user_id, new_block['category'],
|
||||
user_id, new_block['category'],
|
||||
self._filter_blacklist(copy.copy(new_block['fields']), blacklist),
|
||||
new_block['definition'],
|
||||
new_block['edit_info']['update_version']
|
||||
|
||||
@@ -6,7 +6,8 @@ from uuid import uuid4
|
||||
from pytz import UTC
|
||||
|
||||
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):
|
||||
@@ -144,7 +145,7 @@ class ItemFactory(XModuleFactory):
|
||||
|
||||
if 'boilerplate' in kwargs:
|
||||
template_id = kwargs.pop('boilerplate')
|
||||
clz = XModuleDescriptor.load_class(category)
|
||||
clz = XBlock.load_class(category, select=prefer_xmodules)
|
||||
template = clz.get_template(template_id)
|
||||
assert template is not None
|
||||
metadata.update(template.get('metadata', {}))
|
||||
|
||||
@@ -17,7 +17,7 @@ from xmodule.error_module import ErrorDescriptor
|
||||
from xmodule.errortracker import make_error_tracker, exc_info_to_str
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
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 xblock.core import XBlock
|
||||
@@ -238,7 +238,7 @@ def create_block_from_xml(xml_data, system, org=None, course=None, default_class
|
||||
|
||||
"""
|
||||
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)
|
||||
|
||||
# leave next line commented out - useful for low-level debugging
|
||||
@@ -460,6 +460,7 @@ class XMLModuleStore(ModuleStoreReadBase):
|
||||
load_error_modules=self.load_error_modules,
|
||||
policy=policy,
|
||||
mixins=self.xblock_mixins,
|
||||
select=self.xblock_select,
|
||||
)
|
||||
|
||||
course_descriptor = system.process_xml(etree.tostring(course_data, encoding='unicode'))
|
||||
|
||||
@@ -132,6 +132,7 @@ def import_from_xml(
|
||||
course_dirs=course_dirs,
|
||||
load_error_modules=load_error_modules,
|
||||
xblock_mixins=store.xblock_mixins,
|
||||
xblock_select=store.xblock_select,
|
||||
)
|
||||
|
||||
# NOTE: the XmlModuleStore does not implement get_items()
|
||||
|
||||
@@ -12,7 +12,7 @@ samples.
|
||||
import logging
|
||||
|
||||
from collections import defaultdict
|
||||
from .x_module import XModuleDescriptor
|
||||
from xblock.core import XBlock
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -23,7 +23,9 @@ def all_templates():
|
||||
"""
|
||||
# TODO use memcache to memoize w/ expiration
|
||||
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()
|
||||
|
||||
return templates
|
||||
|
||||
@@ -13,7 +13,7 @@ from xmodule.xml_module import is_pointer_tag
|
||||
from xmodule.modulestore import Location
|
||||
from xmodule.modulestore.xml import ImportSystem, XMLModuleStore
|
||||
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.tests import DATA_DIR
|
||||
from xmodule.modulestore.inheritance import InheritanceMixin
|
||||
@@ -61,7 +61,12 @@ class BaseCourseTestCase(unittest.TestCase):
|
||||
"""Get a test course by directory name. If there's more than one, error."""
|
||||
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()
|
||||
self.assertEquals(len(courses), 1)
|
||||
return courses[0]
|
||||
|
||||
@@ -25,6 +25,7 @@ class InMemorySystem(XMLParsingSystem, MakoDescriptorSystem): # pylint: disable
|
||||
error_tracker=Mock(),
|
||||
resources_fs=xml_import_data.filesystem,
|
||||
mixins=xml_import_data.xblock_mixins,
|
||||
select=xml_import_data.xblock_select,
|
||||
render_template=lambda template, context: pprint.pformat((template, context))
|
||||
)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from factory import Factory, lazy_attribute, post_generation, Sequence
|
||||
from lxml import etree
|
||||
|
||||
from xmodule.modulestore.inheritance import InheritanceMixin
|
||||
from xmodule.x_module import only_xmodules
|
||||
|
||||
|
||||
class XmlImportData(object):
|
||||
@@ -19,7 +20,7 @@ class XmlImportData(object):
|
||||
def __init__(self, xml_node, xml=None, org=None, course=None,
|
||||
default_class=None, policy=None,
|
||||
filesystem=None, parent=None,
|
||||
xblock_mixins=()):
|
||||
xblock_mixins=(), xblock_select=None):
|
||||
|
||||
self._xml_node = xml_node
|
||||
self._xml_string = xml
|
||||
@@ -28,6 +29,7 @@ class XmlImportData(object):
|
||||
self.default_class = default_class
|
||||
self.filesystem = filesystem
|
||||
self.xblock_mixins = xblock_mixins
|
||||
self.xblock_select = xblock_select
|
||||
self.parent = parent
|
||||
|
||||
if policy is None:
|
||||
@@ -47,7 +49,8 @@ class XmlImportData(object):
|
||||
return u"XmlImportData{!r}".format((
|
||||
self._xml_node, self._xml_string, self.org,
|
||||
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):
|
||||
|
||||
filesystem = MemoryFS()
|
||||
xblock_mixins = (InheritanceMixin,)
|
||||
xblock_select = only_xmodules
|
||||
url_name = Sequence(str)
|
||||
attribs = {}
|
||||
policy = {}
|
||||
|
||||
@@ -15,9 +15,10 @@ from xmodule.modulestore.exceptions import ItemNotFoundError, InsufficientSpecif
|
||||
|
||||
from xblock.core import XBlock
|
||||
from xblock.fields import Scope, Integer, Float, List, XBlockMixin, String
|
||||
from xmodule.fields import RelativeTime
|
||||
from xblock.fragment import Fragment
|
||||
from xblock.plugin import default_select
|
||||
from xblock.runtime import Runtime
|
||||
from xmodule.fields import RelativeTime
|
||||
from xmodule.errortracker import exc_info_to_str
|
||||
from xmodule.modulestore.locator import BlockUsageLocator
|
||||
|
||||
@@ -564,6 +565,22 @@ class ResourceTemplates(object):
|
||||
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")
|
||||
class XModuleDescriptor(XModuleMixin, HTMLSnippet, ResourceTemplates, XBlock):
|
||||
"""
|
||||
|
||||
@@ -11,7 +11,9 @@ from django.contrib.auth.models import Group, AnonymousUser
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.error_module import ErrorDescriptor
|
||||
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 external_auth.models import ExternalAuthMap
|
||||
@@ -74,13 +76,13 @@ def has_access(user, obj, action, course_context=None):
|
||||
if isinstance(obj, ErrorDescriptor):
|
||||
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):
|
||||
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):
|
||||
return _has_access_location(user, obj, action, course_context)
|
||||
|
||||
@@ -338,7 +340,7 @@ def _dispatch(table, action, user, obj):
|
||||
debug("%s user %s, object %s, action %s",
|
||||
'ALLOWED' if result else 'DENIED',
|
||||
user,
|
||||
obj.location.url() if isinstance(obj, XModuleDescriptor) else str(obj)[:60],
|
||||
obj.location.url() if isinstance(obj, XBlock) else str(obj)[:60],
|
||||
action)
|
||||
return result
|
||||
|
||||
|
||||
@@ -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 util.json_request import JsonResponse
|
||||
from util.sandboxing import can_execute_unsafe_code
|
||||
from xblock.core import XBlock
|
||||
from xblock.fields import Scope
|
||||
from xblock.runtime import DbModel, KeyValueStore
|
||||
from xblock.exceptions import NoSuchHandlerError
|
||||
@@ -38,6 +39,7 @@ from xmodule.modulestore.django import modulestore
|
||||
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.lti_module import LTIModule
|
||||
from xmodule.x_module import XModuleDescriptor
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -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.
|
||||
# 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.
|
||||
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)
|
||||
else:
|
||||
anonymous_student_id = anonymous_id_for_user(user, '')
|
||||
|
||||
@@ -34,6 +34,7 @@ class Command(BaseCommand):
|
||||
default_class='xmodule.hidden_module.HiddenDescriptor',
|
||||
load_error_modules=True,
|
||||
xblock_mixins=settings.XBLOCK_MIXINS,
|
||||
xblock_select=settings.XBLOCK_SELECT_FUNCTION,
|
||||
)
|
||||
|
||||
export_dir = path(args[0])
|
||||
|
||||
@@ -34,7 +34,7 @@ DOC_STORE_CONFIG = {
|
||||
}
|
||||
|
||||
modulestore_options = {
|
||||
'default_class': 'xmodule.raw_module.RawDescriptor',
|
||||
'default_class': 'xmodule.hidden_module.HiddenDescriptor',
|
||||
'fs_root': TEST_ROOT / "data",
|
||||
'render_template': 'edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ FEATURES['ENABLE_LMS_MIGRATION'] = False
|
||||
META_UNIVERSITIES = {}
|
||||
|
||||
modulestore_options = {
|
||||
'default_class': 'xmodule.raw_module.RawDescriptor',
|
||||
'default_class': 'xmodule.hidden_module.HiddenDescriptor',
|
||||
'fs_root': DATA_DIR,
|
||||
'render_template': 'edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ MODULESTORE = {
|
||||
'collection': 'modulestore',
|
||||
},
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.raw_module.RawDescriptor',
|
||||
'default_class': 'xmodule.hidden_module.HiddenDescriptor',
|
||||
'fs_root': DATA_DIR,
|
||||
'render_template': 'edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ from .discussionsettings import *
|
||||
|
||||
from lms.lib.xblock.mixin import LmsBlockMixin
|
||||
from xmodule.modulestore.inheritance import InheritanceMixin
|
||||
from xmodule.x_module import XModuleMixin
|
||||
from xmodule.x_module import XModuleMixin, only_xmodules
|
||||
|
||||
################################### FEATURES ###################################
|
||||
# The display name of the platform to be used in templates/emails/etc.
|
||||
@@ -406,6 +406,14 @@ INIT_MODULESTORE_ON_STARTUP = True
|
||||
# once the responsibility of XBlock creation is moved out of modulestore - cpennington
|
||||
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 ############################################
|
||||
|
||||
CODE_JAIL = {
|
||||
|
||||
@@ -19,7 +19,7 @@ MODULESTORE = {
|
||||
'collection': 'modulestore',
|
||||
},
|
||||
'OPTIONS': {
|
||||
'default_class': 'xmodule.raw_module.RawDescriptor',
|
||||
'default_class': 'xmodule.hidden_module.HiddenDescriptor',
|
||||
'fs_root': GITHUB_REPO_ROOT,
|
||||
'render_template': 'edxmako.shortcuts.render_to_string',
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
-e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk
|
||||
|
||||
# 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/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
|
||||
|
||||
Reference in New Issue
Block a user