diff --git a/lms/djangoapps/courseware/course_tools.py b/lms/djangoapps/courseware/course_tools.py index b13116cd61..ecad90aee0 100644 --- a/lms/djangoapps/courseware/course_tools.py +++ b/lms/djangoapps/courseware/course_tools.py @@ -10,7 +10,7 @@ from crum import get_current_request from django.utils.translation import ugettext as _ from course_modes.models import CourseMode -from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link +from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link from openedx.features.course_experience.course_tools import CourseTool from student.models import CourseEnrollment diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index 31dfa26c86..a7477fe279 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -16,7 +16,6 @@ from django.db.models import Prefetch from django.http import Http404, QueryDict from django.urls import reverse from edx_django_utils.monitoring import function_trace -from edx_when.api import get_dates_for_course from fs.errors import ResourceNotFound from opaque_keys.edx.keys import UsageKey from path import Path as path @@ -28,9 +27,7 @@ from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access_response import MilestoneAccessError, StartDateError from lms.djangoapps.courseware.date_summary import ( CertificateAvailableDate, - CourseAssignmentDate, CourseEndDate, - CourseExpiredDate, CourseStartDate, TodaysDate, VerificationDeadlineDate, @@ -393,14 +390,13 @@ def get_course_info_section(request, user, course, section_key): return html -def get_course_date_blocks(course, user, request=None, include_past_dates=False, num_assignments=None): +def get_course_date_blocks(course, user): """ Return the list of blocks to display on the course info page, sorted by date. """ block_classes = [ CourseEndDate, - CourseExpiredDate, CourseStartDate, TodaysDate, VerificationDeadlineDate, @@ -409,53 +405,17 @@ def get_course_date_blocks(course, user, request=None, include_past_dates=False, if certs_api.get_active_web_certificate(course): block_classes.insert(0, CertificateAvailableDate) - blocks = [cls(course, user) for cls in block_classes] - blocks.extend(get_course_assignment_due_dates( - course, user, request, num_return=num_assignments, include_past_dates=include_past_dates)) + blocks = (cls(course, user) for cls in block_classes) - return sorted((b for b in blocks if b.date and (b.is_enabled or include_past_dates)), key=date_block_key_fn) - - -def date_block_key_fn(block): - """ - If the block's date is None, return the maximum datetime in order - to force it to the end of the list of displayed blocks. - """ - return block.date or datetime.max.replace(tzinfo=pytz.UTC) - - -def get_course_assignment_due_dates(course, user, request, num_return=None, include_past_dates=False): - """ - Returns a list of assignment (at the subsection/sequential level) due date - blocks for the given course. Will return num_return results or all results - if num_return is None in date increasing order. - """ - store = modulestore() - all_course_dates = get_dates_for_course(course.id, user) - date_blocks = [] - for (block_key, date_type), date in all_course_dates.items(): - if date_type == 'due' and block_key.block_type == 'sequential': - try: - item = store.get_item(block_key) - except ItemNotFoundError: - continue - if item.graded: - date_block = CourseAssignmentDate(course, user) - date_block.date = date - - block_url = None - now = datetime.now().replace(tzinfo=pytz.UTC) - assignment_released = item.start < now - if assignment_released: - block_url = reverse('jump_to', args=[course.id, block_key]) - block_url = request.build_absolute_uri(block_url) if request else None - date_block.set_title(item.display_name, block_url) - - date_blocks.append(date_block) - date_blocks = sorted((b for b in date_blocks if b.is_enabled or include_past_dates), key=date_block_key_fn) - if num_return: - return date_blocks[:num_return] - return date_blocks + def block_key_fn(block): + """ + If the block's date is None, return the maximum datetime in order + to force it to the end of the list of displayed blocks. + """ + if block.date is None: + return datetime.max.replace(tzinfo=pytz.UTC) + return block.date + return sorted((b for b in blocks if b.is_enabled), key=block_key_fn) # TODO: Fix this such that these are pulled in as extra course-specific tabs. diff --git a/lms/djangoapps/courseware/date_summary.py b/lms/djangoapps/courseware/date_summary.py index a431983b0c..ffcb774209 100644 --- a/lms/djangoapps/courseware/date_summary.py +++ b/lms/djangoapps/courseware/date_summary.py @@ -20,14 +20,11 @@ from lazy import lazy from pytz import utc from course_modes.models import CourseMode, get_cosmetic_verified_display_price -from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link, verified_upgrade_link_is_valid +from lms.djangoapps.commerce.utils import EcommerceService from lms.djangoapps.verify_student.models import VerificationDeadline from lms.djangoapps.verify_student.services import IDVerificationService -from openedx.core.djangoapps.catalog.utils import get_course_run_details from openedx.core.djangoapps.certificates.api import can_show_certificate_available_date_field from openedx.core.djangolib.markup import HTML, Text -from openedx.features.course_duration_limits.access import get_user_course_expiration_date -from openedx.features.course_duration_limits.models import CourseDurationLimitConfig from openedx.features.course_experience import UPGRADE_DEADLINE_MESSAGE, CourseHomeMessages from student.models import CourseEnrollment @@ -290,14 +287,6 @@ class CourseEndDate(DateSummary): @property def date(self): - if self.course.self_paced: - 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): - return self.course.end - return None - return self.course.end def register_alerts(self, request, course): @@ -329,60 +318,6 @@ class CourseEndDate(DateSummary): ) -class CourseAssignmentDate(DateSummary): - """ - Displays due dates for homework assignments with a link to the homework - assignment if the link is provided. - """ - css_class = 'assignment' - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.assignment_date = None - self.assignment_title = None - - @property - def date(self): - return self.assignment_date - - @date.setter - def date(self, date): - self.assignment_date = date - - @property - def title(self): - return self.assignment_title - - def set_title(self, title, link=None): - if link: - self.assignment_title = HTML( - '{assignment_title}' - ).format(assignment_link=link, assignment_title=title) - else: - self.assignment_title = title - - -class CourseExpiredDate(DateSummary): - """ - Displays the course expiration date for Audit learners (if enabled) - """ - css_class = 'course-expired' - - @property - def date(self): - if not CourseDurationLimitConfig.enabled_for_enrollment(user=self.user, course_key=self.course_id): - return - return get_user_course_expiration_date(self.user, self.course) - - @property - def description(self): - return _('You lose all access to this course, including your progress.') - - @property - def title(self): - return _('Audit Access Expires') - - class CertificateAvailableDate(DateSummary): """ Displays the certificate available date of the course. @@ -449,6 +384,53 @@ class CertificateAvailableDate(DateSummary): ) +def verified_upgrade_deadline_link(user, course=None, course_id=None): + """ + Format the correct verified upgrade link for the specified ``user`` + in a course. + + One of ``course`` or ``course_id`` must be supplied. If both are specified, + ``course`` will take priority. + + Arguments: + user (:class:`~django.contrib.auth.models.User`): The user to display + the link for. + course (:class:`.CourseOverview`): The course to render a link for. + course_id (:class:`.CourseKey`): The course_id of the course to render for. + + Returns: + The formatted link that will allow the user to upgrade to verified + in this course. + """ + if course is not None: + course_id = course.id + return EcommerceService().upgrade_url(user, course_id) + + +def verified_upgrade_link_is_valid(enrollment=None): + """ + Return whether this enrollment can be upgraded. + + Arguments: + enrollment (:class:`.CourseEnrollment`): The enrollment under consideration. + If None, then the enrollment is considered to be upgradeable. + """ + # Return `true` if user is not enrolled in course + if enrollment is None: + return False + + upgrade_deadline = enrollment.upgrade_deadline + + if upgrade_deadline is None: + return False + + if datetime.datetime.now(utc).date() > upgrade_deadline.date(): + return False + + # Show the summary if user enrollment is in which allow user to upsell + return enrollment.is_active and enrollment.mode in CourseMode.UPSELL_TO_VERIFIED_MODES + + class VerifiedUpgradeDeadlineDate(DateSummary): """ Displays the date before which learners must upgrade to the diff --git a/lms/djangoapps/courseware/tests/helpers.py b/lms/djangoapps/courseware/tests/helpers.py index 4a7d86e865..3918d30576 100644 --- a/lms/djangoapps/courseware/tests/helpers.py +++ b/lms/djangoapps/courseware/tests/helpers.py @@ -21,7 +21,7 @@ from xblock.field_data import DictFieldData from edxmako.shortcuts import render_to_string from lms.djangoapps.courseware.access import has_access -from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link +from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link from lms.djangoapps.courseware.masquerade import handle_ajax, setup_masquerade from lms.djangoapps.lms_xblock.field_data import LmsFieldData from openedx.core.djangoapps.content.course_overviews.models import CourseOverview diff --git a/lms/djangoapps/courseware/tests/test_date_summary.py b/lms/djangoapps/courseware/tests/test_date_summary.py index 49908e8697..7f39f211dc 100644 --- a/lms/djangoapps/courseware/tests/test_date_summary.py +++ b/lms/djangoapps/courseware/tests/test_date_summary.py @@ -18,9 +18,7 @@ from course_modes.tests.factories import CourseModeFactory from lms.djangoapps.courseware.courses import get_course_date_blocks from lms.djangoapps.courseware.date_summary import ( CertificateAvailableDate, - CourseAssignmentDate, CourseEndDate, - CourseExpiredDate, CourseStartDate, TodaysDate, VerificationDeadlineDate, @@ -40,11 +38,10 @@ from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory from openedx.core.djangoapps.user_api.preferences.api import set_user_preference from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag -from openedx.features.course_duration_limits.models import CourseDurationLimitConfig from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, UPGRADE_DEADLINE_MESSAGE, CourseHomeMessages from student.tests.factories import TEST_PASSWORD, CourseEnrollmentFactory, UserFactory from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase -from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory +from xmodule.modulestore.tests.factories import CourseFactory @ddt.ddt @@ -132,138 +129,6 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.VERIFIED) self.assert_block_types(course, user, expected_blocks) - def test_enabled_block_types_with_assignments(self): - """ - Creates a course with multiple subsections to test all of the different - cases for assignment dates showing up. Mocks out calling the edx-when - service and then validates the correct data is set and returned. - """ - course = create_course_run(days_till_start=-100) - user = create_user() - request = RequestFactory().request() - request.user = user - CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.VERIFIED) - now = datetime.now(utc) - assignment_title_html = [''] - with self.store.bulk_operations(course.id): - section = ItemFactory.create(category='chapter', parent_location=course.location) - subsection_1 = ItemFactory.create( - category='sequential', - display_name='Released', - parent_location=section.location, - start=now - timedelta(days=1), - due=now + timedelta(days=6), - graded=True, - ) - subsection_2 = ItemFactory.create( - category='sequential', - display_name='Not released', - parent_location=section.location, - start=now + timedelta(days=1), - due=now + timedelta(days=7), - graded=True, - ) - subsection_3 = ItemFactory.create( - category='sequential', - display_name='Third nearest assignment', - parent_location=section.location, - start=now + timedelta(days=1), - due=now + timedelta(days=8), - graded=True, - ) - subsection_4 = ItemFactory.create( - category='sequential', - display_name='Past due date', - parent_location=section.location, - start=now - timedelta(days=14), - due=now - timedelta(days=7), - graded=True, - ) - subsection_5 = ItemFactory.create( - category='sequential', - display_name='Not returned since we do not get non-graded subsections', - parent_location=section.location, - start=now + timedelta(days=1), - due=now - timedelta(days=7), - graded=False, - ) - - with patch('lms.djangoapps.courseware.courses.get_dates_for_course') as mock_get_dates: - mock_get_dates.return_value = { - (subsection_1.location, 'due'): subsection_1.due, - (subsection_1.location, 'start'): subsection_1.start, - (subsection_2.location, 'due'): subsection_2.due, - (subsection_2.location, 'start'): subsection_2.start, - (subsection_3.location, 'due'): subsection_3.due, - (subsection_3.location, 'start'): subsection_3.start, - (subsection_4.location, 'due'): subsection_4.due, - (subsection_4.location, 'start'): subsection_4.start, - (subsection_5.location, 'due'): subsection_5.due, - (subsection_5.location, 'start'): subsection_5.start, - } - # Standard widget case where we restrict the number of assignments. - expected_blocks = ( - TodaysDate, CourseAssignmentDate, CourseAssignmentDate, CourseEndDate, VerificationDeadlineDate - ) - blocks = get_course_date_blocks(course, user, request, num_assignments=2) - self.assertEqual(len(blocks), len(expected_blocks)) - self.assertEqual(set(type(b) for b in blocks), set(expected_blocks)) - assignment_blocks = filter(lambda b: isinstance(b, CourseAssignmentDate), blocks) - for assignment in assignment_blocks: - assignment_title = str(assignment.title) - self.assertNotEqual(assignment_title, 'Third nearest assignment') - self.assertNotEqual(assignment_title, 'Past due date') - self.assertNotEqual(assignment_title, 'Not returned since we do not get non-graded subsections') - # checking if it is _in_ the title instead of being the title since released assignments - # are actually links. Unreleased assignments are just the string of the title. - if 'Released' in assignment_title: - for html_tag in assignment_title_html: - self.assertIn(html_tag, assignment_title) - elif assignment_title == 'Not released': - for html_tag in assignment_title_html: - self.assertNotIn(html_tag, assignment_title) - - # No restrictions on number of assignments to return - expected_blocks = ( - CourseStartDate, TodaysDate, CourseAssignmentDate, CourseAssignmentDate, CourseAssignmentDate, - CourseAssignmentDate, CourseEndDate, VerificationDeadlineDate - ) - blocks = get_course_date_blocks(course, user, request, include_past_dates=True) - self.assertEqual(len(blocks), len(expected_blocks)) - self.assertEqual(set(type(b) for b in blocks), set(expected_blocks)) - assignment_blocks = filter(lambda b: isinstance(b, CourseAssignmentDate), blocks) - for assignment in assignment_blocks: - assignment_title = str(assignment.title) - self.assertNotEqual(assignment_title, 'Not returned since we do not get non-graded subsections') - # checking if it is _in_ the title instead of being the title since released assignments - # are actually links. Unreleased assignments are just the string of the title. - if 'Released' in assignment_title: - for html_tag in assignment_title_html: - self.assertIn(html_tag, assignment_title) - elif assignment_title == 'Not released': - for html_tag in assignment_title_html: - self.assertNotIn(html_tag, assignment_title) - elif assignment_title == 'Third nearest assignment': - # It's still not released - for html_tag in assignment_title_html: - self.assertNotIn(html_tag, assignment_title) - elif 'Past due date' in assignment_title: - self.assertGreater(now, assignment.date) - for html_tag in assignment_title_html: - self.assertIn(html_tag, assignment_title) - - def test_enabled_block_types_with_expired_course(self): - course = create_course_run(days_till_start=-100) - user = create_user() - # These two lines are to trigger the course expired block to be rendered - CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.AUDIT) - CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1, tzinfo=utc)) - - expected_blocks = ( - TodaysDate, CourseEndDate, CourseExpiredDate, VerifiedUpgradeDeadlineDate - ) - self.assert_block_types(course, user, expected_blocks) - @ddt.data( # Course not started ({}, (CourseStartDate, TodaysDate, CourseEndDate)), @@ -312,7 +177,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase): html_elements = [ '

Upcoming Dates

', - '
', '

Upcoming Dates', - '

', '

time til end (end date shown) - {'weeks_to_complete': 4}, # Weeks to complete < time til end (end date not shown) - ) - def test_course_end_date_self_paced(self, cr_details): - """ - In self-paced courses, the end date will now only show up if the learner - views the course within the course's weeks to complete (as defined in - the course-discovery service). E.g. if the weeks to complete is 5 weeks - and the course doesn't end for 10 weeks, there will be no end date, but - if the course ends in 3 weeks, the end date will appear. - """ - now = datetime.now(utc) - end_timedelta_number = 5 - course = CourseFactory.create( - start=now + timedelta(days=-7), end=now + timedelta(weeks=end_timedelta_number), self_paced=True) - user = create_user() - with patch('lms.djangoapps.courseware.date_summary.get_course_run_details') as mock_get_cr_details: - mock_get_cr_details.return_value = cr_details - block = CourseEndDate(course, user) - self.assertEqual(block.title, 'Course End') - if cr_details['weeks_to_complete'] > end_timedelta_number: - self.assertEqual(block.date, course.end) - else: - self.assertIsNone(block.date) - def test_ecommerce_checkout_redirect(self): """Verify the block link redirects to ecommerce checkout if it's enabled.""" sku = 'TESTSKU' diff --git a/lms/djangoapps/courseware/utils.py b/lms/djangoapps/courseware/utils.py deleted file mode 100644 index a378ace954..0000000000 --- a/lms/djangoapps/courseware/utils.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Utility functions that have to do with the courseware.""" - - -import datetime - -from lms.djangoapps.commerce.utils import EcommerceService -from pytz import utc - -from course_modes.models import CourseMode - - -def verified_upgrade_deadline_link(user, course=None, course_id=None): - """ - Format the correct verified upgrade link for the specified ``user`` - in a course. - - One of ``course`` or ``course_id`` must be supplied. If both are specified, - ``course`` will take priority. - - Arguments: - user (:class:`~django.contrib.auth.models.User`): The user to display - the link for. - course (:class:`.CourseOverview`): The course to render a link for. - course_id (:class:`.CourseKey`): The course_id of the course to render for. - - Returns: - The formatted link that will allow the user to upgrade to verified - in this course. - """ - if course is not None: - course_id = course.id - return EcommerceService().upgrade_url(user, course_id) - - -def verified_upgrade_link_is_valid(enrollment=None): - """ - Return whether this enrollment can be upgraded. - - Arguments: - enrollment (:class:`.CourseEnrollment`): The enrollment under consideration. - If None, then the enrollment is considered to be upgradeable. - """ - # Return `true` if user is not enrolled in course - if enrollment is None: - return False - - upgrade_deadline = enrollment.upgrade_deadline - - if upgrade_deadline is None: - return False - - if datetime.datetime.now(utc).date() > upgrade_deadline.date(): - return False - - # Show the summary if user enrollment is in which allow user to upsell - return enrollment.is_active and enrollment.mode in CourseMode.UPSELL_TO_VERIFIED_MODES diff --git a/lms/djangoapps/experiments/utils.py b/lms/djangoapps/experiments/utils.py index 3e4420e33f..c0a524f75f 100644 --- a/lms/djangoapps/experiments/utils.py +++ b/lms/djangoapps/experiments/utils.py @@ -13,7 +13,7 @@ from opaque_keys.edx.keys import CourseKey from course_modes.models import format_course_price, get_cosmetic_verified_display_price, CourseMode from lms.djangoapps.courseware.access import has_staff_access_to_preview_mode -from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link, verified_upgrade_link_is_valid +from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link, verified_upgrade_link_is_valid from entitlements.models import CourseEntitlement from lms.djangoapps.commerce.utils import EcommerceService from openedx.core.djangoapps.catalog.utils import get_programs diff --git a/lms/djangoapps/experiments/views_custom.py b/lms/djangoapps/experiments/views_custom.py index 9e10d9d9cd..99d20d8fac 100644 --- a/lms/djangoapps/experiments/views_custom.py +++ b/lms/djangoapps/experiments/views_custom.py @@ -23,7 +23,7 @@ from openedx.core.lib.api.authentication import OAuth2AuthenticationAllowInactiv from openedx.core.lib.api.permissions import ApiKeyHeaderPermissionIsAuthenticated from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin -from lms.djangoapps.courseware.utils import verified_upgrade_link_is_valid +from lms.djangoapps.courseware.date_summary import verified_upgrade_link_is_valid from course_modes.models import get_cosmetic_verified_display_price from lms.djangoapps.commerce.utils import EcommerceService from lms.djangoapps.experiments.stable_bucketing import stable_bucketing_hash_group diff --git a/lms/static/sass/features/_course-experience.scss b/lms/static/sass/features/_course-experience.scss index b1fe70780b..3f91244b4f 100644 --- a/lms/static/sass/features/_course-experience.scss +++ b/lms/static/sass/features/_course-experience.scss @@ -14,8 +14,8 @@ text-align: center; } - &:not(:last-child) { - margin-bottom: 32px; + &:not(:first-child) { + margin-top: $baseline; } } } @@ -412,69 +412,64 @@ } // date summary -.date-summary { - @include clearfix; +.date-summary-container { + .date-summary { + @include clearfix; - display: flex; - justify-content: space-between; - padding: 12px 0; - &:last-of-type { - padding-bottom: 0; - } + display: flex; + justify-content: space-between; + padding: $baseline/2 $baseline/2 $baseline/2 0; - .left-column { - flex: 0 0 24px; + .left-column { + flex: 5%; - .calendar-icon { - margin-top: 4px; - height: 1em; - width: 16px; - background: url('#{$static-path}/images/calendar-alt-regular.svg'); - background-repeat: no-repeat; - } - } - - .right-column { - flex: auto; - - .localized-datetime { - font-weight: $font-weight-bold; - margin-bottom: 8px; + .calendar-icon { + margin-top: 3px; + height: 1em; + width: auto; + background: url('#{$static-path}/images/calendar-alt-regular.svg'); + background-repeat: no-repeat; + } } - .heading { - font: -apple-system-body; - line-height: 1.5; - font-weight: $font-bold; - color: theme-color("dark"); + .right-column { + flex: 85%; - a { + .localized-datetime { + font-weight: $font-weight-bold; + margin-bottom: 8px; + } + + .heading { + font: -apple-system-body; + line-height: 1; + font-weight: $font-bold; + color: theme-color("dark"); + } + + .description { + margin-bottom: $baseline/2; + display: inline-block; + } + + .heading, .description { + font-size: 0.9rem; + } + + .date-summary-link { font-weight: $font-semibold; + + a { + color: $link-color; + font-weight: $font-regular; + } } } - .description { - margin-bottom: 0; - display: inline-block; + .date { + color: theme-color("dark"); + font: -apple-system-body; } - - .heading, .description { - font-size: 0.9rem; - } - - .date-summary-link { - font-weight: $font-semibold; - - a { - color: $link-color; - font-size: 0.9rem; - } - } - } - - .date { - color: theme-color("dark"); - font: -apple-system-body; } } diff --git a/openedx/core/djangoapps/schedules/resolvers.py b/openedx/core/djangoapps/schedules/resolvers.py index 6437e28238..c7b22a07d0 100644 --- a/openedx/core/djangoapps/schedules/resolvers.py +++ b/openedx/core/djangoapps/schedules/resolvers.py @@ -14,7 +14,7 @@ from edx_ace.recipient import Recipient from edx_ace.recipient_resolver import RecipientResolver from edx_django_utils.monitoring import function_trace, set_custom_metric -from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link, verified_upgrade_link_is_valid +from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link, verified_upgrade_link_is_valid from lms.djangoapps.discussion.notification_prefs.views import UsernameCipher from openedx.core.djangoapps.ace_common.template_context import get_base_template_context from openedx.core.djangoapps.schedules.config import COURSE_UPDATE_SHOW_UNSUBSCRIBE_WAFFLE_SWITCH diff --git a/openedx/features/course_duration_limits/access.py b/openedx/features/course_duration_limits/access.py index 6dfd476157..1b5ed1323b 100644 --- a/openedx/features/course_duration_limits/access.py +++ b/openedx/features/course_duration_limits/access.py @@ -17,7 +17,7 @@ from web_fragments.fragment import Fragment from course_modes.models import CourseMode from lms.djangoapps.courseware.access_response import AccessError from lms.djangoapps.courseware.access_utils import ACCESS_GRANTED -from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link +from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link from lms.djangoapps.courseware.masquerade import get_course_masquerade, is_masquerading_as_specific_student from openedx.core.djangoapps.catalog.utils import get_course_run_details from openedx.core.djangoapps.content.course_overviews.models import CourseOverview diff --git a/openedx/features/course_experience/templates/course_experience/dates-summary.html b/openedx/features/course_experience/templates/course_experience/dates-summary.html index e8a66c083b..36952923c8 100644 --- a/openedx/features/course_experience/templates/course_experience/dates-summary.html +++ b/openedx/features/course_experience/templates/course_experience/dates-summary.html @@ -2,24 +2,26 @@ from django.utils.translation import ugettext as _ %> <%page args="course_date" expression_filter="h"/> -

-
-
-
-
- % if course_date.date: -

- % endif - % if course_date.title: -
${course_date.title}
- % endif - % if course_date.description: -

${course_date.description}

- % endif - % if course_date.link and course_date.link_text: -
- % endif +
+
+
+
+
+
+ % if course_date.date: +

+ % endif + % if course_date.title: + ${course_date.title} + % endif + % if course_date.description: +

${course_date.description}

+ % endif + % if course_date.link and course_date.link_text: + + ${course_date.link_text} + + % endif +
diff --git a/openedx/features/course_experience/tests/views/test_course_home.py b/openedx/features/course_experience/tests/views/test_course_home.py index 74562c19b3..ea0e6e7a4b 100644 --- a/openedx/features/course_experience/tests/views/test_course_home.py +++ b/openedx/features/course_experience/tests/views/test_course_home.py @@ -25,7 +25,7 @@ from experiments.models import ExperimentData from lms.djangoapps.commerce.models import CommerceConfiguration from lms.djangoapps.commerce.utils import EcommerceService from lms.djangoapps.course_goals.api import add_course_goal, remove_course_goal -from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link +from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link from lms.djangoapps.courseware.tests.factories import ( BetaTesterFactory, GlobalStaffFactory, @@ -218,7 +218,7 @@ class TestCourseHomePage(CourseHomePageTestCase): # Fetch the view and verify the query counts # TODO: decrease query count as part of REVO-28 - with self.assertNumQueries(76, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with self.assertNumQueries(74, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): with check_mongo_calls(4): url = course_home_url(self.course) self.client.get(url) diff --git a/openedx/features/course_experience/views/course_dates.py b/openedx/features/course_experience/views/course_dates.py index 91c2bbfd21..204a273494 100644 --- a/openedx/features/course_experience/views/course_dates.py +++ b/openedx/features/course_experience/views/course_dates.py @@ -25,7 +25,7 @@ class CourseDatesFragmentView(EdxFragmentView): """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False) - course_date_blocks = get_course_date_blocks(course, request.user, request, num_assignments=2) + course_date_blocks = get_course_date_blocks(course, request.user) context = { 'course_date_blocks': [block for block in course_date_blocks if block.title != 'current_datetime'] diff --git a/openedx/features/course_experience/views/course_sock.py b/openedx/features/course_experience/views/course_sock.py index a41d9b8f81..695aef426b 100644 --- a/openedx/features/course_experience/views/course_sock.py +++ b/openedx/features/course_experience/views/course_sock.py @@ -6,7 +6,7 @@ Fragment for rendering the course's sock and associated toggle button. from django.template.loader import render_to_string from web_fragments.fragment import Fragment -from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link, verified_upgrade_link_is_valid +from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link, verified_upgrade_link_is_valid from openedx.core.djangoapps.plugin_api.views import EdxFragmentView from openedx.features.discounts.utils import format_strikeout_price from student.models import CourseEnrollment diff --git a/openedx/features/discounts/utils.py b/openedx/features/discounts/utils.py index 53ac8a898e..8b9840e00e 100644 --- a/openedx/features/discounts/utils.py +++ b/openedx/features/discounts/utils.py @@ -11,7 +11,7 @@ from edx_django_utils.cache import RequestCache import pytz from course_modes.models import get_course_prices, format_course_price -from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link +from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from experiments.models import ExperimentData