Esempio n. 1
0
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,
    })
Esempio n. 2
0
 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'
Esempio n. 3
0
 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'
Esempio n. 4
0
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()
Esempio n. 5
0
 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")
Esempio n. 6
0
 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")
Esempio n. 7
0
 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
Esempio n. 8
0
 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)
Esempio n. 9
0
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()
Esempio n. 10
0
 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'
Esempio n. 11
0
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")
Esempio n. 12
0
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})
Esempio n. 13
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")