Commit 2251097c by Nimisha Asthagiri Committed by GitHub

Merge pull request #13437 from edx/cdyer/keep-course-run

Ensure usage keys have course run in locators.
parents 0853e485 ddd58daf
...@@ -17,7 +17,7 @@ from django.db.utils import IntegrityError ...@@ -17,7 +17,7 @@ from django.db.utils import IntegrityError
from model_utils.models import TimeStampedModel from model_utils.models import TimeStampedModel
from coursewarehistoryextended.fields import UnsignedBigIntAutoField from coursewarehistoryextended.fields import UnsignedBigIntAutoField
from opaque_keys.edx.locator import BlockUsageLocator from opaque_keys.edx.keys import CourseKey, UsageKey
from xmodule_django.models import CourseKeyField, UsageKeyField from xmodule_django.models import CourseKeyField, UsageKeyField
...@@ -39,6 +39,17 @@ class BlockRecordSet(frozenset): ...@@ -39,6 +39,17 @@ class BlockRecordSet(frozenset):
self._json = None self._json = None
self._hash = None self._hash = None
def _get_course_key_string(self):
"""
Get the course key as a string. All blocks are from the same course,
so just grab one arbitrarily. If no blocks are present, return None.
"""
if self:
a_block = next(iter(self))
return unicode(a_block.locator.course_key)
else:
return None
def to_json(self): def to_json(self):
""" """
Return a JSON-serialized version of the list of block records, using a Return a JSON-serialized version of the list of block records, using a
...@@ -47,12 +58,18 @@ class BlockRecordSet(frozenset): ...@@ -47,12 +58,18 @@ class BlockRecordSet(frozenset):
if self._json is None: if self._json is None:
sorted_blocks = sorted(self, key=attrgetter('locator')) sorted_blocks = sorted(self, key=attrgetter('locator'))
list_of_block_dicts = [block._asdict() for block in sorted_blocks] list_of_block_dicts = [block._asdict() for block in sorted_blocks]
course_key_string = self._get_course_key_string() # all blocks are from the same course
for block_dict in list_of_block_dicts: for block_dict in list_of_block_dicts:
block_dict['locator'] = unicode(block_dict['locator']) # BlockUsageLocator is not json-serializable block_dict['locator'] = unicode(block_dict['locator']) # BlockUsageLocator is not json-serializable
# Remove spaces from separators for more compact representation data = {
'course_key': course_key_string,
'blocks': list_of_block_dicts,
}
self._json = json.dumps( self._json = json.dumps(
list_of_block_dicts, data,
separators=(',', ':'), separators=(',', ':'), # Remove spaces from separators for more compact representation
sort_keys=True, sort_keys=True,
) )
return self._json return self._json
...@@ -62,10 +79,17 @@ class BlockRecordSet(frozenset): ...@@ -62,10 +79,17 @@ class BlockRecordSet(frozenset):
""" """
Return a BlockRecordSet from a json list. Return a BlockRecordSet from a json list.
""" """
block_dicts = json.loads(blockrecord_json) data = json.loads(blockrecord_json)
course_key = data['course_key']
if course_key is not None:
course_key = CourseKey.from_string(course_key)
else:
# If there was no course key, there are no blocks.
assert len(data['blocks']) == 0
block_dicts = data['blocks']
record_generator = ( record_generator = (
BlockRecord( BlockRecord(
locator=BlockUsageLocator.from_string(block["locator"]), locator=UsageKey.from_string(block["locator"]).replace(course_key=course_key),
weight=block["weight"], weight=block["weight"],
max_score=block["max_score"], max_score=block["max_score"],
) )
......
...@@ -20,6 +20,25 @@ from lms.djangoapps.grades.models import ( ...@@ -20,6 +20,25 @@ from lms.djangoapps.grades.models import (
) )
class BlockRecordSetTestCase(TestCase):
"""
Verify the behavior of BlockRecordSets, particularly around edge cases
"""
empty_json = '{"blocks":[],"course_key":null}'
def test_empty_block_record_set(self):
brs = BlockRecordSet()
self.assertFalse(brs)
self.assertEqual(
brs.to_json(),
self.empty_json
)
self.assertEqual(
BlockRecordSet.from_json(self.empty_json),
brs
)
class GradesModelTestCase(TestCase): class GradesModelTestCase(TestCase):
""" """
Base class for common setup of grades model tests. Base class for common setup of grades model tests.
...@@ -41,8 +60,8 @@ class GradesModelTestCase(TestCase): ...@@ -41,8 +60,8 @@ class GradesModelTestCase(TestCase):
block_type='problem', block_type='problem',
block_id='block_id_b' block_id='block_id_b'
) )
self.record_a = BlockRecord(self.locator_a, 1, 10) self.record_a = BlockRecord(locator=self.locator_a, weight=1, max_score=10)
self.record_b = BlockRecord(self.locator_b, 1, 10) self.record_b = BlockRecord(locator=self.locator_b, weight=1, max_score=10)
@ddt.ddt @ddt.ddt
...@@ -97,8 +116,15 @@ class VisibleBlocksTest(GradesModelTestCase): ...@@ -97,8 +116,15 @@ class VisibleBlocksTest(GradesModelTestCase):
list_of_block_dicts = [self.record_a._asdict()] list_of_block_dicts = [self.record_a._asdict()]
for block_dict in list_of_block_dicts: for block_dict in list_of_block_dicts:
block_dict['locator'] = unicode(block_dict['locator']) # BlockUsageLocator is not json-serializable block_dict['locator'] = unicode(block_dict['locator']) # BlockUsageLocator is not json-serializable
expected_json = json.dumps(list_of_block_dicts, separators=(',', ':'), sort_keys=True) expected_data = {
'course_key': unicode(self.record_a.locator.course_key),
'blocks': [
{'locator': unicode(self.record_a.locator), 'max_score': 10, 'weight': 1},
],
}
expected_json = json.dumps(expected_data, separators=(',', ':'), sort_keys=True)
expected_hash = b64encode(sha1(expected_json).digest()) expected_hash = b64encode(sha1(expected_json).digest())
self.assertEqual(expected_data, json.loads(vblocks.blocks_json))
self.assertEqual(expected_json, vblocks.blocks_json) self.assertEqual(expected_json, vblocks.blocks_json)
self.assertEqual(expected_hash, vblocks.hashed) self.assertEqual(expected_hash, vblocks.hashed)
......
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