Commit 0899ac56 by Robert Raposa Committed by Diana Huang

Fix review comments.

parent 69ba8eb0
...@@ -7,11 +7,9 @@ from nose.plugins.attrib import attr ...@@ -7,11 +7,9 @@ from nose.plugins.attrib import attr
from ..helpers import auto_auth, load_data_str, UniqueCourseTest from ..helpers import auto_auth, load_data_str, UniqueCourseTest
from ...fixtures.course import CourseFixture, XBlockFixtureDesc from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from ...pages.common.logout import LogoutPage
from ...pages.lms.bookmarks import BookmarksPage from ...pages.lms.bookmarks import BookmarksPage
from ...pages.lms.course_home import CourseHomePage from ...pages.lms.course_home import CourseHomePage
from ...pages.lms.courseware import CoursewarePage from ...pages.lms.courseware import CoursewarePage
from ...pages.studio.overview import CourseOutlinePage as StudioCourseOutlinePage
class CourseHomeBaseTest(UniqueCourseTest): class CourseHomeBaseTest(UniqueCourseTest):
...@@ -132,29 +130,10 @@ class CourseHomeA11yTest(CourseHomeBaseTest): ...@@ -132,29 +130,10 @@ class CourseHomeA11yTest(CourseHomeBaseTest):
def setUp(self): def setUp(self):
super(CourseHomeA11yTest, self).setUp() super(CourseHomeA11yTest, self).setUp()
self.logout_page = LogoutPage(self.browser)
def test_course_home_a11y(self): def test_course_home_a11y(self):
""" """
Test the accessibility of the course home page with course outline. 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 = CourseHomePage(self.browser, self.course_id) course_home_page.visit()
course_home_page.visit() course_home_page.a11y_audit.check_for_accessibility_errors()
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()
...@@ -19,9 +19,14 @@ log = logging.getLogger(__name__) ...@@ -19,9 +19,14 @@ log = logging.getLogger(__name__)
class MilestonesTransformer(BlockStructureTransformer): class MilestonesTransformer(BlockStructureTransformer):
""" """
Adds special exams (timed, proctored, practice proctored) to the student view. A transformer that handles both milestones and special (timed) exams.
May exclude special exams.
Excludes all blocks with unfulfilled milestones from the student view. 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 WRITE_VERSION = 1
READ_VERSION = 1 READ_VERSION = 1
...@@ -51,21 +56,19 @@ class MilestonesTransformer(BlockStructureTransformer): ...@@ -51,21 +56,19 @@ class MilestonesTransformer(BlockStructureTransformer):
""" """
Modify block structure according to the behavior of milestones and special exams. Modify block structure according to the behavior of milestones and special exams.
""" """
required_content = self.get_required_content(usage_info, block_structure)
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)
def user_gated_from_block(block_key): def user_gated_from_block(block_key):
""" """
Checks whether the user is gated from accessing this block, first via special exams, Checks whether the user is gated from accessing this block, first via special exams,
then via a general milestones check. then via a general milestones check.
""" """
if usage_info.has_staff_access: if usage_info.has_staff_access:
return False return False
elif self.has_pending_milestones_for_user(block_key, usage_info): elif self.has_pending_milestones_for_user(block_key, usage_info):
return True 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 return True
elif (settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False) and elif (settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False) and
(self.is_special_exam(block_key, block_structure) and (self.is_special_exam(block_key, block_structure) and
...@@ -76,14 +79,13 @@ class MilestonesTransformer(BlockStructureTransformer): ...@@ -76,14 +79,13 @@ class MilestonesTransformer(BlockStructureTransformer):
for block_key in block_structure.topological_traversal(): for block_key in block_structure.topological_traversal():
if user_gated_from_block(block_key): if user_gated_from_block(block_key):
block_structure.remove_block(block_key, False) 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) self.add_special_exam_info(block_key, block_structure, usage_info)
@staticmethod @staticmethod
def is_special_exam(block_key, block_structure): def is_special_exam(block_key, block_structure):
""" """
Test whether the block is a special exam. These exams are always excluded Test whether the block is a special exam.
from the student view.
""" """
return ( return (
block_structure.get_xblock_field(block_key, 'is_proctored_enabled') or block_structure.get_xblock_field(block_key, 'is_proctored_enabled') or
...@@ -106,45 +108,59 @@ class MilestonesTransformer(BlockStructureTransformer): ...@@ -106,45 +108,59 @@ class MilestonesTransformer(BlockStructureTransformer):
def add_special_exam_info(self, block_key, block_structure, usage_info): 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): Get the required content for the course.
# call into edx_proctoring subsystem to get relevant special exam information This takes into account if the user can skip the entrance exam.
#
# This will return None, if (user, course_id, content_id) is not applicable """
special_exam_attempt_context = None course_key = block_structure.root_block_usage_key.course_key
try: user_can_skip_entrance_exam = EntranceExamConfiguration.user_can_skip_entrance_exam(usage_info.user, course_key)
special_exam_attempt_context = get_attempt_status_summary( required_content = milestones_helpers.get_required_content(course_key, usage_info.user)
usage_info.user.id,
unicode(block_key.course_key), if not required_content:
unicode(block_key) return required_content
)
except ProctoredExamNotFoundException as ex: if user_can_skip_entrance_exam:
log.exception(ex) # remove the entrance exam from required content
entrance_exam_id = block_structure.get_xblock_field(block_structure.root_block_usage_key, 'entrance_exam_id')
if special_exam_attempt_context: required_content = [content for content in required_content if not content == entrance_exam_id]
# yes, user has proctoring context about
# this level of the courseware return required_content
# so add to the accordion data context
block_structure.set_transformer_block_field(
block_key,
self,
'special_exam_info',
special_exam_attempt_context,
)
@staticmethod @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 True if the current block associated with the block_key should be gated by the given required_content.
Returns False otherwise. Returns False otherwise.
""" """
if not required_content: if not required_content:
return False 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: if block_key.block_type == 'chapter' and unicode(block_key) not in required_content:
return True return True
......
...@@ -49,6 +49,7 @@ from django.utils.translation import ugettext as _ ...@@ -49,6 +49,7 @@ from django.utils.translation import ugettext as _
## Exam subsections expose exam status message field as well as a status icon ## Exam subsections expose exam status message field as well as a status icon
<% <%
if subsection.get('due') is None: if subsection.get('due') is None:
# examples: Homework, Lab, etc.
data_string = subsection.get('format') data_string = subsection.get('format')
else: else:
if 'special_exam_info' in subsection: 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