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
6d82cf09
Commit
6d82cf09
authored
Jul 25, 2014
by
cahrens
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Correct publish titles, code review feedback.
parent
ef581e11
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
196 additions
and
96 deletions
+196
-96
cms/djangoapps/contentstore/tests/test_contentstore.py
+1
-1
cms/djangoapps/contentstore/utils.py
+1
-1
cms/djangoapps/contentstore/views/component.py
+0
-4
cms/djangoapps/contentstore/views/item.py
+14
-4
cms/djangoapps/contentstore/views/tests/test_course_index.py
+3
-0
cms/djangoapps/contentstore/views/tests/test_item.py
+52
-22
cms/static/js/models/xblock_info.js
+2
-1
cms/static/js/spec/views/pages/container_subviews_spec.js
+51
-16
cms/static/js/spec/views/pages/course_outline_spec.js
+2
-0
cms/static/js/views/pages/container_subviews.js
+0
-1
cms/static/js/views/utils/xblock_utils.js
+15
-2
cms/static/js/views/xblock_outline.js
+1
-0
cms/templates/course_outline.html
+1
-1
cms/templates/js/course-outline.underscore
+7
-15
cms/templates/js/publish-xblock.underscore
+3
-3
cms/templates/js/unit-outline.underscore
+1
-11
common/test/acceptance/pages/studio/html_component_editor.py
+0
-1
common/test/acceptance/tests/test_studio_container.py
+42
-13
No files found.
cms/djangoapps/contentstore/tests/test_contentstore.py
View file @
6d82cf09
...
...
@@ -1209,7 +1209,7 @@ class ContentStoreTest(ContentStoreTestCase):
resp
=
self
.
_show_course_overview
(
course
.
id
)
self
.
assertContains
(
resp
,
'<article class="outline" data-locator="{locator}" data-course-key="{course_key}">'
.
format
(
'<article class="outline
outline-course
" data-locator="{locator}" data-course-key="{course_key}">'
.
format
(
locator
=
'i4x://MITx/999/course/Robot_Super_Course'
,
course_key
=
'MITx/999/Robot_Super_Course'
,
),
...
...
cms/djangoapps/contentstore/utils.py
View file @
6d82cf09
...
...
@@ -149,7 +149,7 @@ def course_image_url(course):
path
=
loc
.
to_deprecated_string
()
return
path
# pylint: disable=invalid-name
def
is_currently_visible_to_students
(
xblock
):
"""
Returns true if there is a published version of the xblock that is currently visible to students.
...
...
cms/djangoapps/contentstore/views/component.py
View file @
6d82cf09
...
...
@@ -178,10 +178,6 @@ def container_handler(request, usage_key_string):
# about the block's ancestors and siblings for use by the Unit Outline.
xblock_info
=
create_xblock_info
(
xblock
,
include_ancestor_info
=
is_unit_page
)
# On the unit page only, add 'has_changes' to indicate when there are changes that can be discarded.
if
is_unit_page
:
xblock_info
[
'has_changes'
]
=
modulestore
()
.
has_changes
(
xblock
.
location
)
# Create the link for preview.
preview_lms_base
=
settings
.
FEATURES
.
get
(
'PREVIEW_LMS_BASE'
)
# need to figure out where this item is in the list of children as the
...
...
cms/djangoapps/contentstore/views/item.py
View file @
6d82cf09
...
...
@@ -632,6 +632,9 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
published
=
modulestore
()
.
has_item
(
xblock
.
location
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
)
currently_visible_to_students
=
is_currently_visible_to_students
(
xblock
)
is_xblock_unit
=
is_unit
(
xblock
)
is_unit_with_changes
=
is_xblock_unit
and
modulestore
()
.
has_changes
(
xblock
.
location
)
xblock_info
=
{
"id"
:
unicode
(
xblock
.
location
),
"display_name"
:
xblock
.
display_name_with_default
,
...
...
@@ -646,7 +649,7 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
"release_date"
:
release_date
,
"release_date_from"
:
_get_release_date_from
(
xblock
)
if
release_date
else
None
,
"currently_visible_to_students"
:
currently_visible_to_students
,
"visibility_state"
:
_compute_visibility_state
(
xblock
,
child_info
)
if
not
xblock
.
category
==
'course'
else
None
"visibility_state"
:
_compute_visibility_state
(
xblock
,
child_info
,
is_unit_with_changes
)
if
not
xblock
.
category
==
'course'
else
None
}
if
data
is
not
None
:
xblock_info
[
"data"
]
=
data
...
...
@@ -656,6 +659,11 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
xblock_info
[
'ancestor_info'
]
=
_create_xblock_ancestor_info
(
xblock
)
if
child_info
:
xblock_info
[
'child_info'
]
=
child_info
# On the unit page only, add 'has_changes' to indicate when there are changes that can be discarded.
# We don't add it in general because it is an expensive operation.
if
is_xblock_unit
:
xblock_info
[
'has_changes'
]
=
is_unit_with_changes
return
xblock_info
...
...
@@ -680,18 +688,20 @@ class VisibilityState(object):
"""
live
=
'live'
ready
=
'ready'
unscheduled
=
'unscheduled'
# unscheduled
unscheduled
=
'unscheduled'
needs_attention
=
'needs_attention'
staff_only
=
'staff_only'
def
_compute_visibility_state
(
xblock
,
child_info
):
def
_compute_visibility_state
(
xblock
,
child_info
,
is_unit_with_changes
):
"""
Returns the current publish state for the specified xblock and its children
"""
if
xblock
.
visible_to_staff_only
:
return
VisibilityState
.
staff_only
elif
is_unit
(
xblock
)
and
modulestore
()
.
has_changes
(
xblock
.
location
):
elif
is_unit_with_changes
:
# Note that a unit that has never been published will fall into this category,
# as well as previously published units with draft content.
return
VisibilityState
.
needs_attention
is_unscheduled
=
xblock
.
start
==
DEFAULT_START_DATE
is_live
=
datetime
.
now
(
UTC
)
>
xblock
.
start
...
...
cms/djangoapps/contentstore/views/tests/test_course_index.py
View file @
6d82cf09
...
...
@@ -231,6 +231,7 @@ class TestCourseOutline(CourseTestCase):
self
.
assertEqual
(
json_response
[
'category'
],
'course'
)
self
.
assertEqual
(
json_response
[
'id'
],
'i4x://MITx/999/course/Robot_Super_Course'
)
self
.
assertEqual
(
json_response
[
'display_name'
],
'Robot Super Course'
)
self
.
assertTrue
(
json_response
[
'published'
])
self
.
assertIsNone
(
json_response
[
'visibility_state'
])
# Now verify the first child
...
...
@@ -240,6 +241,7 @@ class TestCourseOutline(CourseTestCase):
self
.
assertEqual
(
first_child_response
[
'category'
],
'chapter'
)
self
.
assertEqual
(
first_child_response
[
'id'
],
'i4x://MITx/999/chapter/Week_1'
)
self
.
assertEqual
(
first_child_response
[
'display_name'
],
'Week 1'
)
self
.
assertTrue
(
json_response
[
'published'
])
self
.
assertEqual
(
first_child_response
[
'visibility_state'
],
VisibilityState
.
unscheduled
)
self
.
assertTrue
(
len
(
first_child_response
[
'child_info'
][
'children'
])
>
0
)
...
...
@@ -253,6 +255,7 @@ class TestCourseOutline(CourseTestCase):
self
.
assertIsNotNone
(
json_response
[
'display_name'
])
self
.
assertIsNotNone
(
json_response
[
'id'
])
self
.
assertIsNotNone
(
json_response
[
'category'
])
self
.
assertTrue
(
json_response
[
'published'
])
if
json_response
.
get
(
'child_info'
,
None
):
for
child_response
in
json_response
[
'child_info'
][
'children'
]:
self
.
assert_correct_json_response
(
child_response
)
...
...
cms/djangoapps/contentstore/views/tests/test_item.py
View file @
6d82cf09
...
...
@@ -531,8 +531,25 @@ class TestEditItem(ItemTest):
self
.
assertEqual
(
unit2_usage_key
,
children
[
1
])
def
_is_location_published
(
self
,
location
):
"""
Returns whether or not the item with given location has a published version.
"""
return
modulestore
()
.
has_item
(
location
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
)
def
_verify_published_with_no_draft
(
self
,
location
):
"""
Verifies the item with given location has a published version and no draft (unpublished changes).
"""
self
.
assertTrue
(
self
.
_is_location_published
(
location
))
self
.
assertFalse
(
modulestore
()
.
has_changes
(
location
))
def
_verify_published_with_draft
(
self
,
location
):
"""
Verifies the item with given location has a published version and also a draft version (unpublished changes).
"""
self
.
assertTrue
(
self
.
_is_location_published
(
location
))
self
.
assertTrue
(
modulestore
()
.
has_changes
(
location
))
def
test_make_public
(
self
):
""" Test making a private problem public (publishing it). """
# When the problem is first created, it is only in draft (because of its category).
...
...
@@ -541,7 +558,7 @@ class TestEditItem(ItemTest):
self
.
problem_update_url
,
data
=
{
'publish'
:
'make_public'
}
)
self
.
assertTrue
(
self
.
_is_location_published
(
self
.
problem_usage_key
)
)
self
.
_verify_published_with_no_draft
(
self
.
problem_usage_key
)
def
test_make_draft
(
self
):
""" Test creating a draft version of a public problem. """
...
...
@@ -554,17 +571,13 @@ class TestEditItem(ItemTest):
self
.
problem_update_url
,
data
=
{
'publish'
:
'discard_changes'
}
)
self
.
assertTrue
(
self
.
_is_location_published
(
self
.
problem_usage_key
)
)
self
.
_verify_published_with_no_draft
(
self
.
problem_usage_key
)
published
=
modulestore
()
.
get_item
(
self
.
problem_usage_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
)
self
.
assertIsNone
(
published
.
due
)
def
test_republish
(
self
):
""" Test republishing an item. """
new_display_name
=
'New Display Name'
republish_data
=
{
'publish'
:
'republish'
,
'display_name'
:
new_display_name
}
# When the problem is first created, it is only in draft (because of its category).
self
.
assertFalse
(
self
.
_is_location_published
(
self
.
problem_usage_key
))
...
...
@@ -600,7 +613,7 @@ class TestEditItem(ItemTest):
}
}
)
self
.
assertTrue
(
self
.
_is_location_published
(
self
.
problem_usage_key
)
)
self
.
_verify_published_with_no_draft
(
self
.
problem_usage_key
)
published
=
modulestore
()
.
get_item
(
self
.
problem_usage_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
...
...
@@ -616,7 +629,7 @@ class TestEditItem(ItemTest):
self
.
problem_update_url
,
data
=
{
'publish'
:
'make_public'
}
)
self
.
assertTrue
(
self
.
_is_location_published
(
self
.
problem_usage_key
)
)
self
.
_verify_published_with_no_draft
(
self
.
problem_usage_key
)
published
=
modulestore
()
.
get_item
(
self
.
problem_usage_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
)
# Update the draft version and check that published is different.
...
...
@@ -651,7 +664,7 @@ class TestEditItem(ItemTest):
self
.
problem_update_url
,
data
=
{
'publish'
:
'make_public'
}
)
self
.
assertTrue
(
self
.
_is_location_published
(
self
.
problem_usage_key
)
)
self
.
_verify_published_with_no_draft
(
self
.
problem_usage_key
)
published
=
modulestore
()
.
get_item
(
self
.
problem_usage_key
,
revision
=
ModuleStoreEnum
.
RevisionOption
.
published_only
)
# Now make a draft
...
...
@@ -706,8 +719,8 @@ class TestEditItem(ItemTest):
data
=
{
'publish'
:
'make_public'
}
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertTrue
(
self
.
_is_location_published
(
unit_usage_key
)
)
self
.
assertTrue
(
self
.
_is_location_published
(
html_usage_key
)
)
self
.
_verify_published_with_no_draft
(
unit_usage_key
)
self
.
_verify_published_with_no_draft
(
html_usage_key
)
# Make a draft for the unit and verify that the problem also has a draft
resp
=
self
.
client
.
ajax_post
(
...
...
@@ -718,10 +731,8 @@ class TestEditItem(ItemTest):
}
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertTrue
(
self
.
_is_location_published
(
unit_usage_key
))
self
.
assertTrue
(
self
.
_is_location_published
(
html_usage_key
))
self
.
assertTrue
(
modulestore
()
.
get_item
(
unit_usage_key
)
.
has_changes
())
self
.
assertTrue
(
modulestore
()
.
get_item
(
html_usage_key
)
.
has_changes
())
self
.
_verify_published_with_draft
(
unit_usage_key
)
self
.
_verify_published_with_draft
(
html_usage_key
)
class
TestEditSplitModule
(
ItemTest
):
...
...
@@ -1143,6 +1154,7 @@ class TestXBlockInfo(ItemTest):
self
.
assertEqual
(
xblock_info
[
'category'
],
'course'
)
self
.
assertEqual
(
xblock_info
[
'id'
],
'i4x://MITx/999/course/Robot_Super_Course'
)
self
.
assertEqual
(
xblock_info
[
'display_name'
],
'Robot Super Course'
)
self
.
assertTrue
(
xblock_info
[
'published'
])
# Finally, validate the entire response for consistency
self
.
validate_xblock_info_consistency
(
xblock_info
,
has_child_info
=
has_child_info
)
...
...
@@ -1154,6 +1166,7 @@ class TestXBlockInfo(ItemTest):
self
.
assertEqual
(
xblock_info
[
'category'
],
'chapter'
)
self
.
assertEqual
(
xblock_info
[
'id'
],
'i4x://MITx/999/chapter/Week_1'
)
self
.
assertEqual
(
xblock_info
[
'display_name'
],
'Week 1'
)
self
.
assertTrue
(
xblock_info
[
'published'
])
self
.
assertEqual
(
xblock_info
[
'edited_by'
],
'testuser'
)
# Finally, validate the entire response for consistency
...
...
@@ -1166,6 +1179,7 @@ class TestXBlockInfo(ItemTest):
self
.
assertEqual
(
xblock_info
[
'category'
],
'sequential'
)
self
.
assertEqual
(
xblock_info
[
'id'
],
'i4x://MITx/999/sequential/Lesson_1'
)
self
.
assertEqual
(
xblock_info
[
'display_name'
],
'Lesson 1'
)
self
.
assertTrue
(
xblock_info
[
'published'
])
self
.
assertEqual
(
xblock_info
[
'edited_by'
],
'testuser'
)
# Finally, validate the entire response for consistency
...
...
@@ -1178,6 +1192,7 @@ class TestXBlockInfo(ItemTest):
self
.
assertEqual
(
xblock_info
[
'category'
],
'vertical'
)
self
.
assertEqual
(
xblock_info
[
'id'
],
'i4x://MITx/999/vertical/Unit_1'
)
self
.
assertEqual
(
xblock_info
[
'display_name'
],
'Unit 1'
)
self
.
assertTrue
(
xblock_info
[
'published'
])
self
.
assertEqual
(
xblock_info
[
'edited_by'
],
'testuser'
)
# Validate that the correct ancestor info has been included
...
...
@@ -1199,6 +1214,7 @@ class TestXBlockInfo(ItemTest):
self
.
assertEqual
(
xblock_info
[
'category'
],
'video'
)
self
.
assertEqual
(
xblock_info
[
'id'
],
'i4x://MITx/999/video/My_Video'
)
self
.
assertEqual
(
xblock_info
[
'display_name'
],
'My Video'
)
self
.
assertTrue
(
xblock_info
[
'published'
])
self
.
assertEqual
(
xblock_info
[
'edited_by'
],
'testuser'
)
# Finally, validate the entire response for consistency
...
...
@@ -1211,6 +1227,7 @@ class TestXBlockInfo(ItemTest):
self
.
assertIsNotNone
(
xblock_info
[
'display_name'
])
self
.
assertIsNotNone
(
xblock_info
[
'id'
])
self
.
assertIsNotNone
(
xblock_info
[
'category'
])
self
.
assertTrue
(
xblock_info
[
'published'
])
self
.
assertEqual
(
xblock_info
[
'edited_by'
],
'testuser'
)
if
has_ancestor_info
:
self
.
assertIsNotNone
(
xblock_info
.
get
(
'ancestor_info'
,
None
))
...
...
@@ -1243,14 +1260,17 @@ class TestXBlockPublishingInfo(ItemTest):
SECOND_UNIT_PATH
=
[
0
,
1
]
def
_create_child
(
self
,
parent
,
category
,
display_name
,
publish_item
=
False
,
staff_only
=
False
):
"""
Creates a child xblock for the given parent.
"""
return
ItemFactory
.
create
(
parent_location
=
parent
.
location
,
category
=
category
,
display_name
=
display_name
,
user_id
=
self
.
user
.
id
,
publish_item
=
publish_item
,
visible_to_staff_only
=
staff_only
)
def
_get_child
(
self
,
xblock_info
,
index
):
def
_get_child
_xblock_info
(
self
,
xblock_info
,
index
):
"""
Returns the child at the specified index.
Returns the child
xblock info
at the specified index.
"""
children
=
xblock_info
[
'child_info'
][
'children'
]
self
.
assertTrue
(
len
(
children
)
>
index
)
...
...
@@ -1293,12 +1313,12 @@ class TestXBlockPublishingInfo(ItemTest):
def
_verify_visibility_state
(
self
,
xblock_info
,
expected_state
,
path
=
None
):
"""
Verify the publish state of an item in the xblock_info. If no path is provided
then the root item
is
verified.
then the root item
will be
verified.
"""
if
path
:
direct_child
=
self
.
_get_child
(
xblock_info
,
path
[
0
])
direct_child
_xblock_info
=
self
.
_get_child_xblock_info
(
xblock_info
,
path
[
0
])
remaining_path
=
path
[
1
:]
if
len
(
path
)
>
1
else
None
self
.
_verify_visibility_state
(
direct_child
,
expected_state
,
remaining_path
)
self
.
_verify_visibility_state
(
direct_child
_xblock_info
,
expected_state
,
remaining_path
)
else
:
self
.
assertEqual
(
xblock_info
[
'visibility_state'
],
expected_state
)
...
...
@@ -1311,10 +1331,13 @@ class TestXBlockPublishingInfo(ItemTest):
chapter
=
self
.
_create_child
(
self
.
course
,
'chapter'
,
"Test Chapter"
)
self
.
_create_child
(
chapter
,
'sequential'
,
"Empty Sequential"
)
xblock_info
=
self
.
_get_xblock_info
(
chapter
.
location
)
self
.
assertEqual
(
xblock_info
[
'visibility_state'
]
,
VisibilityState
.
unscheduled
)
self
.
assertEqual
(
self
.
_get_child
(
xblock_info
,
0
)[
'visibility_state'
],
VisibilityState
.
unscheduled
)
self
.
_verify_visibility_state
(
xblock_info
,
VisibilityState
.
unscheduled
)
self
.
_verify_visibility_state
(
xblock_info
,
VisibilityState
.
unscheduled
,
path
=
self
.
FIRST_SUBSECTION_PATH
)
def
test_published_unit
(
self
):
"""
Tests the visibility state of a published unit with release date in the future.
"""
chapter
=
self
.
_create_child
(
self
.
course
,
'chapter'
,
"Test Chapter"
)
sequential
=
self
.
_create_child
(
chapter
,
'sequential'
,
"Test Sequential"
)
self
.
_create_child
(
sequential
,
'vertical'
,
"Published Unit"
,
publish_item
=
True
)
...
...
@@ -1327,6 +1350,9 @@ class TestXBlockPublishingInfo(ItemTest):
self
.
_verify_visibility_state
(
xblock_info
,
VisibilityState
.
staff_only
,
path
=
self
.
SECOND_UNIT_PATH
)
def
test_released_unit
(
self
):
"""
Tests the visibility state of a published unit with release date in the past.
"""
chapter
=
self
.
_create_child
(
self
.
course
,
'chapter'
,
"Test Chapter"
)
sequential
=
self
.
_create_child
(
chapter
,
'sequential'
,
"Test Sequential"
)
self
.
_create_child
(
sequential
,
'vertical'
,
"Published Unit"
,
publish_item
=
True
)
...
...
@@ -1339,10 +1365,14 @@ class TestXBlockPublishingInfo(ItemTest):
self
.
_verify_visibility_state
(
xblock_info
,
VisibilityState
.
staff_only
,
path
=
self
.
SECOND_UNIT_PATH
)
def
test_unpublished_changes
(
self
):
"""
Tests the visibility state of a published unit with draft (unpublished) changes.
"""
chapter
=
self
.
_create_child
(
self
.
course
,
'chapter'
,
"Test Chapter"
)
sequential
=
self
.
_create_child
(
chapter
,
'sequential'
,
"Test Sequential"
)
unit
=
self
.
_create_child
(
sequential
,
'vertical'
,
"Published Unit"
,
publish_item
=
True
)
self
.
_create_child
(
sequential
,
'vertical'
,
"Staff Only Unit"
,
staff_only
=
True
)
# Setting the display name creates a draft version of unit.
self
.
_set_display_name
(
unit
.
location
,
'Updated Unit'
)
xblock_info
=
self
.
_get_xblock_info
(
chapter
.
location
)
self
.
_verify_visibility_state
(
xblock_info
,
VisibilityState
.
needs_attention
)
...
...
cms/static/js/models/xblock_info.js
View file @
6d82cf09
...
...
@@ -46,7 +46,8 @@ define(["backbone", "underscore", "js/utils/module"], function(Backbone, _, Modu
"published_by"
:
null
,
/**
* True if the xblock has changes.
* Note: this is not always provided as a performance optimization.
* Note: this is not always provided as a performance optimization. It is only provided for
* verticals functioning as units.
*/
"has_changes"
:
null
,
/**
...
...
cms/static/js/spec/views/pages/container_subviews_spec.js
View file @
6d82cf09
...
...
@@ -27,7 +27,7 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
category
:
'vertical'
,
published
:
false
,
has_changes
:
false
,
visibility_state
:
'unscheduled'
,
visibility_state
:
VisibilityState
.
unscheduled
,
edited_on
:
"Jul 02, 2014 at 14:20 UTC"
,
edited_by
:
"joe"
,
published_on
:
"Jul 01, 2014 at 12:45 UTC"
,
published_by
:
"amako"
,
currently_visible_to_students
:
false
...
...
@@ -116,13 +116,15 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
liveClass
=
"is-live"
,
readyClass
=
"is-ready"
,
staffOnlyClass
=
"is-staff-only"
,
scheduledClass
=
"is-scheduled"
,
unscheduledClass
=
""
,
hasWarningsClass
=
'has-warnings'
,
publishButtonCss
=
".action-publish"
,
discardChangesButtonCss
=
".action-discard"
,
lastDraftCss
=
".wrapper-last-draft"
,
releaseDateTitleCss
=
".wrapper-release .title"
,
releaseDateContentCss
=
".wrapper-release .copy"
,
promptSpies
,
sendDiscardChangesToServer
;
promptSpies
,
sendDiscardChangesToServer
,
verifyPublishingBitUnscheduled
;
sendDiscardChangesToServer
=
function
()
{
// Helper function to do the discard operation, up until the server response.
...
...
@@ -143,45 +145,75 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
);
};
verifyPublishingBitUnscheduled
=
function
()
{
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
liveClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
readyClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
hasWarningsClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
staffOnlyClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
scheduledClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
unscheduledClass
);
};
beforeEach
(
function
()
{
promptSpies
=
spyOnConstructor
(
Prompt
,
"Warning"
,
[
"show"
,
"hide"
]);
promptSpies
.
show
.
andReturn
(
this
.
promptSpies
);
});
it
(
'renders correctly with
unscheduled
content'
,
function
()
{
it
(
'renders correctly with
private
content'
,
function
()
{
var
verifyPrivateState
=
function
()
{
expect
(
containerPage
.
$
(
headerCss
).
text
()).
toContain
(
'Draft (Never published)'
);
expect
(
containerPage
.
$
(
publishButtonCss
)).
not
.
toHaveClass
(
disabledCss
);
expect
(
containerPage
.
$
(
discardChangesButtonCss
)).
toHaveClass
(
disabledCss
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
readyClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
scheduledClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
hasWarningsClass
);
};
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
fetch
({
published
:
false
,
has_changes
:
false
});
fetch
({
published
:
false
,
has_changes
:
false
,
visibility_state
:
VisibilityState
.
needsAttention
});
verifyPrivateState
();
fetch
({
published
:
false
,
has_changes
:
true
});
fetch
({
published
:
false
,
has_changes
:
true
,
visibility_state
:
VisibilityState
.
needsAttention
});
verifyPrivateState
();
});
it
(
'renders correctly with published content'
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
fetch
({
published
:
true
,
has_changes
:
false
,
visibility_state
:
VisibilityState
.
ready
});
fetch
({
published
:
true
,
has_changes
:
false
,
visibility_state
:
VisibilityState
.
ready
,
release_date
:
"Jul 02, 2030 at 14:20 UTC"
});
expect
(
containerPage
.
$
(
headerCss
).
text
()).
toContain
(
'Published'
);
expect
(
containerPage
.
$
(
publishButtonCss
)).
toHaveClass
(
disabledCss
);
expect
(
containerPage
.
$
(
discardChangesButtonCss
)).
toHaveClass
(
disabledCss
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
readyClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
scheduledClass
);
fetch
({
published
:
true
,
has_changes
:
true
,
visibility_state
:
VisibilityState
.
needsAttention
});
fetch
({
published
:
true
,
has_changes
:
true
,
visibility_state
:
VisibilityState
.
needsAttention
,
release_date
:
"Jul 02, 2030 at 14:20 UTC"
});
expect
(
containerPage
.
$
(
headerCss
).
text
()).
toContain
(
'Draft (Unpublished changes)'
);
expect
(
containerPage
.
$
(
publishButtonCss
)).
not
.
toHaveClass
(
disabledCss
);
expect
(
containerPage
.
$
(
discardChangesButtonCss
)).
not
.
toHaveClass
(
disabledCss
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
hasWarningsClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
scheduledClass
);
fetch
({
published
:
true
,
has_changes
:
false
,
visibility_state
:
VisibilityState
.
live
});
fetch
({
published
:
true
,
has_changes
:
false
,
visibility_state
:
VisibilityState
.
live
,
release_date
:
"Jul 02, 1990 at 14:20 UTC"
});
expect
(
containerPage
.
$
(
headerCss
).
text
()).
toContain
(
'Published and Live'
);
expect
(
containerPage
.
$
(
publishButtonCss
)).
toHaveClass
(
disabledCss
);
expect
(
containerPage
.
$
(
discardChangesButtonCss
)).
toHaveClass
(
disabledCss
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
liveClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
scheduledClass
);
fetch
({
published
:
true
,
has_changes
:
false
,
visibility_state
:
VisibilityState
.
unscheduled
,
release_date
:
null
});
expect
(
containerPage
.
$
(
headerCss
).
text
()).
toContain
(
'Published'
);
expect
(
containerPage
.
$
(
publishButtonCss
)).
toHaveClass
(
disabledCss
);
expect
(
containerPage
.
$
(
discardChangesButtonCss
)).
toHaveClass
(
disabledCss
);
verifyPublishingBitUnscheduled
();
});
it
(
'can publish private content'
,
function
()
{
...
...
@@ -217,7 +249,7 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
it
(
'does not refresh if publish fails'
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
readyClass
);
verifyPublishingBitUnscheduled
(
);
// Click publish
containerPage
.
$
(
publishButtonCss
).
click
();
...
...
@@ -228,8 +260,8 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
expect
(
requests
.
length
).
toEqual
(
numRequests
);
// Verify still in draft state.
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
readyClass
);
// Verify still in draft
(unscheduled)
state.
verifyPublishingBitUnscheduled
(
);
// Verify that the "published" value has been cleared out of the model.
expect
(
containerPage
.
model
.
get
(
"publish"
)).
toBeNull
();
});
...
...
@@ -273,7 +305,7 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
it
(
'does not discard changes on cancel'
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
fetch
({
published
:
true
,
has_changes
:
true
});
fetch
({
published
:
true
,
has_changes
:
true
,
visibility_state
:
VisibilityState
.
needsAttention
});
var
numRequests
=
requests
.
length
;
// Click discard changes
...
...
@@ -373,7 +405,8 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
create_sinon
.
expectJsonRequest
(
requests
,
'GET'
,
'/xblock/locator-container'
);
create_sinon
.
respondWithJson
(
requests
,
createXBlockInfo
({
published
:
containerPage
.
model
.
get
(
'published'
),
visibility_state
:
isStaffOnly
?
VisibilityState
.
staffOnly
:
VisibilityState
.
live
visibility_state
:
isStaffOnly
?
VisibilityState
.
staffOnly
:
VisibilityState
.
live
,
release_date
:
"Jul 02, 2000 at 14:20 UTC"
}));
};
...
...
@@ -382,6 +415,7 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
expect
(
containerPage
.
$
(
'.action-staff-lock i'
)).
toHaveClass
(
'icon-check'
);
expect
(
containerPage
.
$
(
'.wrapper-visibility .copy'
).
text
()).
toBe
(
'Staff Only'
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
staffOnlyClass
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
toHaveClass
(
scheduledClass
);
}
else
{
expect
(
containerPage
.
$
(
'.action-staff-lock i'
)).
toHaveClass
(
'icon-check-empty'
);
expect
(
containerPage
.
$
(
'.wrapper-visibility .copy'
).
text
()).
toBe
(
'Staff and Students'
);
...
...
@@ -403,18 +437,19 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
it
(
"can remove staff only setting"
,
function
()
{
promptSpy
=
edit_helpers
.
createPromptSpy
();
renderContainerPage
(
this
,
mockContainerXBlockHtml
,
{
visibility_state
:
VisibilityState
.
staffOnly
visibility_state
:
VisibilityState
.
staffOnly
,
release_date
:
"Jul 02, 2000 at 14:20 UTC"
});
requestStaffOnly
(
false
);
verifyStaffOnly
(
false
);
expect
(
containerPage
.
$
(
bitPublishingCss
)).
not
.
toHaveClass
(
readyClass
);
});
it
(
"does not refresh if removing staff only is canceled"
,
function
()
{
var
requestCount
;
promptSpy
=
edit_helpers
.
createPromptSpy
();
renderContainerPage
(
this
,
mockContainerXBlockHtml
,
{
visibility_state
:
VisibilityState
.
staffOnly
visibility_state
:
VisibilityState
.
staffOnly
,
release_date
:
"Jul 02, 2000 at 14:20 UTC"
});
requestCount
=
requests
.
length
;
containerPage
.
$
(
'.action-staff-lock'
).
click
();
...
...
cms/static/js/spec/views/pages/course_outline_spec.js
View file @
6d82cf09
...
...
@@ -118,6 +118,8 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers"
category
:
'vertical'
,
studio_url
:
'/container/mock-unit'
,
is_container
:
true
,
has_changes
:
false
,
published
:
true
,
visibility_state
:
'unscheduled'
,
edited_on
:
'Jul 02, 2014 at 20:56 UTC'
,
edited_by
:
'MockUser'
...
...
cms/static/js/views/pages/container_subviews.js
View file @
6d82cf09
...
...
@@ -116,7 +116,6 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
published
:
this
.
model
.
get
(
'published'
),
publishedOn
:
this
.
model
.
get
(
'published_on'
),
publishedBy
:
this
.
model
.
get
(
'published_by'
),
releasedToStudents
:
this
.
model
.
get
(
'released_to_students'
),
releaseDate
:
this
.
model
.
get
(
'release_date'
),
releaseDateFrom
:
this
.
model
.
get
(
'release_date_from'
)
}));
...
...
cms/static/js/views/utils/xblock_utils.js
View file @
6d82cf09
...
...
@@ -4,7 +4,7 @@
define
([
"jquery"
,
"underscore"
,
"gettext"
,
"js/views/utils/view_utils"
,
"js/utils/module"
],
function
(
$
,
_
,
gettext
,
ViewUtils
,
ModuleUtils
)
{
var
addXBlock
,
deleteXBlock
,
createUpdateRequestData
,
updateXBlockField
,
VisibilityState
,
getXBlockVisibilityClass
;
getXBlockVisibilityClass
,
getXBlockListTypeClass
;
/**
* Represents the possible visibility states for an xblock:
...
...
@@ -131,11 +131,24 @@ define(["jquery", "underscore", "gettext", "js/views/utils/view_utils", "js/util
return
''
;
};
getXBlockListTypeClass
=
function
(
xblockType
)
{
var
listType
=
'list-unknown'
;
if
(
xblockType
===
'course'
)
{
listType
=
'list-sections'
;
}
else
if
(
xblockType
===
'section'
)
{
listType
=
'list-subsections'
;
}
else
if
(
xblockType
===
'subsection'
)
{
listType
=
'list-units'
;
}
return
listType
;
};
return
{
'VisibilityState'
:
VisibilityState
,
'addXBlock'
:
addXBlock
,
'deleteXBlock'
:
deleteXBlock
,
'updateXBlockField'
:
updateXBlockField
,
'getXBlockVisibilityClass'
:
getXBlockVisibilityClass
'getXBlockVisibilityClass'
:
getXBlockVisibilityClass
,
'getXBlockListTypeClass'
:
getXBlockListTypeClass
};
});
cms/static/js/views/xblock_outline.js
View file @
6d82cf09
...
...
@@ -69,6 +69,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
html
=
this
.
template
({
xblockInfo
:
xblockInfo
,
visibilityClass
:
XBlockViewUtils
.
getXBlockVisibilityClass
(
xblockInfo
.
get
(
'visibility_state'
)),
typeListClass
:
XBlockViewUtils
.
getXBlockListTypeClass
(
xblockType
),
parentInfo
:
this
.
parentInfo
,
xblockType
:
xblockType
,
parentType
:
parentType
,
...
...
cms/templates/course_outline.html
View file @
6d82cf09
...
...
@@ -47,7 +47,7 @@ from contentstore.utils import reverse_usage_url
<h3
class=
"sr"
>
${_("Page Actions")}
</h3>
<ul>
<li
class=
"nav-item"
>
<a
href=
"#"
class=
"button button-new"
data-category=
"chapter"
data-parent=
"${context_course.location}"
data-default-name=
"
Section
"
>
<a
href=
"#"
class=
"button button-new"
data-category=
"chapter"
data-parent=
"${context_course.location}"
data-default-name=
"
${_('Section')}
"
>
<i
class=
"icon-plus"
></i>
${_('New Section')}
</a>
</li>
...
...
cms/templates/js/course-outline.underscore
View file @
6d82cf09
...
...
@@ -2,28 +2,20 @@
var category = xblockInfo.get('category');
var releasedToStudents = xblockInfo.get('released_to_students');
var visibilityState = xblockInfo.get('visibility_state');
var listType = 'list-unknown';
if (xblockType === 'course') {
listType = 'list-sections';
} else if (xblockType === 'section') {
listType = 'list-subsections';
} else if (xblockType === 'subsection') {
listType = 'list-units';
}
var published = xblockInfo.get('published');
var statusMessage = null;
var statusType = null;
if (visibilityState === 'staff_only') {
statusType = 'staff-only';
statusMessage =
'Contains staff only content'
;
statusMessage =
gettext('Contains staff only content')
;
} else if (visibilityState === 'needs_attention') {
if (category === 'vertical') {
statusType = 'warning';
if (releasedToStudents) {
statusMessage =
'Unpublished changes to live content'
;
if (
published &&
releasedToStudents) {
statusMessage =
gettext('Unpublished changes to live content')
;
} else {
statusMessage =
'Unpublished units will not be released'
;
statusMessage =
gettext('Unpublished units will not be released')
;
}
}
}
...
...
@@ -75,7 +67,7 @@ if (statusType === 'warning') {
<% if (category !== 'vertical') { %>
<div class="status-release">
<p>
<span class="sr status-release-label">
Release Status:
</span>
<span class="sr status-release-label">
<%= gettext('Release Status:') %>
</span>
<span class="status-release-value">
<% if (xblockInfo.get('released_to_students')) { %>
<i class="icon icon-check-sign"></i>
...
...
@@ -115,7 +107,7 @@ if (statusType === 'warning') {
</div>
<% } else { %>
<div class="outline-content <%= xblockType %>-content">
<ol class="<%=
listType
%> is-sortable">
<ol class="<%=
typeListClass
%> is-sortable">
</ol>
<% if (childType) { %>
<div class="add-<%= childType %> add-item">
...
...
cms/templates/js/publish-xblock.underscore
View file @
6d82cf09
...
...
@@ -4,9 +4,9 @@ if (visibilityState === 'staff_only') {
title = gettext("Unpublished (Staff only)");
} else if (visibilityState === 'live') {
title = gettext("Published and Live");
} else if (
visibilityState === 'ready'
) {
} else if (
published && !hasChanges
) {
title = gettext("Published");
} else if (
visibilityState === 'needs_attention'
) {
} else if (
published && hasChanges
) {
title = gettext("Draft (Unpublished changes)");
}
...
...
@@ -19,7 +19,7 @@ if (visibilityState === 'live') {
var visibleToStaffOnly = visibilityState === 'staff_only';
%>
<div class="bit-publishing <%= visibilityClass %>">
<div class="bit-publishing <%= visibilityClass %>
<% if (releaseDate) { %>is-scheduled<% } %>
">
<h3 class="bar-mod-title pub-status"><span class="sr"><%= gettext("Publishing Status") %></span>
<%= title %>
</h3>
...
...
cms/templates/js/unit-outline.underscore
View file @
6d82cf09
<%
var listType = 'list-for-' + xblockType;
if (xblockType === 'course') {
listType = 'list-sections';
} else if (xblockType === 'section') {
listType = 'list-subsections';
} else if (xblockType === 'subsection') {
listType = 'list-units';
}
%>
<% if (parentInfo) { %>
<li class="outline-item outline-<%= xblockType %> <%= visibilityClass %>"
data-parent="<%= parentInfo.get('id') %>" data-locator="<%= xblockInfo.get('id') %>">
...
...
@@ -21,7 +11,7 @@ if (xblockType === 'course') {
<% } %>
<div class="<%= xblockType %>-content outline-content">
<ol class="<%=
listType
%>">
<ol class="<%=
typeListClass
%>">
</ol>
<% if (childType) { %>
<div class="add-<%= childType %> add-item">
...
...
common/test/acceptance/pages/studio/html_component_editor.py
View file @
6d82cf09
...
...
@@ -18,4 +18,3 @@ class HtmlComponentEditorView(ComponentEditorView):
ActionChains
(
self
.
browser
)
.
click
(
editor
)
.
\
send_keys
([
Keys
.
CONTROL
,
'a'
])
.
key_up
(
Keys
.
CONTROL
)
.
send_keys
(
content
)
.
perform
()
click_css
(
self
,
'a.action-save'
)
common/test/acceptance/tests/test_studio_container.py
View file @
6d82cf09
...
...
@@ -380,7 +380,7 @@ class UnitPublishingTest(ContainerBase):
__test__
=
True
PUBLISHED_STATUS
=
"Publishing Status
\n
Published"
PUBLISHED_LIVE_STATUS
=
"Publishing Status
\n
Published and Live"
PUBLISHED_LIVE_STATUS
=
"Publishing Status
\n
Published and Live"
DRAFT_STATUS
=
"Publishing Status
\n
Draft (Unpublished changes)"
LOCKED_STATUS
=
"Publishing Status
\n
Unpublished (Staff only)"
RELEASE_TITLE_RELEASED
=
"RELEASED:"
...
...
@@ -398,6 +398,7 @@ class UnitPublishingTest(ContainerBase):
self
.
courseware
=
CoursewarePage
(
self
.
browser
,
self
.
course_id
)
past_start_date
=
datetime
.
datetime
(
1974
,
6
,
22
)
self
.
past_start_date_text
=
"Jun 22, 1974 at 00:00 UTC"
future_start_date
=
datetime
.
datetime
(
2100
,
9
,
13
)
course_fixture
.
add_children
(
XBlockFixtureDesc
(
'chapter'
,
'Test Section'
)
.
add_children
(
...
...
@@ -407,20 +408,29 @@ class UnitPublishingTest(ContainerBase):
)
)
),
XBlockFixtureDesc
(
'chapter'
,
'Unlocked Section'
,
metadata
=
{
'start'
:
past_start_date
.
isoformat
()})
.
add_children
(
XBlockFixtureDesc
(
'sequential'
,
'Unlocked Subsection'
)
.
add_children
(
XBlockFixtureDesc
(
'vertical'
,
'Unlocked Unit'
)
.
add_children
(
XBlockFixtureDesc
(
'problem'
,
'<problem></problem>'
,
data
=
self
.
html_content
)
)
)
XBlockFixtureDesc
(
'chapter'
,
'Unlocked Section'
,
metadata
=
{
'start'
:
past_start_date
.
isoformat
()})
.
add_children
(
XBlockFixtureDesc
(
'sequential'
,
'Unlocked Subsection'
)
.
add_children
(
XBlockFixtureDesc
(
'vertical'
,
'Unlocked Unit'
)
.
add_children
(
XBlockFixtureDesc
(
'problem'
,
'<problem></problem>'
,
data
=
self
.
html_content
)
)
)
),
XBlockFixtureDesc
(
'chapter'
,
'Section With Locked Unit'
)
.
add_children
(
XBlockFixtureDesc
(
'sequential'
,
'Subsection With Locked Unit'
,
metadata
=
{
'start'
:
past_start_date
.
isoformat
()})
.
add_children
(
XBlockFixtureDesc
(
'vertical'
,
'Locked Unit'
,
metadata
=
{
'visible_to_staff_only'
:
True
})
.
add_children
(
XBlockFixtureDesc
(
'discussion'
,
''
,
data
=
self
.
html_content
)
)
)
)
XBlockFixtureDesc
(
'sequential'
,
'Subsection With Locked Unit'
,
metadata
=
{
'start'
:
past_start_date
.
isoformat
()})
.
add_children
(
XBlockFixtureDesc
(
'vertical'
,
'Locked Unit'
,
metadata
=
{
'visible_to_staff_only'
:
True
})
.
add_children
(
XBlockFixtureDesc
(
'discussion'
,
''
,
data
=
self
.
html_content
)
)
)
),
XBlockFixtureDesc
(
'chapter'
,
'Unreleased Section'
,
metadata
=
{
'start'
:
future_start_date
.
isoformat
()})
.
add_children
(
XBlockFixtureDesc
(
'sequential'
,
'Unreleased Subsection'
)
.
add_children
(
XBlockFixtureDesc
(
'vertical'
,
'Unreleased Unit'
)
)
)
)
def
test_publishing
(
self
):
...
...
@@ -658,6 +668,25 @@ class UnitPublishingTest(ContainerBase):
self
.
_view_published_version
(
unit
)
self
.
assertEqual
(
0
,
self
.
courseware
.
num_xblock_components
)
def
test_published_not_live
(
self
):
"""
Scenario: The publish title displays correctly for units that are not live
Given I have a published unit with no unpublished changes that releases in the future
When I go to the unit page in Studio
Then the title in the Publish information box is "Published"
And when I add a component to the unit
Then the title in the Publish information box is "Draft (Unpublished changes)"
And when I click the Publish button
Then the title in the Publish information box is "Published"
"""
unit
=
self
.
go_to_unit_page
(
'Unreleased Section'
,
'Unreleased Subsection'
,
'Unreleased Unit'
)
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_STATUS
)
add_discussion
(
unit
)
self
.
_verify_publish_title
(
unit
,
self
.
DRAFT_STATUS
)
unit
.
publish_action
.
click
()
unit
.
wait_for_ajax
()
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_STATUS
)
def
_view_published_version
(
self
,
unit
):
"""
Goes to the published version, then waits for the browser to load the page.
...
...
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