Merge pull request #18436 from edx/noraiz/EDUCATOR-2773
add delay in score recalculation on enrollment update
This commit is contained in:
@@ -103,6 +103,7 @@ UNENROLLED_TO_ENROLLED = 'from unenrolled to enrolled'
|
||||
ALLOWEDTOENROLL_TO_UNENROLLED = 'from allowed to enroll to enrolled'
|
||||
UNENROLLED_TO_UNENROLLED = 'from unenrolled to unenrolled'
|
||||
DEFAULT_TRANSITION_STATE = 'N/A'
|
||||
SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE = 30
|
||||
|
||||
TRANSITION_STATES = (
|
||||
(UNENROLLED_TO_ALLOWEDTOENROLL, UNENROLLED_TO_ALLOWEDTOENROLL),
|
||||
@@ -1342,7 +1343,15 @@ class CourseEnrollment(models.Model):
|
||||
# Only emit mode change events when the user's enrollment
|
||||
# mode has changed from its previous setting
|
||||
self.emit_event(EVENT_NAME_ENROLLMENT_MODE_CHANGED)
|
||||
ENROLLMENT_TRACK_UPDATED.send(sender=None, user=self.user, course_key=self.course_id)
|
||||
# this signal is meant to trigger a score recalculation celery task,
|
||||
# `countdown` is added to celery task as delay so that cohort is duly updated
|
||||
# before starting score recalculation
|
||||
ENROLLMENT_TRACK_UPDATED.send(
|
||||
sender=None,
|
||||
user=self.user,
|
||||
course_key=self.course_id,
|
||||
countdown=SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE
|
||||
)
|
||||
|
||||
def send_signal(self, event, cost=None, currency=None):
|
||||
"""
|
||||
|
||||
@@ -12,7 +12,13 @@ from nose.plugins.attrib import attr
|
||||
from course_modes.models import CourseMode
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from openedx.core.djangoapps.embargo.test_utils import restrict_course
|
||||
from student.models import CourseEnrollment, CourseEnrollmentAllowed, CourseFullError, EnrollmentClosedError
|
||||
from student.models import (
|
||||
CourseEnrollment,
|
||||
CourseEnrollmentAllowed,
|
||||
CourseFullError,
|
||||
EnrollmentClosedError,
|
||||
SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE,
|
||||
)
|
||||
from student.roles import CourseInstructorRole, CourseStaffRole
|
||||
from student.tests.factories import CourseEnrollmentAllowedFactory, UserFactory
|
||||
from util.testing import UrlResetMixin
|
||||
@@ -340,3 +346,34 @@ class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase):
|
||||
# Still same
|
||||
cea.refresh_from_db()
|
||||
self.assertEqual(cea.user, user1)
|
||||
|
||||
def test_score_recalculation_on_enrollment_update(self):
|
||||
"""
|
||||
Test that an update in enrollment cause score recalculation.
|
||||
Note:
|
||||
Score recalculation task must be called with a delay of SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE
|
||||
"""
|
||||
course_modes = ['verified', 'audit']
|
||||
|
||||
for mode_slug in course_modes:
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=mode_slug,
|
||||
mode_display_name=mode_slug,
|
||||
)
|
||||
CourseEnrollment.enroll(self.user, self.course.id, mode="audit")
|
||||
|
||||
local_task_args = dict(
|
||||
user_id=self.user.id,
|
||||
course_key=str(self.course.id)
|
||||
)
|
||||
|
||||
with patch(
|
||||
'lms.djangoapps.grades.tasks.recalculate_course_and_subsection_grades_for_user.apply_async',
|
||||
return_value=None
|
||||
) as mock_task_apply:
|
||||
CourseEnrollment.enroll(self.user, self.course.id, mode="verified")
|
||||
mock_task_apply.assert_called_once_with(
|
||||
countdown=SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE,
|
||||
kwargs=local_task_args
|
||||
)
|
||||
|
||||
@@ -241,12 +241,13 @@ def recalculate_course_grade_only(sender, course, course_structure, user, **kwar
|
||||
|
||||
@receiver(ENROLLMENT_TRACK_UPDATED)
|
||||
@receiver(COHORT_MEMBERSHIP_UPDATED)
|
||||
def recalculate_course_and_subsection_grades(sender, user, course_key, **kwargs):
|
||||
def recalculate_course_and_subsection_grades(sender, user, course_key, countdown=None, **kwargs): # pylint: disable=unused-argument
|
||||
"""
|
||||
Updates a saved course grade, forcing the subsection grades
|
||||
from which it is calculated to update along the way.
|
||||
"""
|
||||
recalculate_course_and_subsection_grades_for_user.apply_async(
|
||||
countdown=countdown,
|
||||
kwargs=dict(
|
||||
user_id=user.id,
|
||||
course_key=six.text_type(course_key)
|
||||
|
||||
Reference in New Issue
Block a user