Commit 1fdd12a0 by Justin Riley

add 'Submission History' to proctor admin panel

Staff users can now navigate to a problem, click 'Proctor Submission
History' button in the proctor admin panel, type a username and view
the user's attempts for each problem they've attempted within the
problem bank.
parent fc7a3767
...@@ -219,6 +219,10 @@ class ProctorModule(ProctorFields, XModule): ...@@ -219,6 +219,10 @@ class ProctorModule(ProctorFields, XModule):
username = data.get("username") username = data.get("username")
wipe_history = data.get("wipe_history") == "on" wipe_history = data.get("wipe_history") == "on"
return self.reset(username, wipe_history=wipe_history) return self.reset(username, wipe_history=wipe_history)
if dispatch == 'submission_history':
username = data.get("username")
return self.submission_history(username)
#if dispatch == 'status': #if dispatch == 'status':
#return self.status() #return self.status()
# if dispatch == 'grades': # if dispatch == 'grades':
...@@ -259,6 +263,29 @@ class ProctorModule(ProctorFields, XModule): ...@@ -259,6 +263,29 @@ class ProctorModule(ProctorFields, XModule):
'error': True, 'errstr': str(err)} 'error': True, 'errstr': str(err)}
return json.dumps(status) return json.dumps(status)
def submission_history(self, username):
try:
pminfo = module_tree_reset.ProctorModuleInfo(self.runtime.course_id)
pset = self.get_children()[0]
rand = pset.get_children()[0]
locations = [i.location.url() for i in rand.get_children()]
shist = pminfo.submission_history(username, locations)
entries = shist.get('history_entries')
status = []
for e in entries:
state = json.loads(e.state)
status.append(dict(location=e.student_module.module_state_key,
attempt=state['attempts'],
created=str(e.created),
grade=e.grade,
max_grade=e.max_grade,
answers=state['student_answers']))
except Exception as err:
log.exception("Failed to get status for %s" % username)
status = {'msg': 'Error getting grades for %s' % username,
'error': True, 'errstr': str(err)}
return json.dumps(status)
# TODO: investigate whether this is needed or not # TODO: investigate whether this is needed or not
# #
# def grades(self): # def grades(self):
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
<% override_label = "On" if staff_release else "Off" %> <% override_label = "On" if staff_release else "Off" %>
<div aria-hidden="true" class="wrap-instructor-info"> <div aria-hidden="true" class="wrap-instructor-info">
<a class="instructor-info-action" href="#proctor_admin_${element_id}" id="proctor_admin" rel="leanModal">${_("Proctor Student Admin")}</a> <a class="instructor-info-action" href="#proctor_admin_${element_id}" id="proctor_admin" rel="leanModal">${_("Proctor Student Admin")}</a>
<a class="instructor-info-action" href="#proctor_history_${element_id}" id="proctor_history" rel="leanModal">${_("Proctor Submission History")}</a>
<a class="instructor-info-action" href="#proctor_release_${element_id}" id="proctor_override">${_("Proctor Override")}: <b>${_(override_label)}</b></a> <a class="instructor-info-action" href="#proctor_release_${element_id}" id="proctor_override">${_("Proctor Override")}: <b>${_(override_label)}</b></a>
</div> </div>
<hr/> <hr/>
...@@ -28,6 +29,24 @@ ...@@ -28,6 +29,24 @@
</div> </div>
</section> </section>
<section aria-hidden="true" class="modal history-modal" id="proctor_history_${element_id}" style="width:80%; left:20%; height:80%; overflow:auto;" >
<div class="inner-wrapper" style="color:black">
<header>
<h2>${_("Proctor Submission History")}</h2>
</header>
<form id="proctor_${element_id}_history_form">
<label for="proctor_${element_id}_student_username_hist">${_("User:")}</label>
<input name="username" id="proctor_${element_id}_student_username_hist" type="text" placeholder=""/>
<input name="location" type="hidden" id="proctor_${element_id}_hist_location" value="${location}"/>
<div class="submit">
<button id="proctor_${element_id}_hist_submit" name="submit" type="submit">${_("Fetch Submission History")}</button>
</div>
</form>
<div id="proctor_${element_id}_hist_text" class="staff_info" style="display:block">
</div>
</div>
</section>
<script type="text/javascript"> <script type="text/javascript">
proctor_override = function(){ proctor_override = function(){
var data = {enabled: "${not staff_release}"}; var data = {enabled: "${not staff_release}"};
...@@ -37,39 +56,75 @@ proctor_override = function(){ ...@@ -37,39 +56,75 @@ proctor_override = function(){
} }
$('#proctor_override').click(proctor_override); $('#proctor_override').click(proctor_override);
$('#proctor_${element_id}_reset_form').submit(function(e) { setup_form = function(url, form_el, uname_el, submit_el, text_el, success){
e.preventDefault(); var submit_text = submit_el.html()
$('#proctor_${element_id}_submit').attr("disabled", true);
$('#proctor_${element_id}_submit').html('${_("Processing, please wait...")}'); form_el.submit(function(e) {
$('#proctor_${element_id}_text').html(""); e.preventDefault();
$.ajax({ submit_el.attr("disabled", true);
url: '${ajax_url}/reset', submit_el.html('${_("Processing, please wait...")}');
type: 'POST', text_el.html("");
dataType: 'json', $.ajax({
data: $('#proctor_${element_id}_reset_form').serialize(), url: url,
success: function(data) { type: 'POST',
var msg = ''; dataType: 'json',
if ('error' in data) { data: form_el.serialize(),
msg = "ERROR: " + data['error']; success: success,
} else { error: function(xhr, stat, error){
var uname = $('#proctor_${element_id}_student_username').val(); console.debug(xhr);
msg = "Successfully reset attempts for user: " + uname; console.debug(stat);
} console.debug(error);
$('#proctor_${element_id}_text').html(msg); text_el.html('FATAL: ' + error);
}, },
error: function(xhr, stat, error){ complete: function(){
console.debug(xhr); submit_el.removeAttr("disabled");
console.debug(stat); submit_el.html(submit_text);
console.debug(error); },
$('#proctor_${element_id}_text').html('FATAL: ' + error); });
}, return false;
complete: function(){
$('#proctor_${element_id}_submit').removeAttr("disabled");
$('#proctor_${element_id}_submit').html('${_("Reset Attempts")}');
},
}); });
return false; }
});
reset_success = function(data) {
var text_el = $('#proctor_${element_id}_text');
var uname_el = $('#proctor_${element_id}_student_username');
var msg = '';
if ('error' in data) {
msg = "ERROR: " + data['error'];
} else {
var uname = uname_el.val();
msg = "Successfully reset attempts for user: " + uname;
}
text_el.html(msg);
}
setup_form('${ajax_url}/reset',
$('#proctor_${element_id}_reset_form'),
$('#proctor_${element_id}_student_username'),
$('#proctor_${element_id}_submit'),
$('#proctor_${element_id}_text'),
reset_success);
hist_success = function(data) {
var text_el = $('#proctor_${element_id}_hist_text');
var uname_el = $('#proctor_${element_id}_student_username_hist');
var msg = '';
if ('error' in data) {
msg = "ERROR: " + data['error'];
} else {
var uname = uname_el.val();
msg = "Submission history for " + uname + ":\n" + JSON.stringify(data, undefined, 2);
}
text_el.html(msg);
}
setup_form('${ajax_url}/submission_history',
$('#proctor_${element_id}_history_form'),
$('#proctor_${element_id}_student_username_hist'),
$('#proctor_${element_id}_hist_submit'),
$('#proctor_${element_id}_hist_text'),
hist_success);
</script> </script>
% endif % endif
......
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