Commit c217e3c3 by gradyward

TIM 386 -- Wire up UI messages

Adds Unit Tests to UI messages and fixes Two syntax errors

Added Test Cases and changed return Methodology

Removed Comments that were not in Style

Added cases for Student Training

TIM 386 -- Wire Up UI Messages
parent 09807a80
{% load i18n %}
{% spaceless %}
<div id="openassessment__message" class="openassessment__message message">
<h3 class="message__title">
{% if not_yet_open %}
{% trans "This Task Is Not Yet Available" %}
{% else %}
{% trans "This Assignment Has Closed" %}
{% endif %}
</h3>
<div class="message__content">
<p>
{% if not_yet_open %}
{% trans "Check back to complete the assignment once this section has opened." %}
{% else %}
{% trans "One or more deadlines for this assignment have passed. You will receive an incomplete grade for this assignment." %}
{% endif %}
</p>
</div>
</div>
{% endspaceless %}
\ No newline at end of file
{% load i18n %}
{% spaceless %}
<div id="openassessment__message" class="openassessment__message message">
<h3 class="message__title">{% trans "You Have Completed This Assignment" %} </h3>
<div class="message__content">
<p>
{% if waiting %}
{% trans "Your grade will be available when your peers have completed their assessments of your response." %}
{% else %}
{% blocktrans %}
Review <a data-behavior="ui-scroll" href="#openassessment__grade"> your grade and your assessment details</a>.
{% endblocktrans %}
{% endif %}
</p>
</div>
</div>
{% endspaceless %}
\ No newline at end of file
{% load i18n %}
{% spaceless %}
<div id="openassessment__message" class="openassessment__message message">
<div class="message__content">
<p>
{% if approaching %}
{% blocktrans %}
Assignment submissions will close soon. To receive a grade, first provide a response to the question, then complete the steps below the <strong>Your Response</strong> field.
{% endblocktrans %}
{% else %}
{% blocktrans %}
This assignment has several steps. In the first step, you'll provide a response to the question. The other steps appear below the <strong>Your Response</strong> field.
{% endblocktrans %}
{% endif %}
</p>
</div>
</div>
{% endspaceless %}
\ No newline at end of file
{% load i18n %}
{% spaceless %}
<div id="openassessment__message" class="openassessment__message message">
<h3 class="message__title">
{% if waiting %}
{% trans "Waiting for Peer Submissions" %}
{% elif peer_not_released %}
{% trans "The Period For Peer Evaluation Has Not Started" %}
{% else %}
{% trans "Your Response Has Been Submitted For Peer Assessment" %}
{% endif %}
</h3>
<div class="message__content">
<p>
{% if peer_not_released %}
{% trans "Check back later when the assessment period has opened." %}
{% else %}
{% if peer_approaching %}
<strong> {% trans "Peer evaluation of this assignment will close soon. " %} </strong>
{% endif %}
{% if waiting %}
{% trans "All submitted peer responses have been assessed. Check back later to see if more students have submitted responses. " %}
{% endif %}
{% if has_self %}
{% blocktrans %}
You'll receive your grade after you complete the <a data-behavior="ui-scroll" href=#openassessment__peer-assessment">peer assessment</a> and <a data-behavior="ui-scroll" href="#openassessment__self-assessment">self assessment</a> steps, and after your peers have assessed your response.
{% endblocktrans %}
{% else %}
{% blocktrans %}
You'll receive your grade after you complete the <a data-behavior="ui-scroll" href="#openassessment__peer-assessment">peer assessment</a> step.
{% endblocktrans %}
{% endif %}
{% endif %}
</p>
</div>
</div>
{% endspaceless %}
\ No newline at end of file
{% load i18n %}
{% spaceless %}
<div id="openassessment__message" class="openassessment__message message">
<h3 class="message__title">
{% if self_not_released %}
{% trans "The Period For Self Evaluation Has Not Started" %}
{% elif has_peer %}
{% trans "Your Response Has Been Submitted For Peer Assessment" %}
{% else %}
{% trans "Your Response Is Ready For Self Assessment" %}
{% endif %}
</h3>
<div class="message__content">
<p>
{% if self_not_released %}
{% trans "Check back later when the assessment period has opened." %}
{% else %}
{% if self_approaching %}
<strong> {% trans "Self evaluation of this assignment will close soon. " %} </strong>
{% endif %}
{% if has_peer %}
{% blocktrans %}
You'll receive your grade after the required number of your peers have assessed your response and you complete the <a data-behavior="ui-scroll" href="#openassessment__self-assessment">self assessment</a> step.
{% endblocktrans %}
{% else %}
{% blocktrans %}
You'll receive your grade after you complete the <a data-behavior="ui-scroll" href="#openassessment__self-assessment">self assessment</a> step.
{% endblocktrans %}
{% endif %}
{% endif %}
</p>
</div>
</div>
{% endspaceless %}
\ No newline at end of file
{% load i18n %}
{% spaceless %}
<div id="openassessment__message" class="openassessment__message message">
<div class="message__content">
<p>
{% if approaching %}
{% trans "Student training for peer assessment will close soon. " %}
{% endif %}
{% trans "Complete the student training section to move on to peer assessment." %}
</p>
</div>
</div>
{% endspaceless %}
\ No newline at end of file
{% load i18n %}
{% spaceless %}
<div id="openassessment__message" class="openassessment__message message">
<h3 class="message__title">{% trans "Instructions Unavailable" %} </h3>
<div class="message__content">
<p> {% trans "The instructions for this step could not be loaded." %}</p>
</div>
</div>
{% endspaceless %}
\ No newline at end of file
......@@ -20,14 +20,16 @@
</ol>
</nav>
{% block message %}
<!-- if the problem is unstarted or response hasn't been submitted -->
<div id="openassessment__message" class="openassessment__message message">
<div class="message__content">
<p>{% trans "This assignment has several steps. In the first step, you'll provide a response to the question. The other steps appear below the <strong>Your Response</strong> field." %}</p>
<div class="wrapper-openassessment__message">
{% block message %}
<div id="openassessment__message" class="openassessment__message message">
<h3 class="message__title">Instructions</h3>
<div class="message__content">
<p>{% trans "This assignment has several steps. In the first step, you'll provide a response to the question. The other steps appear below the Your Response field." %}</p>
</div>
</div>
{% endblock %}
</div>
{% endblock %}
<div class="wrapper--openassessment__prompt">
{% if question %}
......
"""
Message step in the OpenAssessment XBlock.
"""
import datetime as dt
import pytz
from xblock.core import XBlock
class MessageMixin(object):
"""
Message Mixin introduces all handlers for displaying the banner message
MessageMixin is a Mixin for the OpenAssessmentBlock. Functions in the
MessageMixin call into the OpenAssessmentBlock functions and will not work
outside of OpenAssessmentBlock.
"""
@XBlock.handler
def render_message(self, data, suffix=''):
"""
Render the message step.
Args:
data: Not used.
Kwargs:
suffix: Not used.
Returns:
unicode: HTML content of the message banner.
"""
# Retrieve the status of the workflow and information about deadlines.
workflow = self.get_workflow_info()
deadline_info = self._get_deadline_info()
# Finds the cannonical status of the workflow and the is_closed status of the problem
status = workflow.get('status')
is_closed = deadline_info.get('general').get('is_closed')
# Finds the status_information which describes the closed status of the current step (defaults to submission)
status_info = deadline_info.get(status, deadline_info.get("submission"))
status_is_closed = status_info.get('is_closed')
# Default context is empty
context = {}
# Default path leads to an "instruction-unavailable" block
path = 'openassessmentblock/message/oa_message_unavailable.html'
# Render the instruction message based on the status of the workflow
# and the closed status.
if status == "done" or status == "waiting":
path, context = self.render_message_complete(status)
elif is_closed or status_is_closed:
path, context = self.render_message_closed(status_info)
elif status == "self":
path, context = self.render_message_self(deadline_info)
elif status == "peer":
path, context = self.render_message_peer(deadline_info)
elif status == "training":
path, context = self.render_message_training(deadline_info)
elif status is None:
path, context = self.render_message_open(deadline_info)
return self.render_assessment(path, context)
def render_message_complete(self, status):
"""
Renders the "Complete" message state (Either Waiting or Done)
Args:
status (String): indicates the canonical status of the workflow
Returns:
The path (String) and context (dict) to render the "Complete" message template
"""
context = {
"waiting": (status == "waiting")
}
return 'openassessmentblock/message/oa_message_complete.html', context
def render_message_training(self, deadline_info):
"""
Renders the "Student-Training" message state (Either Waiting or Done)
Args:
status (String): indicates the canonical status of the workflow
Returns:
The path (String) and context (dict) to render the "Complete" message template
"""
approaching = deadline_info.get('training').get('approaching')
context = {
'approaching': approaching
}
return 'openassessmentblock/message/oa_message_training.html', context
def render_message_closed(self, status_info):
"""
Renders the "Closed" message state
Args:
status_info (dict): The dictionary describing the closed status of the current step
Returns:
The path (String) and context (dict) to render the "Closed" template
"""
reason = status_info.get("reason")
context = {
"not_yet_open": (reason == "start")
}
return 'openassessmentblock/message/oa_message_closed.html', context
def render_message_self(self, deadline_info):
"""
Renders the "Self" message state
Args:
deadline_info (dict): The dictionary of boolean assessment near/closed states
Returns:
The path (String) and context (dict) to render the "Self" template
"""
has_peer = 'peer-assessment' in self.assessment_steps
self_info = deadline_info.get("self")
context = {
"has_peer": has_peer,
"self_approaching": self_info.get("approaching"),
"self_closed": self_info.get("is_closed"),
"self_not_released": (self_info.get("reason") == "start")
}
return 'openassessmentblock/message/oa_message_self.html', context
def render_message_peer(self, deadline_info):
"""
Renders the "Peer" message state
Args:
deadline_info (dict): The dictionary of boolean assessment near/closed states
Returns:
The path (String) and context (dict) to render the "Peer" template
"""
#Uses a static field in the XBlock to determine if the PeerAssessment Block was able to pick up an assessment.
waiting = self.no_peers
has_self = 'self-assessment' in self.assessment_steps
peer_info = deadline_info.get("peer")
context = {
"has_self": has_self,
"waiting": waiting,
"peer_approaching": peer_info.get("approaching"),
"peer_closed": peer_info.get("is_closed"),
"peer_not_released": (peer_info.get("reason") == "start")
}
return 'openassessmentblock/message/oa_message_peer.html', context
def render_message_open(self, deadline_info):
"""
Renders the "Open" message state
Args:
deadline_info (dict): The dictionary of boolean assessment near/closed states
Returns:
The path (String) and context (dict) to render the "Open" template
"""
submission_approaching = deadline_info.get("submission").get("approaching")
context = {
"approaching": submission_approaching
}
return 'openassessmentblock/message/oa_message_open.html', context
def _get_deadline_info(self):
"""
Get detailed information about the standing of all deadlines.
Args:
None.
Returns:
dict with the following elements
"submission" : dictionary on submission closure of this^ form
"general" : dictionary on problem (all elements) closure of this^ form
"peer": dictionary on peer closure of this^ form *If Assessment has a Peer Section*
"self": dictionary on self closure of this^ form *If Assessment has a Self Section*
this^ form:
"is_closed": (bool) Indicating whether or not that section has closed
"reason": (str) The reason that the section is closed (None if !is_closed)
"approaching": (bool) Indicates whether or not the section deadline is within a day.
"""
# Methods which use datetime.deltatime to figure out if a deadline is approaching.
now = dt.datetime.utcnow().replace(tzinfo=pytz.utc)
def _is_approaching(date):
# Determines if the deadline is within one day of now. (Approaching = True if so)
delta = date - now
return delta.days == 0
# problem_info has form (is_closed, reason, start_date, due_date)
problem_info = self.is_closed()
# submission_info has form (is_closed, reason, start_date, due_date)
submission_info = self.is_closed("submission")
# The information we will always pass on to the user. Adds additional dicts on peer and self if applicable.
deadline_info = {
"submission": {
"is_closed": submission_info[0],
"reason": submission_info[1],
"approaching": _is_approaching(submission_info[3])
},
"general": {
"is_closed": problem_info[0],
"reason": problem_info[1],
"approaching": _is_approaching(problem_info[3])
}
}
has_training = 'student-training' in self.assessment_steps
if has_training:
training_info = self.is_closed("student-training")
training_dict = {
"training": {
"is_closed": training_info[0],
"reason": training_info[1],
"approaching": _is_approaching(training_info[3])
}
}
deadline_info.update(training_dict)
has_peer = 'peer-assessment' in self.assessment_steps
# peer_info has form (is_closed, reason, start_date, due_date)
if has_peer:
peer_info = self.is_closed("peer-assessment")
peer_dict = {
"peer": {
"is_closed": peer_info[0],
"reason": peer_info[1],
"approaching": _is_approaching(peer_info[3])
}
}
deadline_info.update(peer_dict)
has_self = 'self-assessment' in self.assessment_steps
# self_info has form (is_closed, reason, start_date, due_date)
if has_self:
self_info = self.is_closed("self-assessment")
self_dict = {
"self": {
"is_closed": self_info[0],
"reason": self_info[1],
"approaching": _is_approaching(self_info[3])
}
}
deadline_info.update(self_dict)
return deadline_info
......@@ -16,6 +16,7 @@ from xblock.fragment import Fragment
from openassessment.xblock.grade_mixin import GradeMixin
from openassessment.xblock.defaults import * # pylint: disable=wildcard-import, unused-wildcard-import
from openassessment.xblock.message_mixin import MessageMixin
from openassessment.xblock.peer_assessment_mixin import PeerAssessmentMixin
from openassessment.xblock.lms_mixin import LmsCompatibilityMixin
from openassessment.xblock.self_assessment_mixin import SelfAssessmentMixin
......@@ -81,6 +82,7 @@ def load(path):
class OpenAssessmentBlock(
XBlock,
MessageMixin,
SubmissionMixin,
PeerAssessmentMixin,
SelfAssessmentMixin,
......@@ -148,7 +150,7 @@ class OpenAssessmentBlock(
has_saved = Boolean(
default=False,
scope=Scope.user_state,
help="Indicates whether the user has saved a response"
help="Indicates whether the user has saved a response."
)
saved_response = String(
......@@ -157,6 +159,12 @@ class OpenAssessmentBlock(
help="Saved response submission for the current user."
)
no_peers = Boolean(
default=False,
scope=Scope.user_state,
help="Indicates whether or not there are peers to grade."
)
def get_student_item_dict(self):
"""Create a student_item_dict from our surrounding context.
......@@ -432,7 +440,7 @@ class OpenAssessmentBlock(
self.start, self.due, [submission_range] + assessment_ranges
)
open_range = (start, due)
open_range = (start, due)
assessment_steps = self.assessment_steps
if step == 'submission':
open_range = date_ranges[0]
......@@ -518,3 +526,4 @@ class OpenAssessmentBlock(
return key.to_deprecated_string()
else:
return unicode(key)
......@@ -203,8 +203,12 @@ class PeerAssessmentMixin(object):
if peer_sub:
path = 'openassessmentblock/peer/oa_peer_assessment.html'
context_dict["peer_submission"] = peer_sub
# Sets the XBlock boolean to signal to Message that it WAS NOT able to grab a submission
self.no_peers = False
else:
path = 'openassessmentblock/peer/oa_peer_waiting.html'
# Sets the XBlock boolean to signal to Message that it WAS able to grab a submission
self.no_peers = True
return path, context_dict
......
......@@ -28,6 +28,7 @@ describe("OpenAssessment.PeerView", function() {
this.setUpCollapseExpand = function(sel) {};
this.scrollToTop = function() {};
this.loadAssessmentModules = function() {};
this.loadMessageView = function() {};
};
// Stubs
......
......@@ -19,7 +19,7 @@ OpenAssessment.BaseView = function(runtime, element, server) {
this.selfView = new OpenAssessment.SelfView(this.element, this.server, this);
this.peerView = new OpenAssessment.PeerView(this.element, this.server, this);
this.gradeView = new OpenAssessment.GradeView(this.element, this.server, this);
this.messageView = new OpenAssessment.MessageView(this.element, this.server, this);
// Staff only information about student progress.
this.staffInfoView = new OpenAssessment.StaffInfoView(this.element, this.server, this);
};
......@@ -80,6 +80,26 @@ OpenAssessment.BaseView.prototype = {
this.peerView.load();
this.selfView.load();
this.gradeView.load();
/**
this.messageView.load() is intentionally omitted.
Because of the asynchronous loading, there is no way to tell (from the perspective of the
messageView) whether or not the peer view was able to grab an assessment to assess. Any
asynchronous strategy would run into a race condition based around this problem at some
point. Instead, we created a field in the XBlock called no_peers, which is set by the
Peer XBlock Handler, and which is examined by the Message XBlock Handler.
To Avoid rendering the message more than one time per update/load (and avoiding all comp-
lications that that would likely induce), we chose to load the method view only after
the peer view has been loaded. This is achieved by having the peer view call to render
the message view after rendering itself but before exiting its load method.
*/
},
/**
Refresh the message only (called by PeerView to update and avoid race condition)
**/
loadMessageView: function() {
this.messageView.load();
},
/**
......
/**
Interface for Message banner.
Args:
element (DOM element): The DOM element representing the XBlock.
server (OpenAssessment.Server): The interface to the XBlock server.
baseView (OpenAssessment.BaseView): Container view.
Returns:
OpenAssessment.ResponseView
**/
OpenAssessment.MessageView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
};
OpenAssessment.MessageView.prototype = {
/**
Loads the message view.
**/
load: function() {
var view = this;
var baseView = this.baseView;
this.server.render('message').done(
function(html) {
//Load the HTML
$('#openassessment__message', view.element).replaceWith(html);
}
).fail(function(errMsg) {
baseView.showLoadError('message', errMsg);
});
}
}
\ No newline at end of file
......@@ -33,6 +33,9 @@ OpenAssessment.PeerView.prototype = {
).fail(function(errMsg) {
view.baseView.showLoadError('peer-assessment');
});
// Called to update Messagview with info on whether or not it was able to grab a submission
// See detailed explanation/Methodology in oa_base.loadAssessmentModules
view.baseView.loadMessageView();
},
/**
......
<openassessment submission_due="2099-01-23">
<title>Open Assessment Test</title>
<prompt>
Given the state of the world today, what do you think should be done to
combat poverty? Please answer in a short essay of 200-300 words.
</prompt>
<rubric>
<prompt>Read for conciseness, clarity of thought, and form.</prompt>
<criterion>
<name>𝓒𝓸𝓷𝓬𝓲𝓼𝓮</name>
<prompt>How concise is it?</prompt>
<option points="3">
<name>ﻉซƈﻉɭɭﻉกՇ</name>
<explanation>Extremely concise</explanation>
</option>
<option points="2">
<name>Ġööḋ</name>
<explanation>Concise</explanation>
</option>
<option points="1">
<name>ק๏๏г</name>
<explanation>Wordy</explanation>
</option>
</criterion>
<criterion>
<name>Form</name>
<prompt>How well-formed is it?</prompt>
<option points="3">
<name>Good</name>
<explanation>Good</explanation>
</option>
<option points="2">
<name>Fair</name>
<explanation>Fair</explanation>
</option>
<option points="1">
<name>Poor</name>
<explanation>Poor</explanation>
</option>
</criterion>
</rubric>
<assessments>
<assessment name="peer-assessment" must_grade="1" must_be_graded_by="1" due="2099-05-23"/>
<assessment name="self-assessment" due="2099-05-23"/>
</assessments>
</openassessment>
<openassessment>
<title>Only Self Assessment</title>
<prompt>
Given the state of the world today, what do you think should be done to
combat poverty? Please answer in a short essay of 200-300 words.
</prompt>
<rubric>
<prompt>Read for conciseness, clarity of thought, and form.</prompt>
<criterion>
<name>Concise</name>
<prompt>How concise is it?</prompt>
<option points="0">
<name>Neal Stephenson (late)</name>
<explanation>Neal Stephenson explanation</explanation>
</option>
<option points="1">
<name>HP Lovecraft</name>
<explanation>HP Lovecraft explanation</explanation>
</option>
<option points="3">
<name>Robert Heinlein</name>
<explanation>Robert Heinlein explanation</explanation>
</option>
<option points="4">
<name>Neal Stephenson (early)</name>
<explanation>Neal Stephenson (early) explanation</explanation>
</option>
<option points="5">
<name>Earnest Hemingway</name>
<explanation>Earnest Hemingway</explanation>
</option>
</criterion>
<criterion>
<name>Clear-headed</name>
<prompt>How clear is the thinking?</prompt>
<option points="0">
<name>Yogi Berra</name>
<explanation>Yogi Berra explanation</explanation>
</option>
<option points="1">
<name>Hunter S. Thompson</name>
<explanation>Hunter S. Thompson explanation</explanation>
</option>
<option points="2">
<name>Robert Heinlein</name>
<explanation>Robert Heinlein explanation</explanation>
</option>
<option points="3">
<name>Isaac Asimov</name>
<explanation>Isaac Asimov explanation</explanation>
</option>
<option points="10">
<name>Spock</name>
<explanation>Spock explanation</explanation>
</option>
</criterion>
<criterion>
<name>Form</name>
<prompt>Lastly, how is its form? Punctuation, grammar, and spelling all count.</prompt>
<option points="0">
<name>lolcats</name>
<explanation>lolcats explanation</explanation>
</option>
<option points="1">
<name>Facebook</name>
<explanation>Facebook explanation</explanation>
</option>
<option points="2">
<name>Reddit</name>
<explanation>Reddit explanation</explanation>
</option>
<option points="3">
<name>metafilter</name>
<explanation>metafilter explanation</explanation>
</option>
<option points="4">
<name>Usenet, 1996</name>
<explanation>Usenet, 1996 explanation</explanation>
</option>
<option points="5">
<name>The Elements of Style</name>
<explanation>The Elements of Style explanation</explanation>
</option>
</criterion>
</rubric>
<assessments>
<assessment name="self-assessment" />
</assessments>
</openassessment>
<openassessment>
<title>Open Assessment Test</title>
<prompt>
Given the state of the world today, what do you think should be done to
combat poverty? Please answer in a short essay of 200-300 words.
</prompt>
<rubric>
<prompt>Read for conciseness, clarity of thought, and form.</prompt>
<criterion>
<name>Concise</name>
<prompt>How concise is it?</prompt>
<option points="0">
<name>Neal Stephenson (late)</name>
<explanation>Neal Stephenson explanation</explanation>
</option>
<option points="1">
<name>HP Lovecraft</name>
<explanation>HP Lovecraft explanation</explanation>
</option>
<option points="3">
<name>Robert Heinlein</name>
<explanation>Robert Heinlein explanation</explanation>
</option>
<option points="4">
<name>Neal Stephenson (early)</name>
<explanation>Neal Stephenson (early) explanation</explanation>
</option>
<option points="5">
<name>Earnest Hemingway</name>
<explanation>Earnest Hemingway</explanation>
</option>
</criterion>
<criterion>
<name>Clear-headed</name>
<prompt>How clear is the thinking?</prompt>
<option points="0">
<name>Yogi Berra</name>
<explanation>Yogi Berra explanation</explanation>
</option>
<option points="1">
<name>Hunter S. Thompson</name>
<explanation>Hunter S. Thompson explanation</explanation>
</option>
<option points="2">
<name>Robert Heinlein</name>
<explanation>Robert Heinlein explanation</explanation>
</option>
<option points="3">
<name>Isaac Asimov</name>
<explanation>Isaac Asimov explanation</explanation>
</option>
<option points="10">
<name>Spock</name>
<explanation>Spock explanation</explanation>
</option>
</criterion>
<criterion>
<name>Form</name>
<prompt>Lastly, how is its form? Punctuation, grammar, and spelling all count.</prompt>
<option points="0">
<name>lolcats</name>
<explanation>lolcats explanation</explanation>
</option>
<option points="1">
<name>Facebook</name>
<explanation>Facebook explanation</explanation>
</option>
<option points="2">
<name>Reddit</name>
<explanation>Reddit explanation</explanation>
</option>
<option points="3">
<name>metafilter</name>
<explanation>metafilter explanation</explanation>
</option>
<option points="4">
<name>Usenet, 1996</name>
<explanation>Usenet, 1996 explanation</explanation>
</option>
<option points="5">
<name>The Elements of Style</name>
<explanation>The Elements of Style explanation</explanation>
</option>
</criterion>
</rubric>
<assessments>
<assessment name="peer-assessment" must_grade="5" must_be_graded_by="3" />
</assessments>
</openassessment>
<openassessment>
<title>Student training test</title>
<prompt>Test prompt</prompt>
<rubric>
<prompt>Test rubric prompt</prompt>
<criterion>
<name>Vocabulary</name>
<prompt>How varied is the vocabulary?</prompt>
<option points="0">
<name>Poor</name>
<explanation>Poor job</explanation>
</option>
<option points="1">
<name>Good</name>
<explanation>Good job</explanation>
</option>
<option points="3">
<name>Excellent</name>
<explanation>Excellent job</explanation>
</option>
</criterion>
<criterion>
<name>Grammar</name>
<prompt>How correct is the grammar?</prompt>
<option points="0">
<name>Poor</name>
<explanation>Poor job</explanation>
</option>
<option points="1">
<name>Good</name>
<explanation>Good job</explanation>
</option>
<option points="3">
<name>Excellent</name>
<explanation>Excellent job</explanation>
</option>
</criterion>
</rubric>
<assessments>
<assessment name="student-training">
<example>
<answer>This is my answer.</answer>
<select criterion="Vocabulary" option="Good" />
<select criterion="Grammar" option="Excellent" />
</example>
<example>
<answer>тєѕт αηѕωєя</answer>
<select criterion="Vocabulary" option="Excellent" />
<select criterion="Grammar" option="Poor" />
</example>
</assessment>
<assessment name="peer-assessment" must_grade="5" must_be_graded_by="3" />
<assessment name="self-assessment" />
</assessments>
</openassessment>
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