move piston out to requirements
[wolnelektury.git] / apps / piston / resource.py
diff --git a/apps/piston/resource.py b/apps/piston/resource.py
deleted file mode 100644 (file)
index ee78b0e..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-import sys, inspect
-
-from django.http import (HttpResponse, Http404, HttpResponseNotAllowed,
-    HttpResponseForbidden, HttpResponseServerError)
-from django.views.debug import ExceptionReporter
-from django.views.decorators.vary import vary_on_headers
-from django.conf import settings
-from django.core.mail import send_mail, EmailMessage
-from django.db.models.query import QuerySet
-from django.http import Http404
-
-from emitters import Emitter
-from handler import typemapper
-from doc import HandlerMethod
-from authentication import NoAuthentication
-from utils import coerce_put_post, FormValidationError, HttpStatusCode
-from utils import rc, format_error, translate_mime, MimerDataException
-
-CHALLENGE = object()
-
-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()
-
-        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 determening 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
-
-    @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 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 FormValidationError, e:
-            resp = rc.BAD_REQUEST
-            resp.write(' '+str(e.form.errors))
-
-            return resp
-        except TypeError, e:
-            result = rc.BAD_REQUEST
-            hm = HandlerMethod(meth)
-            sig = hm.signature
-
-            msg = 'Method signature does not match.\n\n'
-
-            if sig:
-                msg += 'Signature should be: %s' % sig
-            else:
-                msg += 'Resource does not expect any parameters.'
-
-            if self.display_errors:
-                msg += '\n\nException was: %s' % str(e)
-
-            result.content = format_error(msg)
-        except Http404:
-            return rc.NOT_FOUND
-        except HttpStatusCode, e:
-            return e.response
-        except Exception, e:
-            """
-            On errors (like code errors), we'd like to be able to
-            give crash reports to both admins and also the calling
-            user. There's two setting parameters for this:
-
-            Parameters::
-             - `PISTON_EMAIL_ERRORS`: Will send a Django formatted
-               error email to people in `settings.ADMINS`.
-             - `PISTON_DISPLAY_ERRORS`: Will return a simple traceback
-               to the caller, so he can tell you what error they got.
-
-            If `PISTON_DISPLAY_ERRORS` is not enabled, the caller will
-            receive a basic "500 Internal Server Error" message.
-            """
-            exc_type, exc_value, tb = sys.exc_info()
-            rep = ExceptionReporter(request, exc_type, exc_value, tb.tb_next)
-            if self.email_errors:
-                self.email_exception(rep)
-            if self.display_errors:
-                return HttpResponseServerError(
-                    format_error('\n'.join(rep.format_exception())))
-            else:
-                raise
-
-        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: stream = srl.stream_render(request)
-            else: stream = srl.render(request)
-
-            if not isinstance(stream, HttpResponse):
-                resp = HttpResponse(stream, mimetype=ct)
-            else:
-                resp = stream
-
-            resp.streaming = self.stream
-
-            return resp
-        except HttpStatusCode, e:
-            return e.response
-
-    @staticmethod
-    def cleanup_request(request):
-        """
-        Removes `oauth_` keys from various dicts on the
-        request object, and returns the sanitized version.
-        """
-        for method_type in ('GET', 'PUT', 'POST', 'DELETE'):
-            block = getattr(request, method_type, { })
-
-            if True in [ k.startswith("oauth_") for k in block.keys() ]:
-                sanitized = block.copy()
-
-                for k in sanitized.keys():
-                    if k.startswith("oauth_"):
-                        sanitized.pop(k)
-
-                setattr(request, method_type, sanitized)
-
-        return request
-
-    # --
-
-    def email_exception(self, reporter):
-        subject = "Piston crash report"
-        html = reporter.get_traceback_html()
-
-        message = EmailMessage(settings.EMAIL_SUBJECT_PREFIX+subject,
-                                html, settings.SERVER_EMAIL,
-                                [ admin[1] for admin in settings.ADMINS ])
-
-        message.content_subtype = 'html'
-        message.send(fail_silently=True)