Commit d7d6f54c by Justin Riley

add fix extensions button to extensions dashboard

If a student was granted an extension on a problem bank and a new
problem gets added to the bank the new problem doesn't inherit the
extensions.  This button is a stop-gap solution to re-apply all of the
extensions to the new problem.
parent 69793068
......@@ -67,6 +67,7 @@ from .tools import (
set_due_date_extension,
strip_if_string,
bulk_email_is_enabled_for_course,
fix_missing_extensions,
)
from xmodule.modulestore import Location
......@@ -1233,6 +1234,19 @@ def reset_due_date(request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
def fix_extensions(request, course_id):
"""
Fix any <problems> missing their parent's 'extended_due'
"""
course = get_course_by_id(course_id)
fix_missing_extensions(course)
return JsonResponse(_('Successfully repaired extensions'))
@handle_dashboard_error
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_query_params('url')
def show_unit_extensions(request, course_id):
"""
......
......@@ -47,6 +47,8 @@ urlpatterns = patterns('', # nopep8
name='show_unit_extensions'),
url(r'^show_student_extensions$', 'instructor.views.api.show_student_extensions',
name='show_student_extensions'),
url(r'^fix_extensions$', 'instructor.views.api.fix_extensions',
name='fix_extensions'),
# Grade downloads...
url(r'^list_report_downloads$',
......
......@@ -190,6 +190,7 @@ def _section_extensions(course):
'reset_due_date_url': reverse('reset_due_date', kwargs={'course_id': course.id}),
'show_unit_extensions_url': reverse('show_unit_extensions', kwargs={'course_id': course.id}),
'show_student_extensions_url': reverse('show_student_extensions', kwargs={'course_id': course.id}),
'fix_extensions_url': reverse('fix_extensions', kwargs={'course_id': course.id}),
}
return section_data
......
"""
Tools for the instructor dashboard
"""
import dateutil
import json
import dateutil
import itertools
from django.conf import settings
from django.contrib.auth.models import User
......@@ -251,3 +252,30 @@ def dump_student_extensions(course, student):
"title": _("Due date extensions for {0} {1} ({2})").format(
student.first_name, student.last_name, student.username),
"data": data}
def fix_missing_extensions(course):
units = get_units_with_due_date(course)
units = dict([(u.location.url(), u) for u in units])
msks = units.keys()
query = StudentModule.objects.filter(
course_id=course.id,
module_state_key__in=msks,
state__contains='extended_due'
)
eunit_map = itertools.groupby(query, lambda el: el.student)
reapplied = {}
for student, extended_modules in eunit_map:
for module in extended_modules:
state = json.loads(module.state)
edue = DATE_FIELD.from_json(state.get('extended_due'))
if not edue:
continue
unit = units.get(module.module_state_key)
print('reapplying extension %s to %s for user %s' %
(edue, unit.location.url(), student.username))
set_due_date_extension(course, unit, student, edue)
r = reapplied.get(student.username, [])
r.append(unit.location.url())
reapplied[student.username] = r
return reapplied
......@@ -23,6 +23,7 @@ class Extensions
@$reset_due_date = @$section.find("input[name='reset-due-date']")
@$show_unit_extensions = @$section.find("input[name='show-unit-extensions']")
@$show_student_extensions = @$section.find("input[name='show-student-extensions']")
@$fix_extensions = @$section.find("input[name='fix-extensions']")
# Gather notification areas
@$section.find(".request-response").hide()
......@@ -66,6 +67,16 @@ class Extensions
success: (data) => @display_response "reset-extension", data
error: (xhr) => @fail_with_error "reset-extension", "Error reseting due date", xhr
@$fix_extensions.click =>
@clear_display()
send_data = {}
$.ajax
dataType: 'json'
url: @$fix_extensions.data 'endpoint'
data: send_data
success: (data) => @display_response "fix-extensions", data
error: (xhr) => @fail_with_error "fix-extensions", "Error fixing extensions", xhr
@$show_unit_extensions.click =>
@clear_display()
@$grid_table.text 'Loading...'
......
......@@ -110,3 +110,18 @@
</p>
</div>
<hr/>
<div id="fix-extensions">
<h2>${_("Fix extensions")}</h2>
<p>
${_("Newly added problems currently do not inherit the extended_due "
"property from it's parent. The button below fixes this issue.")}
</p>
<p class="request-response"></p>
<p class="request-response-error"></p>
<p>
<input type="button" name="fix-extensions"
value="${_("Fix extensions")}"
data-endpoint="${section_data['fix_extensions_url']}">
</p>
</div>
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