Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-ora2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-ora2
Commits
c724f90f
Commit
c724f90f
authored
Jan 29, 2014
by
Stephen Sanchez
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into sanchez/debug_submissions_page
parents
6c634b23
f88acf51
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
73 additions
and
24 deletions
+73
-24
apps/submissions/api.py
+67
-20
apps/submissions/tests/test_api.py
+5
-4
requirements/test.txt
+1
-0
No files found.
apps/submissions/api.py
View file @
c724f90f
...
@@ -77,14 +77,38 @@ def create_submission(student_item_dict, answer, submitted_at=None,
...
@@ -77,14 +77,38 @@ def create_submission(student_item_dict, answer, submitted_at=None,
attempt_number plus one.
attempt_number plus one.
Returns:
Returns:
dict: A representation of the created Submission.
dict: A representation of the created Submission. The submission
contains five attributes: student_item, attempt_number, submitted_at,
created_at, and answer. 'student_item' is the ID of the related student
item for the submission. 'attempt_number' is the attempt this submission
represents for this question. 'submitted_at' represents the time this
submission was submitted, which can be configured, versus the
'created_at' date, which is when the submission is first created.
Raises:
Raises:
SubmissionRequestError: Raised when information regarding the student
SubmissionRequestError: Raised when there are validation errors for the
item fails validation.
student item or submission. This can be caused by the student item
missing required values, the submission being too long, the
attempt_number is negative, or the given submitted_at time is invalid.
SubmissionInternalError: Raised when submission access causes an
SubmissionInternalError: Raised when submission access causes an
internal error.
internal error.
Examples:
>>> student_item_dict = dict(
>>> student_id="Tim",
>>> item_id="item_1",
>>> course_id="course_1",
>>> item_type="type_one"
>>> )
>>> create_submission(student_item_dict, "The answer is 42.", datetime.utcnow, 1)
{
'student_item': 2,
'attempt_number': 1,
'submitted_at': datetime.datetime(2014, 1, 29, 17, 14, 52, 649284 tzinfo=<UTC>),
'created_at': datetime.datetime(2014, 1, 29, 17, 14, 52, 668850, tzinfo=<UTC>),
'answer': u'The answer is 42.'
}
"""
"""
student_item_model
=
_get_or_create_student_item
(
student_item_dict
)
student_item_model
=
_get_or_create_student_item
(
student_item_dict
)
if
attempt_number
is
None
:
if
attempt_number
is
None
:
...
@@ -101,7 +125,8 @@ def create_submission(student_item_dict, answer, submitted_at=None,
...
@@ -101,7 +125,8 @@ def create_submission(student_item_dict, answer, submitted_at=None,
try
:
try
:
answer
=
force_unicode
(
answer
)
answer
=
force_unicode
(
answer
)
except
UnicodeDecodeError
:
except
UnicodeDecodeError
:
raise
SubmissionRequestError
(
u"Submission answer could not be properly decoded to unicode."
)
raise
SubmissionRequestError
(
u"Submission answer could not be properly decoded to unicode."
)
model_kwargs
=
{
model_kwargs
=
{
"student_item"
:
student_item_model
,
"student_item"
:
student_item_model
,
...
@@ -112,13 +137,16 @@ def create_submission(student_item_dict, answer, submitted_at=None,
...
@@ -112,13 +137,16 @@ def create_submission(student_item_dict, answer, submitted_at=None,
model_kwargs
[
"submitted_at"
]
=
submitted_at
model_kwargs
[
"submitted_at"
]
=
submitted_at
try
:
try
:
# Serializer validation requires the student item primary key, rather
# than the student item model itself. Create a copy of the submission
# kwargs and replace the student item model with it's primary key.
validation_data
=
model_kwargs
.
copy
()
validation_data
=
model_kwargs
.
copy
()
validation_data
[
"student_item"
]
=
student_item_model
.
pk
validation_data
[
"student_item"
]
=
student_item_model
.
pk
submission_serializer
=
SubmissionSerializer
(
data
=
validation_data
)
submission_serializer
=
SubmissionSerializer
(
data
=
validation_data
)
submission_serializer
.
is_valid
()
if
not
submission_serializer
.
is_valid
():
if
submission_serializer
.
errors
:
raise
SubmissionRequestError
(
submission_serializer
.
errors
)
raise
SubmissionRequestError
(
submission_serializer
.
errors
)
submission
=
Submission
.
objects
.
create
(
**
model_kwargs
)
submission_serializer
.
save
()
return
submission_serializer
.
data
except
DatabaseError
:
except
DatabaseError
:
error_message
=
u"An error occurred while creating submission {} for student item: {}"
.
format
(
error_message
=
u"An error occurred while creating submission {} for student item: {}"
.
format
(
model_kwargs
,
model_kwargs
,
...
@@ -127,8 +155,6 @@ def create_submission(student_item_dict, answer, submitted_at=None,
...
@@ -127,8 +155,6 @@ def create_submission(student_item_dict, answer, submitted_at=None,
logger
.
exception
(
error_message
)
logger
.
exception
(
error_message
)
raise
SubmissionInternalError
(
error_message
)
raise
SubmissionInternalError
(
error_message
)
return
SubmissionSerializer
(
submission
)
.
data
def
get_submissions
(
student_item_dict
,
limit
=
None
):
def
get_submissions
(
student_item_dict
,
limit
=
None
):
"""Retrieves the submissions for the specified student item,
"""Retrieves the submissions for the specified student item,
...
@@ -138,15 +164,20 @@ def get_submissions(student_item_dict, limit=None):
...
@@ -138,15 +164,20 @@ def get_submissions(student_item_dict, limit=None):
thrown if no submission is found relative to this location.
thrown if no submission is found relative to this location.
Args:
Args:
student_item_dict (dict): The location of the problem
student_item_dict (dict): The location of the problem this submission is
this submission is associated with, as defined by a course, student,
associated with, as defined by a course, student, and item.
and item.
limit (int): Optional parameter for limiting the returned number of
limit (int): Optional parameter for limiting the returned number of
submissions associated with this student item. If not specified, all
submissions associated with this student item. If not specified, all
associated submissions are returned.
associated submissions are returned.
Returns:
Returns:
List dict: A list of dicts for the associated student item.
List dict: A list of dicts for the associated student item. The submission
contains five attributes: student_item, attempt_number, submitted_at,
created_at, and answer. 'student_item' is the ID of the related student
item for the submission. 'attempt_number' is the attempt this submission
represents for this question. 'submitted_at' represents the time this
submission was submitted, which can be configured, versus the
'created_at' date, which is when the submission is first created.
Raises:
Raises:
SubmissionRequestError: Raised when the associated student item fails
SubmissionRequestError: Raised when the associated student item fails
...
@@ -154,10 +185,27 @@ def get_submissions(student_item_dict, limit=None):
...
@@ -154,10 +185,27 @@ def get_submissions(student_item_dict, limit=None):
SubmissionNotFoundError: Raised when a submission cannot be found for
SubmissionNotFoundError: Raised when a submission cannot be found for
the associated student item.
the associated student item.
Examples:
>>> student_item_dict = dict(
>>> student_id="Tim",
>>> item_id="item_1",
>>> course_id="course_1",
>>> item_type="type_one"
>>> )
>>> get_submissions(student_item_dict, 3)
[{
'student_item': 2,
'attempt_number': 1,
'submitted_at': datetime.datetime(2014, 1, 29, 23, 14, 52, 649284, tzinfo=<UTC>),
'created_at': datetime.datetime(2014, 1, 29, 17, 14, 52, 668850, tzinfo=<UTC>),
'answer': u'The answer is 42.'
}]
"""
"""
student_item_model
=
_get_or_create_student_item
(
student_item_dict
)
student_item_model
=
_get_or_create_student_item
(
student_item_dict
)
try
:
try
:
submission_models
=
Submission
.
objects
.
filter
(
student_item
=
student_item_model
)
submission_models
=
Submission
.
objects
.
filter
(
student_item
=
student_item_model
)
except
DatabaseError
:
except
DatabaseError
:
error_message
=
(
error_message
=
(
u"Error getting submission request for student item {}"
u"Error getting submission request for student item {}"
...
@@ -169,7 +217,8 @@ def get_submissions(student_item_dict, limit=None):
...
@@ -169,7 +217,8 @@ def get_submissions(student_item_dict, limit=None):
if
limit
:
if
limit
:
submission_models
=
submission_models
[:
limit
]
submission_models
=
submission_models
[:
limit
]
return
[
SubmissionSerializer
(
submission
)
.
data
for
submission
in
submission_models
]
return
[
SubmissionSerializer
(
submission
)
.
data
for
submission
in
submission_models
]
def
get_score
(
student_item
):
def
get_score
(
student_item
):
...
@@ -216,16 +265,14 @@ def _get_or_create_student_item(student_item_dict):
...
@@ -216,16 +265,14 @@ def _get_or_create_student_item(student_item_dict):
"""
"""
try
:
try
:
try
:
try
:
student_item_model
=
StudentItem
.
objects
.
get
(
**
student_item_dict
)
return
StudentItem
.
objects
.
get
(
**
student_item_dict
)
except
StudentItem
.
DoesNotExist
:
except
StudentItem
.
DoesNotExist
:
student_item_serializer
=
StudentItemSerializer
(
data
=
student_item_dict
)
student_item_serializer
=
StudentItemSerializer
(
data
=
student_item_dict
)
student_item_serializer
.
is_valid
()
if
not
student_item_serializer
.
is_valid
():
if
student_item_serializer
.
errors
:
raise
SubmissionRequestError
(
student_item_serializer
.
errors
)
raise
SubmissionRequestError
(
student_item_serializer
.
errors
)
student_item_model
=
StudentItem
.
objects
.
create
(
**
student_item_dict
)
return
student_item_serializer
.
save
(
)
except
DatabaseError
:
except
DatabaseError
:
error_message
=
u"An error occurred creating student item: {}"
.
format
(
error_message
=
u"An error occurred creating student item: {}"
.
format
(
student_item_dict
)
student_item_dict
)
logger
.
exception
(
error_message
)
logger
.
exception
(
error_message
)
raise
SubmissionInternalError
(
error_message
)
raise
SubmissionInternalError
(
error_message
)
return
student_item_model
apps/submissions/tests/test_api.py
View file @
c724f90f
...
@@ -7,7 +7,8 @@ from nose.tools import raises
...
@@ -7,7 +7,8 @@ from nose.tools import raises
from
mock
import
patch
from
mock
import
patch
from
submissions.api
import
create_submission
,
get_submissions
,
SubmissionRequestError
,
SubmissionInternalError
from
submissions.api
import
create_submission
,
get_submissions
,
SubmissionRequestError
,
SubmissionInternalError
from
submissions.models
import
Submission
,
StudentItem
from
submissions.models
import
Submission
from
submissions.serializers
import
StudentItemSerializer
STUDENT_ITEM
=
dict
(
STUDENT_ITEM
=
dict
(
student_id
=
"Tim"
,
student_id
=
"Tim"
,
...
@@ -73,10 +74,10 @@ class TestApi(TestCase):
...
@@ -73,10 +74,10 @@ class TestApi(TestCase):
mock_filter
.
side_effect
=
DatabaseError
(
"Bad things happened"
)
mock_filter
.
side_effect
=
DatabaseError
(
"Bad things happened"
)
create_submission
(
STUDENT_ITEM
,
ANSWER_ONE
)
create_submission
(
STUDENT_ITEM
,
ANSWER_ONE
)
@patch.object
(
StudentItem
.
objects
,
'creat
e'
)
@patch.object
(
StudentItem
Serializer
,
'sav
e'
)
@raises
(
SubmissionInternalError
)
@raises
(
SubmissionInternalError
)
def
test_create_student_item_validation
(
self
,
mock_
creat
e
):
def
test_create_student_item_validation
(
self
,
mock_
sav
e
):
mock_
creat
e
.
side_effect
=
DatabaseError
(
"Bad things happened"
)
mock_
sav
e
.
side_effect
=
DatabaseError
(
"Bad things happened"
)
create_submission
(
STUDENT_ITEM
,
ANSWER_ONE
)
create_submission
(
STUDENT_ITEM
,
ANSWER_ONE
)
def
test_unicode_enforcement
(
self
):
def
test_unicode_enforcement
(
self
):
...
...
requirements/test.txt
View file @
c724f90f
# Grab everything in base requirements
# Grab everything in base requirements
-r base.txt
-r base.txt
ddt==0.4.0
django-nose==1.2
django-nose==1.2
mock==1.0.1
mock==1.0.1
nose==1.3.0
nose==1.3.0
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment