Commit 0899ac56 by Robert Raposa Committed by Diana Huang

Fix review comments.

parent 69ba8eb0
......@@ -7,11 +7,9 @@ from nose.plugins.attrib import attr
from ..helpers import auto_auth, load_data_str, UniqueCourseTest
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from ...pages.common.logout import LogoutPage
from ...pages.lms.bookmarks import BookmarksPage
from ...pages.lms.course_home import CourseHomePage
from ...pages.lms.courseware import CoursewarePage
from ...pages.studio.overview import CourseOutlinePage as StudioCourseOutlinePage
class CourseHomeBaseTest(UniqueCourseTest):
......@@ -132,29 +130,10 @@ class CourseHomeA11yTest(CourseHomeBaseTest):
def setUp(self):
super(CourseHomeA11yTest, self).setUp()
self.logout_page = LogoutPage(self.browser)
def test_course_home_a11y(self):
"""
Test the accessibility of the course home page with course outline.
"""
with self._logged_in_session():
course_home_page = CourseHomePage(self.browser, self.course_id)
course_home_page.visit()
course_home_page.a11y_audit.check_for_accessibility_errors()
@contextmanager
def _logged_in_session(self, staff=False):
"""
Ensure that the user is logged in and out appropriately at the beginning
and end of the current test.
"""
self.logout_page.visit()
try:
if staff:
auto_auth(self.browser, "STAFF_TESTER", "staff101@example.com", True, self.course_id)
else:
auto_auth(self.browser, self.USERNAME, self.EMAIL, False, self.course_id)
yield
finally:
self.logout_page.visit()
course_home_page = CourseHomePage(self.browser, self.course_id)
course_home_page.visit()
course_home_page.a11y_audit.check_for_accessibility_errors()
......@@ -19,9 +19,14 @@ log = logging.getLogger(__name__)
class MilestonesTransformer(BlockStructureTransformer):
"""
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.
A transformer that handles both milestones and special (timed) exams.
It excludes all blocks with unfulfilled milestones from the student view. An entrance exam is considered a
milestone, and is not considered a "special exam".
It also includes or excludes all special (timed) exams (timed, proctored, practice proctored) in/from the
student view, based on the value of `include_special_exams`.
"""
WRITE_VERSION = 1
READ_VERSION = 1
......@@ -51,21 +56,19 @@ class MilestonesTransformer(BlockStructureTransformer):
"""
Modify block structure according to the behavior of milestones and special exams.
"""
course_key = block_structure.root_block_usage_key.course_key
user_can_skip = EntranceExamConfiguration.user_can_skip_entrance_exam(usage_info.user, course_key)
required_content = milestones_helpers.get_required_content(course_key, usage_info.user)
required_content = self.get_required_content(usage_info, block_structure)
def user_gated_from_block(block_key):
"""
Checks whether the user is gated from accessing this block, first via special exams,
then via a general milestones check.
"""
if usage_info.has_staff_access:
return False
elif self.has_pending_milestones_for_user(block_key, usage_info):
return True
elif self.gated_by_required_content(block_key, block_structure, user_can_skip, required_content):
elif self.gated_by_required_content(block_key, block_structure, required_content):
return True
elif (settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False) and
(self.is_special_exam(block_key, block_structure) and
......@@ -76,14 +79,13 @@ class MilestonesTransformer(BlockStructureTransformer):
for block_key in block_structure.topological_traversal():
if user_gated_from_block(block_key):
block_structure.remove_block(block_key, False)
else:
elif self.is_special_exam(block_key, block_structure):
self.add_special_exam_info(block_key, block_structure, usage_info)
@staticmethod
def is_special_exam(block_key, block_structure):
"""
Test whether the block is a special exam. These exams are always excluded
from the student view.
Test whether the block is a special exam.
"""
return (
block_structure.get_xblock_field(block_key, 'is_proctored_enabled') or
......@@ -106,45 +108,59 @@ class MilestonesTransformer(BlockStructureTransformer):
def add_special_exam_info(self, block_key, block_structure, usage_info):
"""
Adds special exam information to course blocks.
For special exams, add the special exam information to the course blocks.
"""
special_exam_attempt_context = None
try:
# Calls 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 = 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:
# This user has special exam context for this block so add it.
block_structure.set_transformer_block_field(
block_key,
self,
'special_exam_info',
special_exam_attempt_context,
)
@staticmethod
def get_required_content(usage_info, block_structure):
"""
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,
)
Get the required content for the course.
This takes into account if the user can skip the entrance exam.
"""
course_key = block_structure.root_block_usage_key.course_key
user_can_skip_entrance_exam = EntranceExamConfiguration.user_can_skip_entrance_exam(usage_info.user, course_key)
required_content = milestones_helpers.get_required_content(course_key, usage_info.user)
if not required_content:
return required_content
if user_can_skip_entrance_exam:
# remove the entrance exam from required content
entrance_exam_id = block_structure.get_xblock_field(block_structure.root_block_usage_key, 'entrance_exam_id')
required_content = [content for content in required_content if not content == entrance_exam_id]
return required_content
@staticmethod
def gated_by_required_content(block_key, block_structure, user_can_skip, required_content):
def gated_by_required_content(block_key, block_structure, 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
......
......@@ -49,6 +49,7 @@ from django.utils.translation import ugettext as _
## Exam subsections expose exam status message field as well as a status icon
<%
if subsection.get('due') is None:
# examples: Homework, Lab, etc.
data_string = subsection.get('format')
else:
if 'special_exam_info' in subsection:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment