Beispiel #1
0
    def __call__(self, request, result, handler):
        if isinstance(result, ErrorDict):
            result = dictFromErrorDict(result)

        resource = handler.resource

        em_format = resource.determine_emitter(request)
        emitter, ct = Emitter.get(em_format)

        srl = emitter(result,
                      typemapper,
                      handler,
                      handler.fields,
                      anonymous=True)

        try:
            if resource.stream:
                stream = srl.stream_render(request)
            else:
                stream = srl.render(request)

            self.__init__(stream, mimetype=ct)
            self.streaming = resource.stream

        except HttpStatusCode, e:
            return e.response
Beispiel #2
0
def error_resp(message, error_type=None, resp=rc.BAD_REQUEST, status_code=None):
    logging.warn("Status Code " + str(resp.status_code) + ", error_type: " + repr(error_type) + ", message: " + repr(message))
    error_json = {}
    if message and error_type:
        (error_type_resp, error_type) = error_type
        resp = error_type_resp
        error = {}
        error['type'] = error_type
        error['message'] = message
        error_json['error'] = error  
    elif message:
        error = {}
        error['type'] = ''
        error['message'] = message
        error_json['error'] = error
    
    if message or error_type:
        emitter, ct = Emitter.get('json')  #TODO: Make this work for other emitter formats
        srl = emitter(error_json, None, None, None, None)
        rendered_resp = srl.render(HttpRequest())
        final_resp = HttpResponse(rendered_resp, mimetype=ct)
        if status_code:
            final_resp.status_code = status_code
        else:
            final_resp.status_code = resp.status_code
        return final_resp
    else:
        return resp
Beispiel #3
0
def apply_json_emitter(value_to_emit, handler=None):
    emitter, ct = Emitter.get('json')  #TODO: Make this work for other emitter formats
    handler_fields = None

    if handler:
        handler_fields = handler.fields
    srl = emitter(value_to_emit, typemapper, handler, handler_fields, None)
    json = srl.construct()

    return json
Beispiel #4
0
def render_created(self, request, new_obj, new_url):
    """Quick hack to return a 201 Created along with a JSON rendering of 
    what was created"""
    resp = rc.CREATED
    emitter, ct = Emitter.get('json')
    resp['Content-Type'] = ct
    resp['Location'] = new_url
    srl = emitter(new_obj, typemapper, self, self.fields, False)
    resp.content = srl.render(request)
    return resp
Beispiel #5
0
 def form_validation_response(self, e, request,em_format):
     print 'in form_validation_response 1'
     try:
         emitter, ct = Emitter.get(em_format)
         fields = self.handler.fields
     except ValueError:
         result = piston.utils.rc.BAD_REQUEST
         result.content = "Invalid output format specified '%s'." % em_format
         return result
     serialized_errors = dict((key, [unicode(v) for v in values])
                             for key,values in e.form.errors.items())
     srl = emitter(serialized_errors, piston.handler.typemapper, self.handler, fields, False)
     stream = srl.render(request)
     resp = HttpResponse(stream, mimetype=ct, status=400)
     return resp
Beispiel #6
0
def build_error_response(e, request):

    # logger.error(str(e.status_code) + ' API error: ' + e.type)
    content = {"error": True, "type": e.type, "status_code": e.status_code, "explanation": ""}
    content.update(e.extra)
    response = rc.BAD_REQUEST
    format = request.GET.get("format", "json")

    em_info = Emitter.get(format)
    RequestEmitter = em_info[0]
    emitter = RequestEmitter(content, typemapper, "", "", False)
    response.content = emitter.render(request)
    response["Content-Type"] = em_info[1]

    return response
Beispiel #7
0
 def form_validation_response(self, e, request, em_format):
     print 'in form_validation_response 1'
     try:
         emitter, ct = Emitter.get(em_format)
         fields = self.handler.fields
     except ValueError:
         result = piston.utils.rc.BAD_REQUEST
         result.content = "Invalid output format specified '%s'." % em_format
         return result
     serialized_errors = dict((key, [unicode(v) for v in values])
                              for key, values in e.form.errors.items())
     srl = emitter(serialized_errors, piston.handler.typemapper,
                   self.handler, fields, False)
     stream = srl.render(request)
     resp = HttpResponse(stream, mimetype=ct, status=400)
     return resp
Beispiel #8
0
    def render(self, request, *args, **kwargs):
        f = StringIO.StringIO()
        out = csv.writer(f,dialect='excel')
        
        c = self.construct()
        
        if not bool(request.REQUEST.get('headerless', False)):
            out.writerow(self.fields)

        def mapper(row):
            return [row[key] for key in self.fields]

        out.writerows(map(mapper, c))

        # In this case we'll hanlde the HttpResponse wrapping.
        _, ct = Emitter.get('csv')
        response = HttpResponse(f.getvalue(), ct)
        response['Content-Disposition'] = 'attachment; filename=irack.csv'
        return response
Beispiel #9
0
def build_error_response(e, request):

    #logger.error(str(e.status_code) + ' API error: ' + e.type)
    content = {
        "error": True,
        "type": e.type,
        "status_code": e.status_code,
        "explanation": ""
    }
    content.update(e.extra)
    response = rc.BAD_REQUEST
    format = request.GET.get("format", "json")

    em_info = Emitter.get(format)
    RequestEmitter = em_info[0]
    emitter = RequestEmitter(content, typemapper, "", "", False)
    response.content = emitter.render(request)
    response['Content-Type'] = em_info[1]

    return response
Beispiel #10
0
    def __call__(self, request, result, handler):
        if isinstance(result, ErrorDict):
            result = dictFromErrorDict(result)

        resource = handler.resource

        em_format = resource.determine_emitter(request)
        emitter, ct = Emitter.get(em_format)

        srl = emitter(result, typemapper, handler, handler.fields, anonymous=True)

        try:
            if resource.stream:
                stream = srl.stream_render(request)
            else:
                stream = srl.render(request)

            self.__init__(stream, mimetype=ct)
            self.streaming = resource.stream

        except HttpStatusCode, e:
            return e.response
Beispiel #11
0
                    assert range_end != None
                    return (range_start, range_end)


                try:
                    total = result.count()
                    start, end = get_range(request_range[0], request_range[1], total)
                    result = result[start:end + 1]
                    content_range = "items %i-%i/%i" % (start, end, total)
                except BadRangeException, e:
                    resp = rc.BAD_RANGE
                    resp.write("\n%s" % e.value)
                    return resp
        #end paging

        emitter, ct = Emitter.get(em_format)
        fields = handler.fields
        if hasattr(handler, 'list_fields') and (
                isinstance(result, list) or isinstance(result, QuerySet)):
            fields = handler.list_fields

        srl = emitter(result, typemapper, handler, fields, anonymous)

        try:
            """
            Decide whether or not we want a generator here,
            or we just want to buffer up the entire result
            before sending it to the client. Won't matter for
            smaller datasets, but larger will have an impact.
            """
            if self.stream:
Beispiel #12
0
    def __call__(self, request, *args, **kwargs):
        rm = request.method.upper()

        if rm == "PUT":
            coerce_put_post(request)

        actor, anonymous = self.authenticate(request, rm)

        if anonymous is CHALLENGE:
            return actor()
        else:
            handler = actor

        if rm in ('POST', 'PUT'):
            try:
                translate_mime(request)
            except MimerDataException:
                return rc.BAD_REQUEST
            if not hasattr(request, 'data'):
                if rm == 'POST':
                    request.data = request.POST
                else:
                    request.data = request.PUT

        if not rm in handler.allowed_methods:
            return HttpResponseNotAllowed(handler.allowed_methods)

        meth = getattr(handler, self.callmap.get(rm, ''), None)
        if not meth:
            raise Http404

        em_format = self.determine_emitter(request, *args, **kwargs)
        kwargs.pop('emitter_format', None)

        request = self.cleanup_request(request)

        try:
            result = meth(request, *args, **kwargs)
        except ValueError:
            result = rc.BAD_REQUEST
            result.content = 'Invalid arguments'

        try:
            emitter, ct = Emitter.get(em_format)
            fields = handler.fields
            if hasattr(handler, 'list_fields') and isinstance(
                    result, (list, tuple, QuerySet)):
                fields = handler.list_fields
        except ValueError:
            result = rc.BAD_REQUEST
            result.content = "Invalid output format specified '%s'." % em_format
            return result

        status_code = 200

        if isinstance(result, HttpResponse) and not result._is_string:
            status_code = result.status_code
            result = result._container

        srl = emitter(result, typemapper, handler, fields, anonymous)

        try:
            if self.stream: stream = srl.stream_render(request)
            else: stream = srl.render(request)

            if not isinstance(stream, HttpResponse):
                resp = HttpResponse(stream, mimetype=ct, status=status_code)
            else:
                resp = stream
            resp.streaming = self.stream
            return resp
        except HttpStatusCode, e:
            return e.response
Beispiel #13
0
class Resource(object):
    """
    Resource. Create one for your URL mappings, just
    like you would with Django. Takes one argument,
    the handler. The second argument is optional, and
    is an authentication handler. If not specified,
    `NoAuthentication` will be used by default.
    """
    callmap = { 'GET': 'read', 'POST': 'create',
                'PUT': 'update', 'DELETE': 'delete' }

    def __init__(self, handler, authentication=None):
        if not callable(handler):
            raise AttributeError, "Handler not callable."

        self.handler = handler()
        self.csrf_exempt = getattr(self.handler, 'csrf_exempt', True)

        if not authentication:
            self.authentication = (NoAuthentication(),)
        elif isinstance(authentication, (list, tuple)):
            self.authentication = authentication
        else:
            self.authentication = (authentication,)

        # Erroring
        self.email_errors = getattr(settings, 'PISTON_EMAIL_ERRORS', True)
        self.display_errors = getattr(settings, 'PISTON_DISPLAY_ERRORS', True)
        self.stream = getattr(settings, 'PISTON_STREAM_OUTPUT', False)

    def determine_emitter(self, request, *args, **kwargs):
        """
        Function for determining which emitter to use
        for output. It lives here so you can easily subclass
        `Resource` in order to change how emission is detected.

        You could also check for the `Accept` HTTP header here,
        since that pretty much makes sense. Refer to `Mimer` for
        that as well.
        """
        em = kwargs.pop('emitter_format', None)

        if not em:
            em = request.GET.get('format', 'json')

        return em

    def form_validation_response(self, e):
        """
        Method to return form validation error information. 
        You will probably want to override this in your own
        `Resource` subclass.
        """
        resp = rc.BAD_REQUEST
        resp.write(' '+str(e.form.errors))
        return resp

    @property
    def anonymous(self):
        """
        Gets the anonymous handler. Also tries to grab a class
        if the `anonymous` value is a string, so that we can define
        anonymous handlers that aren't defined yet (like, when
        you're subclassing your basehandler into an anonymous one.)
        """
        if hasattr(self.handler, 'anonymous'):
            anon = self.handler.anonymous

            if callable(anon):
                return anon

            for klass in typemapper.keys():
                if anon == klass.__name__:
                    return klass

        return None

    def authenticate(self, request, rm):
        actor, anonymous = False, True

        for authenticator in self.authentication:
            if not authenticator.is_authenticated(request):
                if self.anonymous and \
                    rm in self.anonymous.allowed_methods:

                    actor, anonymous = self.anonymous(), True
                else:
                    actor, anonymous = authenticator.challenge, CHALLENGE
            else:
                return self.handler, self.handler.is_anonymous

        return actor, anonymous

    @vary_on_headers('Authorization')
    def __call__(self, request, *args, **kwargs):
        """
        NB: Sends a `Vary` header so we don't cache requests
        that are different (OAuth stuff in `Authorization` header.)
        """
        rm = request.method.upper()

        # Django's internal mechanism doesn't pick up
        # PUT request, so we trick it a little here.
        if rm == "PUT":
            coerce_put_post(request)

        actor, anonymous = self.authenticate(request, rm)

        if anonymous is CHALLENGE:
            return actor()
        else:
            handler = actor

        # Translate nested datastructs into `request.data` here.
        if rm in ('POST', 'PUT'):
            try:
                translate_mime(request)
            except MimerDataException:
                return rc.BAD_REQUEST
            if not hasattr(request, 'data'):
                if rm == 'POST':
                    request.data = request.POST
                else:
                    request.data = request.PUT

        if not rm in handler.allowed_methods:
            return HttpResponseNotAllowed(handler.allowed_methods)

        meth = getattr(handler, self.callmap.get(rm, ''), None)
        if not meth:
            raise Http404

        # Support emitter both through (?P<emitter_format>) and ?format=emitter.
        em_format = self.determine_emitter(request, *args, **kwargs)

        kwargs.pop('emitter_format', None)

        # Clean up the request object a bit, since we might
        # very well have `oauth_`-headers in there, and we
        # don't want to pass these along to the handler.
        request = self.cleanup_request(request)

        try:
            result = meth(request, *args, **kwargs)
        except Exception, e:
            result = self.error_handler(e, request, meth, em_format)

        try:
            emitter, ct = Emitter.get(em_format)
            fields = handler.fields

            if hasattr(handler, 'list_fields') and isinstance(result, (list, tuple, QuerySet)):
                fields = handler.list_fields
        except ValueError:
            result = rc.BAD_REQUEST
            result.content = "Invalid output format specified '%s'." % em_format
            return result

        status_code = 200

        # If we're looking at a response object which contains non-string
        # content, then assume we should use the emitter to format that 
        # content
        if isinstance(result, HttpResponse) and not result._is_string:
            status_code = result.status_code
            # Note: We can't use result.content here because that method attempts
            # to convert the content into a string which we don't want. 
            # when _is_string is False _container is the raw data
            result = result._container
     
        srl = emitter(result, typemapper, handler, fields, anonymous)

        try:
            """
            Decide whether or not we want a generator here,
            or we just want to buffer up the entire result
            before sending it to the client. Won't matter for
            smaller datasets, but larger will have an impact.
            """
            if self.stream:
                stream = srl.stream_render(request)
            else:
                stream = srl.render(request)

            if not isinstance(stream, HttpResponse):
                resp = HttpResponse(stream, mimetype=ct, status=status_code)
            else:
                resp = stream

            resp.streaming = self.stream

            return resp
        except HttpStatusCode, e:
            return e.response