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
5b305476
Commit
5b305476
authored
Apr 07, 2014
by
Will Daly
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3225 from edx/will/studio-import-xblock-fixes
Explicitly re-save XBlock fields during import
parents
c51d4181
38f819d1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
146 additions
and
0 deletions
+146
-0
common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py
+122
-0
common/lib/xmodule/xmodule/modulestore/xml_importer.py
+24
-0
No files found.
common/lib/xmodule/xmodule/modulestore/tests/test_xml_importer.py
0 → 100644
View file @
5b305476
"""
Tests for XML importer.
"""
from
unittest
import
TestCase
import
mock
from
xblock.core
import
XBlock
from
xblock.fields
import
String
,
Scope
,
ScopeIds
from
xblock.runtime
import
Runtime
,
KvsFieldData
,
DictKeyValueStore
from
xmodule.x_module
import
XModuleMixin
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.inheritance
import
InheritanceMixin
from
xmodule.modulestore.xml_importer
import
remap_namespace
class
StubXBlock
(
XBlock
,
XModuleMixin
,
InheritanceMixin
):
"""
Stub XBlock used for testing.
"""
test_content_field
=
String
(
help
=
"A content field that will be explicitly set"
,
scope
=
Scope
.
content
,
default
=
"default value"
)
test_settings_field
=
String
(
help
=
"A settings field that will be explicitly set"
,
scope
=
Scope
.
settings
,
default
=
"default value"
)
class
RemapNamespaceTest
(
TestCase
):
"""
Test that remapping the namespace from import to the actual course location.
"""
def
setUp
(
self
):
"""
Create a stub XBlock backed by in-memory storage.
"""
self
.
runtime
=
mock
.
MagicMock
(
Runtime
)
self
.
field_data
=
KvsFieldData
(
kvs
=
DictKeyValueStore
())
self
.
scope_ids
=
ScopeIds
(
'Bob'
,
'stubxblock'
,
'123'
,
'import'
)
self
.
xblock
=
StubXBlock
(
self
.
runtime
,
self
.
field_data
,
self
.
scope_ids
)
def
test_remap_namespace_native_xblock
(
self
):
# Set the XBlock's location
self
.
xblock
.
location
=
Location
(
"i4x://import/org/run/stubxblock"
)
# Explicitly set the content and settings fields
self
.
xblock
.
test_content_field
=
"Explicitly set"
self
.
xblock
.
test_settings_field
=
"Explicitly set"
self
.
xblock
.
save
()
# Remap the namespace
target_location_namespace
=
Location
(
"i4x://course/org/run/stubxblock"
)
remap_namespace
(
self
.
xblock
,
target_location_namespace
)
# Check the XBlock's location
self
.
assertEqual
(
self
.
xblock
.
location
,
target_location_namespace
)
# Check the values of the fields.
# The content and settings fields should be preserved
self
.
assertEqual
(
self
.
xblock
.
test_content_field
,
'Explicitly set'
)
self
.
assertEqual
(
self
.
xblock
.
test_settings_field
,
'Explicitly set'
)
# Expect that these fields are marked explicitly set
self
.
assertIn
(
'test_content_field'
,
self
.
xblock
.
get_explicitly_set_fields_by_scope
(
scope
=
Scope
.
content
)
)
self
.
assertIn
(
'test_settings_field'
,
self
.
xblock
.
get_explicitly_set_fields_by_scope
(
scope
=
Scope
.
settings
)
)
def
test_remap_namespace_native_xblock_default_values
(
self
):
# Set the XBlock's location
self
.
xblock
.
location
=
Location
(
"i4x://import/org/run/stubxblock"
)
# Do NOT set any values, so the fields should use the defaults
self
.
xblock
.
save
()
# Remap the namespace
target_location_namespace
=
Location
(
"i4x://course/org/run/stubxblock"
)
remap_namespace
(
self
.
xblock
,
target_location_namespace
)
# Check the values of the fields.
# The content and settings fields should be the default values
self
.
assertEqual
(
self
.
xblock
.
test_content_field
,
'default value'
)
self
.
assertEqual
(
self
.
xblock
.
test_settings_field
,
'default value'
)
# The fields should NOT appear in the explicitly set fields
self
.
assertNotIn
(
'test_content_field'
,
self
.
xblock
.
get_explicitly_set_fields_by_scope
(
scope
=
Scope
.
content
)
)
self
.
assertNotIn
(
'test_settings_field'
,
self
.
xblock
.
get_explicitly_set_fields_by_scope
(
scope
=
Scope
.
settings
)
)
def
test_remap_namespace_native_xblock_inherited_values
(
self
):
# Set the XBlock's location
self
.
xblock
.
location
=
Location
(
"i4x://import/org/run/stubxblock"
)
self
.
xblock
.
save
()
# Remap the namespace
target_location_namespace
=
Location
(
"i4x://course/org/run/stubxblock"
)
remap_namespace
(
self
.
xblock
,
target_location_namespace
)
# Inherited fields should NOT be explicitly set
self
.
assertNotIn
(
'start'
,
self
.
xblock
.
get_explicitly_set_fields_by_scope
(
scope
=
Scope
.
settings
)
)
self
.
assertNotIn
(
'graded'
,
self
.
xblock
.
get_explicitly_set_fields_by_scope
(
scope
=
Scope
.
settings
)
)
common/lib/xmodule/xmodule/modulestore/xml_importer.py
View file @
5b305476
...
@@ -6,6 +6,7 @@ import json
...
@@ -6,6 +6,7 @@ import json
from
.xml
import
XMLModuleStore
,
ImportSystem
,
ParentTracker
from
.xml
import
XMLModuleStore
,
ImportSystem
,
ParentTracker
from
xmodule.modulestore
import
Location
from
xmodule.modulestore
import
Location
from
xmodule.x_module
import
XModuleDescriptor
from
xblock.fields
import
Scope
,
Reference
,
ReferenceList
,
ReferenceValueDict
from
xblock.fields
import
Scope
,
Reference
,
ReferenceList
,
ReferenceValueDict
from
xmodule.contentstore.content
import
StaticContent
from
xmodule.contentstore.content
import
StaticContent
from
.inheritance
import
own_metadata
from
.inheritance
import
own_metadata
...
@@ -488,11 +489,34 @@ def remap_namespace(module, target_location_namespace):
...
@@ -488,11 +489,34 @@ def remap_namespace(module, target_location_namespace):
# This looks a bit wonky as we need to also change the 'name' of the
# This looks a bit wonky as we need to also change the 'name' of the
# imported course to be what the caller passed in
# imported course to be what the caller passed in
if
module
.
location
.
category
!=
'course'
:
if
module
.
location
.
category
!=
'course'
:
# Retrieve the content and settings fields that have been explicitly set
# to ensure that they are properly re-keyed in the XBlock field data.
if
isinstance
(
module
,
XModuleDescriptor
):
rekey_fields
=
[]
else
:
rekey_fields
=
(
module
.
get_explicitly_set_fields_by_scope
(
Scope
.
content
)
.
keys
()
+
module
.
get_explicitly_set_fields_by_scope
(
Scope
.
settings
)
.
keys
()
)
module
.
location
=
module
.
location
.
replace
(
module
.
location
=
module
.
location
.
replace
(
tag
=
target_location_namespace
.
tag
,
tag
=
target_location_namespace
.
tag
,
org
=
target_location_namespace
.
org
,
org
=
target_location_namespace
.
org
,
course
=
target_location_namespace
.
course
course
=
target_location_namespace
.
course
)
)
# Native XBlocks store the field data in a key-value store
# in which one component of the key is the XBlock's location (equivalent to "scope_ids").
# Since we've changed the XBlock's location, we need to re-save
# all the XBlock's fields so they will be stored using the new location in the key.
# However, since XBlocks only save "dirty" fields, we need to first
# explicitly set each field to its current value before triggering the save.
if
len
(
rekey_fields
)
>
0
:
for
rekey_field_name
in
rekey_fields
:
setattr
(
module
,
rekey_field_name
,
getattr
(
module
,
rekey_field_name
))
module
.
save
()
else
:
else
:
#
#
# module is a course module
# module is a course module
...
...
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