Commit e3fe2cbf by muzaffaryousaf

Changing the student anonymous_user_id to student name.

TNL-836
parent d11f3139
......@@ -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,22 +201,45 @@ 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):
"""
Get the anonymous user id from Xblock user service.
Args:
username(str): user's name entered by staff to get info.
course_id(str): 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.
Args:
anonymous_user_id(str):
Returns:
(dict): The student item associated with this XBlock instance. This
includes the student id, item id, and course id.
"""
item_id = self._serialize_opaque_key(self.scope_ids.usage_id)
# 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:
......
......@@ -208,58 +208,59 @@ class StaffInfoMixin(object):
"""
Renders all relative information for a specific student's workflow.
Given a student's ID, we can render a staff-only section of the page
Given a student's username, we can render a staff-only section of the page
with submissions and assessments specific to the student.
Must be course staff to render this view.
"""
try:
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)
except PeerAssessmentInternalError:
return self.render_error(self._(u"Error finding assessment workflow cancellation."))
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);
......@@ -96,7 +96,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) {
......
......@@ -5,6 +5,8 @@ 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 +15,7 @@ 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 +46,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 +77,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 +91,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 +107,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 +123,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 +148,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 +160,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 +172,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'])
......@@ -201,11 +213,11 @@ class TestCourseStaff(XBlockHandlerTestCase):
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"], ['self'])
......@@ -237,6 +249,7 @@ class TestCourseStaff(XBlockHandlerTestCase):
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
......@@ -296,13 +309,14 @@ class TestCourseStaff(XBlockHandlerTestCase):
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"
})
......@@ -318,23 +332,24 @@ 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"
})
......@@ -348,7 +363,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)
......@@ -359,6 +374,7 @@ 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 = {
......@@ -377,7 +393,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'])
......@@ -410,7 +426,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