Merge pull request #36499 from raccoongang/feat/api-for-shifting-all-past-due-dates
feat: api for shifting all relative past due dates
This commit is contained in:
117
openedx/features/course_experience/api/v1/tests/test_utils.py
Normal file
117
openedx/features/course_experience/api/v1/tests/test_utils.py
Normal file
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
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,
|
||||
reset_course_deadlines_for_user,
|
||||
reset_bulk_course_deadlines
|
||||
)
|
||||
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, 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, 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,
|
||||
)
|
||||
|
||||
def test_reset_course_deadlines_for_user(self):
|
||||
"""Test the reset_course_deadlines_for_user utility function directly"""
|
||||
enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
|
||||
enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
|
||||
enrollment.schedule.save()
|
||||
|
||||
result = reset_course_deadlines_for_user(self.user, self.course.id)
|
||||
|
||||
assert result is True
|
||||
assert enrollment.schedule.start_date < Schedule.objects.get(id=enrollment.schedule.id).start_date
|
||||
|
||||
def test_reset_bulk_course_deadlines(self):
|
||||
"""Test the reset_bulk_course_deadlines utility function"""
|
||||
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-all-course-deadlines"), {}
|
||||
)
|
||||
request.user = self.user
|
||||
|
||||
success_keys, failed_keys = reset_bulk_course_deadlines(request, [self.course.id], {})
|
||||
|
||||
assert len(success_keys) == 1
|
||||
assert self.course.id in success_keys
|
||||
assert len(failed_keys) == 0
|
||||
assert enrollment.schedule.start_date < Schedule.objects.get(id=enrollment.schedule.id).start_date
|
||||
@@ -1,7 +1,9 @@
|
||||
"""
|
||||
Tests for reset deadlines endpoint.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
from django.urls import reverse
|
||||
@@ -10,7 +12,6 @@ from edx_toggles.toggles.testutils import override_waffle_flag
|
||||
|
||||
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
|
||||
@@ -19,14 +20,12 @@ from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ResetCourseDeadlinesViewTests(EventTestMixin, BaseCourseHomeTests, MasqueradeMixin):
|
||||
class ResetCourseDeadlinesViewTests(BaseCourseHomeTests, MasqueradeMixin):
|
||||
"""
|
||||
Tests for reset deadlines endpoint.
|
||||
"""
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
# Need to supply tracker name for the EventTestMixin. Also, EventTestMixin needs to come
|
||||
# first in class inheritance so the setUp call here appropriately works
|
||||
super().setUp('openedx.features.course_experience.api.v1.views.tracker')
|
||||
super().setUp()
|
||||
self.course = CourseFactory.create(self_paced=True, start=timezone.now() - datetime.timedelta(days=1000))
|
||||
|
||||
def test_reset_deadlines(self):
|
||||
@@ -37,20 +36,11 @@ class ResetCourseDeadlinesViewTests(EventTestMixin, BaseCourseHomeTests, Masquer
|
||||
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course': self.course.id})
|
||||
assert response.status_code == 400
|
||||
assert enrollment.schedule == Schedule.objects.get(id=enrollment.schedule.id)
|
||||
self.assert_no_events_were_emitted()
|
||||
|
||||
# Test correct post body
|
||||
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
|
||||
assert response.status_code == 200
|
||||
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,
|
||||
)
|
||||
|
||||
@override_waffle_flag(RELATIVE_DATES_FLAG, active=True)
|
||||
@override_waffle_flag(RELATIVE_DATES_DISABLE_RESET_FLAG, active=True)
|
||||
@@ -62,36 +52,6 @@ class ResetCourseDeadlinesViewTests(EventTestMixin, BaseCourseHomeTests, Masquer
|
||||
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
|
||||
assert response.status_code == 200
|
||||
assert enrollment.schedule == Schedule.objects.get(id=enrollment.schedule.id)
|
||||
self.assert_no_events_were_emitted()
|
||||
|
||||
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)
|
||||
|
||||
self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': 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,
|
||||
)
|
||||
|
||||
def test_post_unauthenticated_user(self):
|
||||
self.client.logout()
|
||||
@@ -115,3 +75,52 @@ class ResetCourseDeadlinesViewTests(EventTestMixin, BaseCourseHomeTests, Masquer
|
||||
self.client.logout()
|
||||
response = self.client.get(reverse('course-experience-course-deadlines-mobile', args=[self.course.id]))
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
class ResetAllRelativeCourseDeadlinesViewTests(BaseCourseHomeTests, MasqueradeMixin):
|
||||
"""
|
||||
Tests for reset all relative deadlines endpoint.
|
||||
"""
|
||||
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
super().setUp()
|
||||
self.course = CourseFactory.create(self_paced=True, start=timezone.now() - datetime.timedelta(days=1000))
|
||||
self.enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
|
||||
self.enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
|
||||
self.enrollment.schedule.save()
|
||||
|
||||
def test_reset_all_course_deadlines(self):
|
||||
"""
|
||||
Test reset all course deadlines endpoint
|
||||
"""
|
||||
response = self.client.post(
|
||||
reverse("course-experience-reset-all-course-deadlines"),
|
||||
{},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert self.enrollment.schedule.start_date < Schedule.objects.get(id=self.enrollment.schedule.id).start_date
|
||||
assert str(self.course.id) in response.data.get("success_course_keys")
|
||||
|
||||
def test_reset_all_course_deadlines_failure(self):
|
||||
"""
|
||||
Raise exception on reset_bulk_course_deadlines and assert if failure course id is returned
|
||||
"""
|
||||
with mock.patch(
|
||||
"openedx.features.course_experience.api.v1.views.reset_bulk_course_deadlines",
|
||||
return_value=([], [self.course.id]),
|
||||
):
|
||||
response = self.client.post(reverse("course-experience-reset-all-course-deadlines"), {})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert str(self.course.id) in response.data.get("failed_course_keys")
|
||||
|
||||
def test_post_unauthenticated_user(self):
|
||||
"""
|
||||
Test reset all relative course deadlines endpoint for unauthenticated user
|
||||
"""
|
||||
self.client.logout()
|
||||
response = self.client.post(
|
||||
reverse("course-experience-reset-all-course-deadlines"),
|
||||
{},
|
||||
)
|
||||
assert response.status_code == 401
|
||||
|
||||
@@ -4,9 +4,13 @@ Contains URLs for the Course Experience API
|
||||
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import re_path
|
||||
from django.urls import re_path, path
|
||||
|
||||
from openedx.features.course_experience.api.v1.views import reset_course_deadlines, CourseDeadlinesMobileView
|
||||
from openedx.features.course_experience.api.v1.views import (
|
||||
reset_course_deadlines,
|
||||
reset_all_course_deadlines,
|
||||
CourseDeadlinesMobileView,
|
||||
)
|
||||
|
||||
urlpatterns = []
|
||||
|
||||
@@ -17,6 +21,11 @@ urlpatterns += [
|
||||
reset_course_deadlines,
|
||||
name='course-experience-reset-course-deadlines'
|
||||
),
|
||||
path(
|
||||
'v1/reset_all_course_deadlines/',
|
||||
reset_all_course_deadlines,
|
||||
name='course-experience-reset-all-course-deadlines',
|
||||
)
|
||||
]
|
||||
|
||||
# URL for retrieving course deadlines info
|
||||
|
||||
115
openedx/features/course_experience/api/v1/utils.py
Normal file
115
openedx/features/course_experience/api/v1/utils.py
Normal file
@@ -0,0 +1,115 @@
|
||||
|
||||
"""
|
||||
Course Experience API utilities.
|
||||
"""
|
||||
import logging
|
||||
from eventtracking import tracker
|
||||
|
||||
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
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def reset_course_deadlines_for_user(user, course_key):
|
||||
"""
|
||||
Core function to reset deadlines for a single course and user.
|
||||
|
||||
Args:
|
||||
user: The user object
|
||||
course_key: The course key
|
||||
|
||||
Returns:
|
||||
bool: True if deadlines were reset, False if gated content prevents reset
|
||||
"""
|
||||
# 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)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def reset_bulk_course_deadlines(request, course_keys, research_event_data={}): # lint-amnesty, pylint: disable=dangerous-default-value
|
||||
"""
|
||||
Reset deadlines for multiple courses for the requesting user.
|
||||
|
||||
Args:
|
||||
request (Request): The request object
|
||||
course_keys (list): List of course keys
|
||||
research_event_data (dict): Any data that should be included in the research tracking event
|
||||
|
||||
Returns:
|
||||
tuple: (success_course_keys, failed_course_keys)
|
||||
"""
|
||||
success_course_keys = []
|
||||
failed_course_keys = []
|
||||
|
||||
for course_key in course_keys:
|
||||
try:
|
||||
course_masquerade, user = setup_masquerade(
|
||||
request,
|
||||
course_key,
|
||||
has_access(request.user, 'staff', course_key)
|
||||
)
|
||||
|
||||
if reset_course_deadlines_for_user(user, course_key):
|
||||
success_course_keys.append(course_key)
|
||||
|
||||
course_overview = course_detail(request, user.username, course_key)
|
||||
|
||||
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)
|
||||
else:
|
||||
failed_course_keys.append(course_key)
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
logger.exception('Error occurred while trying to reset deadlines!')
|
||||
failed_course_keys.append(course_key)
|
||||
|
||||
return success_course_keys, failed_course_keys
|
||||
|
||||
|
||||
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_masquerade, user = setup_masquerade(
|
||||
request,
|
||||
course_key,
|
||||
has_access(request.user, 'staff', course_key)
|
||||
)
|
||||
|
||||
if reset_course_deadlines_for_user(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)
|
||||
@@ -5,7 +5,6 @@ import logging
|
||||
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext as _
|
||||
from eventtracking import tracker
|
||||
|
||||
from rest_framework.decorators import api_view, authentication_classes, permission_classes
|
||||
from rest_framework.exceptions import APIException, ParseError
|
||||
@@ -17,17 +16,14 @@ from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthenticat
|
||||
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from lms.djangoapps.course_api.api import course_detail
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from lms.djangoapps.course_goals.models import UserActivity
|
||||
from lms.djangoapps.courseware.access import has_access
|
||||
from lms.djangoapps.courseware.courses import get_course_with_access
|
||||
from lms.djangoapps.courseware.masquerade import is_masquerading, setup_masquerade
|
||||
|
||||
from openedx.core.djangoapps.schedules.utils import reset_self_paced_schedule
|
||||
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
|
||||
from openedx.features.course_experience.api.v1.serializers import CourseDeadlinesMobileSerializer
|
||||
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
|
||||
from openedx.features.course_experience.utils import dates_banner_should_display
|
||||
from openedx.features.course_experience.api.v1.utils import reset_deadlines_for_course, reset_bulk_course_deadlines
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -65,32 +61,7 @@ def reset_course_deadlines(request):
|
||||
|
||||
try:
|
||||
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 endpoint is used in 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)
|
||||
reset_deadlines_for_course(request, course_key, research_event_data)
|
||||
|
||||
body_link = get_learning_mfe_home_url(course_key=course_key, url_fragment='dates')
|
||||
|
||||
@@ -106,6 +77,44 @@ def reset_course_deadlines(request):
|
||||
raise UnableToResetDeadlines from reset_deadlines_exception
|
||||
|
||||
|
||||
@api_view(["POST"])
|
||||
@authentication_classes(
|
||||
(
|
||||
JwtAuthentication,
|
||||
BearerAuthenticationAllowInactiveUser,
|
||||
SessionAuthenticationAllowInactiveUser,
|
||||
)
|
||||
)
|
||||
@permission_classes((IsAuthenticated,))
|
||||
def reset_all_course_deadlines(request):
|
||||
"""
|
||||
Set the start_date of a schedule to today for all enrolled courses
|
||||
|
||||
Request Parameters:
|
||||
research_event_data: 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)
|
||||
|
||||
Returns:
|
||||
success_course_keys: list of course keys for which deadlines were successfully reset
|
||||
failed_course_keys: list of course keys for which deadlines could not be reset
|
||||
"""
|
||||
research_event_data = request.data.get("research_event_data", {})
|
||||
course_keys = list(
|
||||
CourseEnrollment.enrollments_for_user(request.user).select_related("course").values_list("course_id", flat=True)
|
||||
)
|
||||
|
||||
success_course_keys, failed_course_keys = reset_bulk_course_deadlines(
|
||||
request, course_keys, research_event_data
|
||||
)
|
||||
|
||||
return Response(
|
||||
{
|
||||
"success_course_keys": [str(key) for key in success_course_keys],
|
||||
"failed_course_keys": [str(key) for key in failed_course_keys],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class CourseDeadlinesMobileView(RetrieveAPIView):
|
||||
"""
|
||||
**Use Cases**
|
||||
|
||||
Reference in New Issue
Block a user