Commit ef81556c by David Baumgold

Use JsonResponse when it makes sense

parent 090d0d44
...@@ -117,4 +117,4 @@ class ChecklistTestCase(CourseTestCase): ...@@ -117,4 +117,4 @@ class ChecklistTestCase(CourseTestCase):
'name': self.course.location.name, 'name': self.course.location.name,
'checklist_index': 100}) 'checklist_index': 100})
response = self.client.delete(update_url) response = self.client.delete(update_url)
self.assertContains(response, 'Unsupported request', status_code=400) self.assertEqual(response.status_code, 405)
...@@ -188,7 +188,7 @@ def upload_asset(request, org, course, coursename): ...@@ -188,7 +188,7 @@ def upload_asset(request, org, course, coursename):
'msg': 'Upload completed' 'msg': 'Upload completed'
} }
response = HttpResponse(json.dumps(response_payload), mimetype="application/json") response = JsonResponse(response_payload)
response['asset_url'] = StaticContent.get_url_path_from_location(content.location) response['asset_url'] = StaticContent.get_url_path_from_location(content.location)
return response return response
......
import json import json
from django.http import HttpResponse, HttpResponseBadRequest from util.json_request import JsonResponse
from django.http import HttpResponseBadRequest
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django_future.csrf import ensure_csrf_cookie from django_future.csrf import ensure_csrf_cookie
from mitxmako.shortcuts import render_to_response from mitxmako.shortcuts import render_to_response
...@@ -71,7 +72,7 @@ def update_checklist(request, org, course, name, checklist_index=None): ...@@ -71,7 +72,7 @@ def update_checklist(request, org, course, name, checklist_index=None):
course_module.checklists = course_module.checklists course_module.checklists = course_module.checklists
checklists, _ = expand_checklist_action_urls(course_module) checklists, _ = expand_checklist_action_urls(course_module)
modulestore.update_metadata(location, own_metadata(course_module)) modulestore.update_metadata(location, own_metadata(course_module))
return HttpResponse(json.dumps(checklists[index]), mimetype="application/json") return JsonResponse(checklists[index])
else: else:
return HttpResponseBadRequest( return HttpResponseBadRequest(
"Could not save checklist state because the checklist index was out of range or unspecified.", "Could not save checklist state because the checklist index was out of range or unspecified.",
...@@ -81,7 +82,7 @@ def update_checklist(request, org, course, name, checklist_index=None): ...@@ -81,7 +82,7 @@ def update_checklist(request, org, course, name, checklist_index=None):
checklists, modified = expand_checklist_action_urls(course_module) checklists, modified = expand_checklist_action_urls(course_module)
if modified: if modified:
modulestore.update_metadata(location, own_metadata(course_module)) modulestore.update_metadata(location, own_metadata(course_module))
return HttpResponse(json.dumps(checklists), mimetype="application/json") return JsonResponse(checklists)
else: else:
return HttpResponseBadRequest("Unsupported request.", content_type="text/plain") return HttpResponseBadRequest("Unsupported request.", content_type="text/plain")
......
...@@ -15,7 +15,7 @@ from xmodule.modulestore.django import modulestore ...@@ -15,7 +15,7 @@ from xmodule.modulestore.django import modulestore
from xmodule.util.date_utils import get_default_time_display from xmodule.util.date_utils import get_default_time_display
from xblock.core import Scope from xblock.core import Scope
from util.json_request import expect_json from util.json_request import expect_json, JsonResponse
from contentstore.module_info_model import get_module_info, set_module_info from contentstore.module_info_model import get_module_info, set_module_info
from contentstore.utils import get_modulestore, get_lms_link_for_item, \ from contentstore.utils import get_modulestore, get_lms_link_for_item, \
...@@ -236,11 +236,9 @@ def assignment_type_update(request, org, course, category, name): ...@@ -236,11 +236,9 @@ def assignment_type_update(request, org, course, category, name):
raise HttpResponseForbidden() raise HttpResponseForbidden()
if request.method == 'GET': if request.method == 'GET':
return HttpResponse(json.dumps(CourseGradingModel.get_section_grader_type(location)), return JsonResponse(CourseGradingModel.get_section_grader_type(location))
mimetype="application/json")
elif request.method == 'POST': # post or put, doesn't matter. elif request.method == 'POST': # post or put, doesn't matter.
return HttpResponse(json.dumps(CourseGradingModel.update_section_grader_type(location, request.POST)), return JsonResponse(CourseGradingModel.update_section_grader_type(location, request.POST))
mimetype="application/json")
@login_required @login_required
...@@ -309,8 +307,8 @@ def module_info(request, module_location): ...@@ -309,8 +307,8 @@ def module_info(request, module_location):
raise PermissionDenied() raise PermissionDenied()
if real_method == 'GET': if real_method == 'GET':
return HttpResponse(json.dumps(get_module_info(get_modulestore(location), location, rewrite_static_links=rewrite_static_links)), mimetype="application/json") return JsonResponse(get_module_info(get_modulestore(location), location, rewrite_static_links=rewrite_static_links))
elif real_method == 'POST' or real_method == 'PUT': elif real_method == 'POST' or real_method == 'PUT':
return HttpResponse(json.dumps(set_module_info(get_modulestore(location), location, request.POST)), mimetype="application/json") return JsonResponse(set_module_info(get_modulestore(location), location, request.POST))
else: else:
return HttpResponseBadRequest() return HttpResponseBadRequest()
...@@ -11,7 +11,7 @@ from django.conf import settings ...@@ -11,7 +11,7 @@ from django.conf import settings
from django.views.decorators.http import require_http_methods, require_POST from django.views.decorators.http import require_http_methods, require_POST
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseBadRequest from django.http import HttpResponseBadRequest
from util.json_request import JsonResponse from util.json_request import JsonResponse
from mitxmako.shortcuts import render_to_response from mitxmako.shortcuts import render_to_response
...@@ -109,8 +109,9 @@ def create_new_course(request): ...@@ -109,8 +109,9 @@ def create_new_course(request):
try: try:
dest_location = Location('i4x', org, number, 'course', Location.clean(display_name)) dest_location = Location('i4x', org, number, 'course', Location.clean(display_name))
except InvalidLocationError as error: except InvalidLocationError as error:
return HttpResponse(json.dumps({'ErrMsg': "Unable to create course '" + return JsonResponse({
display_name + "'.\n\n" + error.message})) "ErrMsg": "Unable to create course '{name}'.\n\n{err}".format(
name=display_name, err=error.message)})
# see if the course already exists # see if the course already exists
existing_course = None existing_course = None
...@@ -120,13 +121,13 @@ def create_new_course(request): ...@@ -120,13 +121,13 @@ def create_new_course(request):
pass pass
if existing_course is not None: if existing_course is not None:
return HttpResponse(json.dumps({'ErrMsg': 'There is already a course defined with this name.'})) return JsonResponse({'ErrMsg': 'There is already a course defined with this name.'})
course_search_location = ['i4x', dest_location.org, dest_location.course, 'course', None] course_search_location = ['i4x', dest_location.org, dest_location.course, 'course', None]
courses = modulestore().get_items(course_search_location) courses = modulestore().get_items(course_search_location)
if len(courses) > 0: if len(courses) > 0:
return HttpResponse(json.dumps({'ErrMsg': 'There is already a course defined with the same organization and course number.'})) return JsonResponse({'ErrMsg': 'There is already a course defined with the same organization and course number.'})
new_course = modulestore('direct').clone_item(template, dest_location) new_course = modulestore('direct').clone_item(template, dest_location)
...@@ -149,7 +150,7 @@ def create_new_course(request): ...@@ -149,7 +150,7 @@ def create_new_course(request):
# seed the forums # seed the forums
seed_permissions_roles(new_course.location.course_id) seed_permissions_roles(new_course.location.course_id)
return HttpResponse(json.dumps({'id': new_course.location.url()})) return JsonResponse({'id': new_course.location.url()})
@login_required @login_required
...@@ -201,19 +202,16 @@ def course_info_updates(request, org, course, provided_id=None): ...@@ -201,19 +202,16 @@ def course_info_updates(request, org, course, provided_id=None):
real_method = get_request_method(request) real_method = get_request_method(request)
if request.method == 'GET': if request.method == 'GET':
return HttpResponse(json.dumps(get_course_updates(location)), return JsonResponse(get_course_updates(location))
mimetype="application/json")
elif real_method == 'DELETE': elif real_method == 'DELETE':
try: try:
return HttpResponse(json.dumps(delete_course_update(location, return JsonResponse(delete_course_update(location, request.POST, provided_id))
request.POST, provided_id)), mimetype="application/json")
except: except:
return HttpResponseBadRequest("Failed to delete", return HttpResponseBadRequest("Failed to delete",
content_type="text/plain") content_type="text/plain")
elif request.method == 'POST': elif request.method == 'POST':
try: try:
return HttpResponse(json.dumps(update_course_updates(location, return JsonResponse(update_course_updates(location, request.POST, provided_id))
request.POST, provided_id)), mimetype="application/json")
except: except:
return HttpResponseBadRequest("Failed to save", return HttpResponseBadRequest("Failed to save",
content_type="text/plain") content_type="text/plain")
...@@ -304,11 +302,9 @@ def course_settings_updates(request, org, course, name, section): ...@@ -304,11 +302,9 @@ def course_settings_updates(request, org, course, name, section):
if request.method == 'GET': if request.method == 'GET':
# Cannot just do a get w/o knowing the course name :-( # Cannot just do a get w/o knowing the course name :-(
return HttpResponse(json.dumps(manager.fetch(Location(['i4x', org, course, 'course', name])), cls=CourseSettingsEncoder), return JsonResponse(manager.fetch(Location(['i4x', org, course, 'course', name])), encoder=CourseSettingsEncoder)
mimetype="application/json")
elif request.method == 'POST': # post or put, doesn't matter. elif request.method == 'POST': # post or put, doesn't matter.
return HttpResponse(json.dumps(manager.update_from_json(request.POST), cls=CourseSettingsEncoder), return JsonResponse(manager.update_from_json(request.POST), encoder=CourseSettingsEncoder)
mimetype="application/json")
@expect_json @expect_json
...@@ -328,15 +324,13 @@ def course_grader_updates(request, org, course, name, grader_index=None): ...@@ -328,15 +324,13 @@ def course_grader_updates(request, org, course, name, grader_index=None):
if real_method == 'GET': if real_method == 'GET':
# Cannot just do a get w/o knowing the course name :-( # Cannot just do a get w/o knowing the course name :-(
return HttpResponse(json.dumps(CourseGradingModel.fetch_grader(Location(location), grader_index)), return JsonResponse(CourseGradingModel.fetch_grader(Location(location), grader_index))
mimetype="application/json")
elif real_method == "DELETE": elif real_method == "DELETE":
# ??? Should this return anything? Perhaps success fail? # ??? Should this return anything? Perhaps success fail?
CourseGradingModel.delete_grader(Location(location), grader_index) CourseGradingModel.delete_grader(Location(location), grader_index)
return HttpResponse() return JsonResponse()
elif request.method == 'POST': # post or put, doesn't matter. elif request.method == 'POST': # post or put, doesn't matter.
return HttpResponse(json.dumps(CourseGradingModel.update_grader_from_json(Location(location), request.POST)), return JsonResponse(CourseGradingModel.update_grader_from_json(Location(location), request.POST))
mimetype="application/json")
# # NB: expect_json failed on ["key", "key2"] and json payload # # NB: expect_json failed on ["key", "key2"] and json payload
...@@ -354,12 +348,9 @@ def course_advanced_updates(request, org, course, name): ...@@ -354,12 +348,9 @@ def course_advanced_updates(request, org, course, name):
real_method = get_request_method(request) real_method = get_request_method(request)
if real_method == 'GET': if real_method == 'GET':
return HttpResponse(json.dumps(CourseMetadata.fetch(location)), return JsonResponse(CourseMetadata.fetch(location))
mimetype="application/json")
elif real_method == 'DELETE': elif real_method == 'DELETE':
return HttpResponse(json.dumps(CourseMetadata.delete_key(location, return JsonResponse(CourseMetadata.delete_key(location, json.loads(request.body)))
json.loads(request.body))),
mimetype="application/json")
elif real_method == 'POST' or real_method == 'PUT': elif real_method == 'POST' or real_method == 'PUT':
# NOTE: request.POST is messed up because expect_json # 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 # cloned_request.POST.copy() is creating a defective entry w/ the whole payload as the key
...@@ -412,14 +403,12 @@ def course_advanced_updates(request, org, course, name): ...@@ -412,14 +403,12 @@ def course_advanced_updates(request, org, course, name):
# Indicate that tabs should *not* be filtered out of the metadata # Indicate that tabs should *not* be filtered out of the metadata
filter_tabs = False filter_tabs = False
try: try:
response_json = json.dumps(CourseMetadata.update_from_json(location, return JsonResponse(CourseMetadata.update_from_json(location,
request_body, request_body,
filter_tabs=filter_tabs)) filter_tabs=filter_tabs))
except (TypeError, ValueError), e: except (TypeError, ValueError) as e:
return HttpResponseBadRequest("Incorrect setting format. " + str(e), content_type="text/plain") return HttpResponseBadRequest("Incorrect setting format. " + str(e), content_type="text/plain")
return HttpResponse(response_json, mimetype="application/json")
class TextbookValidationError(Exception): class TextbookValidationError(Exception):
pass pass
......
...@@ -31,14 +31,16 @@ class JsonResponse(HttpResponse): ...@@ -31,14 +31,16 @@ class JsonResponse(HttpResponse):
""" """
Django HttpResponse subclass that has sensible defaults for outputting JSON. Django HttpResponse subclass that has sensible defaults for outputting JSON.
""" """
def __init__(self, object=None, *args, **kwargs): def __init__(self, object=None, status=None, encoder=DjangoJSONEncoder,
*args, **kwargs):
if object in (None, ""): if object in (None, ""):
content = "" content = ""
kwargs.setdefault("status", 204) status = status or 204
elif isinstance(object, QuerySet): elif isinstance(object, QuerySet):
content = serialize('json', object) content = serialize('json', object)
else: else:
content = json.dumps(object, indent=2, cls=DjangoJSONEncoder, content = json.dumps(object, cls=encoder, indent=2, ensure_ascii=False)
ensure_ascii=False)
kwargs.setdefault("content_type", "application/json") kwargs.setdefault("content_type", "application/json")
if status:
kwargs["status"] = status
super(JsonResponse, self).__init__(content, *args, **kwargs) super(JsonResponse, self).__init__(content, *args, **kwargs)
...@@ -2,6 +2,7 @@ from django.http import HttpResponse ...@@ -2,6 +2,7 @@ from django.http import HttpResponse
from util.json_request import JsonResponse from util.json_request import JsonResponse
import json import json
import unittest import unittest
import mock
class JsonResponseTestCase(unittest.TestCase): class JsonResponseTestCase(unittest.TestCase):
...@@ -33,10 +34,29 @@ class JsonResponseTestCase(unittest.TestCase): ...@@ -33,10 +34,29 @@ class JsonResponseTestCase(unittest.TestCase):
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
self.assertEqual(resp["content-type"], "application/json") self.assertEqual(resp["content-type"], "application/json")
def test_set_status(self): def test_set_status_kwarg(self):
obj = {"error": "resource not found"} obj = {"error": "resource not found"}
resp = JsonResponse(obj, status=404) resp = JsonResponse(obj, status=404)
compare = json.loads(resp.content) compare = json.loads(resp.content)
self.assertEqual(obj, compare) self.assertEqual(obj, compare)
self.assertEqual(resp.status_code, 404) self.assertEqual(resp.status_code, 404)
self.assertEqual(resp["content-type"], "application/json") self.assertEqual(resp["content-type"], "application/json")
def test_set_status_arg(self):
obj = {"error": "resource not found"}
resp = JsonResponse(obj, 404)
compare = json.loads(resp.content)
self.assertEqual(obj, compare)
self.assertEqual(resp.status_code, 404)
self.assertEqual(resp["content-type"], "application/json")
def test_encoder(self):
obj = [1, 2, 3]
encoder = object()
with mock.patch.object(json, "dumps", return_value="[1,2,3]") as dumps:
resp = JsonResponse(obj, encoder=encoder)
self.assertEqual(resp.status_code, 200)
compare = json.loads(resp.content)
self.assertEqual(obj, compare)
kwargs = dumps.call_args[1]
self.assertIs(kwargs["cls"], encoder)
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