- % if enrollment_mode and relative_dates_flag_is_enabled and self_paced and not is_course_staff: + % if relative_dates_flag_is_enabled and self_paced and not is_course_staff: <%include file="/dates_banner.html" /> % endif
diff --git a/openedx/features/course_experience/tests/views/test_course_outline.py b/openedx/features/course_experience/tests/views/test_course_outline.py index 709bd8ef56..de86b37cbb 100644 --- a/openedx/features/course_experience/tests/views/test_course_outline.py +++ b/openedx/features/course_experience/tests/views/test_course_outline.py @@ -25,6 +25,7 @@ from waffle.models import Switch from waffle.testutils import override_switch from course_modes.models import CourseMode +from course_modes.tests.factories import CourseModeFactory from lms.djangoapps.courseware.tests.factories import StaffFactory from lms.urls import RESET_COURSE_DEADLINES_NAME from gating import api as lms_gating_api @@ -33,6 +34,7 @@ from openedx.core.djangoapps.schedules.models import Schedule from openedx.core.djangoapps.schedules.tests.factories import ScheduleFactory from openedx.core.lib.gating import api as gating_api from openedx.features.course_experience import RELATIVE_DATES_FLAG +from openedx.features.content_type_gating.models import ContentTypeGatingConfig from openedx.features.course_experience.views.course_outline import ( DEFAULT_COMPLETION_TRACKING_START, CourseOutlineFragmentView @@ -170,20 +172,29 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase): @RELATIVE_DATES_FLAG.override(active=True) @ddt.data( - (CourseMode.AUDIT, False, True), - (CourseMode.VERIFIED, False, True), - (CourseMode.MASTERS, False, False), - (CourseMode.VERIFIED, True, False), + ([CourseMode.AUDIT, CourseMode.VERIFIED], CourseMode.AUDIT, False, True), + ([CourseMode.AUDIT, CourseMode.VERIFIED], CourseMode.VERIFIED, False, True), + ([CourseMode.AUDIT, CourseMode.VERIFIED, CourseMode.MASTERS], CourseMode.MASTERS, False, True), + ([CourseMode.PROFESSIONAL], CourseMode.PROFESSIONAL, False, True), + ([CourseMode.AUDIT, CourseMode.VERIFIED], CourseMode.VERIFIED, True, False), ) @ddt.unpack def test_reset_course_deadlines_banner_shows_for_self_paced_course( self, + course_modes, enrollment_mode, is_course_staff, should_display ): + ContentTypeGatingConfig.objects.create( + enabled=True, + enabled_as_of=datetime.datetime(2018, 1, 1), + ) course = self.courses[0] - enrollment = CourseEnrollment.objects.get(course_id=course.id) + for mode in course_modes: + CourseModeFactory.create(course_id=course.id, mode_slug=mode) + + enrollment = CourseEnrollment.objects.get(course_id=course.id, user=self.user) enrollment.mode = enrollment_mode enrollment.save() self.user.is_staff = is_course_staff diff --git a/openedx/features/course_experience/views/course_outline.py b/openedx/features/course_experience/views/course_outline.py index 8005a74f25..750b40e832 100644 --- a/openedx/features/course_experience/views/course_outline.py +++ b/openedx/features/course_experience/views/course_outline.py @@ -31,6 +31,7 @@ from openedx.core.djangoapps.content.course_overviews.models import CourseOvervi from openedx.core.djangoapps.plugin_api.views import EdxFragmentView from openedx.core.djangoapps.schedules.utils import reset_self_paced_schedule from openedx.features.course_experience import RELATIVE_DATES_FLAG +from openedx.features.content_type_gating.models import ContentTypeGatingConfig from student.models import CourseEnrollment from util.milestones_helpers import get_course_content_milestones from xmodule.course_module import COURSE_VISIBILITY_PUBLIC @@ -96,17 +97,18 @@ class CourseOutlineFragmentView(EdxFragmentView): reset_deadlines_url = reverse(RESET_COURSE_DEADLINES_NAME) reset_deadlines_redirect_url_base = COURSE_HOME_VIEW_NAME - course_enrollment = None - if not request.user.is_anonymous: - course_enrollment = CourseEnrollment.objects.filter(course=course_overview, user=request.user).filter( - Q(mode=CourseMode.AUDIT) | Q(mode=CourseMode.VERIFIED)).first() - context['reset_deadlines_url'] = reset_deadlines_url context['reset_deadlines_redirect_url_base'] = reset_deadlines_redirect_url_base context['reset_deadlines_redirect_url_id_dict'] = {'course_id': str(course.id)} - context['enrollment_mode'] = getattr(course_enrollment, 'mode', None) - context['verified_upgrade_link'] = verified_upgrade_deadline_link(request.user, course=course), - context['on_course_outline_page'] = True, + context['verified_upgrade_link'] = verified_upgrade_deadline_link(request.user, course=course) + context['on_course_outline_page'] = True + context['content_type_gating_enabled'] = ContentTypeGatingConfig.enabled_for_enrollment( + user=request.user, + course_key=course_key + ) + # We use javascript to check whether to actually display this banner, so we let the banner assume + # that deadlines have been missed. + context['missed_deadlines'] = True html = render_to_string('course_experience/course-outline-fragment.html', context) return Fragment(html) From d3b11ec25bc28de84220e6b6c2a0796150c388ed Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Wed, 3 Jun 2020 10:14:11 -0400 Subject: [PATCH 2/2] Refactor dates_banner_should_display to only return a single value, and to have a clearer set of conditions --- openedx/features/course_experience/utils.py | 74 ++++++++++++--------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/openedx/features/course_experience/utils.py b/openedx/features/course_experience/utils.py index 1b36959b1f..c95cd36dbe 100644 --- a/openedx/features/course_experience/utils.py +++ b/openedx/features/course_experience/utils.py @@ -262,36 +262,46 @@ def dates_banner_should_display(course_key, request): incomplete sequentials and which enrollment mode is being dealt with for the current user and course. """ - missed_deadlines = False - course_enrollment = None - if RELATIVE_DATES_FLAG.is_enabled(str(course_key)): - course_overview = CourseOverview.objects.get(id=str(course_key)) - course_end_date = getattr(course_overview, 'end_date', None) - is_self_paced = getattr(course_overview, 'self_paced', False) - is_course_staff = bool( - request.user and course_overview and has_access(request.user, 'staff', course_overview, course_overview.id) - ) - if is_self_paced and (not is_course_staff) and (not course_end_date or timezone.now() < course_end_date): - course_enrollment = CourseEnrollment.objects.filter( - course=course_overview, user=request.user, - ).filter( - Q(mode=CourseMode.AUDIT) | Q(mode=CourseMode.VERIFIED) - ).first() - if course_enrollment: - store = modulestore() - course_usage_key = store.make_course_usage_key(course_key) - block_data = get_course_blocks(request.user, course_usage_key, include_completion=True) - for section_key in block_data.get_children(course_usage_key): - if missed_deadlines: - break - for subsection_key in block_data.get_children(section_key): - subsection_due_date = block_data.get_xblock_field(subsection_key, 'due', None) - if subsection_due_date and ( - not block_data.get_xblock_field(subsection_key, 'complete', False) - and block_data.get_xblock_field(subsection_key, 'graded', False) - and subsection_due_date < timezone.now() - ): - missed_deadlines = True - break + if not RELATIVE_DATES_FLAG.is_enabled(str(course_key)): + return False - return missed_deadlines, getattr(course_enrollment, 'mode', None) + course_overview = CourseOverview.objects.get(id=str(course_key)) + course_end_date = getattr(course_overview, 'end_date', None) + is_self_paced = getattr(course_overview, 'self_paced', False) + + # Only display the banner for self-paced courses + if not is_self_paced: + return False + + # Only display the banner for enrolled users + if not CourseEnrollment.is_enrolled(request.user, course_key): + return False + + # Don't display the banner for course staff + is_course_staff = bool( + request.user and course_overview and has_access(request.user, 'staff', course_overview, course_overview.id) + ) + if is_course_staff: + return False + + # Don't display the banner if the course has ended + if course_end_date and course_end_date < timezone.now(): + return False + + store = modulestore() + course_usage_key = store.make_course_usage_key(course_key) + block_data = get_course_blocks(request.user, course_usage_key, include_completion=True) + for section_key in block_data.get_children(course_usage_key): + for subsection_key in block_data.get_children(section_key): + subsection_due_date = block_data.get_xblock_field(subsection_key, 'due', None) + if subsection_due_date and ( + not block_data.get_xblock_field(subsection_key, 'complete', False) + and block_data.get_xblock_field(subsection_key, 'graded', False) + and subsection_due_date < timezone.now() + ): + # Display the banner if the due date for an incomplete graded subsection + # has passed + return True + + # Don't display the banner if there were no missed deadlines + return False