Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
2ad4749a
Commit
2ad4749a
authored
Jan 10, 2014
by
Calen Pennington
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2119 from cpennington/xblocks-behind-feature-flag
Enable pure XBlocks, hidden by feature flags
parents
4a3cffbb
417fe21d
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
151 additions
and
75 deletions
+151
-75
CHANGELOG.rst
+7
-0
cms/djangoapps/contentstore/tests/test_crud.py
+5
-3
cms/djangoapps/contentstore/views/component.py
+15
-8
cms/djangoapps/contentstore/views/item.py
+9
-8
cms/envs/common.py
+14
-1
common/lib/xmodule/xmodule/modulestore/__init__.py
+2
-1
common/lib/xmodule/xmodule/modulestore/django.py
+2
-1
common/lib/xmodule/xmodule/modulestore/mongo/base.py
+5
-6
common/lib/xmodule/xmodule/modulestore/split_mongo/caching_descriptor_system.py
+1
-5
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+7
-5
common/lib/xmodule/xmodule/modulestore/tests/factories.py
+3
-2
common/lib/xmodule/xmodule/modulestore/xml.py
+3
-2
common/lib/xmodule/xmodule/modulestore/xml_importer.py
+1
-0
common/lib/xmodule/xmodule/templates.py
+4
-2
common/lib/xmodule/xmodule/tests/test_import.py
+7
-2
common/lib/xmodule/xmodule/tests/xml/__init__.py
+1
-0
common/lib/xmodule/xmodule/tests/xml/factories.py
+6
-2
common/lib/xmodule/xmodule/x_module.py
+18
-1
lms/djangoapps/courseware/access.py
+8
-6
lms/djangoapps/courseware/model_data.py
+3
-3
lms/djangoapps/courseware/module_render.py
+5
-1
lms/djangoapps/courseware/tests/factories.py
+2
-2
lms/djangoapps/courseware/tests/test_model_data.py
+8
-8
lms/djangoapps/debug/management/commands/dump_xml_courses.py
+1
-0
lms/envs/acceptance.py
+1
-1
lms/envs/cms/dev.py
+1
-1
lms/envs/cms/mixed_dev.py
+1
-1
lms/envs/common.py
+9
-1
lms/envs/dev_mongo.py
+1
-1
requirements/edx/github.txt
+1
-1
No files found.
CHANGELOG.rst
View file @
2ad4749a
...
...
@@ -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.
...
...
cms/djangoapps/contentstore/tests/test_crud.py
View file @
2ad4749a
...
...
@@ -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_
=
X
ModuleDescriptor
.
load_class
(
class_
=
X
Block
.
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
:
...
...
cms/djangoapps/contentstore/views/component.py
View file @
2ad4749a
...
...
@@ -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
=
X
ModuleDescriptor
.
load_class
(
category
)
component_class
=
X
Block
.
load_class
(
category
,
select
=
prefer_xmodules
)
mixologist
=
Mixologist
(
settings
.
XBLOCK_MIXINS
)
return
mixologist
.
mix
(
component_class
)
...
...
cms/djangoapps/contentstore/views/item.py
View file @
2ad4749a
...
...
@@ -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
=
X
ModuleDescriptor
.
load_class
(
category
)
clz
=
X
Block
.
load_class
(
category
,
select
=
prefer_xmodules
)
if
clz
is
not
None
:
template
=
clz
.
get_template
(
template_id
)
if
template
is
not
None
:
...
...
cms/envs/common.py
View file @
2ad4749a
...
...
@@ -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
...
...
common/lib/xmodule/xmodule/modulestore/__init__.py
View file @
2ad4749a
...
...
@@ -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
):
"""
...
...
common/lib/xmodule/xmodule/modulestore/django.py
View file @
2ad4749a
...
...
@@ -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
:
...
...
common/lib/xmodule/xmodule/modulestore/mongo/base.py
View file @
2ad4749a
...
...
@@ -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
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/caching_descriptor_system.py
View file @
2ad4749a
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
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
View file @
2ad4749a
...
...
@@ -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
(
X
ModuleDescriptor
.
load_class
(
category
))
cls
=
self
.
mixologist
.
mix
(
X
Block
.
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'
]
...
...
common/lib/xmodule/xmodule/modulestore/tests/factories.py
View file @
2ad4749a
...
...
@@ -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
=
X
ModuleDescriptor
.
load_class
(
category
)
clz
=
X
Block
.
load_class
(
category
,
select
=
prefer_xmodules
)
template
=
clz
.
get_template
(
template_id
)
assert
template
is
not
None
metadata
.
update
(
template
.
get
(
'metadata'
,
{}))
...
...
common/lib/xmodule/xmodule/modulestore/xml.py
View file @
2ad4749a
...
...
@@ -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
=
X
ModuleDescriptor
.
load_class
(
node
.
tag
,
default_clas
s
)
raw_class
=
X
Block
.
load_class
(
node
.
tag
,
default_class
,
select
=
prefer_xmodule
s
)
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'
))
...
...
common/lib/xmodule/xmodule/modulestore/xml_importer.py
View file @
2ad4749a
...
...
@@ -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()
...
...
common/lib/xmodule/xmodule/templates.py
View file @
2ad4749a
...
...
@@ -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
common/lib/xmodule/xmodule/tests/test_import.py
View file @
2ad4749a
...
...
@@ -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
]
...
...
common/lib/xmodule/xmodule/tests/xml/__init__.py
View file @
2ad4749a
...
...
@@ -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
))
)
...
...
common/lib/xmodule/xmodule/tests/xml/factories.py
View file @
2ad4749a
...
...
@@ -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
=
{}
...
...
common/lib/xmodule/xmodule/x_module.py
View file @
2ad4749a
...
...
@@ -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
):
"""
...
...
lms/djangoapps/courseware/access.py
View file @
2ad4749a
...
...
@@ -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
,
X
ModuleDescriptor
)
else
str
(
obj
)[:
60
],
obj
.
location
.
url
()
if
isinstance
(
obj
,
X
Block
)
else
str
(
obj
)[:
60
],
action
)
return
result
...
...
lms/djangoapps/courseware/model_data.py
View file @
2ad4749a
...
...
@@ -142,7 +142,7 @@ class FieldDataCache(object):
return
self
.
_chunked_query
(
StudentModule
,
'module_state_key__in'
,
(
descriptor
.
location
.
url
(
)
for
descriptor
in
self
.
descriptors
),
(
str
(
descriptor
.
scope_ids
.
usage_id
)
for
descriptor
in
self
.
descriptors
),
course_id
=
self
.
course_id
,
student
=
self
.
user
.
pk
,
)
...
...
@@ -150,14 +150,14 @@ class FieldDataCache(object):
return
self
.
_chunked_query
(
XModuleUserStateSummaryField
,
'usage_id__in'
,
(
descriptor
.
location
.
url
(
)
for
descriptor
in
self
.
descriptors
),
(
str
(
descriptor
.
scope_ids
.
usage_id
)
for
descriptor
in
self
.
descriptors
),
field_name__in
=
set
(
field
.
name
for
field
in
fields
),
)
elif
scope
==
Scope
.
preferences
:
return
self
.
_chunked_query
(
XModuleStudentPrefsField
,
'module_type__in'
,
set
(
descriptor
.
module_class
.
__name__
for
descriptor
in
self
.
descriptors
),
set
(
descriptor
.
scope_ids
.
block_type
for
descriptor
in
self
.
descriptors
),
student
=
self
.
user
.
pk
,
field_name__in
=
set
(
field
.
name
for
field
in
fields
),
)
...
...
lms/djangoapps/courseware/module_render.py
View file @
2ad4749a
...
...
@@ -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
,
''
)
...
...
lms/djangoapps/courseware/tests/factories.py
View file @
2ad4749a
...
...
@@ -131,7 +131,7 @@ class UserStateSummaryFactory(DjangoModelFactory):
field_name
=
'existing_field'
value
=
json
.
dumps
(
'old_value'
)
usage_id
=
location
(
'
def
_id'
)
.
url
()
usage_id
=
location
(
'
usage
_id'
)
.
url
()
class
StudentPrefsFactory
(
DjangoModelFactory
):
...
...
@@ -140,7 +140,7 @@ class StudentPrefsFactory(DjangoModelFactory):
field_name
=
'existing_field'
value
=
json
.
dumps
(
'old_value'
)
student
=
factory
.
SubFactory
(
UserFactory
)
module_type
=
'
MockProblemModule
'
module_type
=
'
mock_problem
'
class
StudentInfoFactory
(
DjangoModelFactory
):
...
...
lms/djangoapps/courseware/tests/test_model_data.py
View file @
2ad4749a
...
...
@@ -15,7 +15,7 @@ from courseware.tests.factories import StudentModuleFactory as cmfStudentModuleF
from
courseware.tests.factories
import
UserStateSummaryFactory
from
courseware.tests.factories
import
StudentPrefsFactory
,
StudentInfoFactory
from
xblock.fields
import
Scope
,
BlockScope
from
xblock.fields
import
Scope
,
BlockScope
,
ScopeIds
from
xmodule.modulestore
import
Location
from
django.test
import
TestCase
from
django.db
import
DatabaseError
...
...
@@ -31,7 +31,7 @@ def mock_field(scope, name):
def
mock_descriptor
(
fields
=
[]):
descriptor
=
Mock
()
descriptor
.
location
=
location
(
'def_id'
)
descriptor
.
scope_ids
=
ScopeIds
(
'user1'
,
'mock_problem'
,
location
(
'def_id'
),
location
(
'usage_id'
)
)
descriptor
.
module_class
.
fields
.
values
.
return_value
=
fields
descriptor
.
fields
.
values
.
return_value
=
fields
descriptor
.
module_class
.
__name__
=
'MockProblemModule'
...
...
@@ -43,15 +43,15 @@ course_id = 'edX/test_course/test'
# The user ids here are 1 because we make a student in the setUp functions, and
# they get an id of 1. There's an assertion in setUp to ensure that assumption
# is still true.
user_state_summary_key
=
partial
(
DjangoKeyValueStore
.
Key
,
Scope
.
user_state_summary
,
None
,
location
(
'
def
_id'
))
settings_key
=
partial
(
DjangoKeyValueStore
.
Key
,
Scope
.
settings
,
None
,
location
(
'
def
_id'
))
user_state_key
=
partial
(
DjangoKeyValueStore
.
Key
,
Scope
.
user_state
,
1
,
location
(
'
def
_id'
))
prefs_key
=
partial
(
DjangoKeyValueStore
.
Key
,
Scope
.
preferences
,
1
,
'
MockProblemModule
'
)
user_state_summary_key
=
partial
(
DjangoKeyValueStore
.
Key
,
Scope
.
user_state_summary
,
None
,
location
(
'
usage
_id'
))
settings_key
=
partial
(
DjangoKeyValueStore
.
Key
,
Scope
.
settings
,
None
,
location
(
'
usage
_id'
))
user_state_key
=
partial
(
DjangoKeyValueStore
.
Key
,
Scope
.
user_state
,
1
,
location
(
'
usage
_id'
))
prefs_key
=
partial
(
DjangoKeyValueStore
.
Key
,
Scope
.
preferences
,
1
,
'
mock_problem
'
)
user_info_key
=
partial
(
DjangoKeyValueStore
.
Key
,
Scope
.
user_info
,
1
,
None
)
class
StudentModuleFactory
(
cmfStudentModuleFactory
):
module_state_key
=
location
(
'
def
_id'
)
.
url
()
module_state_key
=
location
(
'
usage
_id'
)
.
url
()
course_id
=
course_id
...
...
@@ -177,7 +177,7 @@ class TestMissingStudentModule(TestCase):
student_module
=
StudentModule
.
objects
.
all
()[
0
]
self
.
assertEquals
({
'a_field'
:
'a_value'
},
json
.
loads
(
student_module
.
state
))
self
.
assertEquals
(
self
.
user
,
student_module
.
student
)
self
.
assertEquals
(
location
(
'
def
_id'
)
.
url
(),
student_module
.
module_state_key
)
self
.
assertEquals
(
location
(
'
usage
_id'
)
.
url
(),
student_module
.
module_state_key
)
self
.
assertEquals
(
course_id
,
student_module
.
course_id
)
def
test_delete_field_from_missing_student_module
(
self
):
...
...
lms/djangoapps/debug/management/commands/dump_xml_courses.py
View file @
2ad4749a
...
...
@@ -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
])
...
...
lms/envs/acceptance.py
View file @
2ad4749a
...
...
@@ -34,7 +34,7 @@ DOC_STORE_CONFIG = {
}
modulestore_options
=
{
'default_class'
:
'xmodule.
raw_module.Raw
Descriptor'
,
'default_class'
:
'xmodule.
hidden_module.Hidden
Descriptor'
,
'fs_root'
:
TEST_ROOT
/
"data"
,
'render_template'
:
'edxmako.shortcuts.render_to_string'
,
}
...
...
lms/envs/cms/dev.py
View file @
2ad4749a
...
...
@@ -23,7 +23,7 @@ FEATURES['ENABLE_LMS_MIGRATION'] = False
META_UNIVERSITIES
=
{}
modulestore_options
=
{
'default_class'
:
'xmodule.
raw_module.Raw
Descriptor'
,
'default_class'
:
'xmodule.
hidden_module.Hidden
Descriptor'
,
'fs_root'
:
DATA_DIR
,
'render_template'
:
'edxmako.shortcuts.render_to_string'
,
}
...
...
lms/envs/cms/mixed_dev.py
View file @
2ad4749a
...
...
@@ -31,7 +31,7 @@ MODULESTORE = {
'collection'
:
'modulestore'
,
},
'OPTIONS'
:
{
'default_class'
:
'xmodule.
raw_module.Raw
Descriptor'
,
'default_class'
:
'xmodule.
hidden_module.Hidden
Descriptor'
,
'fs_root'
:
DATA_DIR
,
'render_template'
:
'edxmako.shortcuts.render_to_string'
,
}
...
...
lms/envs/common.py
View file @
2ad4749a
...
...
@@ -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
=
{
...
...
lms/envs/dev_mongo.py
View file @
2ad4749a
...
...
@@ -19,7 +19,7 @@ MODULESTORE = {
'collection'
:
'modulestore'
,
},
'OPTIONS'
:
{
'default_class'
:
'xmodule.
raw_module.Raw
Descriptor'
,
'default_class'
:
'xmodule.
hidden_module.Hidden
Descriptor'
,
'fs_root'
:
GITHUB_REPO_ROOT
,
'render_template'
:
'edxmako.shortcuts.render_to_string'
,
}
...
...
requirements/edx/github.txt
View file @
2ad4749a
...
...
@@ -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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment