Merge pull request #16048 from edx/sstudent/EDUCATOR-1288

Sstudent/educator 1288
This commit is contained in:
sanfordstudent
2017-09-21 16:48:46 -04:00
committed by GitHub
10 changed files with 91 additions and 12 deletions

View File

@@ -11,8 +11,10 @@ from xblock.scorable import ScorableXBlockMixin, Score
from courseware.model_data import get_score, set_score
from eventtracking import tracker
from lms.djangoapps.instructor_task.tasks_helper.module_state import GRADES_OVERRIDE_EVENT_TYPE
from openedx.core.djangoapps.course_groups.signals.signals import COHORT_MEMBERSHIP_UPDATED
from openedx.core.lib.grade_utils import is_score_higher_or_equal
from student.models import user_by_anonymous_id
from student.signals.signals import ENROLLMENT_TRACK_UPDATED
from submissions.models import score_reset, score_set
from track.event_transaction_utils import (
create_new_event_transaction_id,
@@ -22,6 +24,7 @@ from track.event_transaction_utils import (
)
from util.date_utils import to_timestamp
from ..config.waffle import waffle, WRITE_ONLY_IF_ENGAGED
from ..constants import ScoreDatabaseTableEnum
from ..new.course_grade_factory import CourseGradeFactory
from ..scores import weighted_score
@@ -31,7 +34,7 @@ from .signals import (
PROBLEM_WEIGHTED_SCORE_CHANGED,
SCORE_PUBLISHED,
SUBSECTION_SCORE_CHANGED,
SUBSECTION_OVERRIDE_CHANGED
SUBSECTION_OVERRIDE_CHANGED,
)
log = getLogger(__name__)
@@ -237,13 +240,28 @@ def enqueue_subsection_update(sender, **kwargs): # pylint: disable=unused-argum
@receiver(SUBSECTION_SCORE_CHANGED)
def recalculate_course_grade(sender, course, course_structure, user, **kwargs): # pylint: disable=unused-argument
def recalculate_course_grade_only(sender, course, course_structure, user, **kwargs): # pylint: disable=unused-argument
"""
Updates a saved course grade.
Updates a saved course grade, but does not update the subsection
grades the user has in this course.
"""
CourseGradeFactory().update(user, course=course, course_structure=course_structure)
@receiver(ENROLLMENT_TRACK_UPDATED)
@receiver(COHORT_MEMBERSHIP_UPDATED)
def force_recalculate_course_and_subsection_grades(sender, user, course_key, **kwargs):
"""
Updates a saved course grade, forcing the subsection grades
from which it is calculated to update along the way.
Does not create a grade if the user has never attempted a problem,
even if the WRITE_ONLY_IF_ENGAGED waffle switch is off.
"""
if waffle().is_enabled(WRITE_ONLY_IF_ENGAGED) or CourseGradeFactory().read(user, course_key=course_key):
CourseGradeFactory().update(user=user, course_key=course_key, force_update_subsections=True)
def _emit_event(kwargs):
"""
Emits a problem submitted event only if there is no current event

View File

@@ -1,7 +1,7 @@
"""
Tests for the score change signals defined in the courseware models module.
"""
import itertools
import re
from datetime import datetime
@@ -10,15 +10,20 @@ import pytz
from django.test import TestCase
from mock import MagicMock, patch
from opaque_keys.edx.locations import CourseLocator
from openedx.core.djangoapps.course_groups.signals.signals import COHORT_MEMBERSHIP_UPDATED
from student.signals.signals import ENROLLMENT_TRACK_UPDATED
from student.tests.factories import UserFactory
from submissions.models import score_reset, score_set
from util.date_utils import to_timestamp
from ..config.waffle import waffle, WRITE_ONLY_IF_ENGAGED
from ..constants import ScoreDatabaseTableEnum
from ..signals.handlers import (
disconnect_submissions_signal_receiver,
problem_raw_score_changed_handler,
submissions_score_reset_handler,
submissions_score_set_handler
submissions_score_set_handler,
)
from ..signals.signals import PROBLEM_RAW_SCORE_CHANGED
@@ -251,3 +256,32 @@ class ScoreChangedSignalRelayTest(TestCase):
with self.assertRaises(ValueError):
with disconnect_submissions_signal_receiver(PROBLEM_RAW_SCORE_CHANGED):
pass
@ddt.ddt
class RecalculateUserGradeSignalsTest(TestCase):
def setUp(self):
super(RecalculateUserGradeSignalsTest, self).setUp()
self.user = UserFactory()
self.course_key = CourseLocator("test_org", "test_course_num", "test_run")
@patch('lms.djangoapps.grades.signals.handlers.CourseGradeFactory.update')
@patch('lms.djangoapps.grades.signals.handlers.CourseGradeFactory.read')
@ddt.data(*itertools.product((COHORT_MEMBERSHIP_UPDATED, ENROLLMENT_TRACK_UPDATED), (True, False), (True, False)))
@ddt.unpack
def test_recalculate_on_signal(self, signal, write_only_if_engaged, has_grade, read_mock, update_mock):
"""
Tests the grades handler for signals that trigger regrading.
The handler should call CourseGradeFactory.update() with the
args below, *except* if the WRITE_ONLY_IF_ENGAGED waffle flag
is inactive and the user does not have a grade.
"""
if not has_grade:
read_mock.return_value = None
with waffle().override(WRITE_ONLY_IF_ENGAGED, active=write_only_if_engaged):
signal.send(sender=None, user=self.user, course_key=self.course_key)
if not write_only_if_engaged and not has_grade:
update_mock.assert_not_called()
else:
update_mock.assert_called_with(course_key=self.course_key, user=self.user, force_update_subsections=True)