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
aafd6a03
Commit
aafd6a03
authored
Apr 10, 2017
by
Diana Huang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add 'format' as a requested field.
parent
31aa776e
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
88 additions
and
86 deletions
+88
-86
common/test/acceptance/tests/lms/test_lms_course_home.py
+0
-22
lms/djangoapps/course_api/blocks/api.py
+4
-4
lms/djangoapps/course_api/blocks/transformers/__init__.py
+1
-1
lms/djangoapps/course_api/blocks/transformers/milestones.py
+56
-48
lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py
+1
-1
openedx/features/course_experience/templates/course_experience/course-outline-fragment.html
+5
-5
openedx/features/course_experience/tests/views/test_course_outline.py
+20
-4
openedx/features/course_experience/views/course_outline.py
+1
-1
No files found.
common/test/acceptance/tests/lms/test_lms_course_home.py
View file @
aafd6a03
...
...
@@ -134,16 +134,6 @@ class CourseHomeA11yTest(CourseHomeBaseTest):
self
.
logout_page
=
LogoutPage
(
self
.
browser
)
self
.
studio_course_outline
=
StudioCourseOutlinePage
(
self
.
browser
,
self
.
course_info
[
'org'
],
self
.
course_info
[
'number'
],
self
.
course_info
[
'run'
]
)
# adds graded assignments to course home for testing course outline a11y
self
.
_set_policy_for_subsection
(
"Homework"
,
0
)
def
test_course_home_a11y
(
self
):
"""
Test the accessibility of the course home page with course outline.
...
...
@@ -153,18 +143,6 @@ class CourseHomeA11yTest(CourseHomeBaseTest):
course_home_page
.
visit
()
course_home_page
.
a11y_audit
.
check_for_accessibility_errors
()
def
_set_policy_for_subsection
(
self
,
policy
,
section
=
0
):
"""
Set the grading policy for the first subsection in the specified section.
If a section index is not provided, 0 is assumed.
"""
with
self
.
_logged_in_session
(
staff
=
True
):
self
.
studio_course_outline
.
visit
()
modal
=
self
.
studio_course_outline
.
section_at
(
section
)
.
subsection_at
(
0
)
.
edit
()
modal
.
policy
=
policy
modal
.
save
()
@contextmanager
def
_logged_in_session
(
self
,
staff
=
False
):
"""
...
...
lms/djangoapps/course_api/blocks/api.py
View file @
aafd6a03
...
...
@@ -51,12 +51,12 @@ def get_blocks(
"""
# create ordered list of transformers, adding BlocksAPITransformer at end.
transformers
=
BlockStructureTransformers
()
can_view_special_exam
=
False
if
requested_fields
is
not
None
and
'special_exam'
in
requested_fields
:
can_view_special_exam
=
True
include_special_exams
=
False
if
requested_fields
is
not
None
and
'special_exam
_info
'
in
requested_fields
:
include_special_exams
=
True
if
user
is
not
None
:
transformers
+=
COURSE_BLOCK_ACCESS_TRANSFORMERS
transformers
+=
[
MilestonesTransformer
(
can_view_special_exam
),
HiddenContentTransformer
()]
transformers
+=
[
MilestonesTransformer
(
include_special_exams
),
HiddenContentTransformer
()]
transformers
+=
[
BlocksAPITransformer
(
block_counts
,
...
...
lms/djangoapps/course_api/blocks/transformers/__init__.py
View file @
aafd6a03
...
...
@@ -45,7 +45,7 @@ SUPPORTED_FIELDS = [
# 'student_view_multi_device'
SupportedFieldType
(
StudentViewTransformer
.
STUDENT_VIEW_MULTI_DEVICE
,
StudentViewTransformer
),
SupportedFieldType
(
'special_exam'
,
MilestonesTransformer
),
SupportedFieldType
(
'special_exam
_info
'
,
MilestonesTransformer
),
# set the block_field_name to None so the entire data for the transformer is serialized
SupportedFieldType
(
None
,
BlockCountsTransformer
,
BlockCountsTransformer
.
BLOCK_COUNTS
),
...
...
lms/djangoapps/course_api/blocks/transformers/milestones.py
View file @
aafd6a03
...
...
@@ -19,7 +19,8 @@ log = logging.getLogger(__name__)
class
MilestonesTransformer
(
BlockStructureTransformer
):
"""
Excludes all special exams (timed, proctored, practice proctored) from the student view.
Adds special exams (timed, proctored, practice proctored) to the student view.
May exclude special exams.
Excludes all blocks with unfulfilled milestones from the student view.
"""
WRITE_VERSION
=
1
...
...
@@ -29,8 +30,8 @@ class MilestonesTransformer(BlockStructureTransformer):
def
name
(
cls
):
return
"milestones"
def
__init__
(
self
,
can_view
_special_exams
=
True
):
self
.
can_view_special_exams
=
can_view
_special_exams
def
__init__
(
self
,
include
_special_exams
=
True
):
self
.
include_special_exams
=
include
_special_exams
@classmethod
def
collect
(
cls
,
block_structure
):
...
...
@@ -51,48 +52,9 @@ class MilestonesTransformer(BlockStructureTransformer):
Modify block structure according to the behavior of milestones and special exams.
"""
def
add_special_exam_info
(
block_key
):
"""
Adds special exam information to course blocks.
"""
if
self
.
is_special_exam
(
block_key
,
block_structure
):
#
# 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
(
usage_info
.
user
.
id
,
unicode
(
block_key
.
course_key
),
unicode
(
block_key
)
)
except
ProctoredExamNotFoundException
as
ex
:
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
block_structure
.
set_transformer_block_field
(
block_key
,
self
,
'special_exam'
,
timed_exam_attempt_context
,
)
root_key
=
block_structure
.
root_block_usage_key
course_key
=
root_key
.
course_key
course_key
=
block_structure
.
root_block_usage_key
.
course_key
user_can_skip
=
EntranceExamConfiguration
.
user_can_skip_entrance_exam
(
usage_info
.
user
,
course_key
)
exam_id
=
block_structure
.
get_xblock_field
(
root_key
,
'entrance_exam_id'
)
required_content
=
milestones_helpers
.
get_required_content
(
course_key
,
usage_info
.
user
)
if
user_can_skip
:
required_content
=
[
content
for
content
in
required_content
if
not
content
==
exam_id
]
def
user_gated_from_block
(
block_key
):
"""
...
...
@@ -103,12 +65,11 @@ class MilestonesTransformer(BlockStructureTransformer):
return
False
elif
self
.
has_pending_milestones_for_user
(
block_key
,
usage_info
):
return
True
elif
required_content
:
if
block_key
.
block_type
==
'chapter'
and
unicode
(
block_key
)
not
in
required_content
:
return
True
elif
self
.
gated_by_required_content
(
block_key
,
block_structure
,
user_can_skip
,
required_content
):
return
True
elif
(
settings
.
FEATURES
.
get
(
'ENABLE_SPECIAL_EXAMS'
,
False
)
and
(
self
.
is_special_exam
(
block_key
,
block_structure
)
and
not
self
.
can_view
_special_exams
)):
not
self
.
include
_special_exams
)):
return
True
return
False
...
...
@@ -116,7 +77,7 @@ class MilestonesTransformer(BlockStructureTransformer):
if
user_gated_from_block
(
block_key
):
block_structure
.
remove_block
(
block_key
,
False
)
else
:
add_special_exam_info
(
block_key
)
self
.
add_special_exam_info
(
block_key
,
block_structure
,
usage_info
)
@staticmethod
def
is_special_exam
(
block_key
,
block_structure
):
...
...
@@ -142,3 +103,50 @@ class MilestonesTransformer(BlockStructureTransformer):
'requires'
,
usage_info
.
user
.
id
))
def
add_special_exam_info
(
self
,
block_key
,
block_structure
,
usage_info
):
"""
Adds special exam information to course blocks.
"""
if
self
.
is_special_exam
(
block_key
,
block_structure
):
# call into edx_proctoring subsystem to get relevant special exam information
#
# This will return None, if (user, course_id, content_id) is not applicable
special_exam_attempt_context
=
None
try
:
special_exam_attempt_context
=
get_attempt_status_summary
(
usage_info
.
user
.
id
,
unicode
(
block_key
.
course_key
),
unicode
(
block_key
)
)
except
ProctoredExamNotFoundException
as
ex
:
log
.
exception
(
ex
)
if
special_exam_attempt_context
:
# yes, user has proctoring context about
# this level of the courseware
# so add to the accordion data context
block_structure
.
set_transformer_block_field
(
block_key
,
self
,
'special_exam_info'
,
special_exam_attempt_context
,
)
@staticmethod
def
gated_by_required_content
(
block_key
,
block_structure
,
user_can_skip
,
required_content
):
"""
Returns True if the current block associated with the block_key should be gated by the given required_content.
Returns False otherwise.
"""
if
not
required_content
:
return
False
exam_id
=
block_structure
.
get_xblock_field
(
block_structure
.
root_block_usage_key
,
'entrance_exam_id'
)
if
user_can_skip
:
required_content
=
[
content
for
content
in
required_content
if
not
content
==
exam_id
]
if
block_key
.
block_type
==
'chapter'
and
unicode
(
block_key
)
not
in
required_content
:
return
True
return
False
lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py
View file @
aafd6a03
...
...
@@ -186,7 +186,7 @@ class MilestonesTransformerTestCase(CourseStructureTestCase, MilestonesTestCaseM
self
.
setup_gated_section
(
self
.
blocks
[
'H'
],
self
.
blocks
[
'A'
])
self
.
get_blocks_and_check_against_expected
(
self
.
staff
,
expected_blocks
)
def
test_
can_view_special
(
self
):
def
test_
special_exams
(
self
):
"""
When the block structure transformers are set to allow users to view special exams,
ensure that we can see the special exams and not any of the otherwise gated blocks.
...
...
openedx/features/course_experience/templates/course_experience/course-outline-fragment.html
View file @
aafd6a03
...
...
@@ -51,26 +51,26 @@ from django.utils.translation import ugettext as _
if
subsection
.
get
('
due
')
is
None:
data_string =
subsection.get('format')
else:
if
'
special_exam
'
in
subsection:
if
'
special_exam
_info
'
in
subsection:
data_string =
_('due
{
date
}')
else:
data_string =
_("{subsection_format}
due
{{
date
}}").
format
(
subsection_format=
subsection.get('format'))
%
>
% if subsection.get('format') or 'special_exam' in subsection:
% if subsection.get('format') or 'special_exam
_info
' in subsection:
<span
class=
"subtitle"
>
% if 'special_exam' in subsection:
## Display the proctored exam status icon and status message
<span
class=
"menu-icon icon fa ${subsection['special_exam
'].get('suggested_icon', 'fa-pencil-square-o')} ${subsection['special_exam
'].get('status', 'eligible')}"
class=
"menu-icon icon fa ${subsection['special_exam
_info'].get('suggested_icon', 'fa-pencil-square-o')} ${subsection['special_exam_info
'].get('status', 'eligible')}"
aria-hidden=
"true"
></span>
<span
class=
"subtitle-name"
>
${subsection['special_exam'].get('short_description', '')}
${subsection['special_exam
_info
'].get('short_description', '')}
</span>
## completed proctored exam statuses should not show the due date
## since the exam has already been submitted by the user
% if not subsection['special_exam'].get('in_completed_state', False):
% if not subsection['special_exam
_info
'].get('in_completed_state', False):
<span
class=
"localized-datetime subtitle-name"
data-datetime=
"${subsection.get('due')}"
...
...
openedx/features/course_experience/tests/views/test_course_outline.py
View file @
aafd6a03
...
...
@@ -47,6 +47,22 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase):
ItemFactory
.
create
(
category
=
'vertical'
,
parent_location
=
section2
.
location
)
course
.
last_accessed
=
None
cls
.
courses
.
append
(
course
)
course
=
CourseFactory
.
create
()
with
cls
.
store
.
bulk_operations
(
course
.
id
):
chapter
=
ItemFactory
.
create
(
category
=
'chapter'
,
parent_location
=
course
.
location
)
section
=
ItemFactory
.
create
(
category
=
'sequential'
,
parent_location
=
chapter
.
location
,
due
=
datetime
.
datetime
.
now
(),
graded
=
True
,
format
=
'Homework'
,
)
ItemFactory
.
create
(
category
=
'vertical'
,
parent_location
=
section
.
location
)
course
.
last_accessed
=
section
.
url_name
cls
.
courses
.
append
(
course
)
@classmethod
def
setUpTestData
(
cls
):
"""Set up and enroll our fake user in the course."""
...
...
@@ -70,14 +86,14 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
response_content
=
response
.
content
.
decode
(
"utf-8"
)
if
course
.
last_accessed
is
not
None
:
self
.
assertIn
(
'Resume Course'
,
response_content
)
else
:
self
.
assertNotIn
(
'Resume Course'
,
response_content
)
self
.
assertIn
(
'Resume Course'
,
response_content
)
for
chapter
in
course
.
children
:
self
.
assertIn
(
chapter
.
display_name
,
response_content
)
for
section
in
chapter
.
children
:
self
.
assertIn
(
section
.
display_name
,
response_content
)
if
section
.
graded
:
self
.
assertIn
(
section
.
due
,
response_content
)
self
.
assertIn
(
section
.
format
,
response_content
)
for
vertical
in
section
.
children
:
self
.
assertNotIn
(
vertical
.
display_name
,
response_content
)
...
...
openedx/features/course_experience/views/course_outline.py
View file @
aafd6a03
...
...
@@ -48,7 +48,7 @@ class CourseOutlineFragmentView(EdxFragmentView):
course_usage_key
,
user
=
request
.
user
,
nav_depth
=
3
,
requested_fields
=
[
'children'
,
'display_name'
,
'type'
,
'due'
,
'graded'
,
'special_exam'
],
requested_fields
=
[
'children'
,
'display_name'
,
'type'
,
'due'
,
'graded'
,
'special_exam
_info'
,
'format
'
],
block_types_filter
=
[
'course'
,
'chapter'
,
'sequential'
]
)
...
...
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