def _create_library(request): """ Helper method for creating a new library. """ display_name = None try: display_name = request.json['display_name'] org = request.json['org'] ensure_organization(org) library = request.json.get('number', None) if library is None: library = request.json['library'] store = modulestore() with store.default_store(ModuleStoreEnum.Type.split): new_lib = store.create_library( org=org, library=library, user_id=request.user.id, fields={"display_name": display_name}, ) # Give the user admin ("Instructor") role for this library: add_instructor(new_lib.location.library_key, request.user, request.user) except KeyError as error: log.exception("Unable to create library - missing required JSON key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library - missing required field '{field}'").format(field=str(error)) }) except InvalidKeyError as error: log.exception("Unable to create library - invalid key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library '{name}'.\n\n{err}").format(name=display_name, err=str(error)) }) except DuplicateCourseError: log.exception("Unable to create library - one already exists with the same key.") return JsonResponseBadRequest({ 'ErrMsg': _( 'There is already a library defined with the same ' 'organization and library code. Please ' 'change your library code so that it is unique within your organization.' ) }) except InvalidOrganizationException: log.exception("Unable to create library - %s is not a valid org short_name.", org) return JsonResponseBadRequest({ 'ErrMsg': _( "'{organization_key}' is not a valid organization identifier." ).format(organization_key=org) }) lib_key_str = str(new_lib.location.library_key) return JsonResponse({ 'url': reverse_library_url('library_handler', lib_key_str), 'library_key': lib_key_str, })
def test_dict(self): obj = {"foo": "bar"} resp = JsonResponseBadRequest(obj) compare = json.loads(resp.content.decode('utf-8')) assert obj == compare assert resp.status_code == 400 assert resp['content-type'] == 'application/json'
def test_set_status_arg(self): obj = {"error": "resource not found"} resp = JsonResponseBadRequest(obj, 404) compare = json.loads(resp.content.decode('utf-8')) assert obj == compare assert resp.status_code == 404 assert resp['content-type'] == 'application/json'
def edxnotes_visibility(request, course_id): """ Handle ajax call from "Show notes" checkbox. """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, "load", course_key) field_data_cache = FieldDataCache([course], course_key, request.user) course_module = get_module_for_descriptor(request.user, request, course, field_data_cache, course_key, course=course) if not is_feature_enabled(course, request.user): raise Http404 try: visibility = json.loads(request.body.decode('utf8'))["visibility"] course_module.edxnotes_visibility = visibility course_module.save() return JsonResponse(status=200) except (ValueError, KeyError): log.warning( u"Could not decode request body as JSON and find a boolean visibility field: '%s'", request.body) return JsonResponseBadRequest()
def test_dict(self): obj = {"foo": "bar"} resp = JsonResponseBadRequest(obj) compare = json.loads(resp.content.decode('utf-8')) self.assertEqual(obj, compare) self.assertEqual(resp.status_code, 400) self.assertEqual(resp["content-type"], "application/json")
def test_set_status_arg(self): obj = {"error": "resource not found"} resp = JsonResponseBadRequest(obj, 404) compare = json.loads(resp.content.decode('utf-8')) 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 = JsonResponseBadRequest(obj, encoder=encoder) assert resp.status_code == 400 compare = json.loads(resp.content.decode('utf-8')) assert obj == compare kwargs = dumps.call_args[1] assert kwargs['cls'] is encoder
def test_encoder(self): obj = [1, 2, 3] encoder = object() with mock.patch.object(json, "dumps", return_value="[1,2,3]") as dumps: resp = JsonResponseBadRequest(obj, encoder=encoder) self.assertEqual(resp.status_code, 400) compare = json.loads(resp.content.decode('utf-8')) self.assertEqual(obj, compare) kwargs = dumps.call_args[1] self.assertIs(kwargs["cls"], encoder)
def tabs_handler(request, course_key_string): """ The restful handler for static tabs. GET html: return page for editing static tabs json: not supported PUT or POST json: update the tab order. It is expected that the request body contains a JSON-encoded dict with entry "tabs". The value for "tabs" is an array of tab locators, indicating the desired order of the tabs. Creating a tab, deleting a tab, or changing its contents is not supported through this method. Instead use the general xblock URL (see item.xblock_handler). """ course_key = CourseKey.from_string(course_key_string) if not has_course_author_access(request.user, course_key): raise PermissionDenied() course_item = modulestore().get_course(course_key) if "application/json" in request.META.get("HTTP_ACCEPT", "application/json"): if request.method == "GET": # lint-amnesty, pylint: disable=no-else-raise raise NotImplementedError("coming soon") else: try: update_tabs_handler(course_item, request.json, request.user) except ValidationError as err: return JsonResponseBadRequest(err.detail) return JsonResponse() elif request.method == "GET": # assume html # get all tabs from the tabs list and select only static tabs (a.k.a. user-created tabs) # present in the same order they are displayed in LMS tabs_to_render = list(get_course_static_tabs(course_item, request.user)) return render_to_response( "edit-tabs.html", { "context_course": course_item, "tabs_to_render": tabs_to_render, "lms_link": get_lms_link_for_item(course_item.location), }, ) else: return HttpResponseNotFound()
def test_empty_string(self): resp = JsonResponseBadRequest("") assert isinstance(resp, HttpResponse) assert resp.content.decode('utf-8') == '' assert resp.status_code == 400 assert resp['content-type'] == 'application/json'
def notes(request, course_id): """ Notes view to handle list and search requests. Query parameters: page: page number to get page_size: number of items in the page text: text string to search. If `text` param is missing then get all the notes for the current user for this course else get only those notes which contain the `text` value. Arguments: request: HTTP request object course_id: course id Returns: Paginated response as JSON. A sample response is below. { "count": 101, "num_pages": 11, "current_page": 1, "results": [ { "chapter": { "index": 4, "display_name": "About Exams and Certificates", "location": "i4x://org/course/category/name@revision", "children": [ "i4x://org/course/category/name@revision" ] }, "updated": "Dec 09, 2015 at 09:31 UTC", "tags": ["shadow","oil"], "quote": "foo bar baz", "section": { "display_name": "edX Exams", "location": "i4x://org/course/category/name@revision", "children": [ "i4x://org/course/category/name@revision", "i4x://org/course/category/name@revision", ] }, "created": "2015-12-09T09:31:17.338305Z", "ranges": [ { "start": "/div[1]/p[1]", "end": "/div[1]/p[1]", "startOffset": 0, "endOffset": 6 } ], "user": "******", "text": "first angry height hungry structure", "course_id": "edx/DemoX/Demo", "id": "1231", "unit": { "url": "/courses/edx%2FDemoX%2FDemo/courseware/1414ffd5143b4b508f739b563ab468b7/workflow/1", "display_name": "EdX Exams", "location": "i4x://org/course/category/name@revision" }, "usage_id": "i4x://org/course/category/name@revision" } ], "next": "http://0.0.0.0:8000/courses/edx%2FDemoX%2FDemo/edxnotes/notes/?page=2&page_size=10", "start": 0, "previous": null } """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, 'load', course_key) if not is_feature_enabled(course, request.user): raise Http404 page = request.GET.get('page') or DEFAULT_PAGE page_size = request.GET.get('page_size') or DEFAULT_PAGE_SIZE text = request.GET.get('text') try: notes_info = get_notes(request, course, page=page, page_size=page_size, text=text) except (EdxNotesParseError, EdxNotesServiceUnavailable) as err: return JsonResponseBadRequest({"error": text_type(err)}, status=500) return HttpResponse(json.dumps(notes_info, cls=NoteJSONEncoder), content_type="application/json")
def update_example_certificate(request): """Callback from the XQueue that updates example certificates. Example certificates are used to verify that certificate generation is configured correctly for a course. Unlike other certificates, example certificates are not associated with a particular user or displayed to students. For this reason, we need a different end-point to update the status of generated example certificates. Arguments: request (HttpRequest) Returns: HttpResponse (200): Status was updated successfully. HttpResponse (400): Invalid parameters. HttpResponse (403): Rate limit exceeded for bad requests. HttpResponse (404): Invalid certificate identifier or access key. """ log.info(u"Received response for example certificate from XQueue.") rate_limiter = BadRequestRateLimiter() # Check the parameters and rate limits # If these are invalid, return an error response. if rate_limiter.is_rate_limit_exceeded(request): log.info( u"Bad request rate limit exceeded for update example certificate end-point." ) return HttpResponseForbidden("Rate limit exceeded") if 'xqueue_body' not in request.POST: log.info( u"Missing parameter 'xqueue_body' for update example certificate end-point" ) rate_limiter.tick_request_counter(request) return JsonResponseBadRequest("Parameter 'xqueue_body' is required.") if 'xqueue_header' not in request.POST: log.info( u"Missing parameter 'xqueue_header' for update example certificate end-point" ) rate_limiter.tick_request_counter(request) return JsonResponseBadRequest("Parameter 'xqueue_header' is required.") try: xqueue_body = json.loads(request.POST['xqueue_body']) xqueue_header = json.loads(request.POST['xqueue_header']) except (ValueError, TypeError): log.info( u"Could not decode params to example certificate end-point as JSON." ) rate_limiter.tick_request_counter(request) return JsonResponseBadRequest("Parameters must be JSON-serialized.") # Attempt to retrieve the example certificate record # so we can update the status. try: uuid = xqueue_body.get('username') access_key = xqueue_header.get('lms_key') cert = ExampleCertificate.objects.get(uuid=uuid, access_key=access_key) except ExampleCertificate.DoesNotExist as e: # If we are unable to retrieve the record, it means the uuid or access key # were not valid. This most likely means that the request is NOT coming # from the XQueue. Return a 404 and increase the bad request counter # to protect against a DDOS attack. log.info( u"Could not find example certificate with uuid '%s' and access key '%s'", uuid, access_key) rate_limiter.tick_request_counter(request) raise Http404 from e if 'error' in xqueue_body: # If an error occurs, save the error message so we can fix the issue. error_reason = xqueue_body.get('error_reason') cert.update_status(ExampleCertificate.STATUS_ERROR, error_reason=error_reason) log.warning(( u"Error occurred during example certificate generation for uuid '%s'. " u"The error response was '%s'."), uuid, error_reason) else: # If the certificate generated successfully, save the download URL # so we can display the example certificate. download_url = xqueue_body.get('url') if download_url is None: rate_limiter.tick_request_counter(request) log.warning( u"No download URL provided for example certificate with uuid '%s'.", uuid) return JsonResponseBadRequest( "Parameter 'download_url' is required for successfully generated certificates." ) else: cert.update_status(ExampleCertificate.STATUS_SUCCESS, download_url=download_url) log.info( u"Successfully updated example certificate with uuid '%s'.", uuid) # Let the XQueue know that we handled the response return JsonResponse({'return_code': 0})
def test_empty_string(self): resp = JsonResponseBadRequest("") self.assertIsInstance(resp, HttpResponse) self.assertEqual(resp.content.decode('utf-8'), "") self.assertEqual(resp.status_code, 400) self.assertEqual(resp["content-type"], "application/json")