Merge pull request #12723 from edx/release
Merge hotfix-2016-06-10 release into master
This commit is contained in:
@@ -140,51 +140,14 @@ def common_exceptions_400(func):
|
||||
return wrapped
|
||||
|
||||
|
||||
def require_query_params(*args, **kwargs):
|
||||
"""
|
||||
Checks for required paremters or renders a 400 error.
|
||||
(decorator with arguments)
|
||||
|
||||
`args` is a *list of required GET parameter names.
|
||||
`kwargs` is a **dict of required GET parameter names
|
||||
to string explanations of the parameter
|
||||
"""
|
||||
required_params = []
|
||||
required_params += [(arg, None) for arg in args]
|
||||
required_params += [(key, kwargs[key]) for key in kwargs]
|
||||
# required_params = e.g. [('action', 'enroll or unenroll'), ['emails', None]]
|
||||
|
||||
def decorator(func): # pylint: disable=missing-docstring
|
||||
def wrapped(*args, **kwargs): # pylint: disable=missing-docstring
|
||||
request = args[0]
|
||||
|
||||
error_response_data = {
|
||||
'error': 'Missing required query parameter(s)',
|
||||
'parameters': [],
|
||||
'info': {},
|
||||
}
|
||||
|
||||
for (param, extra) in required_params:
|
||||
default = object()
|
||||
if request.GET.get(param, default) == default:
|
||||
error_response_data['parameters'].append(param)
|
||||
error_response_data['info'][param] = extra
|
||||
|
||||
if len(error_response_data['parameters']) > 0:
|
||||
return JsonResponse(error_response_data, status=400)
|
||||
else:
|
||||
return func(*args, **kwargs)
|
||||
return wrapped
|
||||
return decorator
|
||||
|
||||
|
||||
def require_post_params(*args, **kwargs):
|
||||
"""
|
||||
Checks for required parameters or renders a 400 error.
|
||||
(decorator with arguments)
|
||||
|
||||
Functions like 'require_query_params', but checks for
|
||||
POST parameters rather than GET parameters.
|
||||
`args` is a *list of required POST parameter names.
|
||||
`kwargs` is a **dict of required POST parameter names
|
||||
to string explanations of the parameter
|
||||
"""
|
||||
required_params = []
|
||||
required_params += [(arg, None) for arg in args]
|
||||
@@ -314,6 +277,7 @@ NAME_INDEX = 2
|
||||
COUNTRY_INDEX = 3
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -604,6 +568,7 @@ def create_and_enroll_user(email, username, name, country, password, course_id,
|
||||
return errors
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -768,6 +733,7 @@ def students_update_enrollment(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('instructor')
|
||||
@@ -848,11 +814,12 @@ def bulk_beta_modify_access(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('instructor')
|
||||
@common_exceptions_400
|
||||
@require_query_params(
|
||||
@require_post_params(
|
||||
unique_student_identifier="email or username of user to change access",
|
||||
rolename="'instructor', 'staff', 'beta', or 'ccx_coach'",
|
||||
action="'allow' or 'revoke'"
|
||||
@@ -874,10 +841,10 @@ def modify_access(request, course_id):
|
||||
request.user, 'instructor', course_id, depth=None
|
||||
)
|
||||
try:
|
||||
user = get_student_from_identifier(request.GET.get('unique_student_identifier'))
|
||||
user = get_student_from_identifier(request.POST.get('unique_student_identifier'))
|
||||
except User.DoesNotExist:
|
||||
response_payload = {
|
||||
'unique_student_identifier': request.GET.get('unique_student_identifier'),
|
||||
'unique_student_identifier': request.POST.get('unique_student_identifier'),
|
||||
'userDoesNotExist': True,
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
@@ -892,8 +859,8 @@ def modify_access(request, course_id):
|
||||
}
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
rolename = request.GET.get('rolename')
|
||||
action = request.GET.get('action')
|
||||
rolename = request.POST.get('rolename')
|
||||
action = request.POST.get('action')
|
||||
|
||||
if rolename not in ROLES:
|
||||
error = strip_tags("unknown rolename '{}'".format(rolename))
|
||||
@@ -928,10 +895,11 @@ def modify_access(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('instructor')
|
||||
@require_query_params(rolename="'instructor', 'staff', or 'beta'")
|
||||
@require_post_params(rolename="'instructor', 'staff', or 'beta'")
|
||||
def list_course_role_members(request, course_id):
|
||||
"""
|
||||
List instructors and staff.
|
||||
@@ -956,7 +924,7 @@ def list_course_role_members(request, course_id):
|
||||
request.user, 'instructor', course_id, depth=None
|
||||
)
|
||||
|
||||
rolename = request.GET.get('rolename')
|
||||
rolename = request.POST.get('rolename')
|
||||
|
||||
if rolename not in ROLES:
|
||||
return HttpResponseBadRequest()
|
||||
@@ -980,6 +948,7 @@ def list_course_role_members(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -996,7 +965,7 @@ def get_problem_responses(request, course_id):
|
||||
Responds with BadRequest if problem location is faulty.
|
||||
"""
|
||||
course_key = CourseKey.from_string(course_id)
|
||||
problem_location = request.GET.get('problem_location', '')
|
||||
problem_location = request.POST.get('problem_location', '')
|
||||
|
||||
try:
|
||||
problem_key = UsageKey.from_string(problem_location)
|
||||
@@ -1025,6 +994,7 @@ def get_problem_responses(request, course_id):
|
||||
return JsonResponse({"status": already_running_status})
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -1223,6 +1193,7 @@ def get_issued_certificates(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -1315,6 +1286,7 @@ def get_students_features(request, course_id, csv=False): # pylint: disable=red
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -1422,6 +1394,7 @@ def get_coupon_codes(request, course_id): # pylint: disable=unused-argument
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -1446,6 +1419,7 @@ def get_enrollment_report(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -1471,6 +1445,7 @@ def get_exec_summary_report(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -1495,6 +1470,7 @@ def get_course_survey_results(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -1901,11 +1877,12 @@ def get_anon_ids(request, course_id): # pylint: disable=unused-argument
|
||||
return csv_response(course_id.to_deprecated_string().replace('/', '-') + '-anon-ids.csv', header, rows)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@common_exceptions_400
|
||||
@require_level('staff')
|
||||
@require_query_params(
|
||||
@require_post_params(
|
||||
unique_student_identifier="email or username of student for whom to get progress url"
|
||||
)
|
||||
def get_student_progress_url(request, course_id):
|
||||
@@ -1913,13 +1890,13 @@ def get_student_progress_url(request, course_id):
|
||||
Get the progress url of a student.
|
||||
Limited to staff access.
|
||||
|
||||
Takes query paremeter unique_student_identifier and if the student exists
|
||||
Takes query parameter unique_student_identifier and if the student exists
|
||||
returns e.g. {
|
||||
'progress_url': '/../...'
|
||||
}
|
||||
"""
|
||||
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
|
||||
user = get_student_from_identifier(request.GET.get('unique_student_identifier'))
|
||||
user = get_student_from_identifier(request.POST.get('unique_student_identifier'))
|
||||
|
||||
progress_url = reverse('student_progress', kwargs={'course_id': course_id.to_deprecated_string(), 'student_id': user.id})
|
||||
|
||||
@@ -1931,10 +1908,11 @@ def get_student_progress_url(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@require_query_params(
|
||||
@require_post_params(
|
||||
problem_to_reset="problem urlname to reset"
|
||||
)
|
||||
@common_exceptions_400
|
||||
@@ -1961,13 +1939,13 @@ def reset_student_attempts(request, course_id):
|
||||
request.user, 'staff', course_id, depth=None
|
||||
)
|
||||
|
||||
problem_to_reset = strip_if_string(request.GET.get('problem_to_reset'))
|
||||
student_identifier = request.GET.get('unique_student_identifier', None)
|
||||
problem_to_reset = strip_if_string(request.POST.get('problem_to_reset'))
|
||||
student_identifier = request.POST.get('unique_student_identifier', None)
|
||||
student = None
|
||||
if student_identifier is not None:
|
||||
student = get_student_from_identifier(student_identifier)
|
||||
all_students = request.GET.get('all_students', False) in ['true', 'True', True]
|
||||
delete_module = request.GET.get('delete_module', False) in ['true', 'True', True]
|
||||
all_students = request.POST.get('all_students', False) in ['true', 'True', True]
|
||||
delete_module = request.POST.get('delete_module', False) in ['true', 'True', True]
|
||||
|
||||
# parameter combinations
|
||||
if all_students and student:
|
||||
@@ -2019,6 +1997,7 @@ def reset_student_attempts(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2049,12 +2028,12 @@ def reset_student_attempts_for_entrance_exam(request, course_id): # pylint: dis
|
||||
_("Course has no entrance exam section.")
|
||||
)
|
||||
|
||||
student_identifier = request.GET.get('unique_student_identifier', None)
|
||||
student_identifier = request.POST.get('unique_student_identifier', None)
|
||||
student = None
|
||||
if student_identifier is not None:
|
||||
student = get_student_from_identifier(student_identifier)
|
||||
all_students = request.GET.get('all_students', False) in ['true', 'True', True]
|
||||
delete_module = request.GET.get('delete_module', False) in ['true', 'True', True]
|
||||
all_students = request.POST.get('all_students', False) in ['true', 'True', True]
|
||||
delete_module = request.POST.get('delete_module', False) in ['true', 'True', True]
|
||||
|
||||
# parameter combinations
|
||||
if all_students and student:
|
||||
@@ -2085,10 +2064,11 @@ def reset_student_attempts_for_entrance_exam(request, course_id): # pylint: dis
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('instructor')
|
||||
@require_query_params(problem_to_reset="problem urlname to reset")
|
||||
@require_post_params(problem_to_reset="problem urlname to reset")
|
||||
@common_exceptions_400
|
||||
def rescore_problem(request, course_id):
|
||||
"""
|
||||
@@ -2103,13 +2083,13 @@ def rescore_problem(request, course_id):
|
||||
all_students and unique_student_identifier cannot both be present.
|
||||
"""
|
||||
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
|
||||
problem_to_reset = strip_if_string(request.GET.get('problem_to_reset'))
|
||||
student_identifier = request.GET.get('unique_student_identifier', None)
|
||||
problem_to_reset = strip_if_string(request.POST.get('problem_to_reset'))
|
||||
student_identifier = request.POST.get('unique_student_identifier', None)
|
||||
student = None
|
||||
if student_identifier is not None:
|
||||
student = get_student_from_identifier(student_identifier)
|
||||
|
||||
all_students = request.GET.get('all_students') in ['true', 'True', True]
|
||||
all_students = request.POST.get('all_students') in ['true', 'True', True]
|
||||
|
||||
if not (problem_to_reset and (all_students or student)):
|
||||
return HttpResponseBadRequest("Missing query parameters.")
|
||||
@@ -2141,6 +2121,7 @@ def rescore_problem(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('instructor')
|
||||
@@ -2161,12 +2142,12 @@ def rescore_entrance_exam(request, course_id):
|
||||
request.user, 'staff', course_id, depth=None
|
||||
)
|
||||
|
||||
student_identifier = request.GET.get('unique_student_identifier', None)
|
||||
student_identifier = request.POST.get('unique_student_identifier', None)
|
||||
student = None
|
||||
if student_identifier is not None:
|
||||
student = get_student_from_identifier(student_identifier)
|
||||
|
||||
all_students = request.GET.get('all_students') in ['true', 'True', True]
|
||||
all_students = request.POST.get('all_students') in ['true', 'True', True]
|
||||
|
||||
if not course.entrance_exam_id:
|
||||
return HttpResponseBadRequest(
|
||||
@@ -2193,6 +2174,7 @@ def rescore_entrance_exam(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2211,6 +2193,7 @@ def list_background_email_tasks(request, course_id): # pylint: disable=unused-a
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2229,6 +2212,7 @@ def list_email_content(request, course_id): # pylint: disable=unused-argument
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2243,8 +2227,8 @@ def list_instructor_tasks(request, course_id):
|
||||
history for problem AND student (intersection)
|
||||
"""
|
||||
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
|
||||
problem_location_str = strip_if_string(request.GET.get('problem_location_str', False))
|
||||
student = request.GET.get('unique_student_identifier', None)
|
||||
problem_location_str = strip_if_string(request.POST.get('problem_location_str', False))
|
||||
student = request.POST.get('unique_student_identifier', None)
|
||||
if student is not None:
|
||||
student = get_student_from_identifier(student)
|
||||
|
||||
@@ -2274,6 +2258,7 @@ def list_instructor_tasks(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2287,7 +2272,7 @@ def list_entrance_exam_instructor_tasks(request, course_id): # pylint: disable=
|
||||
"""
|
||||
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
|
||||
course = get_course_by_id(course_id)
|
||||
student = request.GET.get('unique_student_identifier', None)
|
||||
student = request.POST.get('unique_student_identifier', None)
|
||||
if student is not None:
|
||||
student = get_student_from_identifier(student)
|
||||
|
||||
@@ -2308,6 +2293,7 @@ def list_entrance_exam_instructor_tasks(request, course_id): # pylint: disable=
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2327,6 +2313,7 @@ def list_report_downloads(_request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2348,6 +2335,7 @@ def list_financial_report_downloads(_request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2373,6 +2361,7 @@ def export_ora2_data(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2394,6 +2383,7 @@ def calculate_grades_csv(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2420,10 +2410,11 @@ def problem_grade_report(request, course_id):
|
||||
})
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@require_query_params('rolename')
|
||||
@require_post_params('rolename')
|
||||
def list_forum_members(request, course_id):
|
||||
"""
|
||||
Lists forum members of a certain rolename.
|
||||
@@ -2442,7 +2433,7 @@ def list_forum_members(request, course_id):
|
||||
request.user, course_id, FORUM_ROLE_ADMINISTRATOR
|
||||
)
|
||||
|
||||
rolename = request.GET.get('rolename')
|
||||
rolename = request.POST.get('rolename')
|
||||
|
||||
# default roles require either (staff & forum admin) or (instructor)
|
||||
if not (has_forum_admin or has_instructor_access):
|
||||
@@ -2483,6 +2474,7 @@ def list_forum_members(request, course_id):
|
||||
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@@ -2539,10 +2531,11 @@ def send_email(request, course_id):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@require_query_params(
|
||||
@require_post_params(
|
||||
unique_student_identifier="email or username of user to change access",
|
||||
rolename="the forum role",
|
||||
action="'allow' or 'revoke'",
|
||||
@@ -2569,9 +2562,9 @@ def update_forum_role_membership(request, course_id):
|
||||
request.user, course_id, FORUM_ROLE_ADMINISTRATOR
|
||||
)
|
||||
|
||||
unique_student_identifier = request.GET.get('unique_student_identifier')
|
||||
rolename = request.GET.get('rolename')
|
||||
action = request.GET.get('action')
|
||||
unique_student_identifier = request.POST.get('unique_student_identifier')
|
||||
rolename = request.POST.get('rolename')
|
||||
action = request.POST.get('action')
|
||||
|
||||
# default roles require either (staff & forum admin) or (instructor)
|
||||
if not (has_forum_admin or has_instructor_access):
|
||||
@@ -2629,18 +2622,19 @@ def _display_unit(unit):
|
||||
|
||||
|
||||
@handle_dashboard_error
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@require_query_params('student', 'url', 'due_datetime')
|
||||
@require_post_params('student', 'url', 'due_datetime')
|
||||
def change_due_date(request, course_id):
|
||||
"""
|
||||
Grants a due date extension to a student for a particular unit.
|
||||
"""
|
||||
course = get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(course_id))
|
||||
student = require_student_from_identifier(request.GET.get('student'))
|
||||
unit = find_unit(course, request.GET.get('url'))
|
||||
due_date = parse_datetime(request.GET.get('due_datetime'))
|
||||
student = require_student_from_identifier(request.POST.get('student'))
|
||||
unit = find_unit(course, request.POST.get('url'))
|
||||
due_date = parse_datetime(request.POST.get('due_datetime'))
|
||||
set_due_date_extension(course, unit, student, due_date)
|
||||
|
||||
return JsonResponse(_(
|
||||
@@ -2650,17 +2644,18 @@ def change_due_date(request, course_id):
|
||||
|
||||
|
||||
@handle_dashboard_error
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@require_query_params('student', 'url')
|
||||
@require_post_params('student', 'url')
|
||||
def reset_due_date(request, course_id):
|
||||
"""
|
||||
Rescinds a due date extension for a student on a particular unit.
|
||||
"""
|
||||
course = get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(course_id))
|
||||
student = require_student_from_identifier(request.GET.get('student'))
|
||||
unit = find_unit(course, request.GET.get('url'))
|
||||
student = require_student_from_identifier(request.POST.get('student'))
|
||||
unit = find_unit(course, request.POST.get('url'))
|
||||
set_due_date_extension(course, unit, student, None)
|
||||
if not getattr(unit, "due", None):
|
||||
# It's possible the normal due date was deleted after an extension was granted:
|
||||
@@ -2676,30 +2671,32 @@ def reset_due_date(request, course_id):
|
||||
|
||||
|
||||
@handle_dashboard_error
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@require_query_params('url')
|
||||
@require_post_params('url')
|
||||
def show_unit_extensions(request, course_id):
|
||||
"""
|
||||
Shows all of the students which have due date extensions for the given unit.
|
||||
"""
|
||||
course = get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(course_id))
|
||||
unit = find_unit(course, request.GET.get('url'))
|
||||
unit = find_unit(course, request.POST.get('url'))
|
||||
return JsonResponse(dump_module_extensions(course, unit))
|
||||
|
||||
|
||||
@handle_dashboard_error
|
||||
@require_POST
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_level('staff')
|
||||
@require_query_params('student')
|
||||
@require_post_params('student')
|
||||
def show_student_extensions(request, course_id):
|
||||
"""
|
||||
Shows all of the due date extensions granted to a particular student in a
|
||||
particular course.
|
||||
"""
|
||||
student = require_student_from_identifier(request.GET.get('student'))
|
||||
student = require_student_from_identifier(request.POST.get('student'))
|
||||
course = get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(course_id))
|
||||
return JsonResponse(dump_student_extensions(course, student))
|
||||
|
||||
@@ -3076,7 +3073,6 @@ def generate_certificate_exceptions(request, course_id, generate_for=None):
|
||||
return JsonResponse(response_payload)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@require_global_staff
|
||||
@require_POST
|
||||
|
||||
Reference in New Issue
Block a user