Merge pull request #3242 from edx/will/studio-import-private-fix

Allow import of native XBlocks in draft
This commit is contained in:
Will Daly
2014-04-08 10:02:31 -04:00
8 changed files with 149 additions and 27 deletions

View File

@@ -6,6 +6,7 @@ import json
from .xml import XMLModuleStore, ImportSystem, ParentTracker
from xmodule.modulestore import Location
from xblock.runtime import KvsFieldData, DictKeyValueStore
from xmodule.x_module import XModuleDescriptor
from xblock.fields import Scope, Reference, ReferenceList, ReferenceValueDict
from xmodule.contentstore.content import StaticContent
@@ -366,7 +367,8 @@ def import_course_draft(
error_tracker=errorlog.tracker,
parent_tracker=ParentTracker(),
load_error_modules=False,
field_data=None,
mixins=xml_module_store.xblock_mixins,
field_data=KvsFieldData(kvs=DictKeyValueStore()),
)
# now walk the /vertical directory where each file in there
@@ -440,7 +442,11 @@ def import_course_draft(
for descriptor in drafts[key]:
try:
def _import_module(module):
module.location = module.location.replace(revision='draft')
# Update the module's location to "draft" revision
# We need to call this method (instead of updating the location directly)
# to ensure that pure XBlock field data is updated correctly.
_update_module_location(module, module.location.replace(revision='draft'))
# make sure our parent has us in its list of children
# this is to make sure private only verticals show up
# in the list of children since they would have been
@@ -489,34 +495,15 @@ def remap_namespace(module, target_location_namespace):
# This looks a bit wonky as we need to also change the 'name' of the
# imported course to be what the caller passed in
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()
_update_module_location(
module,
module.location.replace(
tag=target_location_namespace.tag,
org=target_location_namespace.org,
course=target_location_namespace.course
)
module.location = module.location.replace(
tag=target_location_namespace.tag,
org=target_location_namespace.org,
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:
#
# module is a course module
@@ -834,3 +821,42 @@ def perform_xlint(
print("This course can be imported successfully.")
return err_cnt
def _update_module_location(module, new_location):
"""
Update a module's location.
If the module is a pure XBlock (not an XModule), then its field data
keys will need to be updated to include the new location.
Args:
module (XModuleMixin): The module to update.
new_location (Location): The new location of the module.
Returns:
None
"""
# 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 = new_location
# Pure 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()

View File

@@ -0,0 +1,3 @@
<chapter display_name="Test Chapter">
<sequential url_name="b68bb50c4f1f41a3abeec1dac309087d"/>
</chapter>

View File

@@ -0,0 +1 @@
<course url_name="2012_Fall" org="edX" course="pure_xblock_draft"/>

View File

@@ -0,0 +1,3 @@
<course display_name="Test Course" start="2014-01-01T00:00:00Z">
<chapter url_name="150311f8087e47f4858f7db44df32ee5"/>
</course>

View File

@@ -0,0 +1,3 @@
<vertical display_name="Test" parent_sequential_url="i4x://edX/pure_xblock_draft/sequential/b68bb50c4f1f41a3abeec1dac309087d" index_in_children_list="0">
<stubxblock test_field="set by xml" url_name="xblock_test" />
</vertical>

View File

@@ -0,0 +1 @@
<sequential display_name="Test Section"/>

View File

@@ -0,0 +1,3 @@
<course org="edX" course="pure_xblock_public" url_name="2012_Fall">
<stubxblock test_field="set by xml" url_name="xblock_test" />
</course>