diff --git a/lms/djangoapps/support/tasks.py b/lms/djangoapps/support/tasks.py index fc33446887..a8de68a99e 100644 --- a/lms/djangoapps/support/tasks.py +++ b/lms/djangoapps/support/tasks.py @@ -3,6 +3,7 @@ from datetime import datetime import logging from celery import shared_task +from completion.models import BlockCompletion from edx_django_utils.monitoring import set_code_owner_attribute from common.djangoapps.student.models.course_enrollment import CourseEnrollment @@ -56,11 +57,17 @@ def reset_student_course(course_id, learner_email, reset_by_user_email): try: course = get_course(course_overview.id, depth=4) blocks = get_blocks(course) + + # Clear student state and score for data in blocks: try: reset_student_attempts(course.id, user, data.scope_ids.usage_id, reset_by_user, True) except StudentModule.DoesNotExist: pass + + # Clear block completion data + BlockCompletion.objects.clear_learning_context_completion(user, course.id) + update_audit_status(course_reset_audit, CourseResetAudit.CourseResetStatus.COMPLETE) except Exception as e: # pylint: disable=broad-except logging.exception(f'Error occurred for Course Audit with ID {course_reset_audit.id}: {e}.') diff --git a/lms/djangoapps/support/tests/test_tasks.py b/lms/djangoapps/support/tests/test_tasks.py index 7f4818ce73..a0b8c356e5 100644 --- a/lms/djangoapps/support/tests/test_tasks.py +++ b/lms/djangoapps/support/tests/test_tasks.py @@ -44,6 +44,16 @@ class ResetStudentCourse(TestSubmittingProblems): self.p3 = '' self.video = '' + # Patch BlockCompletion for the whole test + completion_patcher = patch('lms.djangoapps.support.tasks.BlockCompletion') + self.mock_block_completion = completion_patcher.start() + self.addCleanup(completion_patcher.stop) + + @property + def mock_clear_block_completion(self): + """ Helper property to access the two-mock-layers-deep clear_learning_context_completion """ + return self.mock_block_completion.objects.clear_learning_context_completion + def basic_setup(self): """ Set up a simple course for testing basic grading functionality. @@ -133,6 +143,7 @@ class ResetStudentCourse(TestSubmittingProblems): ) ]) + self.mock_clear_block_completion.assert_called_once_with(self.student_user, self.course.id) course_reset_audit = CourseResetAudit.objects.get(course_enrollment=self.enrollment) self.assertIsNotNone(course_reset_audit.completed_at) self.assertEqual(course_reset_audit.status, CourseResetAudit.CourseResetStatus.COMPLETE) @@ -169,6 +180,7 @@ class ResetStudentCourse(TestSubmittingProblems): ) ]) + self.mock_clear_block_completion.assert_called_once_with(self.student_user, self.course.id) course_reset_audit = CourseResetAudit.objects.get(course_enrollment=self.enrollment) self.assertRaises(StudentModule.DoesNotExist, mock_reset_student_attempts) self.assertIsNotNone(course_reset_audit.completed_at) @@ -182,6 +194,7 @@ class ResetStudentCourse(TestSubmittingProblems): ): reset_student_course(self.course_id, self.student_user.email, self.user.email) mock_reset_student_attempts.assert_not_called() + self.mock_clear_block_completion.assert_not_called() course_reset_audit = CourseResetAudit.objects.get(course_enrollment=self.enrollment) self.assertIsNone(course_reset_audit.completed_at) self.assertEqual(course_reset_audit.status, CourseResetAudit.CourseResetStatus.FAILED) @@ -194,6 +207,7 @@ class ResetStudentCourse(TestSubmittingProblems): self.basic_setup() reset_student_course(self.course_id, self.student_user.email, self.user.email) mock_reset_student_attempts.assert_called_once() + self.mock_clear_block_completion.assert_not_called() course_reset_audit = CourseResetAudit.objects.get(course_enrollment=self.enrollment) self.assertIsNone(course_reset_audit.completed_at) self.assertEqual(course_reset_audit.status, CourseResetAudit.CourseResetStatus.FAILED)