def _update(user, course_data, force_update_subsections=False): """ Computes, saves, and returns a CourseGrade object for the given user and course. Sends a COURSE_GRADE_CHANGED signal to listeners and COURSE_GRADE_NOW_PASSED if learner has passed course or COURSE_GRADE_NOW_FAILED if learner is now failing course """ should_persist = should_persist_grades(course_data.course_key) if should_persist and force_update_subsections: prefetch(user, course_data.course_key) course_grade = CourseGrade( user, course_data, force_update_subsections=force_update_subsections ) course_grade = course_grade.update() should_persist = should_persist and course_grade.attempted if should_persist: course_grade._subsection_grade_factory.bulk_create_unsaved() PersistentCourseGrade.update_or_create( user_id=user.id, course_id=course_data.course_key, course_version=course_data.version, course_edited_timestamp=course_data.edited_on, grading_policy_hash=course_data.grading_policy_hash, percent_grade=course_grade.percent, letter_grade=course_grade.letter_grade or "", passed=course_grade.passed, ) COURSE_GRADE_CHANGED.send_robust( sender=None, user=user, course_grade=course_grade, course_key=course_data.course_key, deadline=course_data.course.end, ) if course_grade.passed: COURSE_GRADE_NOW_PASSED.send( sender=CourseGradeFactory, user=user, course_id=course_data.course_key, ) else: COURSE_GRADE_NOW_FAILED.send( sender=CourseGradeFactory, user=user, course_id=course_data.course_key, grade=course_grade, ) log.info( u'Grades: Update, %s, User: %s, %s, persisted: %s', course_data.full_string(), user.id, course_grade, should_persist, ) return course_grade
def test_no_recursion_without_persistent_grades(self): """ Course grade signals should not be fired recursively when persistent grades are disabled. """ self.mock_process_signal = Mock() # pylint: disable=attribute-defined-outside-init def handler(**kwargs): """ Mock signal receiver. """ self.mock_process_signal() with persistent_grades_feature_flags(global_flag=False, enabled_for_all_courses=False, course_id=self.course.id, enabled_for_course=False): with override_waffle_switch(AUTO_CERTIFICATE_GENERATION, active=True), mock_get_score(2, 2): COURSE_GRADE_NOW_PASSED.connect(handler) try: CourseGradeFactory().update(self.request.user, self.course) except RecursionError: pytest.fail( "The COURSE_GRADE_NOW_PASSED signal fired recursively." ) self.mock_process_signal.assert_called_once() COURSE_GRADE_NOW_PASSED.disconnect(handler)
def _update(user, course_data, force_update_subsections=False): """ Computes, saves, and returns a CourseGrade object for the given user and course. Sends a COURSE_GRADE_CHANGED signal to listeners and COURSE_GRADE_NOW_PASSED if learner has passed course or COURSE_GRADE_NOW_FAILED if learner is now failing course """ should_persist = should_persist_grades(course_data.course_key) if should_persist and force_update_subsections: prefetch_grade_overrides_and_visible_blocks(user, course_data.course_key) course_grade = CourseGrade( user, course_data, force_update_subsections=force_update_subsections ) course_grade = course_grade.update() should_persist = should_persist and course_grade.attempted if should_persist: course_grade._subsection_grade_factory.bulk_create_unsaved() # lint-amnesty, pylint: disable=protected-access PersistentCourseGrade.update_or_create( user_id=user.id, course_id=course_data.course_key, course_version=course_data.version, course_edited_timestamp=course_data.edited_on, grading_policy_hash=course_data.grading_policy_hash, percent_grade=course_grade.percent, letter_grade=course_grade.letter_grade or "", passed=course_grade.passed, ) COURSE_GRADE_CHANGED.send_robust( sender=None, user=user, course_grade=course_grade, course_key=course_data.course_key, deadline=course_data.course.end, ) if course_grade.passed: COURSE_GRADE_NOW_PASSED.send( sender=CourseGradeFactory, user=user, course_id=course_data.course_key, ) else: COURSE_GRADE_NOW_FAILED.send( sender=CourseGradeFactory, user=user, course_id=course_data.course_key, grade=course_grade, ) log.info( 'Grades: Update, %s, User: %s, %s, persisted: %s', course_data.full_string(), user.id, course_grade, should_persist, ) return course_grade
def _update(user, course_data, read_only, force_update_subsections=False): """ Computes, saves, and returns a CourseGrade object for the given user and course. Sends a COURSE_GRADE_CHANGED signal to listeners and a COURSE_GRADE_NOW_PASSED if learner has passed course. """ course_grade = CourseGrade( user, course_data, force_update_subsections=force_update_subsections) course_grade.update() should_persist = (( not read_only ) and # TODO(TNL-6786) Remove the read_only boolean once all grades are back-filled. should_persist_grades(course_data.course_key) and (not waffle().is_enabled(WRITE_ONLY_IF_ENGAGED) or course_grade.attempted)) if should_persist: course_grade._subsection_grade_factory.bulk_create_unsaved() PersistentCourseGrade.update_or_create( user_id=user.id, course_id=course_data.course_key, course_version=course_data.version, course_edited_timestamp=course_data.edited_on, grading_policy_hash=course_data.grading_policy_hash, percent_grade=course_grade.percent, letter_grade=course_grade.letter_grade or "", passed=course_grade.passed, ) COURSE_GRADE_CHANGED.send_robust( sender=None, user=user, course_grade=course_grade, course_key=course_data.course_key, deadline=course_data.course.end, ) if course_grade.passed: COURSE_GRADE_NOW_PASSED.send( sender=CourseGradeFactory, user=user, course_id=course_data.course_key, ) log.info( u'Grades: Update, %s, User: %s, %s, persisted: %s', course_data.full_string(), user.id, course_grade, should_persist, ) return course_grade
def test_handle_enterprise_learner_passing_grade(self): """ Test to assert transmit_single_learner_data is called when COURSE_GRADE_NOW_PASSED signal is fired """ with patch( 'integrated_channels.integrated_channel.tasks.transmit_single_learner_data.apply_async', return_value=None) as mock_task_apply: course_key = CourseKey.from_string(self.course_id) COURSE_GRADE_NOW_PASSED.disconnect( dispatch_uid='new_passing_learner') COURSE_GRADE_NOW_PASSED.send(sender=None, user=self.user, course_id=course_key) self.assertFalse(mock_task_apply.called) self._create_enterprise_enrollment(self.user.id, self.course_id) task_kwargs = { 'username': self.user.username, 'course_run_id': self.course_id } COURSE_GRADE_NOW_PASSED.send(sender=None, user=self.user, course_id=course_key) mock_task_apply.assert_called_once_with(kwargs=task_kwargs) COURSE_GRADE_NOW_PASSED.connect(listen_for_passing_grade, dispatch_uid='new_passing_learner')