Commit 56c0edec by Stephen Sanchez

My first pass at populate the submission API.

parent 7a722780
...@@ -10,8 +10,14 @@ might be tricky with XML import based courses). ...@@ -10,8 +10,14 @@ might be tricky with XML import based courses).
""" """
def create_evaluation(submission_id, score, rubric): def create_evaluation(submission_id, score, rubric):
pass pass
def get_evaluations(submission_id):
pass
def get_submission_to_evaluate(student_item, scorer_student_id): def get_submission_to_evaluate(student_item, scorer_student_id):
pass pass
...@@ -2,20 +2,61 @@ ...@@ -2,20 +2,61 @@
Public interface for the submissions app. Public interface for the submissions app.
""" """
from datetime import datetime
from submissions.serializers import SubmissionSerializer
from submissions.models import Submission, StudentItem, SubmissionStruct
def create_submission(student_item, answer, submitted_at=None): def create_submission(student_item, answer, submitted_at=None):
# score could be an optional param in the future. student_item = _get_student_item(student_item)
pass submitted_at = submitted_at if submitted_at else datetime.now()
if student_item:
submissions = Submission.objects.filter(student_item=student_item).order_by("submitted_at")[:0]
attempt_number = submissions[0].attempt_number if submissions else 1
submission = Submission.objects.create(
student_item=student_item,
submitted_at=submitted_at,
answer=answer,
attempt_number=attempt_number,
)
return SubmissionStruct(**SubmissionSerializer(submission).data)
def get_submissions(student_item, limit=None): def get_submissions(student_item, limit=None):
pass student_item = _get_student_item(student_item)
item_response = StudentItem.objects.get_or_create(
student_id=student_item.student_id,
course_id=student_item.course_id,
item_id=student_item.item_id,
item_type=student_item.item_type,
)
if limit:
submission_models = Submission.objects.filter(student_item=item_response[0])[:limit]
else:
submission_models = Submission.objects.filter(student_item=item_response[0])
return [SubmissionStruct(**SubmissionSerializer(submission).data) for submission in submission_models]
def get_score(student_item): def get_score(student_item):
pass pass
def get_scores(course_id, student_id, types=None): def get_scores(course_id, student_id, types=None):
pass pass
def set_score(student_item): def set_score(student_item):
pass pass
def _get_student_item(student_item):
student_items = StudentItem.objects.filter(
item_id=student_item.item_id,
student_id=student_item.student_id,
course_id=student_item.course_id,
)
return student_items[0] if student_items else None
\ No newline at end of file
...@@ -5,8 +5,8 @@ workflows, ORA, etc. So the flow is this: ...@@ -5,8 +5,8 @@ workflows, ORA, etc. So the flow is this:
Student submission: Student submission:
* XBlock creates a Submission * XBlock creates a Submission
* submissions app sends a general notification that a submission has happened * submissions app sends a general notification that a submission has happened
* openresponse can listen for that signal if it wants, or query itself on demand * openassessment can listen for that signal if it wants, or query itself on demand
* when openresponse is satistifed that it has collected enough information to * when openassessment is satisfied that it has collected enough information to
score the student, it will push that score information back to this app. score the student, it will push that score information back to this app.
* when the LMS wants to know what raw scores a student has, it calls this app. * when the LMS wants to know what raw scores a student has, it calls this app.
...@@ -15,9 +15,13 @@ Things to consider probably aren't worth the extra effort/complexity in the MVP: ...@@ -15,9 +15,13 @@ Things to consider probably aren't worth the extra effort/complexity in the MVP:
* Version ID (this doesn't work until split-mongostore comes into being) * Version ID (this doesn't work until split-mongostore comes into being)
""" """
from collections import namedtuple
from django.db import models from django.db import models
from django.utils.timezone import now from django.utils.timezone import now
StudentItemStruct = namedtuple("StudentItemStruct", "student_id course_id item_id item_type")
class StudentItem(models.Model): class StudentItem(models.Model):
"""Represents a single item for a single course for a single user. """Represents a single item for a single course for a single user.
...@@ -42,11 +46,10 @@ class StudentItem(models.Model): ...@@ -42,11 +46,10 @@ class StudentItem(models.Model):
unique_together = ( unique_together = (
# For integrity reasons, and looking up all of a student's items # For integrity reasons, and looking up all of a student's items
("course_id", "student_id", "item_id"), ("course_id", "student_id", "item_id"),
# Composite index for getting information across a course
("course_id", "item_id"),
) )
SubmissionStruct = namedtuple("SubmissionStruct", "student_item attempt_number submitted_at created_at answer")
class Submission(models.Model): class Submission(models.Model):
"""A single response by a student for a given problem in a given course. """A single response by a student for a given problem in a given course.
......
from rest_framework import serializers
from submissions.models import StudentItem, Submission, Score
class StudentItemSerializer(serializers.ModelSerializer):
class Meta:
model = StudentItem
fields = ('student_id', 'course_id', 'item_id', 'item_type')
class SubmissionSerializer(serializers.ModelSerializer):
class Meta:
model = Submission
fields = ('student_item', 'attempt_number', 'submitted_at', 'created_at', 'answer')
class ScoreSerializer(serializers.ModelSerializer):
class Meta:
model = Score
fields = ('student_item', 'submission', 'points_earned', 'points_possible', 'created_at')
from django.test import TestCase
from submissions.models import StudentItem, StudentItemStruct
from submissions.api import create_submission, get_submissions
STUDENT_ITEM = StudentItemStruct(
student_id="Tim",
course_id="Demo_Course",
item_id="item_one",
item_type="Peer_Submission"
)
class TestApi(TestCase):
def setUp(self):
StudentItem.objects.create(
student_id=STUDENT_ITEM.student_id,
course_id=STUDENT_ITEM.course_id,
item_id=STUDENT_ITEM.item_id,
item_type=STUDENT_ITEM.student_id
)
def test_create_submission(self):
submission = create_submission(STUDENT_ITEM, "this is my answer!")
self._assert_submission(submission, "this is my answer!", 1, 1)
def test_get_submission(self):
create_submission(STUDENT_ITEM, "this is my answer!")
create_submission(STUDENT_ITEM, "this is my other answer!")
submissions = get_submissions(STUDENT_ITEM)
self._assert_submission(submissions[0], "this is my answer!", 1, 1)
self._assert_submission(submissions[1], "this is my other answer!", 1, 1)
def _assert_submission(self, submission, expected_answer, expected_item, expected_attempt):
self.assertIsNotNone(submission)
self.assertEqual(submission.answer, expected_answer)
self.assertEqual(submission.student_item, expected_item)
self.assertEqual(submission.attempt_number, expected_attempt)
\ No newline at end of file
...@@ -3,3 +3,4 @@ ...@@ -3,3 +3,4 @@
# Third Party Requirements # Third Party Requirements
django==1.4.8 django==1.4.8
djangorestframework==2.3.5
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