Skip to content

Commit 837e9ed

Browse files
Agrendalathxitij2000
authored andcommitted
feat: add Waffle Flag to disable resetting self-paced deadlines by learners
(cherry picked from commit 0258971)
1 parent 923a2d8 commit 837e9ed

File tree

3 files changed

+47
-11
lines changed

3 files changed

+47
-11
lines changed

openedx/features/course_experience/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@
5050
# .. toggle_tickets: https://openedx.atlassian.net/browse/AA-27
5151
RELATIVE_DATES_FLAG = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.relative_dates', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
5252

53+
# .. toggle_name: course_experience.relative_dates_disable_reset
54+
# .. toggle_implementation: CourseWaffleFlag
55+
# .. toggle_default: False
56+
# .. toggle_description: Waffle flag to disable resetting deadlines by learners in self-paced courses. The 'Dates' tab
57+
# will no longer show a banner about missed deadlines. The deadlines banner will also be hidden on unit pages.
58+
# .. toggle_use_cases: open_edx
59+
# .. toggle_creation_date: 2023-04-27
60+
# .. toggle_warning: For this toggle to have an effect, the RELATIVE_DATES_FLAG toggle must be enabled, too.
61+
RELATIVE_DATES_DISABLE_RESET_FLAG = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.relative_dates_disable_reset', __name__)
62+
5363
# .. toggle_name: course_experience.calendar_sync
5464
# .. toggle_implementation: CourseWaffleFlag
5565
# .. toggle_default: False

openedx/features/course_experience/api/v1/tests/test_views.py

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@
22
Tests for reset deadlines endpoint.
33
"""
44
import datetime
5-
import ddt
65

6+
import ddt
77
from django.urls import reverse
88
from django.utils import timezone
9+
from edx_toggles.toggles.testutils import override_waffle_flag
910

1011
from common.djangoapps.course_modes.models import CourseMode
1112
from common.djangoapps.student.models import CourseEnrollment
1213
from common.djangoapps.util.testing import EventTestMixin
13-
from lms.djangoapps.courseware.tests.helpers import MasqueradeMixin
1414
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
15+
from lms.djangoapps.courseware.tests.helpers import MasqueradeMixin
1516
from openedx.core.djangoapps.schedules.models import Schedule
17+
from openedx.features.course_experience import RELATIVE_DATES_DISABLE_RESET_FLAG, RELATIVE_DATES_FLAG
1618
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
1719

1820

@@ -25,17 +27,22 @@ def setUp(self): # pylint: disable=arguments-differ
2527
# Need to supply tracker name for the EventTestMixin. Also, EventTestMixin needs to come
2628
# first in class inheritance so the setUp call here appropriately works
2729
super().setUp('openedx.features.course_experience.api.v1.views.tracker')
30+
self.course = CourseFactory.create(self_paced=True, start=timezone.now() - datetime.timedelta(days=1000))
2831

2932
def test_reset_deadlines(self):
30-
CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
33+
enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
34+
enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
35+
enrollment.schedule.save()
3136
# Test body with incorrect body param (course_key is required)
3237
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course': self.course.id})
3338
assert response.status_code == 400
39+
assert enrollment.schedule == Schedule.objects.get(id=enrollment.schedule.id)
3440
self.assert_no_events_were_emitted()
3541

3642
# Test correct post body
3743
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
3844
assert response.status_code == 200
45+
assert enrollment.schedule.start_date < Schedule.objects.get(id=enrollment.schedule.id).start_date
3946
self.assert_event_emitted(
4047
'edx.ui.lms.reset_deadlines.clicked',
4148
courserun_key=str(self.course.id),
@@ -45,33 +52,44 @@ def test_reset_deadlines(self):
4552
user_id=self.user.id,
4653
)
4754

55+
@override_waffle_flag(RELATIVE_DATES_FLAG, active=True)
56+
@override_waffle_flag(RELATIVE_DATES_DISABLE_RESET_FLAG, active=True)
57+
def test_reset_deadlines_disabled(self):
58+
enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
59+
enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
60+
enrollment.schedule.save()
61+
62+
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
63+
assert response.status_code == 200
64+
assert enrollment.schedule == Schedule.objects.get(id=enrollment.schedule.id)
65+
self.assert_no_events_were_emitted()
66+
4867
def test_reset_deadlines_with_masquerade(self):
4968
""" Staff users should be able to masquerade as a learner and reset the learner's schedule """
50-
course = CourseFactory.create(self_paced=True, start=timezone.now() - datetime.timedelta(days=1))
5169
student_username = self.user.username
5270
student_user_id = self.user.id
53-
student_enrollment = CourseEnrollment.enroll(self.user, course.id)
71+
student_enrollment = CourseEnrollment.enroll(self.user, self.course.id)
5472
student_enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
5573
student_enrollment.schedule.save()
5674

57-
staff_enrollment = CourseEnrollment.enroll(self.staff_user, course.id)
75+
staff_enrollment = CourseEnrollment.enroll(self.staff_user, self.course.id)
5876
staff_enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=30)
5977
staff_enrollment.schedule.save()
6078

6179
self.switch_to_staff()
62-
self.update_masquerade(course=course, username=student_username)
80+
self.update_masquerade(course=self.course, username=student_username)
6381

64-
self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': course.id})
82+
self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
6583
updated_schedule = Schedule.objects.get(id=student_enrollment.schedule.id)
6684
assert updated_schedule.start_date.date() == datetime.datetime.today().date()
6785
updated_staff_schedule = Schedule.objects.get(id=staff_enrollment.schedule.id)
6886
assert updated_staff_schedule.start_date == staff_enrollment.schedule.start_date
6987
self.assert_event_emitted(
7088
'edx.ui.lms.reset_deadlines.clicked',
71-
courserun_key=str(course.id),
89+
courserun_key=str(self.course.id),
7290
is_masquerading=True,
7391
is_staff=False,
74-
org_key=course.org,
92+
org_key=self.course.org,
7593
user_id=student_user_id,
7694
)
7795

openedx/features/course_experience/utils.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from lms.djangoapps.course_blocks.api import get_course_blocks
1010
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
1111
from openedx.core.lib.cache_utils import request_cached
12-
from openedx.features.course_experience import RELATIVE_DATES_FLAG
12+
from openedx.features.course_experience import RELATIVE_DATES_DISABLE_RESET_FLAG, RELATIVE_DATES_FLAG
1313
from common.djangoapps.student.models import CourseEnrollment
1414
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
1515

@@ -155,6 +155,14 @@ def dates_banner_should_display(course_key, user):
155155
if not RELATIVE_DATES_FLAG.is_enabled(course_key):
156156
return False, False
157157

158+
if RELATIVE_DATES_DISABLE_RESET_FLAG.is_enabled(course_key):
159+
# The `missed_deadlines` value is ignored by `reset_course_deadlines` views. Instead, they check the value of
160+
# `missed_gated_content` to determine if learners can reset the deadlines by themselves.
161+
# We could have added this logic directly to `reset_self_paced_schedule`, but this function is used in other
162+
# places (e.g., when an enrollment mode is changed). We want this flag to affect only the use case when
163+
# learners try to reset their deadlines.
164+
return False, True
165+
158166
course_overview = CourseOverview.objects.get(id=str(course_key))
159167

160168
# Only display the banner for self-paced courses

0 commit comments

Comments
 (0)