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
eb02f2ad
Commit
eb02f2ad
authored
Jul 11, 2016
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
LMS Update to hide subsection content based on due-date
TNL-4905
parent
1d768cde
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
233 additions
and
90 deletions
+233
-90
common/lib/xmodule/xmodule/seq_module.py
+139
-71
common/lib/xmodule/xmodule/tests/test_sequence.py
+64
-16
lms/djangoapps/courseware/views/index.py
+2
-1
lms/templates/hidden_content.html
+26
-0
lms/templates/seq_module.html
+2
-2
No files found.
common/lib/xmodule/xmodule/seq_module.py
View file @
eb02f2ad
...
@@ -4,6 +4,8 @@ xModule implementation of a learning sequence
...
@@ -4,6 +4,8 @@ xModule implementation of a learning sequence
# pylint: disable=abstract-method
# pylint: disable=abstract-method
import
collections
import
collections
from
datetime
import
datetime
from
django.utils.timezone
import
UTC
import
json
import
json
import
logging
import
logging
from
pkg_resources
import
resource_string
from
pkg_resources
import
resource_string
...
@@ -38,13 +40,22 @@ class SequenceFields(object):
...
@@ -38,13 +40,22 @@ class SequenceFields(object):
# NOTE: Position is 1-indexed. This is silly, but there are now student
# NOTE: Position is 1-indexed. This is silly, but there are now student
# positions saved on prod, so it's not easy to fix.
# positions saved on prod, so it's not easy to fix.
position
=
Integer
(
help
=
"Last tab viewed in this sequence"
,
scope
=
Scope
.
user_state
)
position
=
Integer
(
help
=
"Last tab viewed in this sequence"
,
scope
=
Scope
.
user_state
)
due
=
Date
(
due
=
Date
(
display_name
=
_
(
"Due Date"
),
display_name
=
_
(
"Due Date"
),
help
=
_
(
"Enter the date by which problems are due."
),
help
=
_
(
"Enter the date by which problems are due."
),
scope
=
Scope
.
settings
,
scope
=
Scope
.
settings
,
)
)
# Entrance Exam flag -- see cms/contentstore/views/entrance_exam.py for usage
hide_after_due
=
Boolean
(
display_name
=
_
(
"Hide sequence content After Due Date"
),
help
=
_
(
"If set, the sequence content is hidden for non-staff users after the due date has passed."
),
default
=
False
,
scope
=
Scope
.
settings
,
)
is_entrance_exam
=
Boolean
(
is_entrance_exam
=
Boolean
(
display_name
=
_
(
"Is Entrance Exam"
),
display_name
=
_
(
"Is Entrance Exam"
),
help
=
_
(
help
=
_
(
...
@@ -97,16 +108,6 @@ class ProctoringFields(object):
...
@@ -97,16 +108,6 @@ class ProctoringFields(object):
scope
=
Scope
.
settings
,
scope
=
Scope
.
settings
,
)
)
hide_after_due
=
Boolean
(
display_name
=
_
(
"Hide Exam Results After Due Date"
),
help
=
_
(
"This setting overrides the default behavior of showing exam results after the due date has passed."
" Currently only supported for timed exams."
),
default
=
False
,
scope
=
Scope
.
settings
,
)
is_practice_exam
=
Boolean
(
is_practice_exam
=
Boolean
(
display_name
=
_
(
"Is Practice Exam"
),
display_name
=
_
(
"Is Practice Exam"
),
help
=
_
(
help
=
_
(
...
@@ -177,90 +178,157 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
...
@@ -177,90 +178,157 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
raise
NotFoundError
(
'Unexpected dispatch type'
)
raise
NotFoundError
(
'Unexpected dispatch type'
)
@classmethod
def
verify_current_content_visibility
(
cls
,
due
,
hide_after_due
):
"""
Returns whether the content visibility policy passes
for the given due date and hide_after_due values and
the current date-time.
"""
return
(
not
due
or
not
hide_after_due
or
datetime
.
now
(
UTC
())
<
due
)
def
student_view
(
self
,
context
):
def
student_view
(
self
,
context
):
context
=
context
or
{}
self
.
_capture_basic_metrics
()
banner_text
=
None
special_html_view
=
self
.
_hidden_content_student_view
(
context
)
or
self
.
_special_exam_student_view
()
if
special_html_view
:
masquerading_as_specific_student
=
context
.
get
(
'specific_masquerade'
,
False
)
banner_text
,
special_html
=
special_html_view
if
special_html
and
not
masquerading_as_specific_student
:
return
Fragment
(
special_html
)
return
self
.
_student_view
(
context
,
banner_text
)
def
_special_exam_student_view
(
self
):
"""
Checks whether this sequential is a special exam. If so, returns
a banner_text or the fragment to display depending on whether
staff is masquerading.
"""
if
self
.
is_time_limited
:
special_exam_html
=
self
.
_time_limited_student_view
()
if
special_exam_html
:
banner_text
=
_
(
"This exam is hidden from the learner."
)
return
banner_text
,
special_exam_html
def
_hidden_content_student_view
(
self
,
context
):
"""
Checks whether the content of this sequential is hidden from the
runtime user. If so, returns a banner_text or the fragment to
display depending on whether staff is masquerading.
"""
if
not
self
.
_can_user_view_content
():
subsection_format
=
(
self
.
format
or
_
(
"subsection"
))
.
lower
()
# pylint: disable=no-member
# Translators: subsection_format refers to the assignment
# type of the subsection, such as Homework, Lab, Exam, etc.
banner_text
=
_
(
"Because the due date has passed, "
"this {subsection_format} is hidden from the learner."
)
.
format
(
subsection_format
=
subsection_format
)
hidden_content_html
=
self
.
system
.
render_template
(
'hidden_content.html'
,
{
'subsection_format'
:
subsection_format
,
'progress_url'
:
context
.
get
(
'progress_url'
),
}
)
return
banner_text
,
hidden_content_html
def
_can_user_view_content
(
self
):
"""
Returns whether the runtime user can view the content
of this sequential.
"""
return
(
self
.
runtime
.
user_is_staff
or
self
.
verify_current_content_visibility
(
self
.
due
,
self
.
hide_after_due
)
)
def
_student_view
(
self
,
context
,
banner_text
=
None
):
"""
Returns the rendered student view of the content of this
sequential. If banner_text is given, it is added to the
content.
"""
display_items
=
self
.
get_display_items
()
display_items
=
self
.
get_display_items
()
self
.
_update_position
(
context
,
len
(
display_items
))
fragment
=
Fragment
()
params
=
{
'items'
:
self
.
_render_student_view_for_items
(
context
,
display_items
,
fragment
),
'element_id'
:
self
.
location
.
html_id
(),
'item_id'
:
self
.
location
.
to_deprecated_string
(),
'position'
:
self
.
position
,
'tag'
:
self
.
location
.
category
,
'ajax_url'
:
self
.
system
.
ajax_url
,
'next_url'
:
context
.
get
(
'next_url'
),
'prev_url'
:
context
.
get
(
'prev_url'
),
'banner_text'
:
banner_text
,
}
fragment
.
add_content
(
self
.
system
.
render_template
(
"seq_module.html"
,
params
))
self
.
_capture_full_seq_item_metrics
(
display_items
)
self
.
_capture_current_unit_metrics
(
display_items
)
return
fragment
def
_update_position
(
self
,
context
,
number_of_display_items
):
"""
Update the user's sequential position given the context and the
number_of_display_items
"""
# If we're rendering this sequence, but no position is set yet,
# If we're rendering this sequence, but no position is set yet,
# or exceeds the length of the displayable items,
# or exceeds the length of the displayable items,
# default the position to the first element
# default the position to the first element
if
context
.
get
(
'requested_child'
)
==
'first'
:
if
context
.
get
(
'requested_child'
)
==
'first'
:
self
.
position
=
1
self
.
position
=
1
elif
context
.
get
(
'requested_child'
)
==
'last'
:
elif
context
.
get
(
'requested_child'
)
==
'last'
:
self
.
position
=
len
(
display_items
)
or
1
self
.
position
=
number_of_display_items
or
1
elif
self
.
position
is
None
or
self
.
position
>
len
(
display_items
)
:
elif
self
.
position
is
None
or
self
.
position
>
number_of_display_items
:
self
.
position
=
1
self
.
position
=
1
## Returns a set of all types of all sub-children
def
_render_student_view_for_items
(
self
,
context
,
display_items
,
fragment
):
contents
=
[]
"""
Updates the given fragment with rendered student views of the given
fragment
=
Fragment
()
display_items. Returns a list of dict objects with information about
context
=
context
or
{}
the given display_items.
"""
bookmarks_service
=
self
.
runtime
.
service
(
self
,
"bookmarks"
)
bookmarks_service
=
self
.
runtime
.
service
(
self
,
"bookmarks"
)
context
[
"username"
]
=
self
.
runtime
.
service
(
self
,
"user"
)
.
get_current_user
()
.
opt_attrs
[
'edx-platform.username'
]
context
[
"username"
]
=
self
.
runtime
.
service
(
self
,
"user"
)
.
get_current_user
()
.
opt_attrs
[
'edx-platform.username'
]
parent_module
=
self
.
get_parent
()
display_names
=
[
display_names
=
[
parent_module
.
display_name_with_default
,
self
.
get_parent
()
.
display_name_with_default
,
self
.
display_name_with_default
self
.
display_name_with_default
]
]
contents
=
[]
# We do this up here because proctored exam functionality could bypass
for
item
in
display_items
:
# rendering after this section.
is_bookmarked
=
bookmarks_service
.
is_bookmarked
(
usage_key
=
item
.
scope_ids
.
usage_id
)
self
.
_capture_basic_metrics
()
# Is this sequential part of a timed or proctored exam?
masquerading
=
context
.
get
(
'specific_masquerade'
,
False
)
special_exam_html
=
None
if
self
.
is_time_limited
:
special_exam_html
=
self
.
_time_limited_student_view
(
context
)
# Do we have an applicable alternate rendering
# from the edx_proctoring subsystem?
if
special_exam_html
and
not
masquerading
:
fragment
.
add_content
(
special_exam_html
)
return
fragment
for
child
in
display_items
:
is_bookmarked
=
bookmarks_service
.
is_bookmarked
(
usage_key
=
child
.
scope_ids
.
usage_id
)
context
[
"bookmarked"
]
=
is_bookmarked
context
[
"bookmarked"
]
=
is_bookmarked
progress
=
child
.
get_progress
()
progress
=
item
.
get_progress
()
rendered_
child
=
child
.
render
(
STUDENT_VIEW
,
context
)
rendered_
item
=
item
.
render
(
STUDENT_VIEW
,
context
)
fragment
.
add_frag_resources
(
rendered_
child
)
fragment
.
add_frag_resources
(
rendered_
item
)
child
info
=
{
item
info
=
{
'content'
:
rendered_
child
.
content
,
'content'
:
rendered_
item
.
content
,
'page_title'
:
getattr
(
child
,
'tooltip_title'
,
''
),
'page_title'
:
getattr
(
item
,
'tooltip_title'
,
''
),
'progress_status'
:
Progress
.
to_js_status_str
(
progress
),
'progress_status'
:
Progress
.
to_js_status_str
(
progress
),
'progress_detail'
:
Progress
.
to_js_detail_str
(
progress
),
'progress_detail'
:
Progress
.
to_js_detail_str
(
progress
),
'type'
:
child
.
get_icon_class
(),
'type'
:
item
.
get_icon_class
(),
'id'
:
child
.
scope_ids
.
usage_id
.
to_deprecated_string
(),
'id'
:
item
.
scope_ids
.
usage_id
.
to_deprecated_string
(),
'bookmarked'
:
is_bookmarked
,
'bookmarked'
:
is_bookmarked
,
'path'
:
" > "
.
join
(
display_names
+
[
child
.
display_name_with_default
]),
'path'
:
" > "
.
join
(
display_names
+
[
item
.
display_name_with_default
]),
}
contents
.
append
(
childinfo
)
params
=
{
'items'
:
contents
,
'element_id'
:
self
.
location
.
html_id
(),
'item_id'
:
self
.
location
.
to_deprecated_string
(),
'position'
:
self
.
position
,
'tag'
:
self
.
location
.
category
,
'ajax_url'
:
self
.
system
.
ajax_url
,
'next_url'
:
context
.
get
(
'next_url'
),
'prev_url'
:
context
.
get
(
'prev_url'
),
'override_hidden_exam'
:
masquerading
and
special_exam_html
is
not
None
,
}
}
fragment
.
add_content
(
self
.
system
.
render_template
(
"seq_module.html"
,
params
)
)
contents
.
append
(
iteminfo
)
self
.
_capture_full_seq_item_metrics
(
display_items
)
return
contents
self
.
_capture_current_unit_metrics
(
display_items
)
# Get all descendant XBlock types and counts
return
fragment
def
_locations_in_subtree
(
self
,
node
):
def
_locations_in_subtree
(
self
,
node
):
"""
"""
...
@@ -328,7 +396,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
...
@@ -328,7 +396,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
for
block_type
,
count
in
curr_block_counts
.
items
():
for
block_type
,
count
in
curr_block_counts
.
items
():
newrelic
.
agent
.
add_custom_parameter
(
'seq.current.block_counts.{}'
.
format
(
block_type
),
count
)
newrelic
.
agent
.
add_custom_parameter
(
'seq.current.block_counts.{}'
.
format
(
block_type
),
count
)
def
_time_limited_student_view
(
self
,
context
):
def
_time_limited_student_view
(
self
):
"""
"""
Delegated rendering of a student view when in a time
Delegated rendering of a student view when in a time
limited view. This ultimately calls down into edx_proctoring
limited view. This ultimately calls down into edx_proctoring
...
...
common/lib/xmodule/xmodule/tests/test_sequence.py
View file @
eb02f2ad
...
@@ -2,6 +2,10 @@
...
@@ -2,6 +2,10 @@
Tests for sequence module.
Tests for sequence module.
"""
"""
# pylint: disable=no-member
# pylint: disable=no-member
from
datetime
import
timedelta
import
ddt
from
django.utils.timezone
import
now
from
freezegun
import
freeze_time
from
mock
import
Mock
from
mock
import
Mock
from
xblock.reference.user_service
import
XBlockUser
,
UserService
from
xblock.reference.user_service
import
XBlockUser
,
UserService
from
xmodule.tests
import
get_test_system
from
xmodule.tests
import
get_test_system
...
@@ -24,10 +28,15 @@ class StubUserService(UserService):
...
@@ -24,10 +28,15 @@ class StubUserService(UserService):
return
user
return
user
@ddt.ddt
class
SequenceBlockTestCase
(
XModuleXmlImportTest
):
class
SequenceBlockTestCase
(
XModuleXmlImportTest
):
"""
"""
Tests for the Sequence Module.
Tests for the Sequence Module.
"""
"""
TODAY
=
now
()
TOMORROW
=
TODAY
+
timedelta
(
days
=
1
)
DAY_AFTER_TOMORROW
=
TOMORROW
+
timedelta
(
days
=
1
)
@classmethod
@classmethod
def
setUpClass
(
cls
):
def
setUpClass
(
cls
):
super
(
SequenceBlockTestCase
,
cls
)
.
setUpClass
()
super
(
SequenceBlockTestCase
,
cls
)
.
setUpClass
()
...
@@ -54,13 +63,16 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
...
@@ -54,13 +63,16 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
chapter_1
=
xml
.
ChapterFactory
.
build
(
parent
=
course
)
# has 2 child sequences
chapter_1
=
xml
.
ChapterFactory
.
build
(
parent
=
course
)
# has 2 child sequences
xml
.
ChapterFactory
.
build
(
parent
=
course
)
# has 0 child sequences
xml
.
ChapterFactory
.
build
(
parent
=
course
)
# has 0 child sequences
chapter_3
=
xml
.
ChapterFactory
.
build
(
parent
=
course
)
# has 1 child sequence
chapter_3
=
xml
.
ChapterFactory
.
build
(
parent
=
course
)
# has 1 child sequence
chapter_4
=
xml
.
ChapterFactory
.
build
(
parent
=
course
)
# has
2 child sequences
chapter_4
=
xml
.
ChapterFactory
.
build
(
parent
=
course
)
# has
1 child sequence, with hide_after_due
xml
.
SequenceFactory
.
build
(
parent
=
chapter_1
)
xml
.
SequenceFactory
.
build
(
parent
=
chapter_1
)
xml
.
SequenceFactory
.
build
(
parent
=
chapter_1
)
xml
.
SequenceFactory
.
build
(
parent
=
chapter_1
)
sequence_3_1
=
xml
.
SequenceFactory
.
build
(
parent
=
chapter_3
)
# has 3 verticals
sequence_3_1
=
xml
.
SequenceFactory
.
build
(
parent
=
chapter_3
)
# has 3 verticals
xml
.
SequenceFactory
.
build
(
parent
=
chapter_4
)
xml
.
SequenceFactory
.
build
(
# sequence_4_1
xml
.
SequenceFactory
.
build
(
parent
=
chapter_4
)
parent
=
chapter_4
,
hide_after_due
=
str
(
True
),
due
=
str
(
cls
.
TOMORROW
),
)
for
_
in
range
(
3
):
for
_
in
range
(
3
):
xml
.
VerticalFactory
.
build
(
parent
=
sequence_3_1
)
xml
.
VerticalFactory
.
build
(
parent
=
sequence_3_1
)
...
@@ -98,9 +110,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
...
@@ -98,9 +110,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
def
test_render_student_view
(
self
):
def
test_render_student_view
(
self
):
html
=
self
.
_get_rendered_student_view
(
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_3_1
,
self
.
sequence_3_1
,
requested_child
=
None
,
extra_context
=
dict
(
next_url
=
'NextSequential'
,
prev_url
=
'PrevSequential'
),
next_url
=
'NextSequential'
,
prev_url
=
'PrevSequential'
)
)
self
.
_assert_view_at_position
(
html
,
expected_position
=
1
)
self
.
_assert_view_at_position
(
html
,
expected_position
=
1
)
self
.
assertIn
(
unicode
(
self
.
sequence_3_1
.
location
),
html
)
self
.
assertIn
(
unicode
(
self
.
sequence_3_1
.
location
),
html
)
...
@@ -115,20 +125,15 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
...
@@ -115,20 +125,15 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_3_1
,
requested_child
=
'last'
)
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_3_1
,
requested_child
=
'last'
)
self
.
_assert_view_at_position
(
html
,
expected_position
=
3
)
self
.
_assert_view_at_position
(
html
,
expected_position
=
3
)
def
_get_rendered_student_view
(
self
,
sequence
,
requested_child
,
next_url
=
None
,
prev_url
=
None
):
def
_get_rendered_student_view
(
self
,
sequence
,
requested_child
=
None
,
extra_context
=
None
):
"""
"""
Returns the rendered student view for the given sequence and the
Returns the rendered student view for the given sequence and the
requested_child parameter.
requested_child parameter.
"""
"""
return
sequence
.
xmodule_runtime
.
render
(
context
=
{
'requested_child'
:
requested_child
}
sequence
,
if
extra_context
:
STUDENT_VIEW
,
context
.
update
(
extra_context
)
{
return
sequence
.
xmodule_runtime
.
render
(
sequence
,
STUDENT_VIEW
,
context
)
.
content
'requested_child'
:
requested_child
,
'next_url'
:
next_url
,
'prev_url'
:
prev_url
,
},
)
.
content
def
_assert_view_at_position
(
self
,
rendered_html
,
expected_position
):
def
_assert_view_at_position
(
self
,
rendered_html
,
expected_position
):
"""
"""
...
@@ -140,3 +145,46 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
...
@@ -140,3 +145,46 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
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
)
for
child
in
self
.
sequence_3_1
.
children
:
for
child
in
self
.
sequence_3_1
.
children
:
self
.
assertIn
(
"'page_title': '{}'"
.
format
(
child
.
name
),
html
)
self
.
assertIn
(
"'page_title': '{}'"
.
format
(
child
.
name
),
html
)
def
test_hidden_content_before_due
(
self
):
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_4_1
)
self
.
assertIn
(
"seq_module.html"
,
html
)
self
.
assertIn
(
"'banner_text': None"
,
html
)
@freeze_time
(
DAY_AFTER_TOMORROW
)
@ddt.data
(
(
None
,
'subsection'
),
(
'Homework'
,
'homework'
),
)
@ddt.unpack
def
test_hidden_content_past_due
(
self
,
format_type
,
expected_text
):
progress_url
=
'http://test_progress_link'
self
.
_set_sequence_format
(
self
.
sequence_4_1
,
format_type
)
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_4_1
,
extra_context
=
dict
(
progress_url
=
progress_url
),
)
self
.
assertIn
(
"hidden_content.html"
,
html
)
self
.
assertIn
(
progress_url
,
html
)
self
.
assertIn
(
"'subsection_format': '{}'"
.
format
(
expected_text
),
html
)
@freeze_time
(
DAY_AFTER_TOMORROW
)
def
test_masquerade_hidden_content_past_due
(
self
):
self
.
_set_sequence_format
(
self
.
sequence_4_1
,
"Homework"
)
html
=
self
.
_get_rendered_student_view
(
self
.
sequence_4_1
,
extra_context
=
dict
(
specific_masquerade
=
True
),
)
self
.
assertIn
(
"seq_module.html"
,
html
)
self
.
assertIn
(
"'banner_text': 'Because the due date has passed, "
"this homework is hidden from the learner.'"
,
html
)
def
_set_sequence_format
(
self
,
sequence
,
format_type
):
"""
Sets the format field on the given sequence to the
given value.
"""
sequence
.
_xmodule
.
format
=
format_type
# pylint: disable=protected-access
lms/djangoapps/courseware/views/index.py
View file @
eb02f2ad
...
@@ -447,7 +447,7 @@ class CoursewareIndex(View):
...
@@ -447,7 +447,7 @@ class CoursewareIndex(View):
return
"{url}?child={requested_child}"
.
format
(
return
"{url}?child={requested_child}"
.
format
(
url
=
reverse
(
url
=
reverse
(
'courseware_section'
,
'courseware_section'
,
args
=
[
unicode
(
self
.
course
.
id
),
section_info
[
'chapter_url_name'
],
section_info
[
'url_name'
]],
args
=
[
unicode
(
self
.
course
_key
),
section_info
[
'chapter_url_name'
],
section_info
[
'url_name'
]],
),
),
requested_child
=
requested_child
,
requested_child
=
requested_child
,
)
)
...
@@ -455,6 +455,7 @@ class CoursewareIndex(View):
...
@@ -455,6 +455,7 @@ class CoursewareIndex(View):
section_context
=
{
section_context
=
{
'activate_block_id'
:
self
.
request
.
GET
.
get
(
'activate_block_id'
),
'activate_block_id'
:
self
.
request
.
GET
.
get
(
'activate_block_id'
),
'requested_child'
:
self
.
request
.
GET
.
get
(
"child"
),
'requested_child'
:
self
.
request
.
GET
.
get
(
"child"
),
'progress_url'
:
reverse
(
'progress'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course_key
)}),
}
}
if
previous_of_active_section
:
if
previous_of_active_section
:
section_context
[
'prev_url'
]
=
_compute_section_url
(
previous_of_active_section
,
'last'
)
section_context
[
'prev_url'
]
=
_compute_section_url
(
previous_of_active_section
,
'last'
)
...
...
lms/templates/hidden_content.html
0 → 100644
View file @
eb02f2ad
<
%
page
expression_filter=
"h"
/>
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
from
openedx
.
core
.
djangolib
.
markup
import
HTML
,
Text
%
>
<div
class=
"sequence hidden-content proctored-exam completed"
>
<h3>
${_("The due date for this {subsection_format} has passed.").format(
subsection_format=subsection_format,
)}
</h3>
<hr>
<p>
${Text(_(
"Because the due date has passed, this {subsection_format} "
"is no longer available.{line_break}If you have completed this {subsection_format}, "
"your grade is available on the {link_start}progress page{link_end}."
)).format(
subsection_format=subsection_format,
line_break=HTML("
<br>
"),
link_start=HTML("
<a
href=
'{}'
>
").format(progress_url),
link_end=HTML("
</a>
"),
)}
</p>
</div>
lms/templates/seq_module.html
View file @
eb02f2ad
...
@@ -3,12 +3,12 @@
...
@@ -3,12 +3,12 @@
<div
id=
"sequence_${element_id}"
class=
"sequence"
data-id=
"${item_id}"
data-position=
"${position}"
data-ajax-url=
"${ajax_url}"
data-next-url=
"${next_url}"
data-prev-url=
"${prev_url}"
>
<div
id=
"sequence_${element_id}"
class=
"sequence"
data-id=
"${item_id}"
data-position=
"${position}"
data-ajax-url=
"${ajax_url}"
data-next-url=
"${next_url}"
data-prev-url=
"${prev_url}"
>
<div
class=
"path"
></div>
<div
class=
"path"
></div>
% if
override_hidden_exam
:
% if
banner_text
:
<div
class=
"pattern-library-shim alert alert-information subsection-header"
tabindex=
"-1"
>
<div
class=
"pattern-library-shim alert alert-information subsection-header"
tabindex=
"-1"
>
<span
class=
"pattern-library-shim icon alert-icon icon-bullhorn"
aria-hidden=
"true"
></span>
<span
class=
"pattern-library-shim icon alert-icon icon-bullhorn"
aria-hidden=
"true"
></span>
<div
class=
"pattern-library-shim alert-message"
>
<div
class=
"pattern-library-shim alert-message"
>
<p
class=
"pattern-library-shim alert-copy"
>
<p
class=
"pattern-library-shim alert-copy"
>
${
_("This exam is hidden from the learner.")
}
${
banner_text
}
</p>
</p>
</div>
</div>
</div>
</div>
...
...
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