Change expect_json to put parsed json in new attr
This commit is contained in:
@@ -33,6 +33,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
|
||||
@@ -388,22 +409,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)
|
||||
@@ -1934,7 +1932,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)
|
||||
|
||||
|
||||
@@ -43,7 +43,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…')
|
||||
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…'),
|
||||
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):
|
||||
|
||||
@@ -321,7 +321,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'),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user