refactor: rename and refactor functions and view

This commit is contained in:
Kyrylo Kholodenko
2025-09-19 15:03:06 +03:00
parent 6c45c3ab93
commit 3c31cdb9eb
5 changed files with 127 additions and 41 deletions

View File

@@ -13,7 +13,11 @@ 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 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
@@ -82,3 +86,32 @@ class TestResetDeadlinesForCourse(EventTestMixin, BaseCourseHomeTests, Masquerad
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

View File

@@ -89,30 +89,27 @@ class ResetAllRelativeCourseDeadlinesViewTests(BaseCourseHomeTests, MasqueradeMi
self.enrollment.schedule.start_date = timezone.now() - datetime.timedelta(days=100)
self.enrollment.schedule.save()
def test_reset_all_relative_course_deadlines(self):
def test_reset_all_course_deadlines(self):
"""
Test reset all relative course deadlines endpoint
Test reset all course deadlines endpoint
"""
response = self.client.post(
reverse("course-experience-reset-all-relative-course-deadlines"),
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_relative_course_deadlines_failure(self):
def test_reset_all_course_deadlines_failure(self):
"""
Raise exception on reset_deadlines_for_course and assert if failure course id is returned
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_deadlines_for_course",
side_effect=Exception("Test Exception"),
"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-relative-course-deadlines"),
{},
)
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")
@@ -123,7 +120,7 @@ class ResetAllRelativeCourseDeadlinesViewTests(BaseCourseHomeTests, MasqueradeMi
"""
self.client.logout()
response = self.client.post(
reverse("course-experience-reset-all-relative-course-deadlines"),
reverse("course-experience-reset-all-course-deadlines"),
{},
)
assert response.status_code == 401

View File

@@ -8,7 +8,7 @@ from django.urls import re_path
from openedx.features.course_experience.api.v1.views import (
reset_course_deadlines,
reset_all_relative_course_deadlines,
reset_all_course_deadlines,
CourseDeadlinesMobileView,
)
@@ -22,9 +22,9 @@ urlpatterns += [
name='course-experience-reset-course-deadlines'
),
re_path(
r'v1/reset_all_relative_course_deadlines/',
reset_all_relative_course_deadlines,
name='course-experience-reset-all-relative-course-deadlines',
r'v1/reset_all_course_deadlines/',
reset_all_course_deadlines,
name='course-experience-reset-all-course-deadlines',
)
]

View File

@@ -2,6 +2,7 @@
"""
Course Experience API utilities.
"""
import logging
from eventtracking import tracker
from lms.djangoapps.courseware.access import has_access
@@ -11,6 +12,76 @@ 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
@@ -29,14 +100,7 @@ def reset_deadlines_for_course(request, course_key, research_event_data={}): #
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)
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

View File

@@ -23,7 +23,7 @@ from lms.djangoapps.courseware.courses import get_course_with_access
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.api.v1.utils import reset_deadlines_for_course
from openedx.features.course_experience.api.v1.utils import reset_deadlines_for_course, reset_bulk_course_deadlines
log = logging.getLogger(__name__)
@@ -86,7 +86,7 @@ def reset_course_deadlines(request):
)
)
@permission_classes((IsAuthenticated,))
def reset_all_relative_course_deadlines(request):
def reset_all_course_deadlines(request):
"""
Set the start_date of a schedule to today for all enrolled courses
@@ -99,26 +99,18 @@ def reset_all_relative_course_deadlines(request):
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 = (
course_keys = list(
CourseEnrollment.enrollments_for_user(request.user).select_related("course").values_list("course_id", flat=True)
)
failed_course_keys = []
success_course_keys = []
for course_key in course_keys:
try:
reset_deadlines_for_course(request, course_key, research_event_data)
success_course_keys.append(str(course_key))
except Exception: # pylint: disable=broad-exception-caught
log.exception(f"Error occurred while trying to reset deadlines for course {course_key}!")
failed_course_keys.append(str(course_key))
continue
success_course_keys, failed_course_keys = reset_bulk_course_deadlines(
request, course_keys, research_event_data
)
return Response(
{
"success_course_keys": success_course_keys,
"failed_course_keys": failed_course_keys,
"success_course_keys": [str(key) for key in success_course_keys],
"failed_course_keys": [str(key) for key in failed_course_keys],
}
)