Commit 095e1f0c by Stephen Sanchez

Some additional doc around all the functions in the front end.

We will want to flesh out the specifics of each Mixin, and associated UI models, as we complete each associated UI story.
parent b491ad87
......@@ -181,7 +181,7 @@ class OpenAssessmentBlock(XBlock, SubmissionMixin, PeerAssessmentMixin, SelfAsse
)
def get_xblock_trace(self):
"""Uniquely identify this xblock by context.
"""Uniquely identify this XBlock by context.
Every XBlock has a scope_ids, which is a NamedTuple describing
important contextual information. Per @nedbat, the usage_id attribute
......@@ -189,13 +189,19 @@ class OpenAssessmentBlock(XBlock, SubmissionMixin, PeerAssessmentMixin, SelfAsse
identifies this student. With the two of them, we can trace all the
interactions emanating from this interaction.
Useful for logging, debugging, and uniqueification."""
Useful for logging, debugging, and uniqueification.
"""
return self.scope_ids.usage_id, self.scope_ids.user_id
def get_student_item_dict(self):
"""Create a student_item_dict from our surrounding context.
See also: submissions.api for details.
Returns:
(dict): The student item associated with this XBlock instance. This
includes the student id, item id, and course id.
"""
item_id, student_id = self.get_xblock_trace()
student_item_dict = dict(
......@@ -208,10 +214,20 @@ class OpenAssessmentBlock(XBlock, SubmissionMixin, PeerAssessmentMixin, SelfAsse
def student_view(self, context=None):
"""The main view of OpenAssessmentBlock, displayed when viewing courses.
The main view which displays the general layout for Open Ended
Assessment Questions. The contents of the XBlock are determined
dynamically based on the assessment workflow configured by the author.
Args:
context: Not used for this view.
Returns:
(Fragment): The HTML Fragment for this XBlock, which determines the
general frame of the Open Ended Assessment Question.
"""
trace = self.get_xblock_trace()
student_item_dict = self.get_student_item_dict()
grade_state = self.get_grade_state()
# All data we intend to pass to the front end.
......@@ -235,7 +251,12 @@ class OpenAssessmentBlock(XBlock, SubmissionMixin, PeerAssessmentMixin, SelfAsse
@staticmethod
def workbench_scenarios():
"""A canned scenario for display in the workbench."""
"""A canned scenario for display in the workbench.
These scenarios are only intended to be used for Workbench XBlock
Development.
"""
return [
(
"OpenAssessmentBlock Poverty Rubric",
......@@ -249,11 +270,28 @@ class OpenAssessmentBlock(XBlock, SubmissionMixin, PeerAssessmentMixin, SelfAsse
@staticmethod
def studio_view(context=None):
"""Determines how the XBlock is rendered for editing in Studio.
Displays the section where Editing can occur within Studio to modify
this XBlock instance.
Args:
context: Not actively used for this view.
Returns:
(Fragment): An HTML fragment for editing the configuration of this
XBlock.
"""
return Fragment(u"<div>Edit the XBlock.</div>")
@classmethod
def parse_xml(cls, node, runtime, keys, id_generator):
"""Instantiate xblock object from runtime XML definition."""
"""Instantiate XBlock object from runtime XML definition.
Inherited by XBlock core.
"""
def unknown_handler(block, child):
"""Recursively embed xblocks for nodes we don't recognize"""
block.runtime.add_node_as_child(block, child, id_generator)
......@@ -280,6 +318,17 @@ class OpenAssessmentBlock(XBlock, SubmissionMixin, PeerAssessmentMixin, SelfAsse
Given the name of an assessment module, find it in the list of
configured modules, and ask for its rendered HTML.
Args:
path (str): The path to the template used to render this HTML
section.
context_dict (dict): A dictionary of context variables used to
populate this HTML section.
Returns:
(Response): A Response Object with the generated HTML fragment. This
is intended for AJAX calls to load dynamically into a larger
document.
"""
if not context_dict:
context_dict = {}
......
......@@ -4,10 +4,35 @@ from openassessment.peer.api import PeerAssessmentWorkflowError
class PeerAssessmentMixin(object):
"""The Peer Assessment Mixin for all Peer Functionality.
Abstracts all functionality and handlers associated with Peer Assessment.
All Peer Assessment API calls should be contained without this Mixin as
well.
PeerAssessmentMixin is a Mixin for the OpenAssessmentBlock. Functions in
the PeerAssessmentMixin call into the OpenAssessmentBlock functions and
will not work outside this scope.
"""
@XBlock.json_handler
def assess(self, data, suffix=''):
"""Place an assessment into OpenAssessment system
Assess a Peer Submission. Performs basic workflow validation to ensure
that an assessment can be performed as this time.
Args:
data (dict): A dictionary containing information required to create
a new peer assessment. Expecting attributes "points_earned",
"total_value", and "submission_uuid". If these attributes are
not available, a new assessment cannot be stored.
Returns:
(tuple): A tuple containing the dictionary representation of the
newly created assessment, and a "Success" string.
"""
assessment = self.get_assessment_module('peer-assessment')
if assessment:
......@@ -31,6 +56,13 @@ class PeerAssessmentMixin(object):
@XBlock.handler
def render_peer_assessment(self, data, suffix=''):
"""Renders the Peer Assessment HTML section of the XBlock
Generates the peer assessment HTML for the first section of an Open
Assessment XBlock. See OpenAssessmentBlock.render_assessment() for
more information on rendering XBlock sections.
"""
assessment = self.get_assessment_module('peer-assessment')
if assessment:
peer_sub = self.get_peer_submission(self.get_student_item_dict(), assessment)
......
......@@ -2,6 +2,17 @@ from xblock.core import XBlock
class SelfAssessmentMixin(object):
"""The Self Assessment Mixin for all Self Assessment Functionality.
Abstracts all functionality and handlers associated with Self Assessment.
All Self Assessment API calls should be contained without this Mixin as
well.
SelfAssessmentMixin is a Mixin for the OpenAssessmentBlock. Functions in
the SelfAssessmentMixin call into the OpenAssessmentBlock functions and
will not work outside this scope.
"""
@XBlock.handler
def render_self_assessment(self, data, suffix=''):
......
/* START Javascript for OpenassessmentComposeXBlock. */
function OpenAssessmentBlock(runtime, element) {
var handlerUrl = runtime.handlerUrl(element, 'assess');
var success_msg = '<p class="success">Thanks for your feedback!</p>';
var failure_msg = '<p class="failure">An error occurred with your feedback</p>';
var click_msg = '<p class="clickhere">(click here to dismiss this message)</p>';
/* Sample Debug Console: http://localhost:8000/submissions/Joe_Bloggs/TestCourse/u_3 */
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};
}
function displayStatus(result) {
var status = result[0];
var error_msg = result[1];
if (status) {
$('.openassessment_response_status_block', element).html(success_msg.concat(click_msg));
} else {
$('.openassessment_response_status_block', element).html(failure_msg.concat(error_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');
});
$('.openassessment_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)),
success: displayStatus
});
});
$(function ($) {
/* Here's where you'd do things on page load. */
$(element).css('background-color', 'LightBlue')
});
}
/* END Javascript for OpenassessmentComposeXBlock. */
......@@ -3,6 +3,17 @@ from submissions import api
class SubmissionMixin(object):
"""Submission Mixin introducing all Submission-related functionality.
Submission Mixin contains all logic and handlers associated with rendering
the submission section of the front end, as well as making all API calls to
the middle tier for constructing new submissions, or fetching submissions.
SubmissionMixin is a Mixin for the OpenAssessmentBlock. Functions in the
SubmissionMixin call into the OpenAssessmentBlock functions and will not
work outside this scope.
"""
submit_errors = {
# Reported to user sometimes, and useful in tests
......@@ -15,11 +26,24 @@ class SubmissionMixin(object):
@XBlock.json_handler
def submit(self, data, suffix=''):
"""
Place the submission text into Openassessment system
"""Place the submission text into Openassessment system
Allows submission of new responses. Performs basic workflow validation
on any new submission to ensure it is acceptable to receive a new
response at this time.
Args:
data (dict): Data should contain one attribute: submission. This is
the response from the student which should be stored in the
Open Assessment system.
suffix (str): Not used in this handler.
Returns:
(tuple): Returns the status (boolean) of this request, the
associated status tag (str), and status text (unicode).
"""
status = False
status_tag = 'ENOSUB'
status_text = None
student_sub = data['submission']
student_item_dict = self.get_student_item_dict()
......@@ -48,7 +72,19 @@ class SubmissionMixin(object):
@staticmethod
def _get_submission_score(student_item_dict, submission=False):
"""Return the most recent score, if any, for student item"""
"""Return the most recent score, if any, for student item
Gets the score, if available.
Args:
student_item_dict (dict): The student item we want to check for a
score.
Returns:
(dict): Dictionary representing the score for this particular
question.
"""
scores = False
if submission:
scores = api.get_score(student_item_dict)
......@@ -56,7 +92,22 @@ class SubmissionMixin(object):
@staticmethod
def _get_user_submission(student_item_dict):
"""Return the most recent submission, if any, by user in student_item_dict"""
"""Return the most recent submission by user in student_item_dict
Given a student item, return the most recent submission. If no
submission is available, return None. All submissions are preserved, but
only the most recent will be returned in this function, since the active
workflow will only be concerned with the most recent submission.
Args:
student_item_dict (dict): The student item we want to get the
latest submission for.
Returns:
(dict): A dictionary representation of a submission to render to
the front end.
"""
submissions = []
try:
submissions = api.get_submissions(student_item_dict)
......@@ -67,4 +118,11 @@ class SubmissionMixin(object):
@XBlock.handler
def render_submission(self, data, suffix=''):
"""Renders the Submission HTML section of the XBlock
Generates the submission HTML for the first section of an Open
Assessment XBlock. See OpenAssessmentBlock.render_assessment() for
more information on rendering XBlock sections.
"""
return self.render_assessment('static/html/oa_response.html')
"""UI Models constructed by the Open Assessment XBlock to generate HTML.
These Models should be fully constructed before reaching any templates used by
the XBlock, such that the templates should only have to render based on the
information provided. If any logic exists in the templates, it is likely that
should be refactored into the XBlock, and the results stored in these models.
"""
class SubmissionUIModel(object):
"""All data to be displayed to the front end regarding submissions.
All the data required to generate the Submission HTML.
"""
def __init__(self):
self.assessment_type = "submission"
......@@ -16,6 +31,11 @@ class SubmissionUIModel(object):
class AssessmentUIModel(object):
"""Generic Assessment UI Model.
Common attributes for displaying Assessment sections of the front end.
"""
def __init__(self):
......@@ -42,6 +62,12 @@ class AssessmentUIModel(object):
class PeerAssessmentUIModel(AssessmentUIModel):
"""All data required to display the Peer Assessment front end.
Attributes and data specific to rendering the Peer Assessment section of
the front end.
"""
def __init__(self):
super(PeerAssessmentUIModel, self).__init__()
......@@ -51,6 +77,12 @@ class PeerAssessmentUIModel(AssessmentUIModel):
class SelfAssessmentUIModel(AssessmentUIModel):
"""All data required to display the Self Assessment front end.
Attributes and data specific to rendering the Self Assessment section of
the front end.
"""
def __init__(self):
super(SelfAssessmentUIModel, self).__init__()
......
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