Commit feb2ae3d by Diana Huang

Create new get_all_course_submission_information endpoint.

parent 48dc2630
...@@ -10,7 +10,7 @@ import json ...@@ -10,7 +10,7 @@ import json
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.db import IntegrityError, DatabaseError, transaction 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 (
...@@ -220,7 +220,7 @@ def get_submission(submission_uuid, read_replica=False): ...@@ -220,7 +220,7 @@ def get_submission(submission_uuid, read_replica=False):
cache_key = Submission.get_cache_key(submission_uuid) cache_key = Submission.get_cache_key(submission_uuid)
try: try:
cached_submission_data = cache.get(cache_key) cached_submission_data = cache.get(cache_key)
except Exception as ex: except Exception:
# The cache backend could raise an exception # The cache backend could raise an exception
# (for example, memcache keys that contain spaces) # (for example, memcache keys that contain spaces)
logger.exception("Error occurred while retrieving submission from the cache") logger.exception("Error occurred while retrieving submission from the cache")
...@@ -413,6 +413,63 @@ def get_all_submissions(course_id, item_id, item_type, read_replica=True): ...@@ -413,6 +413,63 @@ def get_all_submissions(course_id, item_id, item_type, read_replica=True):
yield data yield data
def get_all_course_submission_information(course_id, item_type, read_replica=True):
""" For the given course, get all the submissions, student items, and scores of the given item type.
Args:
course_id (str): The course that we are getting submissions from.
item_type (str): The type of items that we are getting submissions for.
read_replica (bool): Try to use the database's read replica if it's available.
Yields:
A tuple of three dictionaries representing:
(1) a student item with the following fields:
student_id
course_id
student_item
item_type
(2) a submission with the following fields:
student_item
attempt_number
submitted_at
created_at
answer
(3) a score with the following fields:
student_item
submission
points_earned
points_possible
created_at
submission_uuid
"""
submission_qs = Submission.objects
if read_replica:
submission_qs = _use_read_replica(submission_qs)
query = submission_qs.select_related('student_item').prefetch_related('score_set').filter(
student_item__course_id=course_id,
student_item__item_type=item_type,
).iterator()
for submission in query:
student_item = submission.student_item
if submission.score_set.count() > 0:
for score in submission.score_set.all():
yield (
StudentItemSerializer(student_item).data,
SubmissionSerializer(submission).data,
ScoreSerializer(score).data
)
else:
# Make sure we return submission information even if there isn't a score associated with it.
yield (
StudentItemSerializer(student_item).data,
SubmissionSerializer(submission).data,
{}
)
def get_top_submissions(course_id, item_id, item_type, number_of_top_scores, use_cache=True, read_replica=True): def get_top_submissions(course_id, item_id, item_type, number_of_top_scores, use_cache=True, read_replica=True):
"""Get a number of top scores for an assessment based on a particular student item """Get a number of top scores for an assessment based on a particular student item
...@@ -755,7 +812,7 @@ def set_score(submission_uuid, points_earned, points_possible, ...@@ -755,7 +812,7 @@ def set_score(submission_uuid, points_earned, points_possible,
u"No submission matching uuid {}".format(submission_uuid) u"No submission matching uuid {}".format(submission_uuid)
) )
except DatabaseError: except DatabaseError:
error_msg = u"Could not retrieve student item: {} or submission {}.".format( error_msg = u"Could not retrieve submission {}.".format(
submission_uuid submission_uuid
) )
logger.exception(error_msg) logger.exception(error_msg)
......
...@@ -101,6 +101,42 @@ class TestSubmissionsApi(TestCase): ...@@ -101,6 +101,42 @@ class TestSubmissionsApi(TestCase):
self._assert_submission(submissions[1], ANSWER_TWO, student_item.pk, 2) self._assert_submission(submissions[1], ANSWER_TWO, student_item.pk, 2)
self.assertEqual(submissions[1]['student_id'], STUDENT_ITEM['student_id']) self.assertEqual(submissions[1]['student_id'], STUDENT_ITEM['student_id'])
def test_get_course_submissions(self):
submission1 = api.create_submission(STUDENT_ITEM, ANSWER_ONE)
submission2 = api.create_submission(STUDENT_ITEM, ANSWER_TWO)
submission3 = api.create_submission(SECOND_STUDENT_ITEM, ANSWER_ONE)
submission4 = api.create_submission(SECOND_STUDENT_ITEM, ANSWER_TWO)
api.set_score(submission1['uuid'], 1, 4)
api.set_score(submission2['uuid'], 2, 4)
api.set_score(submission3['uuid'], 3, 4)
api.set_score(submission4['uuid'], 4, 4)
submissions_and_scores = list(api.get_all_course_submission_information(
STUDENT_ITEM['course_id'],
STUDENT_ITEM['item_type'],
read_replica=False,
))
student_item1 = self._get_student_item(STUDENT_ITEM)
student_item2 = self._get_student_item(SECOND_STUDENT_ITEM)
self.assertDictEqual(SECOND_STUDENT_ITEM, submissions_and_scores[0][0])
self._assert_submission(submissions_and_scores[0][1], submission4['answer'], student_item2.pk, 2)
self._assert_score(submissions_and_scores[0][2], 4, 4)
self.assertDictEqual(SECOND_STUDENT_ITEM, submissions_and_scores[1][0])
self._assert_submission(submissions_and_scores[1][1], submission3['answer'], student_item2.pk, 1)
self._assert_score(submissions_and_scores[1][2], 3, 4)
self.assertDictEqual(STUDENT_ITEM, submissions_and_scores[2][0])
self._assert_submission(submissions_and_scores[2][1], submission2['answer'], student_item1.pk, 2)
self._assert_score(submissions_and_scores[2][2], 2, 4)
self.assertDictEqual(STUDENT_ITEM, submissions_and_scores[3][0])
self._assert_submission(submissions_and_scores[3][1], submission1['answer'], student_item1.pk, 1)
self._assert_score(submissions_and_scores[3][2], 1, 4)
def test_get_submission(self): def test_get_submission(self):
# Test base case that we can create a submission and get it back # Test base case that we can create a submission and get it back
sub_dict1 = api.create_submission(STUDENT_ITEM, ANSWER_ONE) sub_dict1 = api.create_submission(STUDENT_ITEM, ANSWER_ONE)
......
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