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 ( ...@@ -67,6 +67,7 @@ from .tools import (
set_due_date_extension, set_due_date_extension,
strip_if_string, strip_if_string,
bulk_email_is_enabled_for_course, bulk_email_is_enabled_for_course,
fix_missing_extensions,
) )
from xmodule.modulestore import Location from xmodule.modulestore import Location
...@@ -1233,6 +1234,19 @@ def reset_due_date(request, course_id): ...@@ -1233,6 +1234,19 @@ def reset_due_date(request, course_id):
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff') @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') @require_query_params('url')
def show_unit_extensions(request, course_id): def show_unit_extensions(request, course_id):
""" """
......
...@@ -47,6 +47,8 @@ urlpatterns = patterns('', # nopep8 ...@@ -47,6 +47,8 @@ urlpatterns = patterns('', # nopep8
name='show_unit_extensions'), name='show_unit_extensions'),
url(r'^show_student_extensions$', 'instructor.views.api.show_student_extensions', url(r'^show_student_extensions$', 'instructor.views.api.show_student_extensions',
name='show_student_extensions'), name='show_student_extensions'),
url(r'^fix_extensions$', 'instructor.views.api.fix_extensions',
name='fix_extensions'),
# Grade downloads... # Grade downloads...
url(r'^list_report_downloads$', url(r'^list_report_downloads$',
......
...@@ -190,6 +190,7 @@ def _section_extensions(course): ...@@ -190,6 +190,7 @@ def _section_extensions(course):
'reset_due_date_url': reverse('reset_due_date', kwargs={'course_id': course.id}), '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_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}), '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 return section_data
......
""" """
Tools for the instructor dashboard Tools for the instructor dashboard
""" """
import dateutil
import json import json
import dateutil
import itertools
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
...@@ -251,3 +252,30 @@ def dump_student_extensions(course, student): ...@@ -251,3 +252,30 @@ def dump_student_extensions(course, student):
"title": _("Due date extensions for {0} {1} ({2})").format( "title": _("Due date extensions for {0} {1} ({2})").format(
student.first_name, student.last_name, student.username), student.first_name, student.last_name, student.username),
"data": data} "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 ...@@ -23,6 +23,7 @@ class Extensions
@$reset_due_date = @$section.find("input[name='reset-due-date']") @$reset_due_date = @$section.find("input[name='reset-due-date']")
@$show_unit_extensions = @$section.find("input[name='show-unit-extensions']") @$show_unit_extensions = @$section.find("input[name='show-unit-extensions']")
@$show_student_extensions = @$section.find("input[name='show-student-extensions']") @$show_student_extensions = @$section.find("input[name='show-student-extensions']")
@$fix_extensions = @$section.find("input[name='fix-extensions']")
# Gather notification areas # Gather notification areas
@$section.find(".request-response").hide() @$section.find(".request-response").hide()
...@@ -66,6 +67,16 @@ class Extensions ...@@ -66,6 +67,16 @@ class Extensions
success: (data) => @display_response "reset-extension", data success: (data) => @display_response "reset-extension", data
error: (xhr) => @fail_with_error "reset-extension", "Error reseting due date", xhr 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 => @$show_unit_extensions.click =>
@clear_display() @clear_display()
@$grid_table.text 'Loading...' @$grid_table.text 'Loading...'
......
...@@ -110,3 +110,18 @@ ...@@ -110,3 +110,18 @@
</p> </p>
</div> </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