Commit 8d3fb7fd by Justin Riley

only reset current problem by default in proctor admin

The reset attempts web interface now defaults to only resetting the
current problem. Added "Reset all problems" check box to the reset
attempts form in the 'Proctor Student Admin' interface to enable
resetting *all* problems for a single user.
parent dfa6e4c3
...@@ -223,7 +223,9 @@ class ProctorModule(ProctorFields, XModule): ...@@ -223,7 +223,9 @@ class ProctorModule(ProctorFields, XModule):
if dispatch == 'reset': if dispatch == 'reset':
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) all_problems = data.get("all_problems") == "on"
return self.reset(username, all_problems=all_problems,
wipe_history=wipe_history)
if dispatch == 'submission_history': if dispatch == 'submission_history':
username = data.get("username") username = data.get("username")
return self.submission_history(username) return self.submission_history(username)
...@@ -246,11 +248,15 @@ class ProctorModule(ProctorFields, XModule): ...@@ -246,11 +248,15 @@ class ProctorModule(ProctorFields, XModule):
def get_icon_class(self): def get_icon_class(self):
return self.child.get_icon_class() if self.child else 'other' return self.child.get_icon_class() if self.child else 'other'
def reset(self, username, wipe_history=False): def reset(self, username, all_problems=False, wipe_history=False):
try: try:
pminfo = module_tree_reset.ProctorModuleInfo(self.runtime.course_id) pminfo = module_tree_reset.ProctorModuleInfo(self.runtime.course_id)
pminfo.get_assignments_attempted_and_failed( if all_problems:
username, reset=True, wipe_randomize_history=wipe_history) pminfo.get_assignments_attempted_and_failed(
username, reset=True, wipe_randomize_history=wipe_history)
else:
pminfo.proctor_reset(username, self.location.url(),
wipe_randomize_history=wipe_history)
return self.status(username) return self.status(username)
except Exception: except Exception:
return json.dumps({"error": traceback.format_exc()}) return json.dumps({"error": traceback.format_exc()})
......
#!/usr/bin/python #!/usr/bin/python
import csv import csv
import datetime
from collections import OrderedDict
from courseware.module_tree_reset import ProctorModuleInfo from courseware.module_tree_reset import ProctorModuleInfo
...@@ -43,12 +45,23 @@ arguments.""" ...@@ -43,12 +45,23 @@ arguments."""
courseenrollment__course_id=pminfo.course.id).order_by('username') courseenrollment__course_id=pminfo.course.id).order_by('username')
failed = [] failed = []
for student in students: for student in students:
failed += pminfo.get_assignments_attempted_and_failed( failed += [self._get_od_for_assignment(student, i) for i in
student, reset=not dry_run, pminfo.get_assignments_attempted_and_failed(
wipe_randomize_history=wipe_history) student, reset=not dry_run,
wipe_randomize_history=wipe_history)]
if csv_file: if csv_file:
self.write_to_csv(csv_file, failed) self.write_to_csv(csv_file, failed)
def _get_od_for_assignment(self, student, assignment):
return OrderedDict(id=student.id,
name=student.profile.name,
username=student.username,
assignment=assignment['name'],
problem=assignment['problem'],
date=str(datetime.datetime.now()),
earned=assignment['earned'],
possible=assignment['possible'])
def write_to_csv(self, file_name, failed_assignments): def write_to_csv(self, file_name, failed_assignments):
fieldnames = ['id', 'name', 'username', 'assignment', 'problem', fieldnames = ['id', 'name', 'username', 'assignment', 'problem',
'date', 'earned', 'possible'] 'date', 'earned', 'possible']
......
...@@ -11,11 +11,10 @@ from django.conf import settings ...@@ -11,11 +11,10 @@ from django.conf import settings
from django.dispatch import Signal from django.dispatch import Signal
from django.core.cache import get_cache from django.core.cache import get_cache
from xmodule.modulestore import Location
from courseware.models import StudentModule, StudentModuleHistory
from request_cache.middleware import RequestCache from request_cache.middleware import RequestCache
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from instructor.offline_gradecalc import student_grades from instructor.offline_gradecalc import student_grades
from courseware.models import StudentModule, StudentModuleHistory
log = logging.getLogger("mitx.module_tree_reset") log = logging.getLogger("mitx.module_tree_reset")
...@@ -42,13 +41,13 @@ class TreeNode(object): ...@@ -42,13 +41,13 @@ class TreeNode(object):
try: try:
self.smstate = StudentModule.objects.get( self.smstate = StudentModule.objects.get(
course_id=self.course_id, course_id=self.course_id,
module_state_key=str(self.module.location), module_state_key=self.module.location.url(),
student=student) student=student)
except StudentModule.DoesNotExist: except StudentModule.DoesNotExist:
pass pass
def __str__(self): def __str__(self):
s = "-" * self.level + ("> %s" % str(self.module.location)) s = "-" * self.level + ("> %s" % self.module.location.url())
s += ' (%s)' % self.module.display_name s += ' (%s)' % self.module.display_name
if self.smstate is not None: if self.smstate is not None:
...@@ -218,7 +217,7 @@ class ProctorModuleInfo(object): ...@@ -218,7 +217,7 @@ class ProctorModuleInfo(object):
for rpmod in self.rpmods: for rpmod in self.rpmods:
try: try:
sm = StudentModule.objects.get( sm = StudentModule.objects.get(
module_state_key=str(rpmod.ra_rand.location), module_state_key=rpmod.ra_rand.location.url(),
course_id=self.course.id, course_id=self.course.id,
student=student) # randomize state student=student) # randomize state
except StudentModule.DoesNotExist: except StudentModule.DoesNotExist:
...@@ -226,7 +225,7 @@ class ProctorModuleInfo(object): ...@@ -226,7 +225,7 @@ class ProctorModuleInfo(object):
sm.rpmod = rpmod sm.rpmod = rpmod
try: try:
ps_sm = StudentModule.objects.get( ps_sm = StudentModule.objects.get(
module_state_key=str(rpmod.ra_ps.location), module_state_key=rpmod.ra_ps.location.url(),
course_id=self.course.id, course_id=self.course.id,
student=student) # problemset state student=student) # problemset state
except StudentModule.DoesNotExist: except StudentModule.DoesNotExist:
...@@ -277,7 +276,7 @@ class ProctorModuleInfo(object): ...@@ -277,7 +276,7 @@ class ProctorModuleInfo(object):
s = 'State for student %s:\n' % student s = 'State for student %s:\n' % student
status = {} # this can be turned into a JSON str for the proctor panel status = {} # this can be turned into a JSON str for the proctor panel
status['student'] = dict(username=str(student), status['student'] = dict(username=student.username,
name=student.profile.name, id=student.id) name=student.profile.name, id=student.id)
status['assignments'] = [] status['assignments'] = []
...@@ -303,7 +302,8 @@ class ProctorModuleInfo(object): ...@@ -303,7 +302,8 @@ class ProctorModuleInfo(object):
attempted=attempted, attempted=attempted,
visited=visited, visited=visited,
earned=earned, earned=earned,
possible=possible) possible=possible,
proctor_loc=sm.rpmod.location.url())
status['assignments'].append(stat) status['assignments'].append(stat)
s += "[%s] %s -> %s (%s) %s [%s]\n" % (name, stat['assignment'], s += "[%s] %s -> %s (%s) %s [%s]\n" % (name, stat['assignment'],
stat['pm_sm'], sm.choice, stat['pm_sm'], sm.choice,
...@@ -336,43 +336,42 @@ class ProctorModuleInfo(object): ...@@ -336,43 +336,42 @@ class ProctorModuleInfo(object):
ret["grade_%s" % stat['name']] = '' ret["grade_%s" % stat['name']] = ''
return ret return ret
def _get_od_for_assignment(self, student, assignment): def proctor_reset(self, student, proctor_loc,
return OrderedDict(id=student.id, wipe_randomize_history=False, student_status=None):
name=student.profile.name, student = self._get_student_obj(student)
username=student.username, status = student_status or self.get_student_status(student)
assignment=assignment['name'], assignments = status['assignments']
problem=assignment['problem'], try:
date=str(datetime.datetime.now()), ass = [i for i in assignments if i['proctor_loc'] == proctor_loc]
earned=assignment['earned'], assert len(ass) == 1
possible=assignment['possible']) ass = ass.pop()
except AssertionError:
raise Exception("proctor_loc = %s not found!" % proctor_loc)
if ass['visited'] and ass['earned'] != ass['possible']:
log.info('Resetting %s for student %s' %
(ass['name'], student.username))
pmod = self.ms.get_instance(self.course.id, proctor_loc)
tnset = TreeNodeSet(self.course.id, pmod, self.ms, student)
msg = tnset.reset_randomization(wipe_history=wipe_randomize_history)
log.debug(msg)
return msg
def get_assignments_attempted_and_failed(self, student, reset=False, def get_assignments_attempted_and_failed(self, student, reset=False,
wipe_randomize_history=False): wipe_randomize_history=False):
student = self._get_student_obj(student) student = self._get_student_obj(student)
status = self.get_student_status(student) status = self.get_student_status(student)
failed = [self._get_od_for_assignment(student, a) failed = [a for a in status['assignments'] if a['visited'] and
for a in status['assignments'] a['earned'] != a['possible']]
if a['visited'] and a['earned'] != a['possible']]
for f in failed: for f in failed:
log.info( log.info(
"Student %s Assignment %s attempted '%s' but failed " "Student %s Assignment %s attempted '%s' but failed "
"(%s/%s)" % (student, f['assignment'], f['problem'], "(%s/%s)" % (student.username, f['name'], f['problem'],
f['earned'], f['possible'])) f['earned'], f['possible']))
if reset: if reset:
try: try:
log.info('resetting %s for student %s' % self.proctor_reset(
(f['assignment'], f['username'])) student, f['proctor_loc'], student_status=status,
cloc = self.course.location wipe_randomize_history=wipe_randomize_history)
assi_url = Location(cloc.tag, cloc.org,
cloc.course, 'proctor',
f['assignment'])
pmod = self.ms.get_instance(self.course.id,
assi_url.url())
tnset = TreeNodeSet(self.course.id, pmod, self.ms,
student)
msg = tnset.reset_randomization(
wipe_history=wipe_randomize_history)
log.debug(str(msg))
except Exception: except Exception:
log.exception("Failed to do reset of %s for %s" % log.exception("Failed to do reset of %s for %s" %
(f['assignment'], student)) (f['assignment'], student))
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
<form id="proctor_${element_id}_reset_form"> <form id="proctor_${element_id}_reset_form">
<label for="proctor_${element_id}_student_username">${_("User:")}</label> <label for="proctor_${element_id}_student_username">${_("User:")}</label>
<input name="username" id="proctor_${element_id}_student_username" type="text" placeholder=""/> <input name="username" id="proctor_${element_id}_student_username" type="text" placeholder=""/>
<input name="all_problems" id="proctor_${element_id}_all_problems" type="checkbox"/> Reset all problems?<br/>
<input name="wipe_history" id="proctor_${element_id}_wipe_history" type="checkbox"/> Wipe randomize history? <input name="wipe_history" id="proctor_${element_id}_wipe_history" type="checkbox"/> Wipe randomize history?
<input name="location" type="hidden" id="proctor_${element_id}_reset_location" value="${location}"/> <input name="location" type="hidden" id="proctor_${element_id}_reset_location" value="${location}"/>
<div class="submit"> <div class="submit">
......
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