Commit fc232e5e by Cliff Dyer Committed by GitHub

Merge pull request #57 from edx/neem/score-summaries

return serialized scores from get_scores()
parents 7deafc6d 7a557d7d
...@@ -33,7 +33,7 @@ def load_requirements(*requirements_paths): ...@@ -33,7 +33,7 @@ def load_requirements(*requirements_paths):
setup( setup(
name='edx-submissions', name='edx-submissions',
version='1.2.0', version='2.0.0',
author='edX', author='edX',
description='An API for creating submissions and scores.', description='An API for creating submissions and scores.',
url='http://github.com/edx/edx-submissions.git', url='http://github.com/edx/edx-submissions.git',
......
...@@ -14,7 +14,7 @@ from django.db import IntegrityError, DatabaseError ...@@ -14,7 +14,7 @@ from django.db import IntegrityError, DatabaseError
from dogapi import dog_stats_api from dogapi import dog_stats_api
from submissions.serializers import ( from submissions.serializers import (
SubmissionSerializer, StudentItemSerializer, ScoreSerializer SubmissionSerializer, StudentItemSerializer, ScoreSerializer, UnannotatedScoreSerializer
) )
from submissions.models import Submission, StudentItem, Score, ScoreSummary, ScoreAnnotation, score_set, score_reset from submissions.models import Submission, StudentItem, Score, ScoreSummary, ScoreAnnotation, score_set, score_reset
...@@ -626,7 +626,10 @@ def get_score(student_item): ...@@ -626,7 +626,10 @@ def get_score(student_item):
def get_scores(course_id, student_id): def get_scores(course_id, student_id):
"""Return a dict mapping item_ids -> (points_earned, points_possible). """Return a dict mapping item_ids to scores.
Scores are represented by serialized Score objects in JSON-like dict
format.
This method would be used by an LMS to find all the scores for a given This method would be used by an LMS to find all the scores for a given
student in a given course. student in a given course.
...@@ -654,7 +657,7 @@ def get_scores(course_id, student_id): ...@@ -654,7 +657,7 @@ def get_scores(course_id, student_id):
score_summaries = ScoreSummary.objects.filter( score_summaries = ScoreSummary.objects.filter(
student_item__course_id=course_id, student_item__course_id=course_id,
student_item__student_id=student_id, student_item__student_id=student_id,
).select_related('latest', 'student_item') ).select_related('latest', 'latest__submission', 'student_item')
except DatabaseError: except DatabaseError:
msg = u"Could not fetch scores for course {}, student {}".format( msg = u"Could not fetch scores for course {}, student {}".format(
course_id, student_id course_id, student_id
...@@ -662,10 +665,8 @@ def get_scores(course_id, student_id): ...@@ -662,10 +665,8 @@ def get_scores(course_id, student_id):
logger.exception(msg) logger.exception(msg)
raise SubmissionInternalError(msg) raise SubmissionInternalError(msg)
scores = { scores = {
summary.student_item.item_id: summary.student_item.item_id: UnannotatedScoreSerializer(summary.latest).data
(summary.latest.points_earned, summary.latest.points_possible) for summary in score_summaries if not summary.latest.is_hidden()
for summary in score_summaries
if not summary.latest.is_hidden()
} }
return scores return scores
......
...@@ -96,12 +96,31 @@ class ScoreAnnotationSerializer(serializers.ModelSerializer): ...@@ -96,12 +96,31 @@ class ScoreAnnotationSerializer(serializers.ModelSerializer):
) )
class ScoreSerializer(serializers.ModelSerializer): class UnannotatedScoreSerializer(serializers.ModelSerializer):
# Ensure that the created_at datetime is not converted to a string. # Ensure that the created_at datetime is not converted to a string.
created_at = DateTimeField(format=None, required=False) created_at = DateTimeField(format=None, required=False)
class Meta:
model = Score
fields = (
'student_item',
'submission',
'points_earned',
'points_possible',
'created_at',
# Computed
'submission_uuid',
)
class ScoreSerializer(serializers.ModelSerializer):
# Ensure that the created_at datetime is not converted to a string.
created_at = DateTimeField(format=None, required=False)
annotations = serializers.SerializerMethodField() annotations = serializers.SerializerMethodField()
def get_annotations(self, obj): def get_annotations(self, obj):
""" """
Inspect ScoreAnnotations to attach all relevant annotations. Inspect ScoreAnnotations to attach all relevant annotations.
......
...@@ -363,6 +363,7 @@ class TestSubmissionsApi(TestCase): ...@@ -363,6 +363,7 @@ class TestSubmissionsApi(TestCase):
student_item['student_id'] = None student_item['student_id'] = None
self.assertIs(api.get_score(student_item), None) self.assertIs(api.get_score(student_item), None)
@freeze_time(datetime.datetime.now().replace(tzinfo=pytz.UTC))
def test_get_scores(self): def test_get_scores(self):
student_item = copy.deepcopy(STUDENT_ITEM) student_item = copy.deepcopy(STUDENT_ITEM)
student_item["course_id"] = "get_scores_course" student_item["course_id"] = "get_scores_course"
...@@ -388,14 +389,35 @@ class TestSubmissionsApi(TestCase): ...@@ -388,14 +389,35 @@ class TestSubmissionsApi(TestCase):
scores = api.get_scores( scores = api.get_scores(
student_item["course_id"], student_item["student_id"] student_item["course_id"], student_item["student_id"]
) )
self.assertEqual( self.assertEqual(
scores, scores,
{ {
u"i4x://a/b/c/s1": (2, 5), u'i4x://a/b/c/s1': {
u"i4x://a/b/c/s2": (0, 10), 'created_at': datetime.datetime.now(),
u"i4x://a/b/c/s3": (4, 4), 'points_earned': 2,
} 'points_possible': 5,
) 'student_item': 1,
'submission': 1,
'submission_uuid': s1['uuid'],
},
u'i4x://a/b/c/s2': {
'created_at': datetime.datetime.now(),
'points_earned': 0,
'points_possible': 10,
'student_item': 2,
'submission': 2,
'submission_uuid': s2['uuid'],
},
u'i4x://a/b/c/s3': {
'created_at': datetime.datetime.now(),
'points_earned': 4,
'points_possible': 4,
'student_item': 3,
'submission': 3,
'submission_uuid': s3['uuid'],
},
}
)
def test_get_top_submissions(self): def test_get_top_submissions(self):
student_item_1 = copy.deepcopy(STUDENT_ITEM) student_item_1 = copy.deepcopy(STUDENT_ITEM)
......
...@@ -137,7 +137,8 @@ class TestResetScore(TestCase): ...@@ -137,7 +137,8 @@ class TestResetScore(TestCase):
scores = sub_api.get_scores(self.STUDENT_ITEM['course_id'], self.STUDENT_ITEM['student_id']) scores = sub_api.get_scores(self.STUDENT_ITEM['course_id'], self.STUDENT_ITEM['student_id'])
self.assertIn(self.STUDENT_ITEM['item_id'], scores) self.assertIn(self.STUDENT_ITEM['item_id'], scores)
self.assertEqual(scores[self.STUDENT_ITEM['item_id']], (3, 4)) item_score = scores[self.STUDENT_ITEM['item_id']]
self.assertEqual((item_score['points_earned'], item_score['points_possible']), (3, 4))
def test_reset_then_get_score_for_submission(self): def test_reset_then_get_score_for_submission(self):
# Create a submission for the student and score it # Create a submission for the student and score it
......
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