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
81fecf3e
Commit
81fecf3e
authored
Jan 15, 2014
by
cahrens
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Duplicate children so as to not create a DAG.
parent
0d8d7cb3
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
67 additions
and
27 deletions
+67
-27
cms/djangoapps/contentstore/tests/test_item.py
+44
-12
cms/djangoapps/contentstore/views/item.py
+23
-15
No files found.
cms/djangoapps/contentstore/tests/test_item.py
View file @
81fecf3e
...
...
@@ -21,6 +21,7 @@ from xmodule.modulestore.django import modulestore
from
xmodule.modulestore.django
import
loc_mapper
from
xmodule.modulestore.locator
import
BlockUsageLocator
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore
import
Location
class
ItemTest
(
CourseTestCase
):
...
...
@@ -165,8 +166,12 @@ class TestDuplicateItem(ItemTest):
def
setUp
(
self
):
""" Creates the test course structure and a few components to 'duplicate'. """
super
(
TestDuplicateItem
,
self
)
.
setUp
()
# create a parent sequential
resp
=
self
.
create_xblock
(
parent_locator
=
self
.
unicode_locator
,
category
=
'sequential'
)
# Create a parent chapter (for testing children of children).
resp
=
self
.
create_xblock
(
parent_locator
=
self
.
unicode_locator
,
category
=
'chapter'
)
self
.
chapter_locator
=
self
.
response_locator
(
resp
)
# create a sequential containing a problem and an html component
resp
=
self
.
create_xblock
(
parent_locator
=
self
.
chapter_locator
,
category
=
'sequential'
)
self
.
seq_locator
=
self
.
response_locator
(
resp
)
# create problem and an html component
...
...
@@ -176,15 +181,21 @@ class TestDuplicateItem(ItemTest):
resp
=
self
.
create_xblock
(
parent_locator
=
self
.
seq_locator
,
category
=
'html'
)
self
.
html_locator
=
self
.
response_locator
(
resp
)
# Create a second sequential just (testing children of children)
self
.
create_xblock
(
parent_locator
=
self
.
chapter_locator
,
category
=
'sequential2'
)
def
test_duplicate_equality
(
self
):
"""
Tests that a duplicated xblock is identical to the original,
except for location and display name.
"""
def
verify_duplicate
(
source_locator
,
parent_locator
):
def
duplicate_and_verify
(
source_locator
,
parent_locator
):
locator
=
self
.
_duplicate_item
(
parent_locator
,
source_locator
)
self
.
assertTrue
(
check_equality
(
source_locator
,
locator
),
"Duplicated item differs from original"
)
def
check_equality
(
source_locator
,
duplicate_locator
):
original_item
=
self
.
get_item_from_modulestore
(
source_locator
,
draft
=
True
)
duplicated_item
=
self
.
get_item_from_modulestore
(
locator
,
draft
=
True
)
duplicated_item
=
self
.
get_item_from_modulestore
(
duplicate_
locator
,
draft
=
True
)
self
.
assertNotEqual
(
original_item
.
location
,
...
...
@@ -194,11 +205,32 @@ class TestDuplicateItem(ItemTest):
# Set the location and display name to be the same so we can make sure the rest of the duplicate is equal.
duplicated_item
.
location
=
original_item
.
location
duplicated_item
.
display_name
=
original_item
.
display_name
self
.
assertEqual
(
original_item
,
duplicated_item
,
"Duplicated item differs from original"
)
verify_duplicate
(
self
.
problem_locator
,
self
.
seq_locator
)
verify_duplicate
(
self
.
html_locator
,
self
.
seq_locator
)
verify_duplicate
(
self
.
seq_locator
,
self
.
unicode_locator
)
# Children will also be duplicated, so for the purposes of testing equality, we will set
# the children to the original after recursively checking the children.
if
original_item
.
has_children
:
self
.
assertEqual
(
len
(
original_item
.
children
),
len
(
duplicated_item
.
children
),
"Duplicated item differs in number of children"
)
for
i
in
xrange
(
len
(
original_item
.
children
)):
source_locator
=
loc_mapper
()
.
translate_location
(
self
.
course
.
location
.
course_id
,
Location
(
original_item
.
children
[
i
]),
False
,
True
)
duplicate_locator
=
loc_mapper
()
.
translate_location
(
self
.
course
.
location
.
course_id
,
Location
(
duplicated_item
.
children
[
i
]),
False
,
True
)
if
not
check_equality
(
source_locator
,
duplicate_locator
):
return
False
duplicated_item
.
children
=
original_item
.
children
return
original_item
==
duplicated_item
duplicate_and_verify
(
self
.
problem_locator
,
self
.
seq_locator
)
duplicate_and_verify
(
self
.
html_locator
,
self
.
seq_locator
)
duplicate_and_verify
(
self
.
seq_locator
,
self
.
chapter_locator
)
duplicate_and_verify
(
self
.
chapter_locator
,
self
.
unicode_locator
)
def
test_ordering
(
self
):
"""
...
...
@@ -224,7 +256,7 @@ class TestDuplicateItem(ItemTest):
"source item at wrong position"
)
self
.
assertEqual
(
children
[
source_position
+
1
],
children
[
source_position
+
1
],
self
.
get_old_id
(
locator
)
.
url
(),
"duplicated item not ordered after source item"
)
...
...
@@ -232,7 +264,7 @@ class TestDuplicateItem(ItemTest):
verify_order
(
self
.
problem_locator
,
self
.
seq_locator
,
0
)
# 2 because duplicate of problem should be located before.
verify_order
(
self
.
html_locator
,
self
.
seq_locator
,
2
)
verify_order
(
self
.
seq_locator
,
self
.
unicode
_locator
,
0
)
verify_order
(
self
.
seq_locator
,
self
.
chapter
_locator
,
0
)
# Test duplicating something into a location that is not the parent of the original item.
# Duplicated item should appear at the end.
...
...
@@ -257,10 +289,10 @@ class TestDuplicateItem(ItemTest):
verify_name
(
self
.
html_locator
,
self
.
seq_locator
,
"Duplicate of 'Text'"
)
# The sequence does not have a display_name set, so None gets included as the string 'None'.
verify_name
(
self
.
seq_locator
,
self
.
unicode
_locator
,
"Duplicate of 'None'"
)
verify_name
(
self
.
seq_locator
,
self
.
chapter
_locator
,
"Duplicate of 'None'"
)
# Now send a custom display name for the duplicate.
verify_name
(
self
.
seq_locator
,
self
.
unicode
_locator
,
"customized name"
,
display_name
=
"customized name"
)
verify_name
(
self
.
seq_locator
,
self
.
chapter
_locator
,
"customized name"
,
display_name
=
"customized name"
)
def
_duplicate_item
(
self
,
parent_locator
,
source_locator
,
display_name
=
None
):
data
=
{
...
...
cms/djangoapps/contentstore/views/item.py
View file @
81fecf3e
...
...
@@ -19,6 +19,7 @@ from xmodule.modulestore.django import modulestore, loc_mapper
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
,
InvalidLocationError
from
xmodule.modulestore.inheritance
import
own_metadata
from
xmodule.modulestore.locator
import
BlockUsageLocator
from
xmodule.modulestore
import
Location
from
xmodule.x_module
import
prefer_xmodules
from
util.json_request
import
expect_json
,
JsonResponse
...
...
@@ -138,12 +139,19 @@ def xblock_handler(request, tag=None, package_id=None, branch=None, version_guid
if
'duplicate_source_locator'
in
request
.
json
:
parent_locator
=
BlockUsageLocator
(
request
.
json
[
'parent_locator'
])
duplicate_source_locator
=
BlockUsageLocator
(
request
.
json
[
'duplicate_source_locator'
])
new_locator
=
_duplicate_item
(
parent_locator
,
duplicate_source_locator
,
# _duplicate_item is dealing with locations to facilitate the recursive call for
# duplicating children.
parent_location
=
loc_mapper
()
.
translate_locator_to_location
(
parent_locator
)
duplicate_source_location
=
loc_mapper
()
.
translate_locator_to_location
(
duplicate_source_locator
)
dest_location
=
_duplicate_item
(
parent_location
,
duplicate_source_location
,
request
.
json
.
get
(
'display_name'
)
)
return
JsonResponse
({
"locator"
:
unicode
(
new_locator
)})
course_location
=
loc_mapper
()
.
translate_locator_to_location
(
BlockUsageLocator
(
parent_locator
),
get_course
=
True
)
dest_locator
=
loc_mapper
()
.
translate_location
(
course_location
.
course_id
,
dest_location
,
False
,
True
)
return
JsonResponse
({
"locator"
:
unicode
(
dest_locator
)})
else
:
return
_create_item
(
request
)
else
:
...
...
@@ -300,13 +308,10 @@ def _create_item(request):
return
JsonResponse
({
"locator"
:
unicode
(
locator
)})
def
_duplicate_item
(
parent_locat
or
,
duplicate_source_locator
,
display_nam
e
):
def
_duplicate_item
(
parent_locat
ion
,
duplicate_source_location
,
display_name
=
Non
e
):
"""
Duplicate an existing xblock as a child of the supplied parent_locat
or
.
Duplicate an existing xblock as a child of the supplied parent_locat
ion
.
"""
parent_location
=
loc_mapper
()
.
translate_locator_to_location
(
parent_locator
)
duplicate_source_location
=
loc_mapper
()
.
translate_locator_to_location
(
duplicate_source_locator
)
store
=
get_modulestore
(
duplicate_source_location
)
source_item
=
store
.
get_item
(
duplicate_source_location
)
# Change the blockID to be unique.
...
...
@@ -327,9 +332,13 @@ def _duplicate_item(parent_locator, duplicate_source_locator, display_name):
system
=
source_item
.
system
if
hasattr
(
source_item
,
'system'
)
else
None
,
)
# Children are not automatically copied over. Not all xblocks have a 'children' attribute.
if
hasattr
(
source_item
,
'children'
):
get_modulestore
(
dest_location
)
.
update_children
(
dest_location
,
source_item
.
children
)
# Children are not automatically copied over (and not all xblocks have a 'children' attribute).
# Because DAGs are not fully supported, we need to actually duplicate each child as well.
if
source_item
.
has_children
:
copied_children
=
[]
for
child
in
source_item
.
children
:
copied_children
.
append
(
_duplicate_item
(
dest_location
,
Location
(
child
))
.
url
())
get_modulestore
(
dest_location
)
.
update_children
(
dest_location
,
copied_children
)
if
category
not
in
DETACHED_CATEGORIES
:
parent
=
get_modulestore
(
parent_location
)
.
get_item
(
parent_location
)
...
...
@@ -337,13 +346,12 @@ def _duplicate_item(parent_locator, duplicate_source_locator, display_name):
# Otherwise, add child to end.
if
duplicate_source_location
.
url
()
in
parent
.
children
:
source_index
=
parent
.
children
.
index
(
duplicate_source_location
.
url
())
parent
.
children
.
insert
(
source_index
+
1
,
dest_location
.
url
())
parent
.
children
.
insert
(
source_index
+
1
,
dest_location
.
url
())
else
:
parent
.
children
.
append
(
dest_location
.
url
())
get_modulestore
(
parent_location
)
.
update_children
(
parent_location
,
parent
.
children
)
course_location
=
loc_mapper
()
.
translate_locator_to_location
(
BlockUsageLocator
(
parent_locator
),
get_course
=
True
)
return
loc_mapper
()
.
translate_location
(
course_location
.
course_id
,
dest_location
,
False
,
True
)
return
dest_location
def
_delete_item_at_location
(
item_location
,
delete_children
=
False
,
delete_all_versions
=
False
):
...
...
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