Commit 5350e316 by J. Cliff Dyer

fixup: extract some common code.

parent 0e2534f3
...@@ -16,7 +16,7 @@ from lazy import lazy ...@@ -16,7 +16,7 @@ from lazy import lazy
import logging import logging
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models, transaction from django.db import models
from django.utils.timezone import now from django.utils.timezone import now
from model_utils.models import TimeStampedModel from model_utils.models import TimeStampedModel
...@@ -321,40 +321,36 @@ class PersistentSubsectionGrade(TimeStampedModel): ...@@ -321,40 +321,36 @@ class PersistentSubsectionGrade(TimeStampedModel):
) )
@classmethod @classmethod
def update_or_create_grade(cls, **kwargs): def update_or_create_grade(cls, **params):
""" """
Wrapper for objects.update_or_create. Wrapper for objects.update_or_create.
""" """
cls._prepare_params_and_visible_blocks(kwargs) cls._prepare_params_and_visible_blocks(params)
user_id = kwargs.pop('user_id') user_id = params.pop('user_id')
usage_key = kwargs.pop('usage_key') usage_key = params.pop('usage_key')
attempted = kwargs.pop('attempted') attempted = params.pop('attempted')
with transaction.atomic():
grade, _ = cls.objects.update_or_create( grade, _ = cls.objects.update_or_create(
user_id=user_id, user_id=user_id,
course_id=usage_key.course_key, course_id=usage_key.course_key,
usage_key=usage_key, usage_key=usage_key,
defaults=kwargs, defaults=params,
) )
if attempted and not grade.first_attempted: if attempted and not grade.first_attempted:
grade.first_attempted = now() grade.first_attempted = now()
grade.save() grade.save()
grade.full_clean() grade.full_clean()
return grade return grade
@classmethod @classmethod
def create_grade(cls, **kwargs): def create_grade(cls, **params):
""" """
Wrapper for objects.create. Wrapper for objects.create.
""" """
cls._prepare_params_and_visible_blocks(kwargs) cls._prepare_params_and_visible_blocks(params)
cls._prepare_attempted_for_create(params, now())
attempted = kwargs.pop('attempted') grade = cls(**params)
grade = cls(**kwargs)
if attempted:
grade.first_attempted = now()
grade.full_clean() grade.full_clean()
grade.save() grade.save()
return grade return grade
...@@ -370,14 +366,13 @@ class PersistentSubsectionGrade(TimeStampedModel): ...@@ -370,14 +366,13 @@ class PersistentSubsectionGrade(TimeStampedModel):
map(cls._prepare_params, grade_params_iter) map(cls._prepare_params, grade_params_iter)
VisibleBlocks.bulk_get_or_create([params['visible_blocks'] for params in grade_params_iter], course_key) VisibleBlocks.bulk_get_or_create([params['visible_blocks'] for params in grade_params_iter], course_key)
map(cls._prepare_params_visible_blocks_id, grade_params_iter) map(cls._prepare_params_visible_blocks_id, grade_params_iter)
first_attempt_timestamp = now() first_attempt_timestamp = now()
for params in grade_params_iter: for params in grade_params_iter:
if params.pop('attempted'): cls._prepare_attempted_for_create(params, first_attempt_timestamp)
params['first_attempted'] = first_attempt_timestamp grades = [PersistentSubsectionGrade(**params) for params in grade_params_iter]
elif params['earned_all'] != 0.0 or params['earned_graded'] != 0.0: for grade in grades:
raise ValidationError("Unattempted problems cannot have a non-zero score.") grade.full_clean()
return cls.objects.bulk_create([PersistentSubsectionGrade(**params) for params in grade_params_iter]) return cls.objects.bulk_create(grades)
@classmethod @classmethod
def _prepare_params_and_visible_blocks(cls, params): def _prepare_params_and_visible_blocks(cls, params):
...@@ -399,6 +394,15 @@ class PersistentSubsectionGrade(TimeStampedModel): ...@@ -399,6 +394,15 @@ class PersistentSubsectionGrade(TimeStampedModel):
params['visible_blocks'] = BlockRecordList.from_list(params['visible_blocks'], params['course_id']) params['visible_blocks'] = BlockRecordList.from_list(params['visible_blocks'], params['course_id'])
@classmethod @classmethod
def _prepare_attempted_for_create(cls, params, timestamp):
"""
When creating objects, an attempted subsection gets its timestamp set
unconditionally.
"""
if params.pop('attempted'):
params['first_attempted'] = timestamp
@classmethod
def _prepare_params_visible_blocks_id(cls, params): def _prepare_params_visible_blocks_id(cls, params):
""" """
Prepares the visible_blocks_id field for the grade record, Prepares the visible_blocks_id field for the grade record,
......
...@@ -113,7 +113,7 @@ class RecalculateSubsectionGradeTest(ModuleStoreTestCase): ...@@ -113,7 +113,7 @@ class RecalculateSubsectionGradeTest(ModuleStoreTestCase):
with self.store.default_store(default_store): with self.store.default_store(default_store):
self.set_up_course() self.set_up_course()
self.assertTrue(PersistentGradesEnabledFlag.feature_enabled(self.course.id)) self.assertTrue(PersistentGradesEnabledFlag.feature_enabled(self.course.id))
with check_mongo_calls(2) and self.assertNumQueries(24 + added_queries): with check_mongo_calls(2) and self.assertNumQueries(22 + added_queries):
self._apply_recalculate_subsection_grade() self._apply_recalculate_subsection_grade()
@patch('lms.djangoapps.grades.signals.signals.SUBSECTION_SCORE_CHANGED.send') @patch('lms.djangoapps.grades.signals.signals.SUBSECTION_SCORE_CHANGED.send')
...@@ -161,7 +161,7 @@ class RecalculateSubsectionGradeTest(ModuleStoreTestCase): ...@@ -161,7 +161,7 @@ class RecalculateSubsectionGradeTest(ModuleStoreTestCase):
self.assertTrue(PersistentGradesEnabledFlag.feature_enabled(self.course.id)) self.assertTrue(PersistentGradesEnabledFlag.feature_enabled(self.course.id))
ItemFactory.create(parent=self.sequential, category='problem', display_name='problem2') ItemFactory.create(parent=self.sequential, category='problem', display_name='problem2')
ItemFactory.create(parent=self.sequential, category='problem', display_name='problem3') ItemFactory.create(parent=self.sequential, category='problem', display_name='problem3')
with check_mongo_calls(2) and self.assertNumQueries(24 + added_queries): with check_mongo_calls(2) and self.assertNumQueries(22 + added_queries):
self._apply_recalculate_subsection_grade() self._apply_recalculate_subsection_grade()
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
......
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