Commit d7bf8590 by muzaffaryousaf

Changing the student_id to student_username.

Consuming the 'user' service in 'render_student_info'

TNL-836
parent bec80881
......@@ -129,15 +129,15 @@
<form id="openassessment_student_info_form">
<ul>
<li class="openassessment__student-info_list">
<label for="openassessment__student_id" class="label">{% trans "Get Student Info" %}</label>
<label for="openassessment__student_username" class="label">{% trans "Get Student Info" %}</label>
</li>
<li class="openassessment__student-info_list">
<input id="openassessment__student_id" type="text" class="value" maxlength="255">
<input id="openassessment__student_username" type="text" class="value" maxlength="255">
</li>
</ul>
<ul class="list list--actions">
<li class="list--actions__item">
<a aria-role="button" href="" id="submit_student_id" class="action--submit"><span class="copy">{% trans "Submit" %}</span></a>
<a aria-role="button" href="" id="submit_student_username" class="action--submit"><span class="copy">{% trans "Submit" %}</span></a>
</li>
</ul>
</form>
......
......@@ -90,6 +90,7 @@ def load(path):
return data.decode("utf8")
@XBlock.needs("i18n")
@XBlock.needs("user")
class OpenAssessmentBlock(
MessageMixin,
SubmissionMixin,
......@@ -200,7 +201,21 @@ class OpenAssessmentBlock(
help="Indicates whether or not there are peers to grade."
)
def get_student_item_dict(self):
@property
def course_id(self):
return self._serialize_opaque_key(self.xmodule_runtime.course_id) # pylint:disable=E1101
def get_anonymous_user_id(self, username, course_id):
"""
Args:
username: user's name entered by staff to get info.
course_id: course id.
Returns:
A unique id for (user, course) pair
"""
return self.runtime.service(self, 'user').get_anonymous_user_id(username, course_id)
def get_student_item_dict(self, anonymous_user_id=None):
"""Create a student_item_dict from our surrounding context.
See also: submissions.api for details.
......@@ -215,8 +230,11 @@ class OpenAssessmentBlock(
# This is not the real way course_ids should work, but this is a
# temporary expediency for LMS integration
if hasattr(self, "xmodule_runtime"):
course_id = self._serialize_opaque_key(self.xmodule_runtime.course_id) # pylint:disable=E1101
student_id = self.xmodule_runtime.anonymous_student_id # pylint:disable=E1101
course_id = self.course_id # pylint:disable=E1101
if anonymous_user_id:
student_id = anonymous_user_id
else:
student_id = self.xmodule_runtime.anonymous_student_id # pylint:disable=E1101
else:
course_id = "edX/Enchantment_101/April_1"
if self.scope_ids.user_id is None:
......
......@@ -204,48 +204,49 @@ class StaffInfoMixin(object):
Must be course staff to render this view.
"""
student_id = data.params.get('student_id', '')
path, context = self.get_student_info_path_and_context(student_id)
student_username = data.params.get('student_username', '')
path, context = self.get_student_info_path_and_context(student_username)
return self.render_assessment(path, context)
def get_student_info_path_and_context(self, student_id):
def get_student_info_path_and_context(self, student_username):
"""
Get the proper path and context for rendering the the student info
section of the staff debug panel.
Args:
student_id (unicode): The ID of the student to report.
student_username (unicode): The username of the student to report.
"""
submission_uuid = None
submission = None
assessment_steps = self.assessment_steps
if student_id:
student_item = self.get_student_item_dict()
student_item['student_id'] = student_id
# If there is a submission available for the requested student, present
# it. If not, there will be no other information to collect.
submissions = submission_api.get_submissions(student_item, 1)
if submissions:
submission_uuid = submissions[0]['uuid']
submission = submissions[0]
if 'file_key' in submission.get('answer', {}):
file_key = submission['answer']['file_key']
try:
submission['image_url'] = file_api.get_download_url(file_key)
except file_api.FileUploadError:
# Log the error, but do not prevent the rest of the student info
# from being displayed.
msg = (
u"Could not retrieve image URL for staff debug page. "
u"The student ID is '{student_id}', and the file key is {file_key}"
).format(student_id=student_id, file_key=file_key)
logger.exception(msg)
if student_username:
anonymous_user_id = self.get_anonymous_user_id(student_username, self.course_id)
student_item = self.get_student_item_dict(anonymous_user_id=anonymous_user_id)
if anonymous_user_id:
# If there is a submission available for the requested student, present
# it. If not, there will be no other information to collect.
submissions = submission_api.get_submissions(student_item, 1)
if submissions:
submission_uuid = submissions[0]['uuid']
submission = submissions[0]
if 'file_key' in submission.get('answer', {}):
file_key = submission['answer']['file_key']
try:
submission['image_url'] = file_api.get_download_url(file_key)
except file_api.FileUploadError:
# Log the error, but do not prevent the rest of the student info
# from being displayed.
msg = (
u"Could not retrieve image URL for staff debug page. "
u"The student username is '{student_username}', and the file key is {file_key}"
).format(student_username=student_username, file_key=file_key)
logger.exception(msg)
example_based_assessment = None
self_assessment = None
......
......@@ -48,8 +48,8 @@ OpenAssessment.StaffInfoView.prototype = {
loadStudentInfo: function() {
var view = this;
var sel = $('#openassessment__staff-info', this.element);
var student_id = sel.find('#openassessment__student_id').val();
this.server.studentInfo(student_id).done(
var student_username = sel.find('#openassessment__student_username').val();
this.server.studentInfo(student_username).done(
function(html) {
// Load the HTML and install event handlers
$('#openassessment__student-info', view.element).replaceWith(html);
......@@ -81,7 +81,7 @@ OpenAssessment.StaffInfoView.prototype = {
);
// Install a click handler for requesting student info
sel.find('#submit_student_id').click(
sel.find('#submit_student_username').click(
function(eventObject) {
eventObject.preventDefault();
view.loadStudentInfo();
......
......@@ -121,14 +121,14 @@ if (typeof OpenAssessment.Server == "undefined" || !OpenAssessment.Server) {
/**
Load the Student Info section in Staff Info.
**/
studentInfo: function(student_id) {
studentInfo: function(student_username) {
var url = this.url('render_student_info');
return $.Deferred(function(defer) {
$.ajax({
url: url,
type: "POST",
dataType: "html",
data: {student_id: student_id}
data: {student_username: student_username}
}).done(function(data) {
defer.resolveWith(this, [data]);
}).fail(function(data) {
......
......@@ -3,8 +3,11 @@ from collections import namedtuple
import json
import datetime
import urllib
from mock import Mock, patch
from django.test.utils import override_settings
import ddt
from openassessment.assessment.api import peer as peer_api
from openassessment.assessment.api import self as self_api
from openassessment.assessment.api import ai as ai_api
......@@ -13,6 +16,8 @@ from openassessment.assessment.errors.ai import AIError, AIGradingInternalError
from openassessment.fileupload.api import FileUploadInternalError
from submissions import api as sub_api
from openassessment.xblock.test.base import scenario, XBlockHandlerTestCase
from xblock.core import XBlock
ALGORITHM_ID = 'fake'
......@@ -43,6 +48,14 @@ ASSESSMENT_DICT = {
}
class NullUserService(object):
"""
A simple implementation of the runtime "user" service.
"""
def get_anonymous_user_id(self, username, course_id):
return username
class TestCourseStaff(XBlockHandlerTestCase):
"""
Tests for course staff debug panel.
......@@ -66,7 +79,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
@scenario('data/basic_scenario.xml', user_id='Bob')
def test_course_staff_debug_info(self, xblock):
# If we're not course staff, we shouldn't see the debug info
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.scope_ids.usage_id, False, False, "Bob"
)
resp = self.request(xblock, 'render_staff_info', json.dumps({}))
......@@ -80,7 +93,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
@scenario('data/basic_scenario.xml', user_id='Bob')
def test_course_student_debug_info(self, xblock):
# If we're not course staff, we shouldn't see the debug info
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.scope_ids.usage_id, False, False, "Bob"
)
resp = self.request(xblock, 'render_student_info', json.dumps({}))
......@@ -96,7 +109,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
# If we are in Studio preview mode, don't show the staff debug info
# In this case, the runtime will tell us that we're staff,
# but no user ID will be set.
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.scope_ids.usage_id, True, False, "Bob"
)
......@@ -112,7 +125,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
@scenario('data/staff_dates_scenario.xml', user_id='Bob')
def test_staff_debug_dates_table(self, xblock):
# Simulate that we are course staff
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.scope_ids.usage_id, True, False, "Bob"
)
......@@ -137,7 +150,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
@scenario('data/basic_scenario.xml', user_id='Bob')
def test_staff_debug_dates_distant_past_and_future(self, xblock):
# Simulate that we are course staff
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.scope_ids.usage_id, True, False, "Bob"
)
......@@ -149,7 +162,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
@scenario('data/basic_scenario.xml', user_id='Bob')
def test_staff_debug_student_info_no_submission(self, xblock):
# Simulate that we are course staff
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.scope_ids.usage_id, True, False, "Bob"
)
request = namedtuple('Request', 'params')
......@@ -161,14 +174,15 @@ class TestCourseStaff(XBlockHandlerTestCase):
@scenario('data/peer_only_scenario.xml', user_id='Bob')
def test_staff_debug_student_info_peer_only(self, xblock):
# Simulate that we are course staff
xblock.xmodule_runtime = self._create_mock_runtime(
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 = sub_api.create_submission(bob_item, {'text':"Bob Answer"})
submission = sub_api.create_submission(bob_item, {'text': "Bob Answer"})
peer_api.on_start(submission["uuid"])
workflow_api.create_workflow(submission["uuid"], ['peer'])
......@@ -196,16 +210,20 @@ class TestCourseStaff(XBlockHandlerTestCase):
self.assertEquals("openassessmentblock/staff_debug/student_info.html", path)
@scenario('data/self_only_scenario.xml', user_id='Bob')
# @XBlock.register_temp_plugin(PureXBlock, identifier='pure')
# @ddt.data("user")
def test_staff_debug_student_info_self_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.xmodule_runtime = self._create_mock_runtime(
xblock.scope_ids.usage_id, True, True, "Bob"
)
xblock.runtime._services['user'] = NullUserService()
print xblock.runtime.__dict__
bob_item = STUDENT_ITEM.copy()
bob_item["item_id"] = xblock.scope_ids.usage_id
# Create a submission for Bob, and corresponding workflow.
submission = sub_api.create_submission(bob_item, {'text':"Bob Answer"})
submission = sub_api.create_submission(bob_item, {'text': "Bob Answer"})
peer_api.on_start(submission["uuid"])
workflow_api.create_workflow(submission["uuid"], ['self'])
......@@ -227,16 +245,17 @@ class TestCourseStaff(XBlockHandlerTestCase):
@scenario('data/self_only_scenario.xml', user_id='Bob')
def test_staff_debug_student_info_image_submission(self, xblock):
# Simulate that we are course staff
xblock.xmodule_runtime = self._create_mock_runtime(
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 an image submission for Bob
sub_api.create_submission(bob_item, {
'text':"Bob Answer",
'text': "Bob Answer",
'file_key': "test_key"
})
......@@ -252,23 +271,25 @@ class TestCourseStaff(XBlockHandlerTestCase):
self.assertEquals('http://www.example.com/image.jpeg', context['submission']['image_url'])
# Check the fully rendered template
payload = urllib.urlencode({"student_id": "Bob"})
payload = urllib.urlencode({"student_username": "Bob"})
resp = self.request(xblock, "render_student_info", payload)
self.assertIn("http://www.example.com/image.jpeg", resp)
@scenario('data/self_only_scenario.xml', user_id='Bob')
def test_staff_debug_student_info_file_download_url_error(self, xblock):
# Simulate that we are course staff
xblock.xmodule_runtime = self._create_mock_runtime(
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 an image submission for Bob
sub_api.create_submission(bob_item, {
'text':"Bob Answer",
'text': "Bob Answer",
'file_key': "test_key"
})
......@@ -282,7 +303,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
self.assertNotIn('image_url', context['submission'])
# Check the fully rendered template
payload = urllib.urlencode({"student_id": "Bob"})
payload = urllib.urlencode({"student_username": "Bob"})
resp = self.request(xblock, "render_student_info", payload)
self.assertIn("Bob Answer", resp)
......@@ -293,6 +314,8 @@ class TestCourseStaff(XBlockHandlerTestCase):
xblock.xmodule_runtime = self._create_mock_runtime(
xblock.scope_ids.usage_id, True, False, "Bob"
)
xblock.runtime._services['user'] = NullUserService()
# Commonly chosen options for assessments
options_selected = {
......@@ -311,7 +334,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
bob_item["item_id"] = xblock.scope_ids.usage_id
# Create a submission for Bob, and corresponding workflow.
submission = sub_api.create_submission(bob_item, {'text':"Bob Answer"})
submission = sub_api.create_submission(bob_item, {'text': "Bob Answer"})
peer_api.on_start(submission["uuid"])
workflow_api.create_workflow(submission["uuid"], ['peer', 'self'])
......@@ -344,7 +367,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
# Now Bob should be fully populated in the student info view.
request = namedtuple('Request', 'params')
request.params = {"student_id": "Bob"}
request.params = {"student_username": "Bob"}
# Verify that we can render without error
resp = xblock.render_student_info(request)
self.assertIn("bob answer", resp.body.lower())
......
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