Ejemplo n.º 1
0
def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, user):
    """
    Invoke an XBlock handler, either authenticated or not.

    """
    location = unquote_slashes(usage_id)

    # Check parameters and fail fast if there's a problem
    if not Location.is_valid(location):
        raise Http404("Invalid location")

    # Check submitted files
    files = request.FILES or {}
    error_msg = _check_files_limits(files)
    if error_msg:
        return HttpResponse(json.dumps({"success": error_msg}))

    try:
        descriptor = modulestore().get_instance(course_id, location)
    except ItemNotFoundError:
        log.warn(
            "Invalid location for course id {course_id}: {location}".format(course_id=course_id, location=location)
        )
        raise Http404

    field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course_id, user, descriptor)
    instance = get_module(user, request, location, field_data_cache, course_id, grade_bucket_type="ajax")
    if instance is None:
        # Either permissions just changed, or someone is trying to be clever
        # and load something they shouldn't have access to.
        log.debug("No module %s for user %s -- access denied?", location, user)
        raise Http404

    req = django_to_webob_request(request)
    try:
        resp = instance.handle(handler, req, suffix)

    except NoSuchHandlerError:
        log.exception("XBlock %s attempted to access missing handler %r", instance, handler)
        raise Http404

    # If we can't find the module, respond with a 404
    except NotFoundError:
        log.exception("Module indicating to user that request doesn't exist")
        raise Http404

    # For XModule-specific errors, we log the error and respond with an error message
    except ProcessingError as err:
        log.warning("Module encountered an error while processing AJAX call", exc_info=True)
        return JsonResponse(object={"success": err.args[0]}, status=200)

    # If any other error occurred, re-raise it to trigger a 500 response
    except Exception:
        log.exception("error executing xblock handler")
        raise

    return webob_to_django_response(resp)
 def parse_sources(xml_element):
     """ Parse xml_element 'sources' attr and return a list of location strings. """
     result = []
     sources = xml_element.get('sources')
     if sources:
         locations = [location.strip() for location in sources.split(';')]
         for location in locations:
             if Location.is_valid(location):  # Check valid location url.
                 result.append(location)
     return result
Ejemplo n.º 3
0
 def parse_sources(xml_element):
     """ Parse xml_element 'sources' attr and return a list of location strings. """
     result = []
     sources = xml_element.get('sources')
     if sources:
         locations = [location.strip() for location in sources.split(';')]
         for location in locations:
             if Location.is_valid(location):  # Check valid location url.
                 result.append(location)
     return result
Ejemplo n.º 4
0
 def parse_sources(xml_element, system, return_descriptor=False):
     """Parse xml_element 'sources' attr and:
     if return_descriptor=True - return list of descriptors
     if return_descriptor=False - return list of locations
     """
     result = []
     sources = xml_element.get('sources')
     if sources:
         locations = [location.strip() for location in sources.split(';')]
         for location in locations:
             if Location.is_valid(location):  # Check valid location url.
                 try:
                     if return_descriptor:
                         descriptor = system.load_item(location)
                         result.append(descriptor)
                     else:
                         result.append(location)
                 except ItemNotFoundError:
                     msg = "Invalid module by location."
                     log.exception(msg)
                     system.error_tracker(msg)
     return result
Ejemplo n.º 5
0
 def parse_sources(xml_element, system, return_descriptor=False):
     """Parse xml_element 'sources' attr and:
     if return_descriptor=True - return list of descriptors
     if return_descriptor=False - return list of locations
     """
     result = []
     sources = xml_element.get('sources')
     if sources:
         locations = [location.strip() for location in sources.split(';')]
         for location in locations:
             if Location.is_valid(location):  # Check valid location url.
                 try:
                     if return_descriptor:
                         descriptor = system.load_item(location)
                         result.append(descriptor)
                     else:
                         result.append(location)
                 except ItemNotFoundError:
                     msg = "Invalid module by location."
                     log.exception(msg)
                     system.error_tracker(msg)
     return result
Ejemplo n.º 6
0
def modx_dispatch(request, dispatch, location, course_id):
    ''' Generic view for extensions. This is where AJAX calls go.

    Arguments:

      - request -- the django request.
      - dispatch -- the command string to pass through to the module's handle_ajax call
           (e.g. 'problem_reset').  If this string contains '?', only pass
           through the part before the first '?'.
      - location -- the module location. Used to look up the XModule instance
      - course_id -- defines the course context for this request.

    Raises PermissionDenied if the user is not logged in. Raises Http404 if
    the location and course_id do not identify a valid module, the module is
    not accessible by the user, or the module raises NotFoundError. If the
    module raises any other error, it will escape this function.
    '''
    # ''' (fix emacs broken parsing)

    # Check parameters and fail fast if there's a problem
    if not Location.is_valid(location):
        raise Http404("Invalid location")

    if not request.user.is_authenticated():
        raise PermissionDenied

    # Get the submitted data
    data = request.POST.copy()

    # Get and check submitted files
    files = request.FILES or {}
    error_msg = _check_files_limits(files)
    if error_msg:
        return HttpResponse(json.dumps({'success': error_msg}))
    for key in files:  # Merge files into to data dictionary
        data[key] = files.getlist(key)

    try:
        descriptor = modulestore().get_instance(course_id, location)
    except ItemNotFoundError:
        log.warn(
            "Invalid location for course id {course_id}: {location}".format(
                course_id=course_id, location=location))
        raise Http404

    field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
        course_id, request.user, descriptor)

    instance = get_module(request.user,
                          request,
                          location,
                          field_data_cache,
                          course_id,
                          grade_bucket_type='ajax')
    if instance is None:
        # Either permissions just changed, or someone is trying to be clever
        # and load something they shouldn't have access to.
        log.debug("No module {0} for user {1}--access denied?".format(
            location, request.user))
        raise Http404

    # Let the module handle the AJAX
    try:
        ajax_return = instance.handle_ajax(dispatch, data)
        # Save any fields that have changed to the underlying KeyValueStore
        instance.save()

    # If we can't find the module, respond with a 404
    except NotFoundError:
        log.exception("Module indicating to user that request doesn't exist")
        raise Http404

    # For XModule-specific errors, we log the error and respond with an error message
    except ProcessingError as err:
        log.warning("Module encountered an error while processing AJAX call",
                    exc_info=True)
        return JsonResponse(object={'success': err.args[0]}, status=200)

    # If any other error occurred, re-raise it to trigger a 500 response
    except:
        log.exception("error processing ajax call")
        raise

    # Return whatever the module wanted to return to the client/caller
    return HttpResponse(ajax_return)
Ejemplo n.º 7
0
def modx_dispatch(request, dispatch, location, course_id):
    ''' Generic view for extensions. This is where AJAX calls go.

    Arguments:

      - request -- the django request.
      - dispatch -- the command string to pass through to the module's handle_ajax call
           (e.g. 'problem_reset').  If this string contains '?', only pass
           through the part before the first '?'.
      - location -- the module location. Used to look up the XModule instance
      - course_id -- defines the course context for this request.

    Raises PermissionDenied if the user is not logged in. Raises Http404 if
    the location and course_id do not identify a valid module, the module is
    not accessible by the user, or the module raises NotFoundError. If the
    module raises any other error, it will escape this function.
    '''
    # ''' (fix emacs broken parsing)

    # Check parameters and fail fast if there's a problem
    if not Location.is_valid(location):
        raise Http404("Invalid location")

    if not request.user.is_authenticated():
        raise PermissionDenied

    # Get the submitted data
    data = request.POST.copy()

    # Get and check submitted files
    files = request.FILES or {}
    error_msg = _check_files_limits(files)
    if error_msg:
        return HttpResponse(json.dumps({'success': error_msg}))
    for key in files:  # Merge files into to data dictionary
        data[key] = files.getlist(key)

    try:
        descriptor = modulestore().get_instance(course_id, location)
    except ItemNotFoundError:
        log.warn(
            "Invalid location for course id {course_id}: {location}".format(
                course_id=course_id,
                location=location
            )
        )
        raise Http404

    field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
        course_id,
        request.user,
        descriptor
    )

    instance = get_module(request.user, request, location, field_data_cache, course_id, grade_bucket_type='ajax')
    if instance is None:
        # Either permissions just changed, or someone is trying to be clever
        # and load something they shouldn't have access to.
        log.debug("No module {0} for user {1}--access denied?".format(location, request.user))
        raise Http404

    # Let the module handle the AJAX
    try:
        ajax_return = instance.handle_ajax(dispatch, data)
        # Save any fields that have changed to the underlying KeyValueStore
        instance.save()

    # If we can't find the module, respond with a 404
    except NotFoundError:
        log.exception("Module indicating to user that request doesn't exist")
        raise Http404

    # For XModule-specific errors, we log the error and respond with an error message
    except ProcessingError as err:
        log.warning("Module encountered an error while processing AJAX call",
                    exc_info=True)
        return JsonResponse(object={'success': err.args[0]}, status=200)

    # If any other error occurred, re-raise it to trigger a 500 response
    except:
        log.exception("error processing ajax call")
        raise

    # Return whatever the module wanted to return to the client/caller
    return HttpResponse(ajax_return)
Ejemplo n.º 8
0
 def test_is_valid(self, loc):
     self.assertTrue(Location.is_valid(loc))
Ejemplo n.º 9
0
def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix,
                           user):
    """
    Invoke an XBlock handler, either authenticated or not.

    """
    location = unquote_slashes(usage_id)

    # Check parameters and fail fast if there's a problem
    if not Location.is_valid(location):
        raise Http404("Invalid location")

    # Check submitted files
    files = request.FILES or {}
    error_msg = _check_files_limits(files)
    if error_msg:
        return HttpResponse(json.dumps({'success': error_msg}))

    try:
        descriptor = modulestore().get_instance(course_id, location)
    except ItemNotFoundError:
        log.warn(
            "Invalid location for course id {course_id}: {location}".format(
                course_id=course_id, location=location))
        raise Http404

    field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
        course_id, user, descriptor)
    instance = get_module(user,
                          request,
                          location,
                          field_data_cache,
                          course_id,
                          grade_bucket_type='ajax')
    if instance is None:
        # Either permissions just changed, or someone is trying to be clever
        # and load something they shouldn't have access to.
        log.debug("No module %s for user %s -- access denied?", location, user)
        raise Http404

    req = django_to_webob_request(request)
    try:
        resp = instance.handle(handler, req, suffix)

    except NoSuchHandlerError:
        log.exception("XBlock %s attempted to access missing handler %r",
                      instance, handler)
        raise Http404

    # If we can't find the module, respond with a 404
    except NotFoundError:
        log.exception("Module indicating to user that request doesn't exist")
        raise Http404

    # For XModule-specific errors, we log the error and respond with an error message
    except ProcessingError as err:
        log.warning("Module encountered an error while processing AJAX call",
                    exc_info=True)
        return JsonResponse(object={'success': err.args[0]}, status=200)

    # If any other error occurred, re-raise it to trigger a 500 response
    except Exception:
        log.exception("error executing xblock handler")
        raise

    return webob_to_django_response(resp)
Ejemplo n.º 10
0
def test_is_valid():
    for v in valid:
        assert_equals(Location.is_valid(v), True)

    for v in invalid:
        assert_equals(Location.is_valid(v), False)
Ejemplo n.º 11
0
 def test_is_invalid(self, loc):
     self.assertFalse(Location.is_valid(loc))
Ejemplo n.º 12
0
 def test_is_valid(self, loc):
     self.assertTrue(Location.is_valid(loc))
Ejemplo n.º 13
0
def handle_xblock_callback(request, course_id, usage_id, handler, suffix=None):
    """
    Generic view for extensions. This is where AJAX calls go.

    Arguments:

      - request -- the django request.
      - location -- the module location. Used to look up the XModule instance
      - course_id -- defines the course context for this request.

    Raises PermissionDenied if the user is not logged in. Raises Http404 if
    the location and course_id do not identify a valid module, the module is
    not accessible by the user, or the module raises NotFoundError. If the
    module raises any other error, it will escape this function.
    """
    location = unquote_slashes(usage_id)

    # Check parameters and fail fast if there's a problem
    if not Location.is_valid(location):
        raise Http404("Invalid location")

    if not request.user.is_authenticated():
        raise PermissionDenied

    # Check submitted files
    files = request.FILES or {}
    error_msg = _check_files_limits(files)
    if error_msg:
        return HttpResponse(json.dumps({'success': error_msg}))

    try:
        descriptor = modulestore().get_instance(course_id, location)
    except ItemNotFoundError:
        log.warn(
            "Invalid location for course id {course_id}: {location}".format(
                course_id=course_id,
                location=location
            )
        )
        raise Http404

    field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
        course_id,
        request.user,
        descriptor
    )

    instance = get_module(request.user, request, location, field_data_cache, course_id, grade_bucket_type='ajax')
    if instance is None:
        # Either permissions just changed, or someone is trying to be clever
        # and load something they shouldn't have access to.
        log.debug("No module %s for user %s -- access denied?", location, request.user)
        raise Http404

    req = django_to_webob_request(request)
    try:
        resp = instance.handle(handler, req, suffix)

    except NoSuchHandlerError:
        log.exception("XBlock %s attempted to access missing handler %r", instance, handler)
        raise Http404

    # If we can't find the module, respond with a 404
    except NotFoundError:
        log.exception("Module indicating to user that request doesn't exist")
        raise Http404

    # For XModule-specific errors, we log the error and respond with an error message
    except ProcessingError as err:
        log.warning("Module encountered an error while processing AJAX call",
                    exc_info=True)
        return JsonResponse(object={'success': err.args[0]}, status=200)

    # If any other error occurred, re-raise it to trigger a 500 response
    except Exception:
        log.exception("error executing xblock handler")
        raise

    return webob_to_django_response(resp)
Ejemplo n.º 14
0
 def test_is_invalid(self, loc):
     self.assertFalse(Location.is_valid(loc))
Ejemplo n.º 15
0
def modx_dispatch(request, dispatch, location, course_id):
    ''' Generic view for extensions. This is where AJAX calls go.

    Arguments:

      - request -- the django request.
      - dispatch -- the command string to pass through to the module's handle_ajax call
           (e.g. 'problem_reset').  If this string contains '?', only pass
           through the part before the first '?'.
      - location -- the module location. Used to look up the XModule instance
      - course_id -- defines the course context for this request.

    Raises PermissionDenied if the user is not logged in. Raises Http404 if
    the location and course_id do not identify a valid module, the module is
    not accessible by the user, or the module raises NotFoundError. If the
    module raises any other error, it will escape this function.
    '''
    # ''' (fix emacs broken parsing)

    # Check parameters and fail fast if there's a problem
    if not Location.is_valid(location):
        raise Http404("Invalid location")

    if not request.user.is_authenticated():
        raise PermissionDenied

    # Check for submitted files and basic file size checks
    p = request.POST.copy()
    if request.FILES:
        for fileinput_id in request.FILES.keys():
            inputfiles = request.FILES.getlist(fileinput_id)

            if len(inputfiles) > settings.MAX_FILEUPLOADS_PER_INPUT:
                too_many_files_msg = 'Submission aborted! Maximum %d files may be submitted at once' %\
                    settings.MAX_FILEUPLOADS_PER_INPUT
                return HttpResponse(json.dumps({'success':
                                                too_many_files_msg}))

            for inputfile in inputfiles:
                if inputfile.size > settings.STUDENT_FILEUPLOAD_MAX_SIZE:  # Bytes
                    file_too_big_msg = 'Submission aborted! Your file "%s" is too large (max size: %d MB)' %\
                                        (inputfile.name, settings.STUDENT_FILEUPLOAD_MAX_SIZE / (1000 ** 2))
                    return HttpResponse(
                        json.dumps({'success': file_too_big_msg}))
            p[fileinput_id] = inputfiles

    try:
        descriptor = modulestore().get_instance(course_id, location)
    except ItemNotFoundError:
        log.warn(
            "Invalid location for course id {course_id}: {location}".format(
                course_id=course_id, location=location))
        raise Http404

    model_data_cache = ModelDataCache.cache_for_descriptor_descendents(
        course_id, request.user, descriptor)

    instance = get_module(request.user,
                          request,
                          location,
                          model_data_cache,
                          course_id,
                          grade_bucket_type='ajax')
    if instance is None:
        # Either permissions just changed, or someone is trying to be clever
        # and load something they shouldn't have access to.
        log.debug("No module {0} for user {1}--access denied?".format(
            location, request.user))
        raise Http404

    # Let the module handle the AJAX
    try:
        ajax_return = instance.handle_ajax(dispatch, p)

    # If we can't find the module, respond with a 404
    except NotFoundError:
        log.exception("Module indicating to user that request doesn't exist")
        raise Http404

    # For XModule-specific errors, we respond with 400
    except ProcessingError:
        log.warning("Module encountered an error while prcessing AJAX call",
                    exc_info=True)
        return HttpResponseBadRequest()

    # If any other error occurred, re-raise it to trigger a 500 response
    except:
        log.exception("error processing ajax call")
        raise

    # Return whatever the module wanted to return to the client/caller
    return HttpResponse(ajax_return)
Ejemplo n.º 16
0
def test_is_valid():
    for v in valid:
        assert_equals(Location.is_valid(v), True)

    for v in invalid:
        assert_equals(Location.is_valid(v), False)
def modx_dispatch(request, dispatch, location, course_id):
    """ Generic view for extensions. This is where AJAX calls go.

    Arguments:

      - request -- the django request.
      - dispatch -- the command string to pass through to the module's handle_ajax call
           (e.g. 'problem_reset').  If this string contains '?', only pass
           through the part before the first '?'.
      - location -- the module location. Used to look up the XModule instance
      - course_id -- defines the course context for this request.

    Raises PermissionDenied if the user is not logged in. Raises Http404 if
    the location and course_id do not identify a valid module, the module is
    not accessible by the user, or the module raises NotFoundError. If the
    module raises any other error, it will escape this function.
    """
    # ''' (fix emacs broken parsing)

    # Check parameters and fail fast if there's a problem
    if not Location.is_valid(location):
        raise Http404("Invalid location")

    if not request.user.is_authenticated():
        raise PermissionDenied

    # Get the submitted data
    data = request.POST.copy()

    # Get and check submitted files
    files = request.FILES or {}
    error_msg = _check_files_limits(files)
    if error_msg:
        return HttpResponse(json.dumps({"success": error_msg}))
    for key in files:  # Merge files into to data dictionary
        data[key] = files.getlist(key)

    # @begin:dispatch poll_compare request
    # @data:2013-11-20
    data_data = request.POST.get("data", None)
    if not data_data is None:
        data["data"] = request.POST.get("data", None)
        return modx_dispatch_pollCompate(request=request, course_id=course_id, user=request.user, data=data)
    # @end

    try:
        descriptor = modulestore().get_instance(course_id, location)
    except ItemNotFoundError:
        log.warn(
            "Invalid location for course id {course_id}: {location}".format(course_id=course_id, location=location)
        )
        raise Http404

    field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course_id, request.user, descriptor)

    instance = get_module(request.user, request, location, field_data_cache, course_id, grade_bucket_type="ajax")
    if instance is None:
        # Either permissions just changed, or someone is trying to be clever
        # and load something they shouldn't have access to.
        log.debug("No module {0} for user {1}--access denied?".format(location, request.user))
        raise Http404

    # Let the module handle the AJAX
    try:
        ajax_return = instance.handle_ajax(dispatch, data)

        # @begin:complete_course_survey
        # @data:2013-12-13
        try:
            if hasattr(instance, "complete_survey") and dispatch == "problem_check":
                if instance.complete_survey and dispatch == "problem_check":
                    student = request.user
                    course_descriptor = get_course_by_id(course_id)
                    field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
                        course_id, student, course_descriptor, depth=None
                    )
                    course_instance = get_module(
                        student,
                        request,
                        course_descriptor.location,
                        field_data_cache,
                        course_id,
                        grade_bucket_type="ajax",
                    )
                    percent = grade(student, request, course_descriptor, field_data_cache)["percent"]
                    ajax_return_json = json.loads(ajax_return)
                    if ajax_return_json["success"] == u"correct":
                        completed_course_prompt = "<p style='color:red'>Congratulations on completing this course!  You can access your certificate and completed course on your dashboard.</p>"
                        # @begin:Use dynamic score to judge that if you pass the subject.
                        # @data:2015-11-19
                        uncompleted_course_prompt = (
                            "<p style='color:red'>This course requires a passing score of "
                            + str(int(course_descriptor.grade_cutoffs["Pass"] * 100))
                            + " percent or higher.  Please reference your scores in &quot;My Progress&quot; to retake or complete the assignments.</p>"
                        )
                        if percent >= course_descriptor.grade_cutoffs["Pass"]:  # 0.85
                            # @end
                            course_instance.complete_course = True
                            course_instance.complete_date = datetime.now(UTC())
                            ajax_return_json["contents"] = completed_course_prompt + ajax_return_json["contents"]
                            instance.save()
                            # True North Logic integration
                            if tnl_course(student, course_id):
                                domain = tnl_domain_from_user(student)
                                tnl_instance = TNLInstance(domain)
                                tnl_instance.register_completion(student, course_id, percent)
                        else:
                            course_instance.complete_course = False
                            course_instance.complete_date = datetime.fromtimestamp(0, UTC())
                            ajax_return_json["contents"] = uncompleted_course_prompt + ajax_return_json["contents"]
                        ajax_return = json.dumps(ajax_return_json)
                    else:
                        course_instance.complete_course = False
                        course_instance.complete_date = datetime.fromtimestamp(0, UTC())
                        instance.save()
                    course_instance.save()
                else:
                    # Save any fields that have changed to the underlying KeyValueStore
                    instance.save()
            else:
                instance.save()
        except ItemNotFoundError:
            instance.save()
        # @end

    # If we can't find the module, respond with a 404
    except NotFoundError:
        log.exception("Module indicating to user that request doesn't exist")
        raise Http404

    # For XModule-specific errors, we log the error and respond with an error message
    except ProcessingError as err:
        log.warning("Module encountered an error while processing AJAX call", exc_info=True)
        return JsonResponse(object={"success": err.args[0]}, status=200)

    # If any other error occurred, re-raise it to trigger a 500 response
    except:
        log.exception("error processing ajax call")
        raise

    # Return whatever the module wanted to return to the client/caller
    return HttpResponse(ajax_return)
Ejemplo n.º 18
0
def modx_dispatch(request, dispatch, location, course_id):
    ''' Generic view for extensions. This is where AJAX calls go.

    Arguments:

      - request -- the django request.
      - dispatch -- the command string to pass through to the module's handle_ajax call
           (e.g. 'problem_reset').  If this string contains '?', only pass
           through the part before the first '?'.
      - location -- the module location. Used to look up the XModule instance
      - course_id -- defines the course context for this request.

    Raises PermissionDenied if the user is not logged in. Raises Http404 if
    the location and course_id do not identify a valid module, the module is
    not accessible by the user, or the module raises NotFoundError. If the
    module raises any other error, it will escape this function.
    '''
    # ''' (fix emacs broken parsing)

    # Check parameters and fail fast if there's a problem
    if not Location.is_valid(location):
        raise Http404("Invalid location")

    if not request.user.is_authenticated():
        raise PermissionDenied

    # Check for submitted files and basic file size checks
    p = request.POST.copy()
    if request.FILES:
        for fileinput_id in request.FILES.keys():
            inputfiles = request.FILES.getlist(fileinput_id)

            if len(inputfiles) > settings.MAX_FILEUPLOADS_PER_INPUT:
                too_many_files_msg = 'Submission aborted! Maximum %d files may be submitted at once' %\
                    settings.MAX_FILEUPLOADS_PER_INPUT
                return HttpResponse(json.dumps({'success': too_many_files_msg}))

            for inputfile in inputfiles:
                if inputfile.size > settings.STUDENT_FILEUPLOAD_MAX_SIZE:   # Bytes
                    file_too_big_msg = 'Submission aborted! Your file "%s" is too large (max size: %d MB)' %\
                        (inputfile.name, settings.STUDENT_FILEUPLOAD_MAX_SIZE / (
                            1000 ** 2))
                    return HttpResponse(json.dumps({'success': file_too_big_msg}))
            p[fileinput_id] = inputfiles

    try:
        descriptor = modulestore().get_instance(course_id, location)
    except ItemNotFoundError:
        log.warn(
            "Invalid location for course id {course_id}: {location}".format(
                course_id=course_id,
                location=location
            )
        )
        raise Http404

    model_data_cache = ModelDataCache.cache_for_descriptor_descendents(
        course_id,
        request.user, descriptor)

    instance = get_module(request.user, request, location,
                          model_data_cache, course_id, grade_bucket_type='ajax')
    if instance is None:
        # Either permissions just changed, or someone is trying to be clever
        # and load something they shouldn't have access to.
        log.debug("No module {0} for user {1}--access denied?".format(
            location, request.user))
        raise Http404

    # Let the module handle the AJAX
    try:
        ajax_return = instance.handle_ajax(dispatch, p)

    # If we can't find the module, respond with a 404
    except NotFoundError:
        log.exception("Module indicating to user that request doesn't exist")
        raise Http404

    # For XModule-specific errors, we respond with 400
    except ProcessingError:
        log.warning("Module encountered an error while prcessing AJAX call",
                    exc_info=True)
        return HttpResponseBadRequest()

    # If any other error occurred, re-raise it to trigger a 500 response
    except:
        log.exception("error processing ajax call")
        raise

    # Return whatever the module wanted to return to the client/caller
    return HttpResponse(ajax_return)