Commit 61ab0d3a by Stephen Sanchez

Changing to mixins

parent e39b9718
from django.template import Context
from django.template.loader import get_template
class AssessmentBlock(object):
assessment_type = None
name = ''
start_datetime = None
due_datetime = None
must_grade = 1
must_be_graded_by = 0
navigation_text = ""
path = ""
title = ""
def create_ui_model(self):
return {
"assessment_type": self.assessment_type,
"name": self.name,
"start_datetime": self.start_datetime,
"due_datetime": self.due_datetime,
"must_grade": self.must_grade,
"must_be_graded_by": self.must_be_graded_by,
"navigation_text": self.navigation_text,
"title": self.title
}
def render(self, context_dict):
template = get_template(self.path)
context = Context(context_dict)
return template.render(context)
\ No newline at end of file
from django.template import Context
from django.template.loader import get_template
from webob import Response
class AssessmentMixin(object):
def render(self, path):
"""Render an Assessment Module's HTML
Given the name of an assessment module, find it in the list of
configured modules, and ask for its rendered HTML.
"""
context_dict = {
"xblock_trace": self._get_xblock_trace(),
"rubric_instructions": self.rubric_instructions,
"rubric_criteria": self.rubric_criteria,
}
template = get_template(path)
context = Context(context_dict)
return Response(template.render(context), content_type='application/html', charset='UTF-8')
def _get_assessment_module(self, mixin_name):
"""Get a configured assessment module by name.
"""
for assessment in self.rubric_assessments:
if assessment.name == mixin_name:
return assessment
\ No newline at end of file
"""An XBlock where students can read a question and compose their response"""
import datetime
import json
from django.template.context import Context
from django.template.loader import get_template
import pkg_resources
from webob import Response
from xblock.core import XBlock
from xblock.fields import List, Scope, String
from xblock.fragment import Fragment
from openassessment.xblock.peer_assessment_block import PeerAssessmentBlock
from openassessment.xblock.submission_block import SubmissionBlock
from openassessment.xblock.peer_assessment_mixin import PeerAssessmentMixin
from openassessment.xblock.self_assessment_mixin import SelfAssessmentMixin
from openassessment.xblock.submission_mixin import SubmissionMixin
from openassessment.xblock.ui_models import PeerAssessmentUIModel
from scenario_parser import ScenarioParser
......@@ -112,7 +112,7 @@ DEFAULT_RUBRIC_CRITERIA = [
}
]
DEFAULT_PEER_ASSESSMENT = PeerAssessmentBlock()
DEFAULT_PEER_ASSESSMENT = PeerAssessmentUIModel()
DEFAULT_PEER_ASSESSMENT.name = "peer-assessment"
DEFAULT_PEER_ASSESSMENT.start_datetime = datetime.datetime.now().isoformat()
DEFAULT_PEER_ASSESSMENT.must_grade = 5
......@@ -122,12 +122,14 @@ DEFAULT_ASSESSMENT_MODULES = [
DEFAULT_PEER_ASSESSMENT,
]
def load(path):
"""Handy helper for getting resources from our kit."""
data = pkg_resources.resource_string(__name__, path)
return data.decode("utf8")
class OpenAssessmentBlock(XBlock):
class OpenAssessmentBlock(XBlock, SubmissionMixin, PeerAssessmentMixin, SelfAssessmentMixin):
"""Displays a question and gives an area where students can compose a response."""
start_datetime = String(
......@@ -230,49 +232,6 @@ class OpenAssessmentBlock(XBlock):
frag.initialize_js('OpenAssessmentBlock')
return frag
@XBlock.handler
def render_assessment(self, data, suffix=''):
"""Render an Assessment Module's HTML
Given the name of an assessment module, find it in the list of
configured modules, and ask for its rendered HTML.
"""
body = json.loads(data.body)
context_dict = {
"xblock_trace": self._get_xblock_trace(),
"rubric_instructions": self.rubric_instructions,
"rubric_criteria": self.rubric_criteria,
}
assessment = self._get_assessment_module(body['assessment'])
if assessment:
return Response(assessment.render(context_dict), content_type='application/html', charset="UTF-8")
@XBlock.json_handler
def assess(self, data, suffix=''):
# TODO Pass name through the handler.
assessment = self._get_assessment_module('peer-assessment')
if assessment:
return assessment.assess(
self._get_student_item_dict(),
self.rubric_criteria,
data
)
def _get_assessment_module(self, name):
"""Get a configured assessment module by name.
"""
for assessment in self.rubric_assessments:
if assessment.name == name:
return assessment
@XBlock.json_handler
def submit(self, data, suffix=''):
"""
Place the submission text into Openassessment system
"""
return SubmissionBlock().submit(self._get_student_item_dict(), data)
@staticmethod
def workbench_scenarios():
"""A canned scenario for display in the workbench."""
......@@ -301,7 +260,6 @@ class OpenAssessmentBlock(XBlock):
sparser = ScenarioParser(block, node, unknown_handler)
block = sparser.parse()
block.rubric_assessments.insert(0, SubmissionBlock())
return block
def _get_grade_state(self):
......
from xblock.core import XBlock
from openassessment.peer import api as peer_api
from openassessment.peer.api import PeerAssessmentWorkflowError
from openassessment.xblock.assessment_block import AssessmentBlock
from openassessment.xblock.assessment_mixin import AssessmentMixin
class PeerAssessmentBlock(AssessmentBlock):
class PeerAssessmentMixin(AssessmentMixin):
assessment_type = "peer-assessment"
path = "static/html/oa_peer_assessment.html"
title = "Assess Peers' Responses"
navigation_text = "Your assessment(s) of peer responses"
@classmethod
def assess(cls, student_item_dict, rubric_criteria, data):
@XBlock.json_handler
def assess(self, data, suffix=''):
"""Place an assessment into Openassessment system
"""
with self._get_assessment_module('peer-assessment') as assessment:
assessment_dict = {
"points_earned": map(int, data["points_earned"]),
"points_possible": sum(c['total_value'] for c in rubric_criteria),
"points_possible": sum(c['total_value'] for c in self.rubric_criteria),
"feedback": "Not yet implemented.",
}
assessment = peer_api.create_assessment(
data["submission_uuid"],
student_item_dict["student_id"],
int(cls.must_grade),
int(cls.must_be_graded_by),
self._get_student_item_dict()["student_id"],
int(assessment.must_grade),
int(assessment.must_be_graded_by),
assessment_dict
)
......@@ -33,17 +30,21 @@ class PeerAssessmentBlock(AssessmentBlock):
return assessment, "Success"
def get_peer_submission(self, student_item_dict):
@XBlock.handler
def render_peer_assessment(self, data, suffix=''):
return super(PeerAssessmentMixin, self).render('static/html/oa_peer_assessment.html')
def get_peer_submission(self, student_item_dict, assessment):
peer_submission = False
try:
peer_submission = peer_api.get_submission_to_assess(
student_item_dict, self.must_be_graded_by
student_item_dict, assessment.must_be_graded_by
)
# context_dict["peer_submission"] = peer_submission
peer_submission = peer_api.get_submission_to_assess(
student_item_dict,
self.must_be_graded_by
assessment.must_be_graded_by
)
except PeerAssessmentWorkflowError:
......
# -*- coding: utf-8 -*-
"""XBlock scenario parsing routines"""
from openassessment.xblock.peer_assessment_block import PeerAssessmentBlock
from openassessment.xblock.self_assessment_block import SelfAssessmentBlock
from openassessment.xblock.ui_models import PeerAssessmentUIModel, SelfAssessmentUIModel, SubmissionUIModel
class ScenarioParser(object):
......@@ -76,16 +75,16 @@ class ScenarioParser(object):
must_grade="5"
must_be_graded_by="3" />
</peer-assessment>"""
assessment_list = []
assessment_list = [SubmissionUIModel()]
for asmnt in assessments:
assessment = None
assessment_type = asmnt.tag
if 'peer-assessment' == assessment_type:
assessment = PeerAssessmentBlock()
assessment = PeerAssessmentUIModel()
assessment.must_grade = int(asmnt.attrib.get('must_grade', 1))
assessment.must_be_graded_by = int(asmnt.attrib.get('must_be_graded_by', 0))
elif 'self-assessment' == assessment_type:
assessment = SelfAssessmentBlock()
assessment = SelfAssessmentUIModel()
if assessment:
assessment.name = asmnt.attrib.get('name', '')
......
from openassessment.xblock.assessment_block import AssessmentBlock
class SelfAssessmentBlock(AssessmentBlock):
assessment_type = "self-assessment"
navigation_text = "Your assessment of your response"
path = "static/html/oa_self_assessment.html"
title = "Assess Your Response"
\ No newline at end of file
from xblock.core import XBlock
from openassessment.xblock.assessment_mixin import AssessmentMixin
class SelfAssessmentMixin(AssessmentMixin):
@XBlock.handler
def render_self_assessment(self, data, suffix=''):
return self.render('static/html/oa_self_assessment.html')
......@@ -12,7 +12,7 @@
<!-- CASE: default/not started -->
<li id="openassessment__peer-assessment" class="openassessment__steps__step step--peer-assessment">
{#<header class="step__header">#}
<div id="peer_submission_uuid" hidden="true">{{ peer_submission.uuid }}</div>
<h2 class="step__title">
<span class="step__label">Evaluate Peers' Responses</span>
<span class="step__deadline">due <span class="date">January 30, 2014</span> at <span class="time">15:00 UTC</span></span>
......
......@@ -2,90 +2,90 @@
function OpenAssessmentBlock(runtime, element) {
var handlerUrl = runtime.handlerUrl(element, 'submit');
var renderUrl = runtime.handlerUrl(element, 'render_assessment');
var renderSubmissionUrl = runtime.handlerUrl(element, 'render_submission');
var renderPeerUrl = runtime.handlerUrl(element, 'render_peer_assessment');
var renderSelfUrl = runtime.handlerUrl(element, 'render_self_assessment');
/* Sample Debug Console: http://localhost:8000/submissions/Joe_Bloggs/TestCourse/u_3 */
/*
Peer Assessment Functions
Submission Functions
*/
function prepare_assessment_post(element) {
var selector = $("input[type=radio]:checked", element);
var values = [];
for (i=0; i<selector.length; i++) {
values[i] = selector[i].value;
}
return {"submission_uuid":$("div#peer_submission_uuid")[0].innerText, "points_earned":values};
}
$('.openassessment_submit', element).click(function(eventObject) {
function render_submissions(data) {
$('#submission', element).replaceWith(data);
$('#step--response__submit', element).click(function(eventObject) {
$.ajax({
type: "POST",
url: handlerUrl,
/* data: JSON.stringify({"submission": $('.openassessment_submission', element).val()}), */
data: JSON.stringify(prepare_assessment_post(element)),
data: JSON.stringify({"submission": $('#submission__answer__value', element).val()}),
success: function(data) {
$.ajax({
type: "POST",
url: renderUrl,
data: JSON.stringify({"assessment": "peer-assessment"}),
url: renderPeerUrl,
success: function(data) {
$('#peer-assessment', element).replaceWith(data);
render_peer_assessment(data);
}
});
$.ajax({
type: "POST",
url: renderUrl,
data: JSON.stringify({"assessment": "self-assessment"}),
url: renderSubmissionUrl,
success: function(data) {
$('#self-assessment', element).replaceWith(data);
render_submissions(data);
}
});
}
});
});
$(function ($) {
/* Here's where you'd do things on page load. */
$.ajax({
type: "POST",
url: renderUrl,
data: JSON.stringify({"assessment": "submission"}),
success: function(data) {
$('#submission', element).replaceWith(data);
}
/*
Submission Functions
Peer Assessment Functions
*/
$('#step--response__submit', element).click(function(eventObject) {
function render_peer_assessment(data) {
$('#peer-assessment', element).replaceWith(data);
function prepare_assessment_post(element) {
var selector = $("input[type=radio]:checked", element);
var values = [];
for (var i=0; i<selector.length; i++) {
values[i] = selector[i].value;
}
return {"submission_uuid":$("div#peer_submission_uuid")[0].innerText, "points_earned":values};
}
$('#peer-assessment--001__assessment__submit', element).click(function(eventObject) {
$.ajax({
type: "POST",
url: handlerUrl,
data: JSON.stringify({"submission": $('#submission__answer__value', element).val()}),
/* data: JSON.stringify({"submission": $('.openassessment_submission', element).val()}), */
data: JSON.stringify(prepare_assessment_post(element)),
success: function(data) {
alert("Success?")
$.ajax({
type: "POST",
url: renderUrl,
data: JSON.stringify({"assessment": "submission"}),
url: renderSelfUrl,
success: function(data) {
$('#submission', element).replaceWith(data);
$('#self-assessment', element).replaceWith(data);
}
});
$.ajax({
type: "POST",
url: renderUrl,
data: JSON.stringify({"assessment": "peer-assessment"}),
url: renderPeerUrl,
success: function(data) {
$('#peer-assessment', element).replaceWith(data);
render_peer_assessment(data)
}
});
},
fail: function(data) {alert("FAIL!!")}
}
});
});
}
$(function ($) {
/* Here's where you'd do things on page load. */
$.ajax({
type: "POST",
url: renderSubmissionUrl,
success: function(data) {
render_submissions(data);
}
});
});
}
......
from openassessment.xblock.assessment_block import AssessmentBlock
from xblock.core import XBlock
from openassessment.xblock.assessment_mixin import AssessmentMixin
from submissions import api
class SubmissionBlock(AssessmentBlock):
assessment_type = "submission"
name = "submission"
navigation_text = "Your response to this problem"
path = "static/html/oa_response.html"
title = "Your Response"
class SubmissionMixin(AssessmentMixin):
submit_errors = {
# Reported to user sometimes, and useful in tests
......@@ -18,10 +13,12 @@ class SubmissionBlock(AssessmentBlock):
'EUNKNOWN': 'API returned unclassified exception',
}
def submit(self, student_item_dict, data):
@XBlock.json_handler
def submit(self, data, suffix=''):
"""
Place the submission text into Openassessment system
"""
student_item_dict = self._get_student_item_dict()
status = False
status_text = None
student_sub = data['submission']
......@@ -40,3 +37,7 @@ class SubmissionBlock(AssessmentBlock):
# relies on success being orthogonal to errors
status_text = status_text if status_text else self.submit_errors[status_tag]
return status, status_tag, status_text
@XBlock.handler
def render_submission(self, data, suffix=''):
return super(SubmissionMixin, self).render('static/html/oa_response.html')
......@@ -7,7 +7,7 @@ import webob
from django.test import TestCase
from mock import patch
from openassessment.xblock.submission_block import SubmissionBlock
from openassessment.xblock.submission_mixin import SubmissionMixin
from submissions import api
from submissions.api import SubmissionRequestError, SubmissionInternalError
......@@ -98,7 +98,7 @@ class TestOpenAssessment(TestCase):
result = json.loads(resp.body)
self.assertFalse(result[0])
self.assertEqual(result[1], "EUNKNOWN")
self.assertEqual(result[2], SubmissionBlock().submit_errors["EUNKNOWN"])
self.assertEqual(result[2], SubmissionMixin().submit_errors["EUNKNOWN"])
@patch.object(api, 'create_submission')
def test_submission_API_failure(self, mock_submit):
......
......@@ -76,19 +76,22 @@ class TestScenarioParser(TestCase):
assessments_xml = etree.fromstring(assessments)
parsed_list = self.test_parser.get_assessments(assessments_xml)
# Need to capture Submissions in Tests
self.assertEqual(parsed_list[0].assessment_type, 'submission')
# Self assessments take all the parameters, but mostly ignore them.
self.assertEqual(parsed_list[0].assessment_type, 'self-assessment')
self.assertEqual(parsed_list[0].name, '0382e03c808e4f2bb12dfdd2d45d5c4b')
self.assertEqual(parsed_list[0].must_grade, 1)
self.assertEqual(parsed_list[0].must_be_graded_by, 0)
self.assertEqual(parsed_list[1].assessment_type, 'self-assessment')
self.assertEqual(parsed_list[1].name, '0382e03c808e4f2bb12dfdd2d45d5c4b')
self.assertEqual(parsed_list[1].must_grade, 1)
self.assertEqual(parsed_list[1].must_be_graded_by, 0)
# Peer assessments are more interesting
self.assertEqual(parsed_list[1].assessment_type, 'peer-assessment')
self.assertEqual(parsed_list[1].name, '')
self.assertEqual(parsed_list[1].must_grade, 5)
self.assertEqual(parsed_list[1].must_be_graded_by, 3)
self.assertEqual(parsed_list[2].assessment_type, 'peer-assessment')
self.assertEqual(parsed_list[2].name, '')
self.assertEqual(parsed_list[2].must_grade, 5)
self.assertEqual(parsed_list[2].must_be_graded_by, 3)
# We can parse arbitrary workflow descriptions as a list of assessments.
# Whether or not the workflow system can use them is another matter
self.assertEqual(parsed_list[2].assessment_type, 'self-assessment')
self.assertEqual(parsed_list[3].assessment_type, 'self-assessment')
class SubmissionUIModel(object):
def __init__(self):
self.assessment_type = "submission"
self.name = "submission"
self.navigation_text = "Your response to this problem"
self.title = "Your Response"
def create_ui_model(self):
return {
"assessment_type": self.assessment_type,
"name": self.name,
"navigation_text": self.navigation_text,
"title": self.title
}
class AssessmentUIModel(object):
def __init__(self):
self.assessment_type = None
self.name = ''
self.start_datetime = None
self.due_datetime = None
self.must_grade = 1
self.must_be_graded_by = 0
self.navigation_text = ""
self.title = ""
def create_ui_model(self):
return {
"assessment_type": self.assessment_type,
"name": self.name,
"start_datetime": self.start_datetime,
"due_datetime": self.due_datetime,
"must_grade": self.must_grade,
"must_be_graded_by": self.must_be_graded_by,
"navigation_text": self.navigation_text,
"title": self.title
}
class PeerAssessmentUIModel(AssessmentUIModel):
def __init__(self):
super(PeerAssessmentUIModel, self).__init__()
self.assessment_type = "peer-assessment"
self.title = "Assess Peers' Responses"
self.navigation_text = "Your assessment(s) of peer responses"
class SelfAssessmentUIModel(AssessmentUIModel):
def __init__(self):
super(SelfAssessmentUIModel, self).__init__()
self.assessment_type = "self-assessment"
self.navigation_text = "Your assessment of your response"
self.title = "Assess Your Response"
\ No newline at end of file
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