forked from openedx/edx-platform
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: [AXM-1568] api for shifting past due dates for multiple courses
- Loading branch information
Showing
5 changed files
with
271 additions
and
78 deletions.
There are no files selected for viewing
84 changes: 84 additions & 0 deletions
84
openedx/features/course_experience/api/v1/tests/test_utils.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
""" | ||
Tests utils of course expirience feature. | ||
""" | ||
import datetime | ||
|
||
from django.urls import reverse | ||
from django.utils import timezone | ||
from rest_framework.test import APIRequestFactory | ||
|
||
from common.djangoapps.course_modes.models import CourseMode | ||
from common.djangoapps.student.models import CourseEnrollment | ||
from common.djangoapps.util.testing import EventTestMixin | ||
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests | ||
from lms.djangoapps.courseware.tests.helpers import MasqueradeMixin | ||
from openedx.core.djangoapps.schedules.models import Schedule | ||
from openedx.features.course_experience.api.v1.utils import reset_deadlines_for_course | ||
from xmodule.modulestore.tests.factories import CourseFactory | ||
|
||
|
||
class TestResetDeadlinesForCourse(EventTestMixin, BaseCourseHomeTests, MasqueradeMixin): | ||
""" | ||
Tests for reset deadlines endpoint. | ||
""" | ||
def setUp(self): # pylint: disable=arguments-differ | ||
super().setUp("openedx.features.course_experience.api.v1.utils.tracker") | ||
self.course = CourseFactory.create(self_paced=True, start=timezone.now() - datetime.timedelta(days=1000)) | ||
|
||
def test_reset_deadlines_for_course(self): | ||
enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED) | ||
enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100) | ||
enrollment.schedule.save() | ||
|
||
request = APIRequestFactory().post( | ||
reverse("course-experience-reset-course-deadlines"), {"course_key": self.course.id} | ||
) | ||
request.user = self.user | ||
|
||
reset_deadlines_for_course(request, str(self.course.id), {}) | ||
|
||
assert enrollment.schedule.start_date < Schedule.objects.get(id=enrollment.schedule.id).start_date | ||
self.assert_event_emitted( | ||
"edx.ui.lms.reset_deadlines.clicked", | ||
courserun_key=str(self.course.id), | ||
is_masquerading=False, | ||
is_staff=False, | ||
org_key=self.course.org, | ||
user_id=self.user.id, | ||
) | ||
|
||
def test_reset_deadlines_with_masquerade(self): | ||
"""Staff users should be able to masquerade as a learner and reset the learner's schedule""" | ||
student_username = self.user.username | ||
student_user_id = self.user.id | ||
student_enrollment = CourseEnrollment.enroll(self.user, self.course.id) | ||
student_enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100) | ||
student_enrollment.schedule.save() | ||
|
||
staff_enrollment = CourseEnrollment.enroll(self.staff_user, self.course.id) | ||
staff_enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=30) | ||
staff_enrollment.schedule.save() | ||
|
||
self.switch_to_staff() | ||
self.update_masquerade(course=self.course, username=student_username) | ||
|
||
request = APIRequestFactory().post( | ||
reverse("course-experience-reset-course-deadlines"), {"course_key": self.course.id} | ||
) | ||
request.user = self.staff_user | ||
request.session = self.client.session | ||
|
||
reset_deadlines_for_course(request, str(self.course.id), {}) | ||
|
||
updated_schedule = Schedule.objects.get(id=student_enrollment.schedule.id) | ||
assert updated_schedule.start_date.date() == datetime.datetime.today().date() | ||
updated_staff_schedule = Schedule.objects.get(id=staff_enrollment.schedule.id) | ||
assert updated_staff_schedule.start_date == staff_enrollment.schedule.start_date | ||
self.assert_event_emitted( | ||
"edx.ui.lms.reset_deadlines.clicked", | ||
courserun_key=str(self.course.id), | ||
is_masquerading=True, | ||
is_staff=False, | ||
org_key=self.course.org, | ||
user_id=student_user_id, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
|
||
""" | ||
Course Experience API utilities. | ||
""" | ||
from eventtracking import tracker | ||
from opaque_keys.edx.keys import CourseKey | ||
|
||
from lms.djangoapps.courseware.access import has_access | ||
from lms.djangoapps.courseware.masquerade import is_masquerading, setup_masquerade | ||
from lms.djangoapps.course_api.api import course_detail | ||
from openedx.core.djangoapps.schedules.utils import reset_self_paced_schedule | ||
from openedx.features.course_experience.utils import dates_banner_should_display | ||
|
||
|
||
def reset_deadlines_for_course(request, course_key, research_event_data={}): # lint-amnesty, pylint: disable=dangerous-default-value | ||
""" | ||
Set the start_date of a schedule to today, which in turn will adjust due dates for | ||
sequentials belonging to a self paced course | ||
Args: | ||
request (Request): The request object | ||
course_key (str): The course key | ||
research_event_data (dict): Any data that should be included in the research tracking event | ||
Example: sending the location of where the reset deadlines banner (i.e. outline-tab) | ||
""" | ||
|
||
course_key = CourseKey.from_string(course_key) | ||
course_masquerade, user = setup_masquerade( | ||
request, | ||
course_key, | ||
has_access(request.user, 'staff', course_key) | ||
) | ||
|
||
# We ignore the missed_deadlines because this util is used in endpoint from the Learning MFE for | ||
# learners who have remaining attempts on a problem and reset their due dates in order to | ||
# submit additional attempts. This can apply for 'completed' (submitted) content that would | ||
# not be marked as past_due | ||
_missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, user) | ||
if not missed_gated_content: | ||
reset_self_paced_schedule(user, course_key) | ||
|
||
course_overview = course_detail(request, user.username, course_key) | ||
# For context here, research_event_data should already contain `location` indicating | ||
# the page/location dates were reset from and could also contain `block_id` if reset | ||
# within courseware. | ||
research_event_data.update({ | ||
'courserun_key': str(course_key), | ||
'is_masquerading': is_masquerading(user, course_key, course_masquerade), | ||
'is_staff': has_access(user, 'staff', course_key).has_access, | ||
'org_key': course_overview.display_org_with_default, | ||
'user_id': user.id, | ||
}) | ||
tracker.emit('edx.ui.lms.reset_deadlines.clicked', research_event_data) |
Oops, something went wrong.