Commit afb12dfd by Eric Fischer

Show staff assessment in staff tools

Generalizing the display of completed assessments in staff tools, and
including staff assessments in the view, which had previously been missing.

Includes a new unit test for this behavior, and updates acceptance tests as well.
parent aa670033
{% load i18n %}
<div class="staff-info__status ui-staff__content__section wrapper--ui--collapse staff-info__{{ class_type }}__assessments">
<div class="ui-staff ui-toggle-visibility is--collapsed">
<h2 class="staff-info__title ui-staff__subtitle ui-toggle-visibility__control">
<i class="icon fa fa-caret-right" aria-hidden="true"></i>
<span>{{ translated_title }}</span>
</h2>
<div class="ui-toggle-visibility__content">
{% for assessment in assessments %}
{% with assessment_num=forloop.counter %}
{% if assessments|length > 1 %}
<h4 class="title--sub">
{% blocktrans %}
Assessment {{ assessment_num }}:
{% endblocktrans %}
</h4>
{% endif %}
<table class="staff-info__status__table" summary="{% trans "Assessment" %}">
<thead>
<tr>
<th abbr="{% trans "Criterion" %}" scope="col">{% trans "Criterion" %}</th>
<th abbr="{% trans "Selected Option" %}" scope="col">{% trans "Selected Option" %}</th>
<th abbr="{% trans "Feedback" %}" scope="col">{% trans "Feedback" %}</th>
<th abbr="{% trans "Points" %}" scope="col">{% trans "Points" %}</th>
<th abbr="{% trans "Points Possible" %}" scope="col">{% trans "Points Possible" %}</th>
</tr>
</thead>
<tbody>
{% for criterion in rubric_criteria %}
{% for part in assessment.parts %}
{% if part.option.criterion.name == criterion.name %}
<tr>
<td class="label">{{ criterion.label }}</td>
<td class="value">{{ part.option.label }}</td>
<td class="value">{{ part.feedback }}</td>
<td class="value">{{ part.option.points }}</td>
<td class="value">{{ criterion.total_value }}</td>
</tr>
{% endif %}
{% endfor %}
{% endfor %}
</tbody>
</table>
{% if assessment.feedback %}
<h4 class="title--sub">{% trans "Overall Feedback" %}</h4>
<div class="student__answer__display__content">
{{ assessment.feedback|linebreaks }}
</div>
{% endif %}
{% endwith %}
{% endfor %}
</div>
</div>
</div>
...@@ -378,6 +378,7 @@ class StaffAreaMixin(object): ...@@ -378,6 +378,7 @@ class StaffAreaMixin(object):
self_assessment = None self_assessment = None
peer_assessments = None peer_assessments = None
submitted_assessments = None submitted_assessments = None
staff_assessment = staff_api.get_latest_staff_assessment(submission_uuid)
if "peer-assessment" in assessment_steps: if "peer-assessment" in assessment_steps:
peer_assessments = peer_api.get_assessments(submission_uuid) peer_assessments = peer_api.get_assessments(submission_uuid)
...@@ -394,17 +395,18 @@ class StaffAreaMixin(object): ...@@ -394,17 +395,18 @@ class StaffAreaMixin(object):
workflow_cancellation = self.get_workflow_cancellation_info(submission_uuid) workflow_cancellation = self.get_workflow_cancellation_info(submission_uuid)
context.update({ context.update({
'expanded_view': expanded_view,
'example_based_assessment': [example_based_assessment] if example_based_assessment else None,
'self_assessment': [self_assessment] if self_assessment else None,
'peer_assessments': peer_assessments,
'submitted_assessments': submitted_assessments,
'staff_assessment': [staff_assessment] if staff_assessment else None,
'score': workflow.get('score'), 'score': workflow.get('score'),
'workflow_status': workflow.get('status'), 'workflow_status': workflow.get('status'),
'workflow_cancellation': workflow_cancellation, 'workflow_cancellation': workflow_cancellation,
'peer_assessments': peer_assessments,
'submitted_assessments': submitted_assessments,
'self_assessment': self_assessment,
'example_based_assessment': example_based_assessment,
'expanded_view': expanded_view,
}) })
if peer_assessments or self_assessment or example_based_assessment: if peer_assessments or self_assessment or example_based_assessment or staff_assessment:
max_scores = peer_api.get_rubric_max_scores(submission_uuid) max_scores = peer_api.get_rubric_max_scores(submission_uuid)
for criterion in context["rubric_criteria"]: for criterion in context["rubric_criteria"]:
criterion["total_value"] = max_scores[criterion["name"]] criterion["total_value"] = max_scores[criterion["name"]]
......
...@@ -87,6 +87,6 @@ ...@@ -87,6 +87,6 @@
</criterion> </criterion>
</rubric> </rubric>
<assessments> <assessments>
<assessment name="staff-assessment" /> <assessment name="staff-assessment" required="true"/>
</assessments> </assessments>
</openassessment> </openassessment>
...@@ -8,6 +8,7 @@ from django.test.utils import override_settings ...@@ -8,6 +8,7 @@ from django.test.utils import override_settings
from openassessment.assessment.api import peer as peer_api from openassessment.assessment.api import peer as peer_api
from openassessment.assessment.api import self as self_api from openassessment.assessment.api import self as self_api
from openassessment.assessment.api import staff as staff_api
from openassessment.assessment.api import ai as ai_api from openassessment.assessment.api import ai as ai_api
from openassessment.workflow import api as workflow_api from openassessment.workflow import api as workflow_api
from openassessment.assessment.errors.ai import AIError, AIGradingInternalError from openassessment.assessment.errors.ai import AIError, AIGradingInternalError
...@@ -202,7 +203,9 @@ class TestCourseStaff(XBlockHandlerTestCase): ...@@ -202,7 +203,9 @@ class TestCourseStaff(XBlockHandlerTestCase):
# Now Bob should be fully populated in the student info view. # Now Bob should be fully populated in the student info view.
path, context = xblock.get_student_info_path_and_context("Bob") path, context = xblock.get_student_info_path_and_context("Bob")
self.assertEquals("Bob Answer 1", context['submission']['answer']['parts'][0]['text']) self.assertEquals("Bob Answer 1", context['submission']['answer']['parts'][0]['text'])
self.assertIsNotNone(context['peer_assessments'])
self.assertIsNone(context['self_assessment']) self.assertIsNone(context['self_assessment'])
self.assertIsNone(context['staff_assessment'])
self.assertEquals("openassessmentblock/staff_area/oa_student_info.html", path) self.assertEquals("openassessmentblock/staff_area/oa_student_info.html", path)
@scenario('data/self_only_scenario.xml', user_id='Bob') @scenario('data/self_only_scenario.xml', user_id='Bob')
...@@ -231,7 +234,40 @@ class TestCourseStaff(XBlockHandlerTestCase): ...@@ -231,7 +234,40 @@ class TestCourseStaff(XBlockHandlerTestCase):
path, context = xblock.get_student_info_path_and_context("Bob") path, context = xblock.get_student_info_path_and_context("Bob")
self.assertEquals("Bob Answer 1", context['submission']['answer']['parts'][0]['text']) self.assertEquals("Bob Answer 1", context['submission']['answer']['parts'][0]['text'])
self.assertEquals(None, context['peer_assessments']) self.assertIsNone(context['peer_assessments'])
self.assertIsNotNone(context['self_assessment'])
self.assertIsNone(context['staff_assessment'])
self.assertEquals("openassessmentblock/staff_area/oa_student_info.html", path)
@scenario('data/staff_grade_scenario.xml', user_id='Bob')
def test_staff_area_student_info_staff_only(self, xblock):
# Simulate that we are course staff
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.scope_ids.usage_id, True, False, "Bob"
)
xblock.runtime._services['user'] = NullUserService()
bob_item = STUDENT_ITEM.copy()
bob_item["item_id"] = xblock.scope_ids.usage_id
# Create a submission for Bob, and corresponding workflow.
submission = self._create_submission(
bob_item, prepare_submission_for_serialization(("Bob Answer 1", "Bob Answer 2")), ['staff']
)
# Bob assesses himself.
staff_api.create_assessment(
submission['uuid'],
STUDENT_ITEM["student_id"],
ASSESSMENT_DICT['options_selected'],
ASSESSMENT_DICT['criterion_feedback'],
ASSESSMENT_DICT['overall_feedback'],
{'criteria': xblock.rubric_criteria},
)
path, context = xblock.get_student_info_path_and_context("Bob")
self.assertEquals("Bob Answer 1", context['submission']['answer']['parts'][0]['text'])
self.assertIsNone(context['peer_assessments'])
self.assertIsNone(context['self_assessment'])
self.assertIsNotNone(context['staff_assessment'])
self.assertEquals("openassessmentblock/staff_area/oa_student_info.html", path) self.assertEquals("openassessmentblock/staff_area/oa_student_info.html", path)
@scenario('data/basic_scenario.xml', user_id='Bob') @scenario('data/basic_scenario.xml', user_id='Bob')
......
...@@ -519,17 +519,19 @@ class StaffAreaTest(OpenAssessmentTest): ...@@ -519,17 +519,19 @@ class StaffAreaTest(OpenAssessmentTest):
Given I am viewing the staff area of an ORA problem Given I am viewing the staff area of an ORA problem
When I search for a learner in staff tools When I search for a learner in staff tools
And the learner has submitted a response to an ORA problem with self-assessment And the learner has submitted a response to an ORA problem with self-assessment
And I've made a staff override assessment of the learner
Then I see the correct learner information sections Then I see the correct learner information sections
""" """
username = self.do_self_assessment() username = self.do_self_assessment()
self.do_staff_override(username)
self.staff_area_page.visit() self.staff_area_page.visit()
# Click on staff tools and search for user # Click on staff tools and search for user
self.staff_area_page.show_learner(username) self.staff_area_page.show_learner(username)
self.assertEqual( self.assertEqual(
[u"Learner's Response", u"Learner's Self Assessment", u"Learner's Final Grade", [u"Learner's Response", u"Learner's Self Assessment", u"Staff Assessment for This Learner",
u"Submit Assessment Grade Override", u"Remove Submission From Peer Grading"], u"Learner's Final Grade", u"Submit Assessment Grade Override", u"Remove Submission From Peer Grading"],
self.staff_area_page.learner_report_sections self.staff_area_page.learner_report_sections
) )
...@@ -742,7 +744,7 @@ class FullWorkflowMixin(object): ...@@ -742,7 +744,7 @@ class FullWorkflowMixin(object):
PEER_ASSESSMENT_STAFF_AREA_SCORE = "Final grade: 0 out of 8" PEER_ASSESSMENT_STAFF_AREA_SCORE = "Final grade: 0 out of 8"
SELF_ASSESSMENT = [2, 3] SELF_ASSESSMENT = [2, 3]
STAFF_AREA_SELF_ASSESSMENT = ['Good', u'5', u'5', u'Excellent', u'3', u'3'] STAFF_AREA_SELF_ASSESSMENT = ['Good', u'', u'5', u'5', u'Excellent', u'', u'3', u'3']
SUBMITTED_ASSESSMENT = [0, 3] SUBMITTED_ASSESSMENT = [0, 3]
STAFF_AREA_SUBMITTED = ['Poor', u'', u'0', u'5', u'Excellent', u'', u'3', u'3'] STAFF_AREA_SUBMITTED = ['Poor', u'', u'0', u'5', u'Excellent', u'', u'3', u'3']
...@@ -829,7 +831,7 @@ class FullWorkflowMixin(object): ...@@ -829,7 +831,7 @@ class FullWorkflowMixin(object):
self.staff_area_page.expand_learner_report_sections() self.staff_area_page.expand_learner_report_sections()
self.assertEqual(peer_assessments, self.staff_area_page.status_text('peer__assessments')) self.assertEqual(peer_assessments, self.staff_area_page.status_text('peer__assessments'))
self.assertEqual(submitted_assessments, self.staff_area_page.status_text('submitted__assessments')) self.assertEqual(submitted_assessments, self.staff_area_page.status_text('submitted__assessments'))
self.assertEqual(self_assessment, self.staff_area_page.status_text('self__assessment')) self.assertEqual(self_assessment, self.staff_area_page.status_text('self__assessments'))
def verify_submission_has_peer_grade(self, learner, max_attempts=5): def verify_submission_has_peer_grade(self, learner, max_attempts=5):
""" """
......
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