Commit 4ac98443 by Joe Blaylock

Merge pull request #21 from edx/jrbl/submit-error-checking

More mature error handling around API calls
parents 2e463f15 20946e5f
Stephen Sanchez <steve@edx.org>
Joe Blaylock <jrbl@stanford.edu>
Will Daly <will@edx.org>
David Ormsbee <dormsbee@edx.org>
Stephen Sanchez <steve@edx.org>
\ No newline at end of file
......@@ -19,11 +19,17 @@ class OpenAssessmentBlock(XBlock):
Displays a question and gives an area where students can compose a response.
"""
question = String(
default=u"Undefined question",
prompt = String(
default=u"This prompt is unconfigured. Perhaps you could enter some text telling us a little about yourself?",
scope=Scope.content,
help="A question to display to a student"
help="A prompt to display to a student",
)
course_id = String(
default=u"TestCourse",
scope=Scope.content,
help="The course_id associated with this prompt (until we can get it from runtime).",
)
def _get_xblock_trace(self):
"""Uniquely identify this xblock by context.
......@@ -39,8 +45,7 @@ class OpenAssessmentBlock(XBlock):
def student_view(self, context=None):
"""
The primary view of the OpenassessmentComposeXBlock, shown to students
when viewing courses.
The main view of OpenAssessmentBlock, displayed when viewing courses.
"""
def load(path):
"""Handy helper for getting resources from our kit."""
......@@ -48,14 +53,14 @@ class OpenAssessmentBlock(XBlock):
return data.decode("utf8")
trace = self._get_xblock_trace()
html = Template(load("static/html/openassessment_compose.html"),
html = Template(load("static/html/openassessment.html"),
default_filters=mako_default_filters,
input_encoding='utf-8',
)
frag = Fragment(html.render_unicode(xblock_trace=trace, question=self.question))
frag.add_css(load("static/css/openassessment_compose.css"))
frag.add_javascript(load("static/js/src/openassessment_compose.js"))
frag.initialize_js('OpenassessmentComposeXBlock')
frag = Fragment(html.render_unicode(xblock_trace=trace, question=self.prompt))
frag.add_css(load("static/css/openassessment.css"))
frag.add_javascript(load("static/js/src/openassessment.js"))
frag.initialize_js('OpenAssessmentBlock')
return frag
@XBlock.json_handler
......@@ -68,22 +73,34 @@ class OpenAssessmentBlock(XBlock):
student_item_dict = dict(
student_id=student_id,
item_id=item_id,
# XXX: The XBlock API doesn't make course_id's available
course_id='TestCourse',
item_type='peer' # XXX: FIXME this is the only implementation so far
course_id=self.course_id,
item_type='openassessment' # Is this the tag we want? Why?
)
response = api.create_submission(student_item_dict, student_sub)
return '{"sub": "%s"}' % response
# TO-DO: change this to create the scenarios you'd like to see in the
# workbench while developing your XBlock.
status = False
try:
response = api.create_submission(student_item_dict, student_sub)
status = True if response else False
except api.SubmissionError:
status = False
return status
# Arbitrary attributes can be defined on the
@staticmethod
def workbench_scenarios():
"""A canned scenario for display in the workbench."""
return [
("OpenAssessmentBlock",
"""<vertical_demo>
<openassessment/>
<openassessment prompt="This is my prompt. There are many like it, but this one is mine." />
</vertical_demo>
"""),
]
# <h3>Censorship in the Libraries</h3>
#
# <p>'All of us can think of a book that we hope none of our children or any other children have taken off the shelf. But if I have the right to remove that book from the shelf -- that work I abhor -- then you also have exactly the same right and so does everyone else. And then we have no books left on the shelf for any of us.' --Katherine Paterson, Author
# </p>
#
# <p>
# Write a persuasive essay to a newspaper reflecting your views on censorship in libraries. Do you believe that certain materials, such as books, music, movies, magazines, etc., should be removed from the shelves if they are found offensive? Support your position with convincing arguments from your own experience, observations, and/or reading.
# </p>
/* START CSS for OpenAssessmentBlock */
.openassessment_block .openassessment_question {
font-weight: bold;
}
.openassessment_block textarea {
width: 80%;
height: 30%;
}
.openassessment_response_status_block {
background-color: white;
border: 4px solid black;
display: none;
position: absolute;
left: 75;
top: 75;
z-index: 100;
}
.openassessment_response_status_block p {
font-weight: bold;
font-size: xx-large;
}
.openassessment_response_status_block .clickhere {
font-size: small;
font-color: black;
font-weight: normal;
text-align: center;
}
.openassessment_response_status_block .success {
font-color: green;
}
.openassessment_response_status_block .failure {
font-color: red;
}
.clickhere_span {
font-size: small;
font-weight: normal;
}
/* END CSS for OpenAssessmentBlock */
/* START CSS for OpenassessmentComposeXBlock */
.openassessment_compose_block .openassessment_question {
font-weight: bold;
}
.openassessment_compose_block textarea {
width: 80%;
height: 30%;
}
/* END CSS for OpenassessmentComposeXBlock */
<!-- START openassessment_compose-xblock HTML -->
<div class="openassessment_compose_block" id="openassessment_compose_block_${xblock_trace[0]}">
<!-- START OpenAssessmentBlock HTML -->
<div class="openassessment_block" id="openassessment_block_${xblock_trace[0]}">
<p class="openassessment_question" id="openassessment_question_${xblock_trace[0]}">${question}</p>
<textarea class="openassessment_submission" id="openassessment_submission_${xblock_trace[0]}">Compose your response here</textarea>
<input type="button" class="openassessment_submit" id="openassessment_submit_${xblock_trace[0]}" value="Submit" />
</div>
<!-- END openassessment_compose-xblock HTML -->
<div class="openassessment_response_status_block" id=openassessment_response_status_block_${xblock_trace[0]}">
This message should be invisible; consider upgrading your browser.
</div>
<!-- END OpenAssessmentBlock HTML -->
/* START Javascript for OpenassessmentComposeXBlock. */
function OpenassessmentComposeXBlock(runtime, element) {
function OpenAssessmentBlock(runtime, element) {
/* Sample Debug Console: http://localhost:8000/submissions/Joe_Bloggs/TestCourse/u_3 */
var success_msg = '<p class="failure">Your submission has been received, thank you!</p>';
var failure_msg = '<p class="success">An error occurred with your submission</p>';
var click_msg = '<p class="clickhere">(click here to dismiss this message)</p>';
function itWorked(result) {
alert(result);
if (itWorked) {
$('.openassessment_response_status_block', element).html(success_msg.concat(click_msg));
} else {
$('.openassessment_response_status_block', element).html(failure_msg.concat(click_msg));
}
$('.openassessment_response_status_block', element).css('display', 'block');
}
$('.openassessment_response_status_block', element).click(function(eventObject) {
$('.openassessment_response_status_block', element).css('display', 'none');
});
var handlerUrl = runtime.handlerUrl(element, 'submit');
$('.openassessment_submit', element).click(function(eventObject) {
$.ajax({
type: "POST",
......@@ -18,7 +30,7 @@ function OpenassessmentComposeXBlock(runtime, element) {
$(function ($) {
/* Here's where you'd do things on page load. */
$(element).css('background-color', 'DarkOrchid')
$(element).css('background-color', 'LightBlue')
});
}
/* END Javascript for OpenassessmentComposeXBlock. */
"""
Tests the Open Assessment XBlock functionality.
"""
import json
import webob
from django.test import TestCase
from mock import patch
from workbench.runtime import WorkbenchRuntime
from submissions import api
from submissions.api import SubmissionInternalError
class TestOpenAssessment(TestCase):
runtime = None
assessment = None
def setUp(self):
self.runtime = WorkbenchRuntime()
self.runtime.user_id = "Bob"
assessment_id = self.runtime.parse_xml_string(
"""<openassessment
prompt="This is my prompt. There are many like it, but this one is mine."
course_id="RopesCourse"
/>
""", self.runtime.id_generator)
self.assessment = self.runtime.get_block(assessment_id)
def make_request(self, body):
"""Mock request method."""
request = webob.Request({})
request.body = body
return request
def text_of_response(self, response):
"""Return the text of response."""
return "".join(response.app_iter)
def test_submit_submission(self):
"""
Verify we can submit an answer to the XBlock and get the expected return
value.
"""
json_data = json.dumps(
{"submission": "This is my answer to this test question!"}
)
resp = self.runtime.handle(
self.assessment, 'submit',
self.make_request(json_data)
)
result = self.text_of_response(resp)
self.assertEqual("true", result)
@patch.object(api, 'create_submission')
def test_submission_failure(self, mock_submit):
"""
Nothing from the front end currently causes an exception. However the
backend could have an internal error that will bubble up. This will
mock an internal error and ensure the front end returns the proper
value.
"""
mock_submit.side_effect = SubmissionInternalError("Cat on fire.")
json_data = json.dumps(
{"submission": "This is my answer to this test question!"}
)
resp = self.runtime.handle(
self.assessment, 'submit',
self.make_request(json_data)
)
result = self.text_of_response(resp)
self.assertEquals("false", result)
def test_load_student_view(self):
"""
View basic test for verifying we're returned some HTML about the
Open Assessment XBlock. We don't want to match too heavily against the
contents.
"""
xblock_fragment = self.runtime.render(self.assessment, "student_view")
self.assertTrue(xblock_fragment.body_html().find("Openassessmentblock"))
......@@ -5,7 +5,7 @@ Test-specific Django settings.
# Inherit from base settings
from .base import *
TEST_APPS = ('openassessment.peer', 'submissions',)
TEST_APPS = ('openassessment.peer', 'submissions', "openassessment.xblock")
# Configure nose
NOSE_ARGS = [
......
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