Esempio n. 1
0
def _create_library(request):
    """
    Helper method for creating a new library.
    """
    if not auth.has_access(request.user, CourseCreatorRole()):
        log.exception(u"User %s tried to create a library without permission",
                      request.user.username)
        raise PermissionDenied()
    display_name = None
    try:
        display_name = request.json['display_name']
        org = request.json['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=error.message))
        })
    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=error.message)
        })
    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.'
              )
        })

    lib_key_str = unicode(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 _create_library(request):
    """
    Helper method for creating a new library.
    """
    display_name = None
    try:
        display_name = request.json['display_name']
        org = request.json['org']
        library = request.json.get('number', None)

        # [COLARAZ_CUSTOM]
        if not request.user.is_superuser and not org in configuration_helpers.get_value('course_org_filter'):
            log.exception('Unable to create library - invalid organization ({}).'.format(org))
            return JsonResponseBadRequest({
                "ErrMsg": _("Unable to create library '{}'.\n\n{} is not a valid organization.").format(display_name, org)
            })


        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=text_type(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=text_type(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.'
            )
        })

    lib_key_str = unicode(new_lib.location.library_key)
    return JsonResponse({
        'url': reverse_library_url('library_handler', lib_key_str),
        'library_key': lib_key_str,
    })
Esempio n. 3
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)["visibility"]
        course_module.edxnotes_visibility = visibility
        course_module.save()
        return JsonResponse(status=200)
    except (ValueError, KeyError):
        log.warning(
            "Could not decode request body as JSON and find a boolean visibility field: '%s'",
            request.body)
        return JsonResponseBadRequest()
Esempio n. 4
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. 5
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. 6
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. 7
0
def search_notes(request, course_id):
    """
    Handles search requests.
    """
    course_key = CourseKey.from_string(course_id)
    course = get_course_with_access(request.user, "load", course_key)

    if not is_feature_enabled(course):
        raise Http404

    if "text" not in request.GET:
        return HttpResponseBadRequest()

    query_string = request.GET["text"]
    try:
        search_results = search(request.user, course, query_string)
    except (EdxNotesParseError, EdxNotesServiceUnavailable) as err:
        return JsonResponseBadRequest({"error": err.message}, status=500)

    return HttpResponse(search_results)
Esempio n. 8
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.

    """
    logger.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):
        logger.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:
        logger.info(
            u"Missing parameter 'xqueue_body' for update example certificate end-point"
        )
        rate_limiter.tick_bad_request_counter(request)
        return JsonResponseBadRequest("Parameter 'xqueue_body' is required.")

    if 'xqueue_header' not in request.POST:
        logger.info(
            u"Missing parameter 'xqueue_header' for update example certificate end-point"
        )
        rate_limiter.tick_bad_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):
        logger.info(
            u"Could not decode params to example certificate end-point as JSON."
        )
        rate_limiter.tick_bad_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:
        # 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.
        logger.info(
            u"Could not find example certificate with uuid '%s' and access key '%s'",
            uuid, access_key)
        rate_limiter.tick_bad_request_counter(request)
        raise Http404

    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)
        logger.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_bad_request_counter(request)
            logger.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)
            logger.info(
                "Successfully updated example certificate with uuid '%s'.",
                uuid)

    # Let the XQueue know that we handled the response
    return JsonResponse({'return_code': 0})
Esempio n. 9
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. 10
0
def custom_settings_handler(request, course_key_string):
    """
    Course settings configuration
    GET
        html: get the page
        json: get the model
    PUT, POST
        json: update the Course's settings. The payload is a json rep of the
            metadata dicts.
    """
    course_key = CourseKey.from_string(course_key_string)
    with modulestore().bulk_operations(course_key):
        course_module = get_course_and_check_access(course_key, request.user)
        if 'text/html' in request.META.get('HTTP_ACCEPT',
                                           '') and request.method == 'GET':

            return render_to_response(
                'custom_settings.html', {
                    'context_course':
                    course_module,
                    'is_new':
                    course_module.is_new,
                    'invitation_only':
                    course_module.invitation_only,
                    'visible_to_manager_only':
                    course_module.visible_to_manager_only,
                })
        elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
            if request.method == 'GET':
                return JsonResponse(CourseMetadata.fetch(course_module))
            else:
                try:
                    # validate data formats and update the course module.
                    # Note: don't update mongo yet, but wait until after any tabs are changed
                    is_valid, errors, updated_data = CourseMetadata.validate_and_update_from_json(
                        course_module,
                        request.json,
                        user=request.user,
                    )

                    if is_valid:
                        try:
                            additional_info = {
                                'is_new':
                                request.POST.get('is_new', False),
                                'invitation_only':
                                request.POST.get('invitation_only', False),
                                'visible_to_manager_only':
                                request.POST.get('visible_to_manager_only',
                                                 False)
                            }
                            CourseMetadata.update_from_dict(
                                additional_info, course_module, request.user)
                            course_search_index_handler(
                                request, course_key_string)
                        except InvalidTabsException as err:
                            log.exception(err.message)
                            response_message = [{
                                'message':
                                _('An error occurred while trying to save your tabs'
                                  ),
                                'model': {
                                    'display_name': _('Tabs Exception')
                                }
                            }]
                            return JsonResponseBadRequest(response_message)

                        return JsonResponse(updated_data)
                    else:
                        return JsonResponseBadRequest(errors)

                # Handle all errors that validation doesn't catch
                except (TypeError, ValueError, InvalidTabsException) as err:
                    return HttpResponseBadRequest(django.utils.html.escape(
                        err.message),
                                                  content_type="text/plain")
Esempio n. 11
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")
Esempio n. 12
0
 def test_empty(self):
     resp = JsonResponseBadRequest()
     self.assertIsInstance(resp, HttpResponseBadRequest)
     self.assertEqual(resp.content, "")
     self.assertEqual(resp.status_code, 400)
     self.assertEqual(resp["content-type"], "application/json")