Switching to new dashboard API and adding rescore to actions list
This commit is contained in:
@@ -66,6 +66,15 @@ class StaffDebugPage(PageObject):
|
||||
self.q(css='input[id^=sd_fu_]').fill(user)
|
||||
self.q(css='section.staff-modal a#staff-debug-sdelete').click()
|
||||
|
||||
def rescore(self, user=None):
|
||||
"""
|
||||
This clicks on the reset attempts link with an optionally
|
||||
specified user.
|
||||
"""
|
||||
if user:
|
||||
self.q(css='input[id^=sd_fu_]').first.fill(user)
|
||||
self.q(css='section.staff-modal a#staff-debug-rescore').click()
|
||||
|
||||
@property
|
||||
def idash_msg(self):
|
||||
"""
|
||||
|
||||
@@ -16,6 +16,7 @@ class StaffDebugTest(UniqueCourseTest):
|
||||
Tests that verify the staff debug info.
|
||||
"""
|
||||
USERNAME = "STAFF_TESTER"
|
||||
EMAIL = "johndoe@example.com"
|
||||
|
||||
def setUp(self):
|
||||
super(StaffDebugTest, self).setUp()
|
||||
@@ -49,7 +50,7 @@ class StaffDebugTest(UniqueCourseTest):
|
||||
|
||||
# Auto-auth register for the course.
|
||||
# Do this as global staff so that you will see the Staff View
|
||||
AutoAuthPage(self.browser, username=self.USERNAME,
|
||||
AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL,
|
||||
course_id=self.course_id, staff=True).visit()
|
||||
|
||||
def _goto_staff_page(self):
|
||||
@@ -63,15 +64,14 @@ class StaffDebugTest(UniqueCourseTest):
|
||||
|
||||
def test_reset_attempts_empty(self):
|
||||
"""
|
||||
Test that we fail properly when there is no student state
|
||||
Test that we reset even when there is no student state
|
||||
"""
|
||||
|
||||
staff_debug_page = self._goto_staff_page().open_staff_debug_info()
|
||||
staff_debug_page.reset_attempts()
|
||||
msg = staff_debug_page.idash_msg[0]
|
||||
self.assertIn((u"Found a single student. Found module. Couldn't "
|
||||
"reset module state for {0}/").format(self.USERNAME),
|
||||
msg)
|
||||
self.assertEqual(u'Successfully reset the attempts '
|
||||
'for user {}'.format(self.USERNAME), msg)
|
||||
|
||||
def test_delete_state_empty(self):
|
||||
"""
|
||||
@@ -80,8 +80,8 @@ class StaffDebugTest(UniqueCourseTest):
|
||||
staff_debug_page = self._goto_staff_page().open_staff_debug_info()
|
||||
staff_debug_page.delete_state()
|
||||
msg = staff_debug_page.idash_msg[0]
|
||||
self.assertIn((u"Found a single student. Found module. "
|
||||
"Deleted student module state for"), msg)
|
||||
self.assertEqual(u'Successfully deleted student state '
|
||||
'for user {}'.format(self.USERNAME), msg)
|
||||
|
||||
def test_reset_attempts_state(self):
|
||||
"""
|
||||
@@ -93,10 +93,25 @@ class StaffDebugTest(UniqueCourseTest):
|
||||
staff_debug_page = staff_page.open_staff_debug_info()
|
||||
staff_debug_page.reset_attempts()
|
||||
msg = staff_debug_page.idash_msg[0]
|
||||
self.assertIn((u"Found a single student. Found module. Module "
|
||||
"state successfully reset!"), msg)
|
||||
self.assertEqual(u'Successfully reset the attempts '
|
||||
'for user {}'.format(self.USERNAME), msg)
|
||||
|
||||
def test_student_state_state(self):
|
||||
def test_rescore_state(self):
|
||||
"""
|
||||
Rescore the student
|
||||
"""
|
||||
staff_page = self._goto_staff_page()
|
||||
staff_page.answer_problem()
|
||||
|
||||
staff_debug_page = staff_page.open_staff_debug_info()
|
||||
staff_debug_page.rescore()
|
||||
msg = staff_debug_page.idash_msg[0]
|
||||
# Since we aren't running celery stuff, this will fail badly
|
||||
# for now, but is worth excercising that bad of a response
|
||||
self.assertEqual(u'Unsuccessfully rescored problem. '
|
||||
'Unknown Error Occurred.', msg)
|
||||
|
||||
def test_student_state_delete(self):
|
||||
"""
|
||||
Successfully delete the student state with an answer
|
||||
"""
|
||||
@@ -106,5 +121,31 @@ class StaffDebugTest(UniqueCourseTest):
|
||||
staff_debug_page = staff_page.open_staff_debug_info()
|
||||
staff_debug_page.delete_state()
|
||||
msg = staff_debug_page.idash_msg[0]
|
||||
self.assertIn((u"Found a single student. Found module. "
|
||||
"Deleted student module state for"), msg)
|
||||
self.assertEqual(u'Successfully deleted student state '
|
||||
'for user {}'.format(self.USERNAME), msg)
|
||||
|
||||
def test_student_by_email(self):
|
||||
"""
|
||||
Successfully reset the student attempts using their email address
|
||||
"""
|
||||
staff_page = self._goto_staff_page()
|
||||
staff_page.answer_problem()
|
||||
|
||||
staff_debug_page = staff_page.open_staff_debug_info()
|
||||
staff_debug_page.reset_attempts(self.EMAIL)
|
||||
msg = staff_debug_page.idash_msg[0]
|
||||
self.assertEqual(u'Successfully reset the attempts '
|
||||
'for user {}'.format(self.EMAIL), msg)
|
||||
|
||||
def test_bad_student(self):
|
||||
"""
|
||||
Test negative response with invalid user
|
||||
"""
|
||||
staff_page = self._goto_staff_page()
|
||||
staff_page.answer_problem()
|
||||
|
||||
staff_debug_page = staff_page.open_staff_debug_info()
|
||||
staff_debug_page.delete_state('INVALIDUSER')
|
||||
msg = staff_debug_page.idash_msg[0]
|
||||
self.assertEqual(u'Unsuccessfully deleted student state. '
|
||||
'User does not exist.', msg)
|
||||
|
||||
@@ -6,7 +6,7 @@ describe('StaffDebugActions', function() {
|
||||
describe('get_url ', function() {
|
||||
it('defines url to courseware ajax entry point', function() {
|
||||
spyOn(StaffDebug, "get_current_url").andReturn("/courses/edX/Open_DemoX/edx_demo_course/courseware/stuff");
|
||||
expect(StaffDebug.get_url('instructor')).toBe('/courses/edX/Open_DemoX/edx_demo_course/instructor');
|
||||
expect(StaffDebug.get_url('rescore_problem')).toBe('/courses/edX/Open_DemoX/edx_demo_course/instructor_dashboard/api/rescore_problem');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,21 +26,22 @@ describe('StaffDebugActions', function() {
|
||||
$('#' + fixture_id).remove();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', function() {
|
||||
it('makes an ajax call with the expected parameters', function() {
|
||||
$('body').append(fixture);
|
||||
|
||||
spyOn($, 'ajax');
|
||||
StaffDebug.reset(loc)
|
||||
StaffDebug.reset(loc);
|
||||
|
||||
expect($.ajax.mostRecentCall.args[0]['type']).toEqual('POST');
|
||||
expect($.ajax.mostRecentCall.args[0]['type']).toEqual('GET');
|
||||
expect($.ajax.mostRecentCall.args[0]['data']).toEqual({
|
||||
'action': "Reset student's attempts",
|
||||
'problem_for_student': loc,
|
||||
'unique_student_identifier': 'userman'
|
||||
'problem_to_reset': loc,
|
||||
'unique_student_identifier': 'userman',
|
||||
'delete_module': false
|
||||
});
|
||||
expect($.ajax.mostRecentCall.args[0]['url']).toEqual('/instructor');
|
||||
expect($.ajax.mostRecentCall.args[0]['url']).toEqual(
|
||||
'/instructor_dashboard/api/reset_student_attempts'
|
||||
);
|
||||
$('#' + fixture_id).remove();
|
||||
});
|
||||
});
|
||||
@@ -49,17 +50,40 @@ describe('StaffDebugActions', function() {
|
||||
$('body').append(fixture);
|
||||
|
||||
spyOn($, 'ajax');
|
||||
StaffDebug.sdelete(loc)
|
||||
StaffDebug.sdelete(loc);
|
||||
|
||||
expect($.ajax.mostRecentCall.args[0]['type']).toEqual('POST');
|
||||
expect($.ajax.mostRecentCall.args[0]['type']).toEqual('GET');
|
||||
expect($.ajax.mostRecentCall.args[0]['data']).toEqual({
|
||||
'action': "Delete student state for module",
|
||||
'problem_for_student': loc,
|
||||
'unique_student_identifier': 'userman'
|
||||
'problem_to_reset': loc,
|
||||
'unique_student_identifier': 'userman',
|
||||
'delete_module': true
|
||||
});
|
||||
expect($.ajax.mostRecentCall.args[0]['url']).toEqual('/instructor');
|
||||
expect($.ajax.mostRecentCall.args[0]['url']).toEqual(
|
||||
'/instructor_dashboard/api/reset_student_attempts'
|
||||
);
|
||||
|
||||
$('#' + fixture_id).remove();
|
||||
});
|
||||
});
|
||||
describe('rescore', function() {
|
||||
it('makes an ajax call with the expected parameters', function() {
|
||||
$('body').append(fixture);
|
||||
|
||||
spyOn($, 'ajax');
|
||||
StaffDebug.rescore(loc);
|
||||
|
||||
expect($.ajax.mostRecentCall.args[0]['type']).toEqual('GET');
|
||||
expect($.ajax.mostRecentCall.args[0]['data']).toEqual({
|
||||
'problem_to_reset': loc,
|
||||
'unique_student_identifier': 'userman',
|
||||
'delete_module': false
|
||||
});
|
||||
expect($.ajax.mostRecentCall.args[0]['url']).toEqual(
|
||||
'/instructor_dashboard/api/rescore_problem'
|
||||
);
|
||||
$('#' + fixture_id).remove();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ var StaffDebug = (function(){
|
||||
|
||||
get_url = function(action){
|
||||
var pathname = this.get_current_url();
|
||||
var url = pathname.substr(0,pathname.indexOf('/courseware')) + '/' + action;
|
||||
var url = pathname.substr(0,pathname.indexOf('/courseware')) + '/instructor_dashboard/api/' + action;
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -19,50 +19,89 @@ var StaffDebug = (function(){
|
||||
return uname;
|
||||
}
|
||||
|
||||
do_idash_action = function(locname, idaction){
|
||||
do_idash_action = function(action){
|
||||
var pdata = {
|
||||
'action': idaction,
|
||||
'problem_for_student': locname,
|
||||
'unique_student_identifier': get_user(locname)
|
||||
'problem_to_reset': action.location,
|
||||
'unique_student_identifier': get_user(action.location),
|
||||
'delete_module': action.delete_module
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: get_url('instructor'),
|
||||
type: "GET",
|
||||
url: get_url(action.method),
|
||||
data: pdata,
|
||||
success: function(data){
|
||||
var msg = $("#idash_msg", data);
|
||||
$("#result_" + locname).html( msg );
|
||||
},
|
||||
error: function(request, status, error) {
|
||||
var text = _.template(
|
||||
gettext('Something has gone wrong with this request. \
|
||||
The server replied with a status of: {error}'),
|
||||
{error: error},
|
||||
gettext('Successfully {action} for user {user}'),
|
||||
{
|
||||
action: action.description,
|
||||
user: data.student
|
||||
},
|
||||
{interpolate: /\{(.+?)\}/g}
|
||||
)
|
||||
var html = _.template(
|
||||
'<p id="idash_msg"><font color="red">{text}</font></p>',
|
||||
'<p id="idash_msg" class="success">{text}</p>',
|
||||
{text: text},
|
||||
{interpolate: /\{(.+?)\}/g}
|
||||
)
|
||||
$("#result_"+locname).html(html);
|
||||
$("#result_"+action.location).html(html);
|
||||
},
|
||||
dataType: 'html'
|
||||
error: function(request, status, error) {
|
||||
var response_json;
|
||||
try {
|
||||
response_json = $.parseJSON(request.responseText);
|
||||
} catch(e) {
|
||||
response_json = { error: gettext('Unknown Error Occurred.') };
|
||||
}
|
||||
var text = _.template(
|
||||
gettext('Unsuccessfully {action}. {error}'),
|
||||
{
|
||||
error: response_json.error,
|
||||
action: action.description
|
||||
},
|
||||
{interpolate: /\{(.+?)\}/g}
|
||||
)
|
||||
var html = _.template(
|
||||
'<p id="idash_msg" class="error">{text}</p>',
|
||||
{text: text},
|
||||
{interpolate: /\{(.+?)\}/g}
|
||||
)
|
||||
$("#result_"+action.location).html(html);
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
}
|
||||
|
||||
reset = function(locname){
|
||||
do_idash_action(locname, "Reset student's attempts");
|
||||
this.do_idash_action({
|
||||
location: locname,
|
||||
method: 'reset_student_attempts',
|
||||
description: gettext('reset the attempts'),
|
||||
delete_module: false
|
||||
});
|
||||
}
|
||||
|
||||
sdelete = function(locname){
|
||||
do_idash_action(locname, "Delete student state for module");
|
||||
this.do_idash_action({
|
||||
location: locname,
|
||||
method: 'reset_student_attempts',
|
||||
description: gettext('deleted student state'),
|
||||
delete_module: true
|
||||
});
|
||||
}
|
||||
|
||||
rescore = function(locname){
|
||||
this.do_idash_action({
|
||||
location: locname,
|
||||
method: 'rescore_problem',
|
||||
description: gettext('rescored problem'),
|
||||
delete_module: false
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
reset: reset,
|
||||
sdelete: sdelete,
|
||||
rescore: rescore,
|
||||
do_idash_action: do_idash_action,
|
||||
get_current_url: get_current_url,
|
||||
get_url: get_url,
|
||||
@@ -80,4 +119,8 @@ $(document).ready(function() {
|
||||
StaffDebug.sdelete($(this).data('location'));
|
||||
return false;
|
||||
});
|
||||
$('#staff-debug-rescore').click(function() {
|
||||
StaffDebug.rescore($(this).data('location'));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -191,6 +191,15 @@ div.course-wrapper {
|
||||
}
|
||||
}
|
||||
|
||||
div.staff_actions {
|
||||
p.error {
|
||||
color: $error-red
|
||||
}
|
||||
p.success {
|
||||
color: $success-color;
|
||||
}
|
||||
}
|
||||
|
||||
div.staff_info {
|
||||
display: none;
|
||||
@include clearfix();
|
||||
|
||||
@@ -54,20 +54,25 @@ ${block_content}
|
||||
<h2>${_('Staff Debug')}</h2>
|
||||
</header>
|
||||
|
||||
<hr />
|
||||
<h3>${_('Actions')}</h3>
|
||||
<div>
|
||||
<label for="sd_fu_${location.name}">${_('For User')}:</label>
|
||||
<input type="text" id="sd_fu_${location.name}" placeholder="${user.username}"/>
|
||||
</div>
|
||||
<div>
|
||||
[
|
||||
<a href="#" id="staff-debug-reset" data-location="${location.name}">${_('Reset Student Attempts')}</a>
|
||||
|
|
||||
<a href="#" id="staff-debug-sdelete" data-location="${location.name}">${_('Delete Student State')}</a>
|
||||
]
|
||||
</div>
|
||||
<div id="result_${location.name}"/>
|
||||
<hr />
|
||||
<div class="staff_actions">
|
||||
<h3>${_('Actions')}</h3>
|
||||
<div>
|
||||
<label for="sd_fu_${location.name}">${_('Username')}:</label>
|
||||
<input type="text" id="sd_fu_${location.name}" placeholder="${user.username}"/>
|
||||
</div>
|
||||
<div>
|
||||
[
|
||||
<a href="#" id="staff-debug-reset" data-location="${location.name}">${_('Reset Student Attempts')}</a>
|
||||
|
|
||||
<a href="#" id="staff-debug-sdelete" data-location="${location.name}">${_('Delete Student State')}</a>
|
||||
|
|
||||
<a href="#" id="staff-debug-rescore" data-location="${location.name}">${_('Rescore Student Submission')}</a>
|
||||
|
||||
]
|
||||
</div>
|
||||
<div id="result_${location.name}"/>
|
||||
</div>
|
||||
|
||||
<div class="staff_info" style="display:block">
|
||||
is_released = ${is_released}
|
||||
|
||||
Reference in New Issue
Block a user