From fc21a337aaa6fb277116045a426f9d94b69d0e2c Mon Sep 17 00:00:00 2001 From: Calen Pennington <cale@edx.org> Date: Tue, 26 May 2020 11:25:23 -0400 Subject: [PATCH] Use a fixed time for course duration limits, so that schedule extensions don't extend FBE duration limits --- common/djangoapps/student/tests/test_views.py | 6 +++-- lms/djangoapps/mobile_api/users/tests.py | 6 +++-- .../features/course_duration_limits/access.py | 24 ++++--------------- .../tests/views/test_course_home.py | 4 +++- 4 files changed, 15 insertions(+), 25 deletions(-) diff --git a/common/djangoapps/student/tests/test_views.py b/common/djangoapps/student/tests/test_views.py index a77a49d7e08..5b0d3a769fe 100644 --- a/common/djangoapps/student/tests/test_views.py +++ b/common/djangoapps/student/tests/test_views.py @@ -774,7 +774,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, Links will be removed from the course title, course image and button (View Course/Resume Course). The course card should have an access expired message. """ - CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1)) + CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=self.THREE_YEARS_AGO - timedelta(days=30)) self.override_waffle_switch(True) course = CourseFactory.create(start=self.THREE_YEARS_AGO) @@ -783,9 +783,11 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin, user=self.user, course_id=course.id ) + enrollment.created = self.THREE_YEARS_AGO + timedelta(days=1) + enrollment.save() # pylint: disable=unused-variable - schedule = ScheduleFactory(start_date=self.THREE_YEARS_AGO + timedelta(days=1), enrollment=enrollment) + schedule = ScheduleFactory(enrollment=enrollment) response = self.client.get(reverse('dashboard')) dashboard_html = self._remove_whitespace_from_response(response) diff --git a/lms/djangoapps/mobile_api/users/tests.py b/lms/djangoapps/mobile_api/users/tests.py index cd3da9051ab..e93a7fb42fc 100644 --- a/lms/djangoapps/mobile_api/users/tests.py +++ b/lms/djangoapps/mobile_api/users/tests.py @@ -280,8 +280,10 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest user=self.user, course_id=course.id ) + enrollment.created = self.THREE_YEARS_AGO + datetime.timedelta(days=1) + enrollment.save() + ScheduleFactory( - start_date=self.THREE_YEARS_AGO + datetime.timedelta(days=1), enrollment=enrollment ) else: @@ -318,7 +320,7 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest Test that expired courses are only returned in v1 of API when waffle flag enabled, and un-expired courses always returned ''' - CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime.datetime(2018, 1, 1)) + CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime.datetime(2015, 1, 1)) courses = self._get_enrollment_data(api_version, expired) self._assert_enrollment_results(api_version, courses, num_courses_returned, True) diff --git a/openedx/features/course_duration_limits/access.py b/openedx/features/course_duration_limits/access.py index fd018d7d11e..8696d215615 100644 --- a/openedx/features/course_duration_limits/access.py +++ b/openedx/features/course_duration_limits/access.py @@ -91,26 +91,10 @@ def get_user_course_expiration_date(user, course): if enrollment is None or enrollment.mode != CourseMode.AUDIT: return None - try: - # Content availability date is equivalent to max(enrollment date, course start date) - # for most people. Using the schedule date will provide flexibility to deal with - # more complex business rules in the future. - content_availability_date = enrollment.schedule.start_date - # We have anecdotally observed a case where the schedule.start_date was - # equal to the course start, but should have been equal to the enrollment start - # https://openedx.atlassian.net/browse/PROD-58 - # This section is meant to address that case - if enrollment.created and course.start: - if (content_availability_date.date() == course.start.date() and - course.start < enrollment.created < timezone.now()): - content_availability_date = enrollment.created - # If course teams change the course start date, set the content_availability_date - # to max of enrollment or course start date - elif (content_availability_date.date() < course.start.date() and - content_availability_date.date() < enrollment.created.date()): - content_availability_date = max(enrollment.created, course.start) - except CourseEnrollment.schedule.RelatedObjectDoesNotExist: - content_availability_date = max(enrollment.created, course.start) + # We reset schedule.start in order to change a user's computed deadlines. + # But their expiration date shouldn't change when we adjust their schedule (they don't + # get additional time), so we need to based the expiration date on a fixed start date. + content_availability_date = max(enrollment.created, course.start) return content_availability_date + access_duration 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 ec9e85c7af6..577a5b1cb03 100644 --- a/openedx/features/course_experience/tests/views/test_course_home.py +++ b/openedx/features/course_experience/tests/views/test_course_home.py @@ -588,7 +588,9 @@ class TestCourseHomePageAccess(CourseHomePageTestCase): audit_user = UserFactory(password=self.TEST_PASSWORD) self.client.login(username=audit_user.username, password=self.TEST_PASSWORD) audit_enrollment = CourseEnrollment.enroll(audit_user, course.id, mode=CourseMode.AUDIT) - ScheduleFactory(start_date=THREE_YEARS_AGO + timedelta(days=1), enrollment=audit_enrollment) + audit_enrollment.created = THREE_YEARS_AGO + timedelta(days=1) + audit_enrollment.save() + ScheduleFactory(enrollment=audit_enrollment) response = self.client.get(url) -- GitLab