Commit f76d9925 by Sofiya Semenova

Initial commit

parent ca46bfcf
...@@ -278,7 +278,7 @@ class CourseGrade(CourseGradeBase): ...@@ -278,7 +278,7 @@ class CourseGrade(CourseGradeBase):
def _get_subsection_grade(self, subsection): def _get_subsection_grade(self, subsection):
if self.force_update_subsections: if self.force_update_subsections:
return self._subsection_grade_factory.update(subsection) return self._subsection_grade_factory.update(subsection, self.persist_after_track_change)
else: else:
# Pass read_only here so the subsection grades can be persisted in bulk at the end. # Pass read_only here so the subsection grades can be persisted in bulk at the end.
return self._subsection_grade_factory.create(subsection, read_only=True) return self._subsection_grade_factory.create(subsection, read_only=True)
......
...@@ -57,6 +57,7 @@ class CourseGradeFactory(object): ...@@ -57,6 +57,7 @@ class CourseGradeFactory(object):
course_structure=None, course_structure=None,
course_key=None, course_key=None,
force_update_subsections=False, force_update_subsections=False,
enrollment_track_changed=False
): ):
""" """
Computes, updates, and returns the CourseGrade for the given Computes, updates, and returns the CourseGrade for the given
...@@ -64,9 +65,19 @@ class CourseGradeFactory(object): ...@@ -64,9 +65,19 @@ class CourseGradeFactory(object):
At least one of course, collected_block_structure, course_structure, At least one of course, collected_block_structure, course_structure,
or course_key should be provided. or course_key should be provided.
If the learner's enrollment track has changed, and the
subsection *only* contains track-specific problems that the
user has attempted, should force a re-grade for that section.
See EDUCATOR-1280.
""" """
course_data = CourseData(user, course, collected_block_structure, course_structure, course_key) course_data = CourseData(user, course, collected_block_structure, course_structure, course_key)
return self._update(user, course_data, force_update_subsections=force_update_subsections) return self._update(
user,
course_data,
force_update_subsections=force_update_subsections,
persist_after_track_change=enrollment_track_changed
)
def iter( def iter(
self, self,
...@@ -152,7 +163,7 @@ class CourseGradeFactory(object): ...@@ -152,7 +163,7 @@ class CourseGradeFactory(object):
) )
@staticmethod @staticmethod
def _update(user, course_data, force_update_subsections=False): def _update(user, course_data, force_update_subsections=False, persist_after_track_change=False):
""" """
Computes, saves, and returns a CourseGrade object for the Computes, saves, and returns a CourseGrade object for the
given user and course. given user and course.
...@@ -164,10 +175,15 @@ class CourseGradeFactory(object): ...@@ -164,10 +175,15 @@ class CourseGradeFactory(object):
if should_persist and force_update_subsections: if should_persist and force_update_subsections:
prefetch(user, course_data.course_key) prefetch(user, course_data.course_key)
course_grade = CourseGrade(user, course_data, force_update_subsections=force_update_subsections) course_grade = CourseGrade(
user,
course_data,
force_update_subsections=force_update_subsections,
persist_after_track_change=persist_after_track_change
)
course_grade = course_grade.update() course_grade = course_grade.update()
should_persist = should_persist and course_grade.attempted should_persist = should_persist and (course_grade.attempted or persist_after_track_change)
if should_persist: if should_persist:
course_grade._subsection_grade_factory.bulk_create_unsaved() course_grade._subsection_grade_factory.bulk_create_unsaved()
PersistentCourseGrade.update_or_create( PersistentCourseGrade.update_or_create(
......
...@@ -248,4 +248,9 @@ def recalculate_course_and_subsection_grades(sender, user, course_key, **kwargs) ...@@ -248,4 +248,9 @@ def recalculate_course_and_subsection_grades(sender, user, course_key, **kwargs)
""" """
previous_course_grade = CourseGradeFactory().read(user, course_key=course_key) previous_course_grade = CourseGradeFactory().read(user, course_key=course_key)
if previous_course_grade and previous_course_grade.attempted: if previous_course_grade and previous_course_grade.attempted:
CourseGradeFactory().update(user=user, course_key=course_key, force_update_subsections=True) CourseGradeFactory().update(
user=user,
course_key=course_key,
force_update_subsections=True,
enrollment_track_changed=True
)
...@@ -230,11 +230,11 @@ class CreateSubsectionGrade(NonZeroSubsectionGrade): ...@@ -230,11 +230,11 @@ class CreateSubsectionGrade(NonZeroSubsectionGrade):
super(CreateSubsectionGrade, self).__init__(subsection, all_total, graded_total) super(CreateSubsectionGrade, self).__init__(subsection, all_total, graded_total)
def update_or_create_model(self, student, score_deleted=False): def update_or_create_model(self, student, score_deleted=False, persist_after_track_change=False):
""" """
Saves or updates the subsection grade in a persisted model. Saves or updates the subsection grade in a persisted model.
""" """
if self._should_persist_per_attempted(score_deleted): if self._should_persist_per_attempted(score_deleted, persist_after_track_change=False):
return PersistentSubsectionGrade.update_or_create_grade(**self._persisted_model_params(student)) return PersistentSubsectionGrade.update_or_create_grade(**self._persisted_model_params(student))
@classmethod @classmethod
...@@ -250,17 +250,20 @@ class CreateSubsectionGrade(NonZeroSubsectionGrade): ...@@ -250,17 +250,20 @@ class CreateSubsectionGrade(NonZeroSubsectionGrade):
] ]
return PersistentSubsectionGrade.bulk_create_grades(params, student.id, course_key) return PersistentSubsectionGrade.bulk_create_grades(params, student.id, course_key)
def _should_persist_per_attempted(self, score_deleted=False): def _should_persist_per_attempted(self, score_deleted=False, persist_after_track_change=False):
""" """
Returns whether the SubsectionGrade's model should be Returns whether the SubsectionGrade's model should be
persisted based on settings and attempted status. persisted based on settings and attempted status.
If the learner's score was just deleted, they will have If the learner's score was just deleted, they will have
no attempts but the grade should still be persisted. no attempts but the grade should still be persisted.
""" """
return ( return (
self.all_total.first_attempted is not None or self.all_total.first_attempted is not None or
score_deleted score_deleted or
persist_after_track_change
) )
def _persisted_model_params(self, student): def _persisted_model_params(self, student):
......
...@@ -63,7 +63,7 @@ class SubsectionGradeFactory(object): ...@@ -63,7 +63,7 @@ class SubsectionGradeFactory(object):
) )
self._unsaved_subsection_grades.clear() self._unsaved_subsection_grades.clear()
def update(self, subsection, only_if_higher=None, score_deleted=False): def update(self, subsection, only_if_higher=None, score_deleted=False, persist_after_track_change=False):
""" """
Updates the SubsectionGrade object for the student and subsection. Updates the SubsectionGrade object for the student and subsection.
""" """
...@@ -89,7 +89,10 @@ class SubsectionGradeFactory(object): ...@@ -89,7 +89,10 @@ class SubsectionGradeFactory(object):
): ):
return orig_subsection_grade return orig_subsection_grade
grade_model = calculated_grade.update_or_create_model(self.student, score_deleted) grade_model = calculated_grade.update_or_create_model(
self.student,
score_deleted,
persist_after_track_change)
self._update_saved_subsection_grade(subsection.location, grade_model) self._update_saved_subsection_grade(subsection.location, grade_model)
return calculated_grade return calculated_grade
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment