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