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
OpenEdx
edx-platform
Commits
51905f0c
Commit
51905f0c
authored
Apr 01, 2015
by
Jonathan Piacenti
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Addressed notes for RCB duplication, removed management buttons from RCB container
parent
a6c00635
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
71 additions
and
40 deletions
+71
-40
cms/djangoapps/contentstore/views/item.py
+4
-5
cms/djangoapps/contentstore/views/preview.py
+2
-2
cms/templates/studio_xblock_wrapper.html
+15
-10
common/lib/xmodule/xmodule/library_content_module.py
+14
-20
common/lib/xmodule/xmodule/library_root_xblock.py
+1
-0
common/lib/xmodule/xmodule/library_tools.py
+2
-3
common/lib/xmodule/xmodule/studio_editable.py
+1
-0
common/test/acceptance/pages/studio/container.py
+14
-0
common/test/acceptance/tests/studio/test_studio_library_container.py
+18
-0
No files found.
cms/djangoapps/contentstore/views/item.py
View file @
51905f0c
...
...
@@ -593,18 +593,17 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, user, display_
runtime
=
source_item
.
runtime
,
)
handle_children
=
True
handle_parenting
=
True
children_handled
=
False
if
hasattr
(
dest_module
,
'studio_post_duplicate'
):
# Allow an XBlock to do anything fancy it may need to when duplicated from another block.
# These blocks may handle their own children or parenting if needed. Let them return booleans to
# let us know if we need to handle these or not.
handle_children
,
handle_parenting
=
dest_module
.
studio_post_duplicate
(
store
,
parent_usage_key
,
source_item
)
children_handled
=
dest_module
.
studio_post_duplicate
(
store
,
source_item
)
# 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
and
handle_children
:
if
source_item
.
has_children
and
not
children_handled
:
dest_module
.
children
=
dest_module
.
children
or
[]
for
child
in
source_item
.
children
:
dupe
=
_duplicate_item
(
dest_module
.
location
,
child
,
user
=
user
)
...
...
@@ -613,7 +612,7 @@ def _duplicate_item(parent_usage_key, duplicate_source_usage_key, user, display_
store
.
update_item
(
dest_module
,
user
.
id
)
# pylint: disable=protected-access
if
(
'detached'
not
in
source_item
.
runtime
.
load_block_type
(
category
)
.
_class_tags
)
and
handle_parenting
:
if
(
'detached'
not
in
source_item
.
runtime
.
load_block_type
(
category
)
.
_class_tags
):
parent
=
store
.
get_item
(
parent_usage_key
)
# If source was already a child of the parent, add duplicate immediately afterward.
# Otherwise, add child to end.
...
...
cms/djangoapps/contentstore/views/preview.py
View file @
51905f0c
...
...
@@ -240,7 +240,6 @@ def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False):
# Only add the Studio wrapper when on the container page. The "Pages" page will remain as is for now.
if
not
context
.
get
(
'is_pages_view'
,
None
)
and
view
in
PREVIEW_VIEWS
:
root_xblock
=
context
.
get
(
'root_xblock'
)
can_edit_visibility
=
not
isinstance
(
xblock
.
location
,
LibraryUsageLocator
)
is_root
=
root_xblock
and
xblock
.
location
==
root_xblock
.
location
is_reorderable
=
_is_xblock_reorderable
(
xblock
,
context
)
template_context
=
{
...
...
@@ -251,7 +250,8 @@ def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False):
'is_root'
:
is_root
,
'is_reorderable'
:
is_reorderable
,
'can_edit'
:
context
.
get
(
'can_edit'
,
True
),
'can_edit_visibility'
:
can_edit_visibility
,
'can_edit_visibility'
:
context
.
get
(
'can_edit_visibility'
,
True
),
'can_add'
:
context
.
get
(
'can_add'
,
True
),
}
html
=
render_to_string
(
'studio_xblock_wrapper.html'
,
template_context
)
frag
=
wrap_fragment
(
frag
,
html
)
...
...
cms/templates/studio_xblock_wrapper.html
View file @
51905f0c
...
...
@@ -80,19 +80,24 @@ messages = json.dumps(xblock.validate().to_json())
</a>
</li>
% endif
<li
class=
"action-item action-duplicate"
>
<a
href=
"#"
data-tooltip=
"${_("
Duplicate
")}"
class=
"duplicate-button action-button"
>
<i
class=
"icon fa fa-copy"
></i>
<span
class=
"sr"
>
${_("Duplicate")}
</span>
% if can_add:
<li
class=
"action-item action-duplicate"
>
<a
href=
"#"
data-tooltip=
"${_("
Duplicate
")}"
class=
"duplicate-button action-button"
>
<i
class=
"icon fa fa-copy"
></i>
<span
class=
"sr"
>
${_("Duplicate")}
</span>
</a>
</li>
% endif
% endif
% if can_add:
<!-- If we can add, we can delete. -->
<li
class=
"action-item action-delete"
>
<a
href=
"#"
data-tooltip=
"${_("
Delete
")}"
class=
"delete-button action-button"
>
<i
class=
"icon fa fa-trash-o"
></i>
<span
class=
"sr"
>
${_("Delete")}
</span>
</a>
</li>
% endif
<li
class=
"action-item action-delete"
>
<a
href=
"#"
data-tooltip=
"${_("
Delete
")}"
class=
"delete-button action-button"
>
<i
class=
"icon fa fa-trash-o"
></i>
<span
class=
"sr"
>
${_("Delete")}
</span>
</a>
</li>
% if is_reorderable:
<li
class=
"action-item action-drag"
>
<span
data-tooltip=
"${_('Drag to reorder')}"
class=
"drag-handle action"
></span>
...
...
common/lib/xmodule/xmodule/library_content_module.py
View file @
51905f0c
...
...
@@ -7,6 +7,7 @@ from lxml import etree
from
copy
import
copy
from
capa.responsetypes
import
registry
from
gettext
import
ngettext
from
lazy
import
lazy
from
.mako_module
import
MakoModuleDescriptor
from
opaque_keys.edx.locator
import
LibraryLocator
...
...
@@ -269,6 +270,7 @@ class LibraryContentModule(LibraryContentFields, XModule, StudioEditableModule):
'max_count'
:
self
.
max_count
,
'display_name'
:
self
.
display_name
or
self
.
url_name
,
}))
context
[
'can_edit_visibility'
]
=
False
self
.
render_children
(
context
,
fragment
,
can_reorder
=
False
,
can_add
=
False
)
# else: When shown on a unit page, don't show any sort of preview -
# just the status of this block in the validation area.
...
...
@@ -306,16 +308,12 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe
non_editable_fields
.
extend
([
LibraryContentFields
.
mode
,
LibraryContentFields
.
source_library_version
])
return
non_editable_fields
def
get_tools
(
self
):
@lazy
def
tools
(
self
):
"""
Grab the library tools service or raise an error.
"""
lib_tools
=
self
.
runtime
.
service
(
self
,
'library_tools'
)
if
not
lib_tools
:
# This error is diagnostic. The user won't see it, but it may be helpful
# during debugging.
return
Response
(
_
(
u"Course does not support Library tools."
),
status
=
400
)
return
lib_tools
return
self
.
runtime
.
service
(
self
,
'library_tools'
)
def
get_user_id
(
self
):
"""
...
...
@@ -343,14 +341,12 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe
the version number of the libraries used, so we easily determine if
this block is up to date or not.
"""
lib_tools
=
self
.
get_tools
()
user_perms
=
self
.
runtime
.
service
(
self
,
'studio_user_permissions'
)
user_id
=
self
.
get_user_id
()
lib_
tools
.
update_children
(
self
,
user_id
,
user_perms
)
self
.
tools
.
update_children
(
self
,
user_id
,
user_perms
)
return
Response
()
# pylint: disable=unused-argument
def
studio_post_duplicate
(
self
,
store
,
parent_usage_key
,
source_block
):
def
studio_post_duplicate
(
self
,
store
,
source_block
):
"""
Used by the studio after basic duplication of a source block. We handle the children
ourselves, because we have to properly reference the library upstream and set the overrides.
...
...
@@ -360,32 +356,30 @@ class LibraryContentDescriptor(LibraryContentFields, MakoModuleDescriptor, XmlDe
# The first task will be to refresh our copy of the library to generate the children.
# We must do this at the currently set version of the library block. Otherwise we may not have
# exactly the same children-- someone may be duplicating an out of date block, after all.
lib_tools
=
self
.
get_tools
()
user_id
=
self
.
get_user_id
()
user_perms
=
self
.
runtime
.
service
(
self
,
'studio_user_permissions'
)
# pylint: disable=no-member
lib_
tools
.
update_children
(
self
,
user_id
,
user_perms
,
version
=
self
.
source_library_version
)
self
.
tools
.
update_children
(
self
,
user_id
,
user_perms
,
version
=
self
.
source_library_version
)
# Copy over any overridden settings the course author may have applied to the blocks.
def
copy_overrides
(
source
,
dest
):
"""
Copy any overrides the user has made on blocks in this library.
"""
for
field_name
in
source
.
fields
.
keys
():
field
=
dest
.
fields
[
field_name
]
for
field
in
source
.
fields
.
itervalues
():
if
field
.
scope
==
Scope
.
settings
and
field
.
is_set_on
(
source
):
setattr
(
dest
,
field
_name
,
getattr
(
source
,
field_nam
e
))
setattr
(
dest
,
field
.
name
,
field
.
read_from
(
sourc
e
))
if
source
.
has_children
:
source_children
=
[
s
tore
.
get_item
(
source_key
)
for
source_key
in
source
.
children
]
dest_children
=
[
s
tore
.
get_item
(
dest_key
)
for
dest_key
in
dest
.
children
]
source_children
=
[
s
elf
.
runtime
.
get_block
(
source_key
)
for
source_key
in
source
.
children
]
dest_children
=
[
s
elf
.
runtime
.
get_block
(
dest_key
)
for
dest_key
in
dest
.
children
]
for
source_child
,
dest_child
in
zip
(
source_children
,
dest_children
):
copy_overrides
(
source_child
,
dest_child
)
store
.
update_item
(
dest
,
user_id
)
copy_overrides
(
source_block
,
self
)
#
Don't handle children. Handle parenting
.
return
False
,
True
#
Children have been handled
.
return
True
def
_validate_library_version
(
self
,
validation
,
lib_tools
,
version
,
library_key
):
"""
...
...
common/lib/xmodule/xmodule/library_root_xblock.py
View file @
51905f0c
...
...
@@ -82,6 +82,7 @@ class LibraryRoot(XBlock):
# Children must have a separate context from the library itself. Make a copy.
child_context
=
context
.
copy
()
child_context
[
'show_preview'
]
=
self
.
show_children_previews
child_context
[
'can_edit_visibility'
]
=
False
child
=
self
.
runtime
.
get_block
(
child_key
)
child_view_name
=
StudioEditableModule
.
get_preview_view_name
(
child
)
...
...
common/lib/xmodule/xmodule/library_tools.py
View file @
51905f0c
...
...
@@ -28,9 +28,8 @@ class LibraryToolsService(object):
if
not
isinstance
(
library_key
,
LibraryLocator
):
library_key
=
LibraryLocator
.
from_string
(
library_key
)
library_key
=
LibraryLocator
(
org
=
library_key
.
org
,
library
=
library_key
.
library
,
branch
=
library_key
.
branch
,
version_guid
=
version
)
if
version
:
library_key
.
for_version
(
version
)
try
:
return
self
.
store
.
get_library
(
library_key
,
remove_version
=
False
,
remove_branch
=
False
)
...
...
common/lib/xmodule/xmodule/studio_editable.py
View file @
51905f0c
...
...
@@ -22,6 +22,7 @@ class StudioEditableBlock(object):
for
child
in
self
.
get_children
():
# pylint: disable=no-member
if
can_reorder
:
context
[
'reorderable_items'
]
.
add
(
child
.
location
)
context
[
'can_add'
]
=
can_add
rendered_child
=
child
.
render
(
StudioEditableModule
.
get_preview_view_name
(
child
),
context
)
fragment
.
add_frag_resources
(
rendered_child
)
...
...
common/test/acceptance/pages/studio/container.py
View file @
51905f0c
...
...
@@ -407,6 +407,20 @@ class XBlockWrapper(PageObject):
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.wrapper-xblock.has-group-visibility-set'
))
.
is_present
()
@property
def
has_duplicate_button
(
self
):
"""
Returns true if this xblock has a 'duplicate' button
"""
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'a.duplicate-button'
))
@property
def
has_delete_button
(
self
):
"""
Returns true if this xblock has a 'delete' button
"""
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'a.delete-button'
))
@property
def
has_edit_visibility_button
(
self
):
"""
Returns true if this xblock has an 'edit visibility' button
...
...
common/test/acceptance/tests/studio/test_studio_library_container.py
View file @
51905f0c
...
...
@@ -290,3 +290,21 @@ class StudioLibraryContainerTest(StudioLibraryTest, UniqueCourseTest):
block
.
reset_field_val
(
"Display Name"
)
block
.
save_settings
()
self
.
assertEqual
(
block
.
name
,
name_default
)
def
test_cannot_manage
(
self
):
"""
Scenario: Given I have a library, a course and library content xblock in a course
When I go to studio unit page for library content block
And when I click the "View" link
Then I can see a preview of the blocks drawn from the library.
And I do not see a duplicate button
And I do not see a delete button
"""
block_wrapper_unit_page
=
self
.
_get_library_xblock_wrapper
(
self
.
unit_page
.
xblocks
[
0
]
.
children
[
0
])
container_page
=
block_wrapper_unit_page
.
go_to_container
()
for
block
in
container_page
.
xblocks
:
self
.
assertFalse
(
block
.
has_duplicate_button
)
self
.
assertFalse
(
block
.
has_delete_button
)
self
.
assertFalse
(
block
.
has_edit_visibility_button
)
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