feat: address CR

This commit is contained in:
hajorg
2024-03-14 15:14:07 +01:00
parent 9b6a117a05
commit 72a85ee0ff
2 changed files with 122 additions and 35 deletions

View File

@@ -9,20 +9,30 @@ from common.djangoapps.student.models.course_enrollment import CourseEnrollment
from common.djangoapps.student.models.user import get_user_by_username_or_email
from lms.djangoapps.courseware.courses import get_course
from lms.djangoapps.courseware.models import StudentModule
from lms.djangoapps.grades.rest_api.v1.views import SubmissionHistoryView
from lms.djangoapps.instructor.enrollment import reset_student_attempts
from lms.djangoapps.support.models import CourseResetAudit
log = logging.getLogger(__name__)
def update_audit_status(audit_instance, status, completed_at=False):
def update_audit_status(audit_instance, status):
audit_instance.status = status
if completed_at:
if status == CourseResetAudit.CourseResetStatus.COMPLETE:
audit_instance.completed_at = datetime.now()
audit_instance.save()
def get_blocks(course):
""" Get a list of problem xblock for the course."""
blocks = []
for section in course.get_children():
for subsection in section.get_children():
for vertical in subsection.get_children():
for block in vertical.get_children():
blocks.append(block)
return blocks
@shared_task
@set_code_owner_attribute
def reset_student_course(course_id, learner_email, reset_by_user_email):
@@ -34,21 +44,24 @@ def reset_student_course(course_id, learner_email, reset_by_user_email):
enrollment = CourseEnrollment.objects.get(
course=course_id,
user=user,
is_active=True
is_active=True,
)
course_overview = enrollment.course_overview
course_reset_audit = CourseResetAudit.objects.filter(course_enrollment=enrollment).first()
course_reset_audit = CourseResetAudit.objects.get(
course_enrollment=enrollment,
status=CourseResetAudit.CourseResetStatus.ENQUEUED
)
update_audit_status(course_reset_audit, CourseResetAudit.CourseResetStatus.IN_PROGRESS)
try:
course = get_course(course_overview.id, depth=4)
history = SubmissionHistoryView.get_problem_blocks(course)
for data in history:
blocks = get_blocks(course)
for data in blocks:
try:
reset_student_attempts(course.id, user, data.scope_ids.usage_id, reset_by_user, True)
except StudentModule.DoesNotExist:
pass
update_audit_status(course_reset_audit, CourseResetAudit.CourseResetStatus.COMPLETE, True)
update_audit_status(course_reset_audit, CourseResetAudit.CourseResetStatus.COMPLETE)
except Exception as e: # pylint: disable=broad-except
logging.exception(e)
logging.exception(f'Error occurred for Course Audit with ID {course_reset_audit.id}: {e}.')
update_audit_status(course_reset_audit, CourseResetAudit.CourseResetStatus.FAILED)

View File

@@ -2,10 +2,10 @@
Unit tests for reset_student_course task
"""
from unittest.mock import patch, Mock
from unittest.mock import patch, Mock, call
from xmodule.modulestore.tests.factories import BlockFactory
from lms.djangoapps.courseware.tests.test_submitting_problems import TestSubmittingProblems
from lms.djangoapps.courseware.models import StudentModule
from lms.djangoapps.support.tasks import reset_student_course
@@ -17,7 +17,7 @@ from common.djangoapps.student.tests.factories import UserFactory
class ResetStudentCourse(TestSubmittingProblems):
""" Test expire_waiting_enrollments task """
""" Test reset_student_course task """
USERNAME = "support"
EMAIL = "support@example.com"
PASSWORD = "support"
@@ -36,10 +36,13 @@ class ResetStudentCourse(TestSubmittingProblems):
course=self.opt_in,
course_enrollment=self.enrollment,
reset_by=self.user,
status=CourseResetAudit.CourseResetStatus.FAILED
status=CourseResetAudit.CourseResetStatus.ENQUEUED
)
self.p1 = ''
self.p2 = ''
self.p3 = ''
def basic_setup(self, late=False, reset=False, showanswer=False):
def basic_setup(self):
"""
Set up a simple course for testing basic grading functionality.
"""
@@ -59,41 +62,112 @@ class ResetStudentCourse(TestSubmittingProblems):
self.add_grading_policy(grading_policy)
# set up a simple course with four problems
homework = self.add_graded_section_to_course('homework', late=late, reset=reset, showanswer=showanswer)
homework = self.add_graded_section_to_course('homework')
vertical = BlockFactory.create(
parent_location=homework.location,
category='vertical',
display_name='Subsection 1',
display_name='Unit 1',
)
self.add_dropdown_to_section(vertical.location, 'p1', 1)
self.add_dropdown_to_section(vertical.location, 'p2', 1)
self.add_dropdown_to_section(vertical.location, 'p3', 1)
self.p1 = self.add_dropdown_to_section(vertical.location, 'p1', 1)
self.p2 = self.add_dropdown_to_section(vertical.location, 'p2', 1)
self.p3 = self.add_dropdown_to_section(vertical.location, 'p3', 1)
self.refresh_course()
def test_reset_student_course(self):
self.basic_setup()
reset_student_course(self.course_id, self.student_user.email, self.user.email)
course_reset_audit = CourseResetAudit.objects.filter(course_enrollment=self.enrollment).first()
self.assertTrue(course_reset_audit.completed_at)
self.assertEqual(course_reset_audit.status, CourseResetAudit.CourseResetStatus.COMPLETE)
def test_reset_student_course_student_module_not_found(self):
""" Test that it resets student attempts """
with patch(
'lms.djangoapps.support.tasks.reset_student_attempts',
Mock(side_effect=StudentModule.DoesNotExist('An error occurred'))
):
) as mock_reset_student_attempts:
self.basic_setup()
reset_student_course(self.course_id, self.student_user.email, self.user.email)
course_reset_audit = CourseResetAudit.objects.filter(course_enrollment=self.enrollment).first()
self.assertTrue(course_reset_audit.completed_at)
mock_reset_student_attempts.assert_has_calls([
call(
self.course.id,
self.student_user,
self.p1.location,
self.user,
True
),
call(
self.course.id,
self.student_user,
self.p2.location,
self.user,
True
),
call(
self.course.id,
self.student_user,
self.p3.location,
self.user,
True
)
])
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)
def test_reset_student_course_fail(self):
def test_reset_student_course_student_module_not_found(self):
with patch(
'lms.djangoapps.support.tasks.SubmissionHistoryView.get_problem_blocks',
Mock(side_effect=Exception('An error occurred'))
'lms.djangoapps.support.tasks.reset_student_attempts',
Mock(side_effect=StudentModule.DoesNotExist())
) as mock_reset_student_attempts:
self.basic_setup()
reset_student_course(self.course_id, self.student_user.email, self.user.email)
mock_reset_student_attempts.assert_has_calls([
call(
self.course.id,
self.student_user,
self.p1.location,
self.user,
True
),
call(
self.course.id,
self.student_user,
self.p2.location,
self.user,
True
),
call(
self.course.id,
self.student_user,
self.p3.location,
self.user,
True
)
])
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)
self.assertEqual(course_reset_audit.status, CourseResetAudit.CourseResetStatus.COMPLETE)
@patch('lms.djangoapps.support.tasks.reset_student_attempts')
def test_reset_student_course_fail(self, mock_reset_student_attempts):
with patch(
'lms.djangoapps.support.tasks.get_blocks',
Mock(side_effect=Exception())
):
reset_student_course(self.course_id, self.student_user.email, self.user.email)
course_reset_audit = CourseResetAudit.objects.filter(course_enrollment=self.enrollment).first()
self.assertFalse(course_reset_audit.completed_at)
mock_reset_student_attempts.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)
def test_reset_student_attempts_raise_exception(self):
with patch(
'lms.djangoapps.support.tasks.reset_student_attempts',
Mock(side_effect=Exception())
) as mock_reset_student_attempts:
self.basic_setup()
reset_student_course(self.course_id, self.student_user.email, self.user.email)
mock_reset_student_attempts.assert_called_once()
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)