Commit 80c83f0b by Don Mitchell

Merge pull request #1508 from edx/dhm/expect_json

Change expect_json to put parsed json in new attr
parents 9c6d0d6d 45453fae
......@@ -41,6 +41,27 @@ in the set contentstore.views.item.DETACHED_CATEGORIES nor 'course'.
Studio: Bug fix for text loss in Course Updates when the text exists
before the first tag.
Common: expect_json decorator now puts the parsed json payload into a json attr
on the request instead of overwriting the POST attr
---------- split mongo backend refactoring changelog section ------------
Studio: course catalog, assets, checklists, course outline pages now use course
id syntax w/ restful api style
Common:
separate the non-sql db connection configuration from the modulestore (xblock modeling) configuration.
in split, separate the the db connection and atomic crud ops into a distinct module & class from modulestore
Common: location mapper: % encode periods and dollar signs when used as key in the mapping dict
Common: location mapper: added a bunch of new helper functions for generating
old location style info from a CourseLocator
Common: locators: allow - ~ and . in course, branch, and block ids.
---------- end split mongo backend section ---------
Blades: Hovering over CC button in video player, when transcripts are hidden,
will cause them to show up. Moving the mouse from the CC button will auto hide
them. You can hover over the CC button and then move the mouse to the
......@@ -396,22 +417,6 @@ Studio: Add feedback to end user if there is a problem exporting a course
Studio: Improve link re-writing on imports into a different course-id
---------- split mongo backend refactoring changelog section ------------
Studio: course catalog and course outline pages new use course id syntax w/ restful api style
Common:
separate the non-sql db connection configuration from the modulestore (xblock modeling) configuration.
in split, separate the the db connection and atomic crud ops into a distinct module & class from modulestore
Common: location mapper: % encode periods and dollar signs when used as key in the mapping dict
Common: location mapper: added a bunch of new helper functions for generating old location style info from a CourseLocator
Common: locators: allow - ~ and . in course, branch, and block ids.
---------- end split mongo backend section ---------
XQueue: Fixed (hopefully) worker crash when the connection to RabbitMQ is
dropped suddenly.
......
......@@ -105,7 +105,7 @@ class ChecklistTestCase(CourseTestCase):
self.assertEqual('CourseOutline', get_first_item(payload).get('action_url'))
get_first_item(payload)['is_checked'] = True
returned_checklist = json.loads(self.client.post(update_url, json.dumps(payload), "application/json").content)
returned_checklist = json.loads(self.client.ajax_post(update_url, payload).content)
self.assertTrue(get_first_item(returned_checklist).get('is_checked'))
persisted_checklist = self.get_persisted_checklists()[1]
# Verify that persisted checklist does not have expanded action URLs.
......
......@@ -6,7 +6,6 @@ import mock
from textwrap import dedent
from django.test.client import Client
from django.test.utils import override_settings
from django.conf import settings
from django.core.urlresolvers import reverse
......@@ -20,7 +19,7 @@ from datetime import timedelta
from django.contrib.auth.models import User
from django.dispatch import Signal
from contentstore.utils import get_modulestore
from contentstore.tests.utils import parse_json
from contentstore.tests.utils import parse_json, AjaxEnabledTestClient
from auth.authz import add_user_to_creator_group
......@@ -98,7 +97,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
# Save the data that we've just changed to the db.
self.user.save()
self.client = Client()
self.client = AjaxEnabledTestClient()
self.client.login(username=uname, password=password)
def tearDown(self):
......@@ -420,7 +419,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
if tab['type'] == 'static_tab':
reverse_tabs.insert(0, 'i4x://edX/999/static_tab/{0}'.format(tab['url_slug']))
self.client.post(reverse('reorder_static_tabs'), json.dumps({'tabs': reverse_tabs}), "application/json")
self.client.ajax_post(reverse('reorder_static_tabs'), {'tabs': reverse_tabs})
course = module_store.get_item(Location(['i4x', 'edX', '999', 'course', 'Robot_Super_Course', None]))
......@@ -755,7 +754,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
expected_children = []
for child_loc_url in source_item.children:
child_loc = Location(child_loc_url)
child_loc = child_loc._replace(
child_loc = child_loc.replace(
tag=dest_location.tag,
org=dest_location.org,
course=dest_location.course
......@@ -1333,7 +1332,7 @@ class ContentStoreTest(ModuleStoreTestCase):
self.user.is_staff = True
self.user.save()
self.client = Client()
self.client = AjaxEnabledTestClient()
self.client.login(username=uname, password=password)
self.course_data = {
......@@ -1344,8 +1343,7 @@ class ContentStoreTest(ModuleStoreTestCase):
}
def tearDown(self):
mongo = MongoClient()
mongo.drop_database(TEST_DATA_CONTENTSTORE['DOC_STORE_CONFIG']['db'])
MongoClient().drop_database(TEST_DATA_CONTENTSTORE['DOC_STORE_CONFIG']['db'])
_CONTENTSTORE.clear()
def test_create_course(self):
......@@ -1394,7 +1392,7 @@ class ContentStoreTest(ModuleStoreTestCase):
def test_create_course_duplicate_course(self):
"""Test new course creation - error path"""
self.client.post(reverse('create_new_course'), self.course_data)
self.client.ajax_post(reverse('create_new_course'), self.course_data)
self.assert_course_creation_failed('There is already a course defined with the same organization, course number, and course run. Please change either organization or course number to be unique.')
def assert_course_creation_failed(self, error_message):
......@@ -1403,7 +1401,7 @@ class ContentStoreTest(ModuleStoreTestCase):
"""
course_id = _get_course_id(self.course_data)
initially_enrolled = CourseEnrollment.is_enrolled(self.user, course_id)
resp = self.client.post(reverse('create_new_course'), self.course_data)
resp = self.client.ajax_post(reverse('create_new_course'), self.course_data)
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
self.assertEqual(data['ErrMsg'], error_message)
......@@ -1413,7 +1411,7 @@ class ContentStoreTest(ModuleStoreTestCase):
def test_create_course_duplicate_number(self):
"""Test new course creation - error path"""
self.client.post(reverse('create_new_course'), self.course_data)
self.client.ajax_post(reverse('create_new_course'), self.course_data)
self.course_data['display_name'] = 'Robot Super Course Two'
self.course_data['run'] = '2013_Summer'
......@@ -1422,13 +1420,13 @@ class ContentStoreTest(ModuleStoreTestCase):
def test_create_course_case_change(self):
"""Test new course creation - error path due to case insensitive name equality"""
self.course_data['number'] = 'capital'
self.client.post(reverse('create_new_course'), self.course_data)
self.client.ajax_post(reverse('create_new_course'), self.course_data)
cache_current = self.course_data['org']
self.course_data['org'] = self.course_data['org'].lower()
self.assert_course_creation_failed('There is already a course defined with the same organization and course number. Please change at least one field to be unique.')
self.course_data['org'] = cache_current
self.client.post(reverse('create_new_course'), self.course_data)
self.client.ajax_post(reverse('create_new_course'), self.course_data)
cache_current = self.course_data['number']
self.course_data['number'] = self.course_data['number'].upper()
self.assert_course_creation_failed('There is already a course defined with the same organization and course number. Please change at least one field to be unique.')
......@@ -1437,14 +1435,14 @@ class ContentStoreTest(ModuleStoreTestCase):
"""
Test that a new course can be created whose name is a substring of an existing course
"""
self.client.post(reverse('create_new_course'), self.course_data)
self.client.ajax_post(reverse('create_new_course'), self.course_data)
cache_current = self.course_data['number']
self.course_data['number'] = '{}a'.format(self.course_data['number'])
resp = self.client.post(reverse('create_new_course'), self.course_data)
resp = self.client.ajax_post(reverse('create_new_course'), self.course_data)
self.assertEqual(resp.status_code, 200)
self.course_data['number'] = cache_current
self.course_data['org'] = 'a{}'.format(self.course_data['org'])
resp = self.client.post(reverse('create_new_course'), self.course_data)
resp = self.client.ajax_post(reverse('create_new_course'), self.course_data)
self.assertEqual(resp.status_code, 200)
def test_create_course_with_bad_organization(self):
......@@ -1487,7 +1485,7 @@ class ContentStoreTest(ModuleStoreTestCase):
"""
Checks that the course did not get created due to a PermissionError.
"""
resp = self.client.post(reverse('create_new_course'), self.course_data)
resp = self.client.ajax_post(reverse('create_new_course'), self.course_data)
self.assertEqual(resp.status_code, 403)
def test_course_index_view_with_no_courses(self):
......@@ -1546,7 +1544,7 @@ class ContentStoreTest(ModuleStoreTestCase):
'display_name': 'Section One',
}
resp = self.client.post(reverse('create_item'), section_data)
resp = self.client.ajax_post(reverse('create_item'), section_data)
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
......@@ -1564,7 +1562,7 @@ class ContentStoreTest(ModuleStoreTestCase):
'category': 'problem'
}
resp = self.client.post(reverse('create_item'), problem_data)
resp = self.client.ajax_post(reverse('create_item'), problem_data)
self.assertEqual(resp.status_code, 200)
payload = parse_json(resp)
......@@ -1929,7 +1927,7 @@ def _create_course(test, course_data):
course_id = _get_course_id(course_data)
new_location = loc_mapper().translate_location(course_id, CourseDescriptor.id_to_location(course_id), False, True)
response = test.client.post(reverse('create_new_course'), course_data)
response = test.client.ajax_post(reverse('create_new_course'), course_data)
test.assertEqual(response.status_code, 200)
data = parse_json(response)
test.assertNotIn('ErrMsg', data)
......
......@@ -176,7 +176,7 @@ class CourseDetailsViewTest(CourseTestCase):
payload['end_date'] = CourseDetailsViewTest.convert_datetime_to_iso(details.end_date)
payload['enrollment_start'] = CourseDetailsViewTest.convert_datetime_to_iso(details.enrollment_start)
payload['enrollment_end'] = CourseDetailsViewTest.convert_datetime_to_iso(details.enrollment_end)
resp = self.client.post(url, json.dumps(payload), "application/json")
resp = self.client.ajax_post(url, payload)
self.compare_details_with_encoding(json.loads(resp.content), details.__dict__, field + str(val))
@staticmethod
......@@ -462,6 +462,6 @@ class CourseGraderUpdatesTest(CourseTestCase):
"short_label": "yo momma",
"weight": 17.3,
}
resp = self.client.post(self.url, grader)
resp = self.client.ajax_post(self.url, grader)
self.assertEqual(resp.status_code, 200)
obj = json.loads(resp.content)
......@@ -22,7 +22,7 @@ class CourseUpdateTest(CourseTestCase):
'course': self.course.location.course,
'provided_id': ''})
resp = self.client.post(url, json.dumps(payload), "application/json")
resp = self.client.ajax_post(url, payload)
return json.loads(resp.content)
......@@ -66,7 +66,6 @@ class CourseUpdateTest(CourseTestCase):
payload = json.loads(resp.content)
self.assertTrue(len(payload) == 2)
# can't test non-json paylod b/c expect_json throws error
# try json w/o required fields
self.assertContains(self.client.post(url, json.dumps({'garbage': 1}),
"application/json"),
......@@ -86,7 +85,7 @@ class CourseUpdateTest(CourseTestCase):
payload = {'content': content,
'date': 'January 21, 2013'}
self.assertContains(
self.client.post(url, json.dumps(payload), "application/json"),
self.client.ajax_post(url, payload),
'Failed to save', status_code=400)
# update w/ malformed html
......@@ -98,7 +97,7 @@ class CourseUpdateTest(CourseTestCase):
'provided_id': ''})
self.assertContains(
self.client.post(url, json.dumps(payload), "application/json"),
self.client.ajax_post(url, payload),
'<garbage')
# set to valid html which would break an xml parser
......@@ -152,7 +151,7 @@ class CourseUpdateTest(CourseTestCase):
'course': self.course.location.course,
'provided_id': ''})
resp = self.client.post(url, json.dumps(payload), "application/json")
resp = self.client.ajax_post(url, payload)
payload = json.loads(resp.content)
......
......@@ -54,7 +54,7 @@ class Basetranscripts(CourseTestCase):
'category': 'video',
'type': 'video'
}
resp = self.client.post(reverse('create_item'), data)
resp = self.client.ajax_post(reverse('create_item'), data)
self.item_location = json.loads(resp.content).get('id')
self.assertEqual(resp.status_code, 200)
......@@ -200,7 +200,7 @@ class TestUploadtranscripts(Basetranscripts):
'category': 'non_video',
'type': 'non_video'
}
resp = self.client.post(reverse('create_item'), data)
resp = self.client.ajax_post(reverse('create_item'), data)
item_location = json.loads(resp.content).get('id')
data = '<non_video youtube="0.75:JMD_ifUUfsU,1.0:hI10vDNYz4M" />'
modulestore().update_item(item_location, data)
......@@ -411,7 +411,7 @@ class TestDownloadtranscripts(Basetranscripts):
'category': 'videoalpha',
'type': 'videoalpha'
}
resp = self.client.post(reverse('create_item'), data)
resp = self.client.ajax_post(reverse('create_item'), data)
item_location = json.loads(resp.content).get('id')
subs_id = str(uuid4())
data = textwrap.dedent("""
......@@ -661,7 +661,7 @@ class TestChecktranscripts(Basetranscripts):
'category': 'not_video',
'type': 'not_video'
}
resp = self.client.post(reverse('create_item'), data)
resp = self.client.ajax_post(reverse('create_item'), data)
item_location = json.loads(resp.content).get('id')
subs_id = str(uuid4())
data = textwrap.dedent("""
......
......@@ -29,6 +29,14 @@ def registration(email):
return Registration.objects.get(user__email=email)
class AjaxEnabledTestClient(Client):
def ajax_post(self, path, data=None, content_type="application/json", **kwargs):
if not isinstance(data, basestring):
data = json.dumps(data or {})
kwargs.setdefault("HTTP_X_REQUESTED_WITH", "XMLHttpRequest")
return self.post(path=path, data=data, content_type=content_type, **kwargs)
@override_settings(MODULESTORE=TEST_MODULESTORE)
class CourseTestCase(ModuleStoreTestCase):
def setUp(self):
......@@ -53,7 +61,7 @@ class CourseTestCase(ModuleStoreTestCase):
self.user.is_staff = True
self.user.save()
self.client = Client()
self.client = AjaxEnabledTestClient()
self.client.login(username=uname, password=password)
self.course = CourseFactory.create(
......
......@@ -323,7 +323,7 @@ def assignment_type_update(request, org, course, category, name):
rsp = CourseGradingModel.get_section_grader_type(location)
elif request.method in ('POST', 'PUT'): # post or put, doesn't matter.
rsp = CourseGradingModel.update_section_grader_type(
location, request.POST
location, request.json
)
return JsonResponse(rsp)
......@@ -332,7 +332,7 @@ def assignment_type_update(request, org, course, category, name):
@expect_json
def create_draft(request):
"Create a draft"
location = request.POST['id']
location = request.json['id']
# check permissions for this user within this course
if not has_access(request.user, location):
......@@ -351,7 +351,7 @@ def publish_draft(request):
"""
Publish a draft
"""
location = request.POST['id']
location = request.json['id']
# check permissions for this user within this course
if not has_access(request.user, location):
......@@ -370,7 +370,7 @@ def publish_draft(request):
@expect_json
def unpublish_unit(request):
"Unpublish a unit"
location = request.POST['id']
location = request.json['id']
# check permissions for this user within this course
if not has_access(request.user, location):
......@@ -413,6 +413,6 @@ def module_info(request, module_location):
elif request.method in ("POST", "PUT"):
rsp = set_module_info(
get_modulestore(location),
location, request.POST
location, request.json
)
return JsonResponse(rsp)
......@@ -153,10 +153,10 @@ def create_new_course(request):
if not is_user_in_creator_group(request.user):
raise PermissionDenied()
org = request.POST.get('org')
number = request.POST.get('number')
display_name = request.POST.get('display_name')
run = request.POST.get('run')
org = request.json.get('org')
number = request.json.get('number')
display_name = request.json.get('display_name')
run = request.json.get('run')
try:
dest_location = Location('i4x', org, number, 'course', run)
......@@ -297,7 +297,7 @@ def course_info_updates(request, org, course, provided_id=None):
return JsonResponse(get_course_updates(location))
elif request.method == 'DELETE':
try:
return JsonResponse(delete_course_update(location, request.POST, provided_id))
return JsonResponse(delete_course_update(location, request.json, provided_id))
except:
return HttpResponseBadRequest(
"Failed to delete",
......@@ -306,7 +306,7 @@ def course_info_updates(request, org, course, provided_id=None):
# can be either and sometimes django is rewriting one to the other:
elif request.method in ('POST', 'PUT'):
try:
return JsonResponse(update_course_updates(location, request.POST, provided_id))
return JsonResponse(update_course_updates(location, request.json, provided_id))
except:
return HttpResponseBadRequest(
"Failed to save",
......@@ -415,7 +415,7 @@ def course_settings_updates(request, org, course, name, section):
)
elif request.method in ('POST', 'PUT'): # post or put, doesn't matter.
return JsonResponse(
manager.update_from_json(request.POST),
manager.update_from_json(request.json),
encoder=CourseSettingsEncoder
)
......@@ -447,14 +447,14 @@ def course_grader_updates(request, org, course, name, grader_index=None):
else: # post or put, doesn't matter.
return JsonResponse(CourseGradingModel.update_grader_from_json(
Location(location),
request.POST
request.json
))
# # NB: expect_json failed on ["key", "key2"] and json payload
@require_http_methods(("GET", "POST", "PUT", "DELETE"))
@login_required
@ensure_csrf_cookie
@expect_json
def course_advanced_updates(request, org, course, name):
"""
Restful CRUD operations on metadata. The payload is a json rep of the
......@@ -473,10 +473,6 @@ def course_advanced_updates(request, org, course, name):
json.loads(request.body)
))
else:
# NOTE: request.POST is messed up because expect_json
# cloned_request.POST.copy() is creating a defective entry w/ the whole
# payload as the key
request_body = json.loads(request.body)
# Whether or not to filter the tabs key out of the settings metadata
filter_tabs = True
......@@ -489,7 +485,7 @@ def course_advanced_updates(request, org, course, name):
# the user has indicated that they want the notes module enabled in
# their course
# TODO refactor the above into distinct advanced policy settings
if ADVANCED_COMPONENT_POLICY_KEY in request_body:
if ADVANCED_COMPONENT_POLICY_KEY in request.json:
# Get the course so that we can scrape current tabs
course_module = modulestore().get_item(location)
......@@ -505,7 +501,7 @@ def course_advanced_updates(request, org, course, name):
component_types = tab_component_map.get(tab_type)
found_ac_type = False
for ac_type in component_types:
if ac_type in request_body[ADVANCED_COMPONENT_POLICY_KEY]:
if ac_type in request.json[ADVANCED_COMPONENT_POLICY_KEY]:
# Add tab to the course if needed
changed, new_tabs = add_extra_panel_tab(
tab_type,
......@@ -515,7 +511,7 @@ def course_advanced_updates(request, org, course, name):
# metadata along to CourseMetadata.update_from_json
if changed:
course_module.tabs = new_tabs
request_body.update({'tabs': new_tabs})
request.json.update({'tabs': new_tabs})
# Indicate that tabs should not be filtered out of
# the metadata
filter_tabs = False
......@@ -531,14 +527,14 @@ def course_advanced_updates(request, org, course, name):
)
if changed:
course_module.tabs = new_tabs
request_body.update({'tabs': new_tabs})
request.json.update({'tabs': new_tabs})
# Indicate that tabs should *not* be filtered out of
# the metadata
filter_tabs = False
try:
return JsonResponse(CourseMetadata.update_from_json(
location,
request_body,
request.json,
filter_tabs=filter_tabs
))
except (TypeError, ValueError) as err:
......
......@@ -47,7 +47,7 @@ def save_item(request):
# little smarter and able to pass something more akin to {unset: [field, field]}
try:
item_location = request.POST['id']
item_location = request.json['id']
except KeyError:
import inspect
......@@ -76,30 +76,27 @@ def save_item(request):
store = get_modulestore(Location(item_location))
if request.POST.get('data') is not None:
data = request.POST['data']
if request.json.get('data'):
data = request.json['data']
store.update_item(item_location, data)
# cdodge: note calling request.POST.get('children') will return None if children is an empty array
# so it lead to a bug whereby the last component to be deleted in the UI was not actually
# deleting the children object from the children collection
if 'children' in request.POST and request.POST['children'] is not None:
children = request.POST['children']
if request.json.get('children') is not None:
children = request.json['children']
store.update_children(item_location, children)
# cdodge: also commit any metadata which might have been passed along
if request.POST.get('nullout') is not None or request.POST.get('metadata') is not None:
if request.json.get('nullout') is not None or request.json.get('metadata') is not None:
# the postback is not the complete metadata, as there's system metadata which is
# not presented to the end-user for editing. So let's fetch the original and
# 'apply' the submitted metadata, so we don't end up deleting system metadata
existing_item = modulestore().get_item(item_location)
for metadata_key in request.POST.get('nullout', []):
for metadata_key in request.json.get('nullout', []):
setattr(existing_item, metadata_key, None)
# update existing metadata with submitted metadata (which can be partial)
# IMPORTANT NOTE: if the client passed 'null' (None) for a piece of metadata that means 'remove it'. If
# the intent is to make it None, use the nullout field
for metadata_key, value in request.POST.get('metadata', {}).items():
for metadata_key, value in request.json.get('metadata', {}).items():
field = existing_item.fields[metadata_key]
if value is None:
......@@ -126,10 +123,10 @@ def save_item(request):
@expect_json
def create_item(request):
"""View for create items."""
parent_location = Location(request.POST['parent_location'])
category = request.POST['category']
parent_location = Location(request.json['parent_location'])
category = request.json['category']
display_name = request.POST.get('display_name')
display_name = request.json.get('display_name')
if not has_access(request.user, parent_location):
raise PermissionDenied()
......@@ -140,7 +137,7 @@ def create_item(request):
# get the metadata, display_name, and definition from the request
metadata = {}
data = None
template_id = request.POST.get('boilerplate')
template_id = request.json.get('boilerplate')
if template_id is not None:
clz = XModuleDescriptor.load_class(category)
if clz is not None:
......@@ -169,7 +166,7 @@ def create_item(request):
@expect_json
def delete_item(request):
"""View for removing items."""
item_location = request.POST['id']
item_location = request.json['id']
item_location = Location(item_location)
# check permissions for this user within this course
......@@ -177,8 +174,8 @@ def delete_item(request):
raise PermissionDenied()
# optional parameter to delete all children (default False)
delete_children = request.POST.get('delete_children', False)
delete_all_versions = request.POST.get('delete_all_versions', False)
delete_children = request.json.get('delete_children', False)
delete_all_versions = request.json.get('delete_all_versions', False)
store = get_modulestore(item_location)
......
......@@ -46,7 +46,7 @@ def initialize_course_tabs(course):
@expect_json
def reorder_static_tabs(request):
"Order the static tabs in the requested order"
tabs = request.POST['tabs']
tabs = request.json['tabs']
course = get_course_for_item(tabs[0])
if not has_access(request.user, course.location):
......
......@@ -35,6 +35,19 @@ define ["domReady", "jquery", "underscore.string", "backbone", "gettext",
)
msg.show()
$.postJSON = (url, data, callback) ->
# shift arguments if data argument was omitted
if $.isFunction(data)
callback = data
data = `undefined`
$.ajax
url: url
type: "POST"
contentType: "application/json; charset=utf-8"
dataType: "json"
data: JSON.stringify(data)
success: callback
if onTouchBasedDevice()
$('body').addClass 'touch-based-device'
......
......@@ -64,7 +64,7 @@ define ["backbone", "jquery", "underscore", "gettext", "xblock/runtime.v1",
createItem: (parent, payload) ->
payload.parent_location = parent
$.post(
$.postJSON(
"/create_item"
payload
(data) =>
......
......@@ -82,7 +82,7 @@ define ["jquery", "jquery.ui", "backbone", "js/views/feedback_prompt", "js/views
deleting = new NotificationView.Mini
title: gettext('Deleting&hellip;')
deleting.show()
$.post('/delete_item', {
$.postJSON('/delete_item', {
id: $component.data('id')
}, =>
$component.remove()
......
......@@ -134,7 +134,7 @@ define ["jquery", "jquery.ui", "gettext", "backbone",
title: gettext('Deleting&hellip;'),
deleting.show()
$component = $(event.currentTarget).parents('.component')
$.post('/delete_item', {
$.postJSON('/delete_item', {
id: $component.data('id')
}, =>
deleting.hide()
......@@ -163,7 +163,7 @@ define ["jquery", "jquery.ui", "gettext", "backbone",
deleteDraft: (event) ->
@wait(true)
$.post('/delete_item', {
$.postJSON('/delete_item', {
id: @$el.data('id')
delete_children: true
}, =>
......@@ -177,7 +177,7 @@ define ["jquery", "jquery.ui", "gettext", "backbone",
createDraft: (event) ->
@wait(true)
$.post('/create_draft', {
$.postJSON('/create_draft', {
id: @$el.data('id')
}, =>
analytics.track "Created Draft",
......@@ -191,7 +191,7 @@ define ["jquery", "jquery.ui", "gettext", "backbone",
@wait(true)
@saveDraft()
$.post('/publish_draft', {
$.postJSON('/publish_draft', {
id: @$el.data('id')
}, =>
analytics.track "Published Draft",
......@@ -211,7 +211,7 @@ define ["jquery", "jquery.ui", "gettext", "backbone",
@wait(true)
$.post(target_url, {
$.postJSON(target_url, {
id: @$el.data('id')
}, =>
analytics.track "Set Unit Visibility",
......
......@@ -230,7 +230,7 @@ function createNewUnit(e) {
});
$.post('/create_item', {
$.postJSON('/create_item', {
'parent_location': parent,
'category': category,
'display_name': 'New Unit'
......@@ -279,7 +279,7 @@ function _deleteItem($el, type) {
});
deleting.show();
$.post('/delete_item',
$.postJSON('/delete_item',
{'id': id,
'delete_children': true,
'delete_all_versions': true},
......
......@@ -32,7 +32,7 @@ require(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
'run': run
});
$.post('/create_new_course', {
$.postJSON('/create_new_course', {
'org': org,
'number': number,
'display_name': display_name,
......
......@@ -132,7 +132,7 @@ define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "js/views/fe
'display_name': display_name
});
$.post('/create_item', {
$.postJSON('/create_item', {
'parent_location': parent,
'category': category,
'display_name': display_name
......@@ -182,7 +182,7 @@ define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "js/views/fe
});
$.post('/create_item', {
$.postJSON('/create_item', {
'parent_location': parent,
'category': category,
'display_name': display_name
......
......@@ -14,17 +14,17 @@ def expect_json(view_function):
request.POST with the contents.
"""
@wraps(view_function)
def expect_json_with_cloned_request(request, *args, **kwargs):
def parse_json_into_request(request, *args, **kwargs):
# cdodge: fix postback errors in CMS. The POST 'content-type' header can include additional information
# e.g. 'charset', so we can't do a direct string compare
if request.META.get('CONTENT_TYPE', '').lower().startswith("application/json"):
cloned_request = copy.copy(request)
cloned_request.POST = json.loads(request.body)
return view_function(cloned_request, *args, **kwargs)
if "application/json" in request.META.get('CONTENT_TYPE', ''):
request.json = json.loads(request.body)
else:
return view_function(request, *args, **kwargs)
request.json = {}
return expect_json_with_cloned_request
return view_function(request, *args, **kwargs)
return parse_json_into_request
class JsonResponse(HttpResponse):
......
......@@ -323,7 +323,6 @@ def _get_next(course_id, grader_id, location):
'error': STAFF_ERROR_MESSAGE})
@expect_json
def save_grade(request, course_id):
"""
Save the grade and feedback for a submission, and, if all goes well, return
......
......@@ -274,8 +274,6 @@ if settings.COURSEWARE_ENABLED:
'open_ended_grading.staff_grading_service.get_next', name='staff_grading_get_next'),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading/save_grade$',
'open_ended_grading.staff_grading_service.save_grade', name='staff_grading_save_grade'),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading/save_grade$',
'open_ended_grading.staff_grading_service.save_grade', name='staff_grading_save_grade'),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading/get_problem_list$',
'open_ended_grading.staff_grading_service.get_problem_list', name='staff_grading_get_problem_list'),
......
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