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
3be03d46
Commit
3be03d46
authored
Apr 26, 2016
by
Nimisha Asthagiri
Committed by
Clinton Blackburn
May 02, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix Next Button's 404 error
MA-2305
parent
04cf9ae8
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
158 additions
and
240 deletions
+158
-240
common/lib/xmodule/xmodule/js/src/sequence/display.coffee
+1
-1
common/lib/xmodule/xmodule/seq_module.py
+3
-96
common/lib/xmodule/xmodule/tests/test_sequence.py
+12
-38
common/test/acceptance/tests/lms/test_lms_courseware.py
+8
-0
lms/djangoapps/course_api/blocks/serializers.py
+2
-1
lms/djangoapps/courseware/module_render.py
+90
-72
lms/djangoapps/courseware/tests/test_entrance_exam.py
+2
-1
lms/djangoapps/courseware/tests/test_module_render.py
+12
-4
lms/djangoapps/courseware/tests/test_views.py
+4
-13
lms/djangoapps/courseware/url_helpers.py
+1
-6
lms/djangoapps/courseware/views.py
+23
-8
No files found.
common/lib/xmodule/xmodule/js/src/sequence/display.coffee
View file @
3be03d46
...
...
@@ -251,7 +251,7 @@ class @Sequence
tab_count
:
@
num_contents
widget_placement
:
widget_placement
if
(
direction
==
'next'
)
and
(
@
position
=
=
@
contents
.
length
)
if
(
direction
==
'next'
)
and
(
@
position
>
=
@
contents
.
length
)
window
.
location
.
href
=
@
nextUrl
else
if
(
direction
==
'previous'
)
and
(
@
position
==
1
)
window
.
location
.
href
=
@
prevUrl
...
...
common/lib/xmodule/xmodule/seq_module.py
View file @
3be03d46
...
...
@@ -176,7 +176,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
if
context
.
get
(
'requested_child'
)
==
'first'
:
self
.
position
=
1
elif
context
.
get
(
'requested_child'
)
==
'last'
:
self
.
position
=
len
(
display_items
)
or
None
self
.
position
=
len
(
display_items
)
or
1
elif
self
.
position
is
None
or
self
.
position
>
len
(
display_items
):
self
.
position
=
1
...
...
@@ -237,16 +237,8 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
'position'
:
self
.
position
,
'tag'
:
self
.
location
.
category
,
'ajax_url'
:
self
.
system
.
ajax_url
,
'next_url'
:
_compute_next_url
(
self
.
location
,
parent_module
,
context
.
get
(
'redirect_url_func'
),
),
'prev_url'
:
_compute_previous_url
(
self
.
location
,
parent_module
,
context
.
get
(
'redirect_url_func'
),
),
'next_url'
:
context
.
get
(
'next_url'
),
'prev_url'
:
context
.
get
(
'prev_url'
),
}
fragment
.
add_content
(
self
.
system
.
render_template
(
"seq_module.html"
,
params
))
...
...
@@ -455,88 +447,3 @@ class SequenceDescriptor(SequenceFields, ProctoringFields, MakoModuleDescriptor,
xblock_body
[
"content_type"
]
=
"Sequence"
return
xblock_body
def
_compute_next_url
(
block_location
,
parent_block
,
redirect_url_func
):
"""
Returns the url for the next block after the given block.
"""
def
get_next_block_location
(
parent_block
,
index_in_parent
):
"""
Returns the next block in the parent_block after the block with the given
index_in_parent.
"""
if
index_in_parent
+
1
<
len
(
parent_block
.
children
):
return
parent_block
.
children
[
index_in_parent
+
1
]
else
:
return
None
return
_compute_next_or_prev_url
(
block_location
,
parent_block
,
redirect_url_func
,
get_next_block_location
,
'first'
,
)
def
_compute_previous_url
(
block_location
,
parent_block
,
redirect_url_func
):
"""
Returns the url for the previous block after the given block.
"""
def
get_previous_block_location
(
parent_block
,
index_in_parent
):
"""
Returns the previous block in the parent_block before the block with the given
index_in_parent.
"""
return
parent_block
.
children
[
index_in_parent
-
1
]
if
index_in_parent
else
None
return
_compute_next_or_prev_url
(
block_location
,
parent_block
,
redirect_url_func
,
get_previous_block_location
,
'last'
,
)
def
_compute_next_or_prev_url
(
block_location
,
parent_block
,
redirect_url_func
,
get_next_or_prev_block
,
redirect_url_child_param
,
):
"""
Returns the url for the next or previous block from the given block.
Arguments:
block_location: Location of the block that is being navigated.
parent_block: Parent block of the given block.
redirect_url_func: Function that computes a redirect URL directly to
a block, given the block's location.
get_next_or_prev_block: Function that returns the next or previous
block in the parent, or None if doesn't exist.
redirect_url_child_param: Value to pass for the child parameter to the
redirect_url_func.
"""
if
redirect_url_func
:
index_in_parent
=
parent_block
.
children
.
index
(
block_location
)
next_or_prev_block_location
=
get_next_or_prev_block
(
parent_block
,
index_in_parent
)
if
next_or_prev_block_location
:
return
redirect_url_func
(
block_location
.
course_key
,
next_or_prev_block_location
,
child
=
redirect_url_child_param
,
)
else
:
grandparent
=
parent_block
.
get_parent
()
if
grandparent
:
return
_compute_next_or_prev_url
(
parent_block
.
location
,
grandparent
,
redirect_url_func
,
get_next_or_prev_block
,
redirect_url_child_param
,
)
return
None
common/lib/xmodule/xmodule/tests/test_sequence.py
View file @
3be03d46
...
...
@@ -8,7 +8,7 @@ from xmodule.tests import get_test_system
from
xmodule.tests.xml
import
XModuleXmlImportTest
from
xmodule.tests.xml
import
factories
as
xml
from
xmodule.x_module
import
STUDENT_VIEW
from
xmodule.seq_module
import
_compute_next_url
,
_compute_previous_url
,
SequenceModule
from
xmodule.seq_module
import
SequenceModule
class
StubUserService
(
UserService
):
...
...
@@ -96,11 +96,16 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
self
.
assertEquals
(
seq_module
.
position
,
2
)
# matches position set in the runtime
def
test_render_student_view
(
self
):
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_3_1
,
requested_child
=
None
)
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_3_1
,
requested_child
=
None
,
next_url
=
'NextSequential'
,
prev_url
=
'PrevSequential'
)
self
.
_assert_view_at_position
(
html
,
expected_position
=
1
)
self
.
assertIn
(
unicode
(
self
.
sequence_3_1
.
location
),
html
)
self
.
assertIn
(
"'next_url':
u'{}'"
.
format
(
unicode
(
self
.
chapter_4
.
location
))
,
html
)
self
.
assertIn
(
"'prev_url':
u'{}'"
.
format
(
unicode
(
self
.
chapter_2
.
location
))
,
html
)
self
.
assertIn
(
"'next_url':
'NextSequential'"
,
html
)
self
.
assertIn
(
"'prev_url':
'PrevSequential'"
,
html
)
def
test_student_view_first_child
(
self
):
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_3_1
,
requested_child
=
'first'
)
...
...
@@ -110,7 +115,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_3_1
,
requested_child
=
'last'
)
self
.
_assert_view_at_position
(
html
,
expected_position
=
3
)
def
_get_rendered_student_view
(
self
,
sequence
,
requested_child
):
def
_get_rendered_student_view
(
self
,
sequence
,
requested_child
,
next_url
=
None
,
prev_url
=
None
):
"""
Returns the rendered student view for the given sequence and the
requested_child parameter.
...
...
@@ -119,8 +124,9 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
sequence
,
STUDENT_VIEW
,
{
'redirect_url_func'
:
lambda
course_key
,
block_location
,
child
:
unicode
(
block_location
),
'requested_child'
:
requested_child
,
'next_url'
:
next_url
,
'prev_url'
:
prev_url
,
},
)
.
content
...
...
@@ -130,38 +136,6 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
"""
self
.
assertIn
(
"'position': {}"
.
format
(
expected_position
),
rendered_html
)
def
test_compute_next_url
(
self
):
for
sequence
,
parent
,
expected_next_sequence_location
in
[
(
self
.
sequence_1_1
,
self
.
chapter_1
,
self
.
sequence_1_2
.
location
),
(
self
.
sequence_1_2
,
self
.
chapter_1
,
self
.
chapter_2
.
location
),
(
self
.
sequence_3_1
,
self
.
chapter_3
,
self
.
chapter_4
.
location
),
(
self
.
sequence_4_1
,
self
.
chapter_4
,
self
.
sequence_4_2
.
location
),
(
self
.
sequence_4_2
,
self
.
chapter_4
,
None
),
]:
actual_next_sequence_location
=
_compute_next_url
(
sequence
.
location
,
parent
,
lambda
course_key
,
block_location
,
child
:
block_location
,
)
self
.
assertEquals
(
actual_next_sequence_location
,
expected_next_sequence_location
)
def
test_compute_previous_url
(
self
):
for
sequence
,
parent
,
expected_prev_sequence_location
in
[
(
self
.
sequence_1_1
,
self
.
chapter_1
,
None
),
(
self
.
sequence_1_2
,
self
.
chapter_1
,
self
.
sequence_1_1
.
location
),
(
self
.
sequence_3_1
,
self
.
chapter_3
,
self
.
chapter_2
.
location
),
(
self
.
sequence_4_1
,
self
.
chapter_4
,
self
.
chapter_3
.
location
),
(
self
.
sequence_4_2
,
self
.
chapter_4
,
self
.
sequence_4_1
.
location
),
]:
actual_next_sequence_location
=
_compute_previous_url
(
sequence
.
location
,
parent
,
lambda
course_key
,
block_location
,
child
:
block_location
,
)
self
.
assertEquals
(
actual_next_sequence_location
,
expected_prev_sequence_location
)
def
test_tooltip
(
self
):
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_3_1
,
requested_child
=
None
)
for
child
in
self
.
sequence_3_1
.
children
:
...
...
common/test/acceptance/tests/lms/test_lms_courseware.py
View file @
3be03d46
...
...
@@ -432,12 +432,20 @@ class CoursewareMultipleVerticalsTest(UniqueCourseTest, EventsTestMixin):
XBlockFixtureDesc
(
'sequential'
,
'Test Subsection 1,2'
)
.
add_children
(
XBlockFixtureDesc
(
'problem'
,
'Test Problem 3'
,
data
=
'<problem>problem 3 dummy body</problem>'
),
),
XBlockFixtureDesc
(
'sequential'
,
'Test HIDDEN Subsection'
,
metadata
=
{
'visible_to_staff_only'
:
True
}
)
.
add_children
(
XBlockFixtureDesc
(
'problem'
,
'Test HIDDEN Problem'
,
data
=
'<problem>hidden problem</problem>'
),
),
),
XBlockFixtureDesc
(
'chapter'
,
'Test Section 2'
)
.
add_children
(
XBlockFixtureDesc
(
'sequential'
,
'Test Subsection 2,1'
)
.
add_children
(
XBlockFixtureDesc
(
'problem'
,
'Test Problem 4'
,
data
=
'<problem>problem 4 dummy body</problem>'
),
),
),
XBlockFixtureDesc
(
'chapter'
,
'Test HIDDEN Section'
,
metadata
=
{
'visible_to_staff_only'
:
True
})
.
add_children
(
XBlockFixtureDesc
(
'sequential'
,
'Test HIDDEN Subsection'
),
),
)
.
install
()
# Auto-auth register for the course.
...
...
lms/djangoapps/course_api/blocks/serializers.py
View file @
3be03d46
"""
Serializers for Course Blocks related return objects.
"""
from
django.conf
import
settings
from
rest_framework
import
serializers
from
rest_framework.reverse
import
reverse
...
...
@@ -44,7 +45,7 @@ class BlockSerializer(serializers.Serializer): # pylint: disable=abstract-metho
),
}
if
'lti_url'
in
self
.
context
[
'requested_fields'
]:
if
settings
.
FEATURES
.
get
(
"ENABLE_LTI_PROVIDER"
)
and
'lti_url'
in
self
.
context
[
'requested_fields'
]:
data
[
'lti_url'
]
=
reverse
(
'lti_provider_launch'
,
kwargs
=
{
'course_id'
:
unicode
(
block_key
.
course_key
),
'usage_id'
:
unicode
(
block_key
)},
...
...
lms/djangoapps/courseware/module_render.py
View file @
3be03d46
...
...
@@ -147,7 +147,7 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
user
,
request
,
course
,
field_data_cache
,
course
.
id
,
course
=
course
)
if
course_module
is
None
:
return
None
return
None
,
None
,
None
toc_chapters
=
list
()
chapters
=
course_module
.
get_display_items
()
...
...
@@ -163,9 +163,12 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
if
not
user_must_complete_entrance_exam
(
request
,
user
,
course
):
required_content
=
[
content
for
content
in
required_content
if
not
content
==
course
.
entrance_exam_id
]
previous_of_active_section
,
next_of_active_section
=
None
,
None
last_processed_section
,
last_processed_chapter
=
None
,
None
found_active_section
=
False
for
chapter
in
chapters
:
# Only show required content, if there is required content
# chapter.hide_from_toc is read-only (boo)
# chapter.hide_from_toc is read-only (boo
l
)
display_id
=
slugify
(
chapter
.
display_name_with_default_escaped
)
local_hide_from_toc
=
False
if
required_content
:
...
...
@@ -178,78 +181,39 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
sections
=
list
()
for
section
in
chapter
.
get_display_items
():
active
=
(
chapter
.
url_name
==
active_chapter
and
section
.
url_name
==
active_section
)
# Skip the current section if it is gated
# skip the section if it is gated/hidden from the user
if
gated_content
and
unicode
(
section
.
location
)
in
gated_content
:
continue
if
section
.
hide_from_toc
:
continue
is_section_active
=
(
chapter
.
url_name
==
active_chapter
and
section
.
url_name
==
active_section
)
if
is_section_active
:
found_active_section
=
True
section_context
=
{
'display_name'
:
section
.
display_name_with_default_escaped
,
'url_name'
:
section
.
url_name
,
'format'
:
section
.
format
if
section
.
format
is
not
None
else
''
,
'due'
:
section
.
due
,
'active'
:
is_section_active
,
'graded'
:
section
.
graded
,
}
_add_timed_exam_info
(
user
,
course
,
section
,
section_context
)
# update next and previous of active section, if applicable
if
is_section_active
:
if
last_processed_section
:
previous_of_active_section
=
last_processed_section
.
copy
()
previous_of_active_section
[
'chapter_url_name'
]
=
last_processed_chapter
.
url_name
elif
found_active_section
and
not
next_of_active_section
:
next_of_active_section
=
section_context
.
copy
()
next_of_active_section
[
'chapter_url_name'
]
=
chapter
.
url_name
sections
.
append
(
section_context
)
last_processed_section
=
section_context
last_processed_chapter
=
chapter
if
not
section
.
hide_from_toc
:
section_context
=
{
'display_name'
:
section
.
display_name_with_default_escaped
,
'url_name'
:
section
.
url_name
,
'format'
:
section
.
format
if
section
.
format
is
not
None
else
''
,
'due'
:
section
.
due
,
'active'
:
active
,
'graded'
:
section
.
graded
,
}
#
# Add in rendering context if exam is a timed exam (which includes proctored)
#
section_is_time_limited
=
(
getattr
(
section
,
'is_time_limited'
,
False
)
and
settings
.
FEATURES
.
get
(
'ENABLE_SPECIAL_EXAMS'
,
False
)
)
if
section_is_time_limited
:
# We need to import this here otherwise Lettuce test
# harness fails. When running in 'harvest' mode, the
# test service appears to get into trouble with
# circular references (not sure which as edx_proctoring.api
# doesn't import anything from edx-platform). Odd thing
# is that running: manage.py lms runserver --settings=acceptance
# works just fine, it's really a combination of Lettuce and the
# 'harvest' management command
#
# One idea is that there is some coupling between
# lettuce and the 'terrain' Djangoapps projects in /common
# This would need more investigation
from
edx_proctoring.api
import
get_attempt_status_summary
#
# call into edx_proctoring subsystem
# to get relevant proctoring information regarding this
# level of the courseware
#
# This will return None, if (user, course_id, content_id)
# is not applicable
#
timed_exam_attempt_context
=
None
try
:
timed_exam_attempt_context
=
get_attempt_status_summary
(
user
.
id
,
unicode
(
course
.
id
),
unicode
(
section
.
location
)
)
except
Exception
,
ex
:
# pylint: disable=broad-except
# safety net in case something blows up in edx_proctoring
# as this is just informational descriptions, it is better
# to log and continue (which is safe) than to have it be an
# unhandled exception
log
.
exception
(
ex
)
if
timed_exam_attempt_context
:
# yes, user has proctoring context about
# this level of the courseware
# so add to the accordion data context
section_context
.
update
({
'proctoring'
:
timed_exam_attempt_context
,
})
sections
.
append
(
section_context
)
toc_chapters
.
append
({
'display_name'
:
chapter
.
display_name_with_default_escaped
,
'display_id'
:
display_id
,
...
...
@@ -257,7 +221,61 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
'sections'
:
sections
,
'active'
:
chapter
.
url_name
==
active_chapter
})
return
toc_chapters
return
toc_chapters
,
previous_of_active_section
,
next_of_active_section
def
_add_timed_exam_info
(
user
,
course
,
section
,
section_context
):
"""
Add in rendering context if exam is a timed exam (which includes proctored)
"""
section_is_time_limited
=
(
getattr
(
section
,
'is_time_limited'
,
False
)
and
settings
.
FEATURES
.
get
(
'ENABLE_SPECIAL_EXAMS'
,
False
)
)
if
section_is_time_limited
:
# We need to import this here otherwise Lettuce test
# harness fails. When running in 'harvest' mode, the
# test service appears to get into trouble with
# circular references (not sure which as edx_proctoring.api
# doesn't import anything from edx-platform). Odd thing
# is that running: manage.py lms runserver --settings=acceptance
# works just fine, it's really a combination of Lettuce and the
# 'harvest' management command
#
# One idea is that there is some coupling between
# lettuce and the 'terrain' Djangoapps projects in /common
# This would need more investigation
from
edx_proctoring.api
import
get_attempt_status_summary
#
# call into edx_proctoring subsystem
# to get relevant proctoring information regarding this
# level of the courseware
#
# This will return None, if (user, course_id, content_id)
# is not applicable
#
timed_exam_attempt_context
=
None
try
:
timed_exam_attempt_context
=
get_attempt_status_summary
(
user
.
id
,
unicode
(
course
.
id
),
unicode
(
section
.
location
)
)
except
Exception
,
ex
:
# pylint: disable=broad-except
# safety net in case something blows up in edx_proctoring
# as this is just informational descriptions, it is better
# to log and continue (which is safe) than to have it be an
# unhandled exception
log
.
exception
(
ex
)
if
timed_exam_attempt_context
:
# yes, user has proctoring context about
# this level of the courseware
# so add to the accordion data context
section_context
.
update
({
'proctoring'
:
timed_exam_attempt_context
,
})
def
get_module
(
user
,
request
,
usage_key
,
field_data_cache
,
...
...
lms/djangoapps/courseware/tests/test_entrance_exam.py
View file @
3be03d46
...
...
@@ -583,7 +583,7 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest
self
.
request
.
user
,
self
.
entrance_exam
)
return
toc_for_course
(
toc
,
__
,
__
=
toc_for_course
(
self
.
request
.
user
,
self
.
request
,
self
.
course
,
...
...
@@ -591,6 +591,7 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest
self
.
exam_1
.
url_name
,
self
.
field_data_cache
)
return
toc
def
answer_entrance_exam_problem
(
course
,
request
,
problem
,
user
=
None
):
...
...
lms/djangoapps/courseware/tests/test_module_render.py
View file @
3be03d46
...
...
@@ -668,11 +668,13 @@ class TestTOC(ModuleStoreTestCase):
course
=
self
.
store
.
get_course
(
self
.
toy_course
.
id
,
depth
=
2
)
with
check_mongo_calls
(
toc_finds
):
actual
=
render
.
toc_for_course
(
actual
,
prev_sequential
,
next_sequential
=
render
.
toc_for_course
(
self
.
request
.
user
,
self
.
request
,
course
,
self
.
chapter
,
None
,
self
.
field_data_cache
)
for
toc_section
in
expected
:
self
.
assertIn
(
toc_section
,
actual
)
self
.
assertIsNone
(
prev_sequential
)
self
.
assertIsNone
(
next_sequential
)
# Mongo makes 3 queries to load the course to depth 2:
# - 1 for the course
...
...
@@ -707,11 +709,13 @@ class TestTOC(ModuleStoreTestCase):
'url_name'
:
'secret:magic'
,
'display_name'
:
'secret:magic'
,
'display_id'
:
'secretmagic'
}])
with
check_mongo_calls
(
toc_finds
):
actual
=
render
.
toc_for_course
(
actual
,
prev_sequential
,
next_sequential
=
render
.
toc_for_course
(
self
.
request
.
user
,
self
.
request
,
self
.
toy_course
,
self
.
chapter
,
section
,
self
.
field_data_cache
)
for
toc_section
in
expected
:
self
.
assertIn
(
toc_section
,
actual
)
self
.
assertEquals
(
prev_sequential
[
'url_name'
],
'Toy_Videos'
)
self
.
assertEquals
(
next_sequential
[
'url_name'
],
'video_123456789012'
)
@attr
(
'shard_1'
)
...
...
@@ -852,7 +856,7 @@ class TestProctoringRendering(SharedModuleStoreTestCase):
"""
self
.
_setup_test_data
(
enrollment_mode
,
is_practice_exam
,
attempt_status
)
actual
=
render
.
toc_for_course
(
actual
,
prev_sequential
,
next_sequential
=
render
.
toc_for_course
(
self
.
request
.
user
,
self
.
request
,
self
.
toy_course
,
...
...
@@ -867,6 +871,8 @@ class TestProctoringRendering(SharedModuleStoreTestCase):
else
:
# we expect there not to be a 'proctoring' key in the dict
self
.
assertNotIn
(
'proctoring'
,
section_actual
)
self
.
assertIsNone
(
prev_sequential
)
self
.
assertEquals
(
next_sequential
[
'url_name'
],
u"Welcome"
)
@ddt.data
(
(
...
...
@@ -1108,7 +1114,7 @@ class TestGatedSubsectionRendering(SharedModuleStoreTestCase, MilestonesTestCase
"""
Test generation of TOC for a course with a gated subsection
"""
actual
=
render
.
toc_for_course
(
actual
,
prev_sequential
,
next_sequential
=
render
.
toc_for_course
(
self
.
request
.
user
,
self
.
request
,
self
.
course
,
...
...
@@ -1119,6 +1125,8 @@ class TestGatedSubsectionRendering(SharedModuleStoreTestCase, MilestonesTestCase
self
.
assertIsNotNone
(
self
.
_find_sequential
(
actual
,
'Chapter'
,
'Open_Sequential'
))
self
.
assertIsNone
(
self
.
_find_sequential
(
actual
,
'Chapter'
,
'Gated_Sequential'
))
self
.
assertIsNone
(
self
.
_find_sequential
(
actual
,
'Non-existant_Chapter'
,
'Non-existant_Sequential'
))
self
.
assertIsNone
(
prev_sequential
)
self
.
assertIsNone
(
next_sequential
)
@attr
(
'shard_1'
)
...
...
lms/djangoapps/courseware/tests/test_views.py
View file @
3be03d46
...
...
@@ -35,6 +35,7 @@ from commerce.models import CommerceConfiguration
from
course_modes.models
import
CourseMode
from
course_modes.tests.factories
import
CourseModeFactory
from
courseware.model_data
import
set_score
from
courseware.module_render
import
toc_for_course
from
courseware.testutils
import
RenderXBlockTestMixin
from
courseware.tests.factories
import
StudentModuleFactory
from
courseware.url_helpers
import
get_redirect_url
...
...
@@ -415,16 +416,6 @@ class ViewsTestCase(ModuleStoreTestCase):
get_redirect_url
(
self
.
course_key
,
self
.
section
.
location
),
)
self
.
assertIn
(
'child=first'
,
get_redirect_url
(
self
.
course_key
,
self
.
section
.
location
,
child
=
'first'
),
)
self
.
assertIn
(
'child=last'
,
get_redirect_url
(
self
.
course_key
,
self
.
section
.
location
,
child
=
'last'
),
)
def
test_redirect_to_course_position
(
self
):
mock_module
=
MagicMock
()
mock_module
.
descriptor
.
id
=
'Underwater Basketweaving'
...
...
@@ -926,10 +917,10 @@ class TestAccordionDueDate(BaseDueDateTests):
def
get_text
(
self
,
course
):
""" Returns the HTML for the accordion """
return
views
.
render_accordion
(
self
.
request
.
user
,
self
.
request
,
course
,
unicode
(
course
.
get_children
()[
0
]
.
scope_ids
.
usage_id
),
None
,
None
table_of_contents
,
__
,
__
=
toc_for_course
(
self
.
request
.
user
,
self
.
request
,
course
,
unicode
(
course
.
get_children
()[
0
]
.
scope_ids
.
usage_id
),
None
,
None
)
return
views
.
render_accordion
(
self
.
request
,
course
,
table_of_contents
)
@attr
(
'shard_1'
)
...
...
lms/djangoapps/courseware/url_helpers.py
View file @
3be03d46
...
...
@@ -7,13 +7,12 @@ from xmodule.modulestore.django import modulestore
from
django.core.urlresolvers
import
reverse
def
get_redirect_url
(
course_key
,
usage_key
,
child
=
None
):
def
get_redirect_url
(
course_key
,
usage_key
):
""" Returns the redirect url back to courseware
Args:
course_id(str): Course Id string
location(str): The location id of course component
child(str): Optional child parameter to pass to the URL
Raises:
ItemNotFoundError if no data at the location or NoPathToItem if location not in any class
...
...
@@ -50,8 +49,4 @@ def get_redirect_url(course_key, usage_key, child=None):
)
redirect_url
+=
"?{}"
.
format
(
urlencode
({
'activate_block_id'
:
unicode
(
final_target_id
)}))
if
child
:
redirect_url
+=
"&child={}"
.
format
(
child
)
return
redirect_url
lms/djangoapps/courseware/views.py
View file @
3be03d46
...
...
@@ -158,7 +158,7 @@ def courses(request):
)
def
render_accordion
(
user
,
request
,
course
,
chapter
,
section
,
field_data_cache
):
def
render_accordion
(
request
,
course
,
toc
):
"""
Draws navigation bar. Takes current position in accordion as
parameter.
...
...
@@ -169,9 +169,6 @@ def render_accordion(user, request, course, chapter, section, field_data_cache):
Returns the html string
"""
# grab the table of contents
toc
=
toc_for_course
(
user
,
request
,
course
,
chapter
,
section
,
field_data_cache
)
context
=
dict
([
(
'toc'
,
toc
),
(
'course_id'
,
course
.
id
.
to_deprecated_string
()),
...
...
@@ -442,7 +439,6 @@ def _index_bulk_op(request, course_key, chapter, section, position):
context
=
{
'csrf'
:
csrf
(
request
)[
'csrf_token'
],
'accordion'
:
render_accordion
(
user
,
request
,
course
,
chapter
,
section
,
field_data_cache
),
'COURSE_TITLE'
:
course
.
display_name_with_default_escaped
,
'course'
:
course
,
'init'
:
''
,
...
...
@@ -455,6 +451,8 @@ def _index_bulk_op(request, course_key, chapter, section, position):
'language_preference'
:
language_preference
,
'disable_optimizely'
:
True
,
}
table_of_contents
,
__
,
__
=
toc_for_course
(
user
,
request
,
course
,
chapter
,
section
,
field_data_cache
)
context
[
'accordion'
]
=
render_accordion
(
request
,
course
,
table_of_contents
)
now
=
datetime
.
now
(
UTC
())
effective_start
=
_adjust_start_date_for_beta_testers
(
user
,
course
,
course_key
)
...
...
@@ -472,7 +470,6 @@ def _index_bulk_op(request, course_key, chapter, section, position):
if
course_has_entrance_exam
(
course
):
exam_chapter
=
get_entrance_exam_content
(
request
,
course
)
if
exam_chapter
:
exam_section
=
None
if
exam_chapter
.
get_children
():
exam_section
=
exam_chapter
.
get_children
()[
0
]
if
exam_section
:
...
...
@@ -556,12 +553,30 @@ def _index_bulk_op(request, course_key, chapter, section, position):
# Save where we are in the chapter.
save_child_position
(
chapter_descriptor
,
section
)
table_of_contents
,
prev_section_info
,
next_section_info
=
toc_for_course
(
user
,
request
,
course
,
chapter
,
section
,
field_data_cache
)
context
[
'accordion'
]
=
render_accordion
(
request
,
course
,
table_of_contents
)
def
_compute_section_url
(
section_info
,
requested_child
):
"""
Returns the section URL for the given section_info with the given child parameter.
"""
return
"{url}?child={requested_child}"
.
format
(
url
=
reverse
(
'courseware_section'
,
args
=
[
unicode
(
course
.
id
),
section_info
[
'chapter_url_name'
],
section_info
[
'url_name'
]],
),
requested_child
=
requested_child
,
)
section_render_context
=
{
'activate_block_id'
:
request
.
GET
.
get
(
'activate_block_id'
),
'redirect_url_func'
:
get_redirect_url
,
'requested_child'
:
request
.
GET
.
get
(
"child"
),
'prev_url'
:
_compute_section_url
(
prev_section_info
,
'last'
)
if
prev_section_info
else
None
,
'next_url'
:
_compute_section_url
(
next_section_info
,
'first'
)
if
next_section_info
else
None
,
}
context
[
'accordion'
]
=
render_accordion
(
user
,
request
,
course
,
chapter
,
section
,
field_data_cache
)
context
[
'fragment'
]
=
section_module
.
render
(
STUDENT_VIEW
,
section_render_context
)
context
[
'section_title'
]
=
section_descriptor
.
display_name_with_default_escaped
result
=
render_to_response
(
'courseware/courseware.html'
,
context
)
...
...
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