From 2b2a6cca2302c261a757f44857b15a72a2e746a4 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 4 Jun 2020 14:53:05 -0400 Subject: [PATCH 1/5] Never show the dates banner on archived courses --- .../course_home_api/dates/v1/views.py | 2 +- lms/djangoapps/courseware/views/views.py | 4 ++- lms/templates/dates_banner.html | 34 ++++++++++--------- .../course_experience/views/course_outline.py | 1 + 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lms/djangoapps/course_home_api/dates/v1/views.py b/lms/djangoapps/course_home_api/dates/v1/views.py index 2dbea61418..a8b36f0b04 100644 --- a/lms/djangoapps/course_home_api/dates/v1/views.py +++ b/lms/djangoapps/course_home_api/dates/v1/views.py @@ -2,7 +2,6 @@ Dates Tab Views """ - from rest_framework import status from rest_framework.generics import RetrieveAPIView from rest_framework.permissions import IsAuthenticated @@ -85,6 +84,7 @@ class DatesTabView(RetrieveAPIView): user_timezone = user_timezone_locale['user_timezone'] data = { + 'is_archived': course.end < datetime.now(), 'course_date_blocks': [block for block in blocks if not isinstance(block, TodaysDate)], 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 3fba89aeee..dbf77be430 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -1081,7 +1081,8 @@ def dates(request, course_id): 'missed_gated_content': missed_gated_content, 'reset_deadlines_url': reverse(RESET_COURSE_DEADLINES_NAME), 'reset_deadlines_redirect_url_base': COURSE_DATES_NAME, - 'reset_deadlines_redirect_url_id_dict': {'course_id': str(course.id)} + 'reset_deadlines_redirect_url_id_dict': {'course_id': str(course.id)}, + 'is_archived': course.end < datetime.now(), } return render_to_response('courseware/dates.html', context) @@ -1680,6 +1681,7 @@ def render_xblock(request, usage_key_string, check_if_enrolled=True): 'xqa_server': settings.FEATURES.get('XQA_SERVER', 'http://your_xqa_server.com'), 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, + 'is_archived': course.end < datetime.now(), 'web_app_course_url': reverse(COURSE_HOME_VIEW_NAME, args=[course.id]), 'on_courseware_page': True, 'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course), diff --git a/lms/templates/dates_banner.html b/lms/templates/dates_banner.html index b6f127c5a2..3c79da9fbc 100644 --- a/lms/templates/dates_banner.html +++ b/lms/templates/dates_banner.html @@ -8,14 +8,6 @@ from lms.djangoapps.courseware.date_summary import CourseAssignmentDate from course_modes.models import CourseMode %> -% if on_dates_tab and not missed_deadlines and getattr(course, 'self_paced', False): -
-
- ${_("We've built a suggested schedule to help you stay on track.")} - ${_("But don't worry—it's flexible so you can learn at your own pace. If you happen to fall behind on our suggested dates, you'll be able to adjust them to keep yourself on track.")} -
-
-% endif <% additional_styling_class = 'on-mobile' if is_mobile_app else 'has-button' %> @@ -93,13 +85,23 @@ additional_styling_class = 'on-mobile' if is_mobile_app else 'has-button' % endif -% if on_dates_tab and content_type_gating_enabled and not missed_deadlines: - ${upgrade_to_complete_graded_banner()} -% elif missed_deadlines: - % if missed_gated_content: - ${upgrade_to_reset_banner()} - % else: - ${reset_dates_banner()} + +% if not is_archived: + % if on_dates_tab and not missed_deadlines and getattr(course, 'self_paced', False): +
+
+ ${_("We've built a suggested schedule to help you stay on track.")} + ${_("But don't worry—it's flexible so you can learn at your own pace. If you happen to fall behind on our suggested dates, you'll be able to adjust them to keep yourself on track.")} +
+
+ % endif + % if on_dates_tab and content_type_gating_enabled and not missed_deadlines: + ${upgrade_to_complete_graded_banner()} + % elif missed_deadlines: + % if missed_gated_content: + ${upgrade_to_reset_banner()} + % else: + ${reset_dates_banner()} + % endif % endif % endif - diff --git a/openedx/features/course_experience/views/course_outline.py b/openedx/features/course_experience/views/course_outline.py index f2e8e5a77e..3b226b147f 100644 --- a/openedx/features/course_experience/views/course_outline.py +++ b/openedx/features/course_experience/views/course_outline.py @@ -107,6 +107,7 @@ class CourseOutlineFragmentView(EdxFragmentView): context['on_course_outline_page'] = True context['missed_deadlines'] = missed_deadlines context['missed_gated_content'] = missed_gated_content + context['is_archived'] = course.end < datetime.now() html = render_to_string('course_experience/course-outline-fragment.html', context) return Fragment(html) From 514d10599df8dbbe16c032cd8347c1a1e8c5eb82 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 4 Jun 2020 14:55:18 -0400 Subject: [PATCH 2/5] Refactor dates_banner conditionals slightly --- lms/templates/dates_banner.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lms/templates/dates_banner.html b/lms/templates/dates_banner.html index 3c79da9fbc..b090cbf1d9 100644 --- a/lms/templates/dates_banner.html +++ b/lms/templates/dates_banner.html @@ -87,16 +87,18 @@ additional_styling_class = 'on-mobile' if is_mobile_app else 'has-button' % if not is_archived: - % if on_dates_tab and not missed_deadlines and getattr(course, 'self_paced', False): + % if on_dates_tab and not missed_deadlines: + %if getattr(course, 'self_paced', False):
${_("We've built a suggested schedule to help you stay on track.")} ${_("But don't worry—it's flexible so you can learn at your own pace. If you happen to fall behind on our suggested dates, you'll be able to adjust them to keep yourself on track.")}
- % endif - % if on_dates_tab and content_type_gating_enabled and not missed_deadlines: - ${upgrade_to_complete_graded_banner()} + % endif + % if content_type_gating_enabled: + ${upgrade_to_complete_graded_banner()} + % endif % elif missed_deadlines: % if missed_gated_content: ${upgrade_to_reset_banner()} From 333c9ccddfdda18f056260ec626c6ee86e4299b0 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 4 Jun 2020 15:38:03 -0400 Subject: [PATCH 3/5] Simplify how the course-outline template context is constructed to bring it into parity with other template contexts --- .../course_experience/views/course_outline.py | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/openedx/features/course_experience/views/course_outline.py b/openedx/features/course_experience/views/course_outline.py index 3b226b147f..31f2290c42 100644 --- a/openedx/features/course_experience/views/course_outline.py +++ b/openedx/features/course_experience/views/course_outline.py @@ -67,15 +67,6 @@ class CourseOutlineFragmentView(EdxFragmentView): if not course_block_tree: return None - context = { - 'csrf': csrf(request)['csrf_token'], - 'course': course_overview, - 'due_date_display_format': course.due_date_display_format, - 'blocks': course_block_tree, - 'enable_links': user_is_enrolled or course.course_visibility == COURSE_VISIBILITY_PUBLIC, - 'course_key': course_key, - } - resume_block = get_resume_block(course_block_tree) if user_is_enrolled else None if not resume_block: @@ -86,28 +77,32 @@ class CourseOutlineFragmentView(EdxFragmentView): missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, request.user) - context['gated_content'] = gated_content - context['xblock_display_names'] = xblock_display_names - - page_context = kwargs.get('page_context', None) - if page_context: - context['self_paced'] = page_context.get('pacing_type', 'instructor_paced') == 'self_paced' - - # We're using this flag to prevent old self-paced dates from leaking out on courses not - # managed by edx-when. - context['in_edx_when'] = edx_when_api.is_enabled_for_course(course_key) - reset_deadlines_url = reverse(RESET_COURSE_DEADLINES_NAME) reset_deadlines_redirect_url_base = COURSE_HOME_VIEW_NAME - 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['verified_upgrade_link'] = verified_upgrade_deadline_link(request.user, course=course) - context['on_course_outline_page'] = True - context['missed_deadlines'] = missed_deadlines - context['missed_gated_content'] = missed_gated_content - context['is_archived'] = course.end < datetime.now() + context = { + 'csrf': csrf(request)['csrf_token'], + 'course': course_overview, + 'due_date_display_format': course.due_date_display_format, + 'blocks': course_block_tree, + 'enable_links': user_is_enrolled or course.course_visibility == COURSE_VISIBILITY_PUBLIC, + 'course_key': course_key, + 'gated_content': gated_content, + 'xblock_display_names': xblock_display_names, + 'self_paced': course.self_paced, + + # We're using this flag to prevent old self-paced dates from leaking out on courses not + # managed by edx-when. + 'in_edx_when': edx_when_api.is_enabled_for_course(course_key), + 'reset_deadlines_url': reset_deadlines_url, + 'reset_deadlines_redirect_url_base': reset_deadlines_redirect_url_base, + 'reset_deadlines_redirect_url_id_dict': {'course_id': str(course.id)}, + 'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course), + 'on_course_outline_page': True, + 'missed_deadlines': missed_deadlines, + 'missed_gated_content': missed_gated_content, + 'is_archived': course.end < datetime.now(), + } html = render_to_string('course_experience/course-outline-fragment.html', context) return Fragment(html) From 1cf46e76d0a8274ac1b3c2aaa3f1358cdf9fca96 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 11 Jun 2020 09:08:55 -0400 Subject: [PATCH 4/5] Don't compare None to a date when a course doesn't have an end date --- lms/djangoapps/course_home_api/dates/v1/views.py | 2 +- lms/djangoapps/courseware/date_summary.py | 2 +- lms/djangoapps/courseware/views/views.py | 4 ++-- openedx/core/djangoapps/programs/tests/test_utils.py | 2 +- openedx/features/course_experience/views/course_outline.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lms/djangoapps/course_home_api/dates/v1/views.py b/lms/djangoapps/course_home_api/dates/v1/views.py index a8b36f0b04..ae47567cb4 100644 --- a/lms/djangoapps/course_home_api/dates/v1/views.py +++ b/lms/djangoapps/course_home_api/dates/v1/views.py @@ -84,7 +84,7 @@ class DatesTabView(RetrieveAPIView): user_timezone = user_timezone_locale['user_timezone'] data = { - 'is_archived': course.end < datetime.now(), + 'is_archived': course.end and course.end < datetime.now(), 'course_date_blocks': [block for block in blocks if not isinstance(block, TodaysDate)], 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, diff --git a/lms/djangoapps/courseware/date_summary.py b/lms/djangoapps/courseware/date_summary.py index a03f248ef5..e1bd3864c6 100644 --- a/lms/djangoapps/courseware/date_summary.py +++ b/lms/djangoapps/courseware/date_summary.py @@ -327,7 +327,7 @@ class CourseEndDate(DateSummary): weeks_to_complete = get_course_run_details(self.course.id, ['weeks_to_complete']).get('weeks_to_complete') if weeks_to_complete: course_duration = datetime.timedelta(weeks=weeks_to_complete) - if self.course.end < (self.current_time + course_duration): + if self.course.end and self.course.end < (self.current_time + course_duration): return self.course.end return None diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index dbf77be430..eb88637ff6 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -1082,7 +1082,7 @@ def dates(request, course_id): 'reset_deadlines_url': reverse(RESET_COURSE_DEADLINES_NAME), 'reset_deadlines_redirect_url_base': COURSE_DATES_NAME, 'reset_deadlines_redirect_url_id_dict': {'course_id': str(course.id)}, - 'is_archived': course.end < datetime.now(), + 'is_archived': course.end and course.end < datetime.now(), } return render_to_response('courseware/dates.html', context) @@ -1681,7 +1681,7 @@ def render_xblock(request, usage_key_string, check_if_enrolled=True): 'xqa_server': settings.FEATURES.get('XQA_SERVER', 'http://your_xqa_server.com'), 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, - 'is_archived': course.end < datetime.now(), + 'is_archived': course.end and course.end < datetime.now(), 'web_app_course_url': reverse(COURSE_HOME_VIEW_NAME, args=[course.id]), 'on_courseware_page': True, 'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course), diff --git a/openedx/core/djangoapps/programs/tests/test_utils.py b/openedx/core/djangoapps/programs/tests/test_utils.py index cfaaba190f..d8abf1173a 100644 --- a/openedx/core/djangoapps/programs/tests/test_utils.py +++ b/openedx/core/djangoapps/programs/tests/test_utils.py @@ -794,7 +794,7 @@ class TestProgramDataExtender(ModuleStoreTestCase): 'certificate_url': None, 'course_url': reverse('course_root', args=[self.course.id]), 'enrollment_open_date': strftime_localized(DEFAULT_ENROLLMENT_START_DATE, 'SHORT_DATE'), - 'is_course_ended': self.course.end < datetime.datetime.now(utc), + 'is_course_ended': self.course.end and self.course.end < datetime.datetime.now(utc), 'is_enrolled': False, 'is_enrollment_open': True, 'upgrade_url': None, diff --git a/openedx/features/course_experience/views/course_outline.py b/openedx/features/course_experience/views/course_outline.py index 31f2290c42..bb989b3a47 100644 --- a/openedx/features/course_experience/views/course_outline.py +++ b/openedx/features/course_experience/views/course_outline.py @@ -101,7 +101,7 @@ class CourseOutlineFragmentView(EdxFragmentView): 'on_course_outline_page': True, 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, - 'is_archived': course.end < datetime.now(), + 'is_archived': course.end and course.end < datetime.now(), } html = render_to_string('course_experience/course-outline-fragment.html', context) From 86e2677f2638e18dac6a25b3ddce8de89441b80d Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Thu, 11 Jun 2020 09:11:15 -0400 Subject: [PATCH 5/5] Use a standard function to find out if a course has ended --- lms/djangoapps/course_home_api/dates/v1/views.py | 2 +- lms/djangoapps/courseware/views/views.py | 4 ++-- lms/templates/dates_banner.html | 2 +- openedx/core/djangoapps/programs/tests/test_utils.py | 2 +- openedx/features/course_experience/views/course_outline.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lms/djangoapps/course_home_api/dates/v1/views.py b/lms/djangoapps/course_home_api/dates/v1/views.py index ae47567cb4..efd184466a 100644 --- a/lms/djangoapps/course_home_api/dates/v1/views.py +++ b/lms/djangoapps/course_home_api/dates/v1/views.py @@ -84,7 +84,7 @@ class DatesTabView(RetrieveAPIView): user_timezone = user_timezone_locale['user_timezone'] data = { - 'is_archived': course.end and course.end < datetime.now(), + 'has_ended': course.has_ended(), 'course_date_blocks': [block for block in blocks if not isinstance(block, TodaysDate)], 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index eb88637ff6..45c7462cd3 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -1082,7 +1082,7 @@ def dates(request, course_id): 'reset_deadlines_url': reverse(RESET_COURSE_DEADLINES_NAME), 'reset_deadlines_redirect_url_base': COURSE_DATES_NAME, 'reset_deadlines_redirect_url_id_dict': {'course_id': str(course.id)}, - 'is_archived': course.end and course.end < datetime.now(), + 'has_ended': course.has_ended(), } return render_to_response('courseware/dates.html', context) @@ -1681,7 +1681,7 @@ def render_xblock(request, usage_key_string, check_if_enrolled=True): 'xqa_server': settings.FEATURES.get('XQA_SERVER', 'http://your_xqa_server.com'), 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, - 'is_archived': course.end and course.end < datetime.now(), + 'has_ended': course.has_ended(), 'web_app_course_url': reverse(COURSE_HOME_VIEW_NAME, args=[course.id]), 'on_courseware_page': True, 'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course), diff --git a/lms/templates/dates_banner.html b/lms/templates/dates_banner.html index b090cbf1d9..3b140cf53c 100644 --- a/lms/templates/dates_banner.html +++ b/lms/templates/dates_banner.html @@ -86,7 +86,7 @@ additional_styling_class = 'on-mobile' if is_mobile_app else 'has-button' -% if not is_archived: +% if not has_ended: % if on_dates_tab and not missed_deadlines: %if getattr(course, 'self_paced', False):
diff --git a/openedx/core/djangoapps/programs/tests/test_utils.py b/openedx/core/djangoapps/programs/tests/test_utils.py index d8abf1173a..61acf1dbd9 100644 --- a/openedx/core/djangoapps/programs/tests/test_utils.py +++ b/openedx/core/djangoapps/programs/tests/test_utils.py @@ -794,7 +794,7 @@ class TestProgramDataExtender(ModuleStoreTestCase): 'certificate_url': None, 'course_url': reverse('course_root', args=[self.course.id]), 'enrollment_open_date': strftime_localized(DEFAULT_ENROLLMENT_START_DATE, 'SHORT_DATE'), - 'is_course_ended': self.course.end and self.course.end < datetime.datetime.now(utc), + 'is_course_ended': self.course.has_ended(), 'is_enrolled': False, 'is_enrollment_open': True, 'upgrade_url': None, diff --git a/openedx/features/course_experience/views/course_outline.py b/openedx/features/course_experience/views/course_outline.py index bb989b3a47..1b4f7b1f8c 100644 --- a/openedx/features/course_experience/views/course_outline.py +++ b/openedx/features/course_experience/views/course_outline.py @@ -101,7 +101,7 @@ class CourseOutlineFragmentView(EdxFragmentView): 'on_course_outline_page': True, 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, - 'is_archived': course.end and course.end < datetime.now(), + 'has_ended': course.has_ended(), } html = render_to_string('course_experience/course-outline-fragment.html', context)