diff options
Diffstat (limited to 'flywheel/resource.py')
| -rw-r--r-- | flywheel/resource.py | 43 |
1 files changed, 24 insertions, 19 deletions
diff --git a/flywheel/resource.py b/flywheel/resource.py index c76ce2dd..c15f01ed 100644 --- a/flywheel/resource.py +++ b/flywheel/resource.py @@ -9,7 +9,6 @@ from decimal import Decimal import re from itertools import chain -# TODO: Authentication # TODO: Display user login in top panel: http://stackoverflow.com/questions/806835/django-redirect-to-previous-page-after-login # TODO: Figure how out references and named urls need to work nicely # TODO: POST on existing 404 URL, PUT on existing 404 URL @@ -73,6 +72,7 @@ class Resource(object): """Make the class callable so it can be used as a Django view.""" self = object.__new__(cls) self.__init__(request) + # TODO: Remove this debugging code try: return self._handle_request(request, *args, **kwargs) except: @@ -132,12 +132,6 @@ class Resource(object): return self.parsers[0] - def reverse(self, view, *args, **kwargs): - """Return a fully qualified URI for a given view or resource. - Add the domain using the Sites framework if possible, otherwise fallback to using the current request.""" - return self.add_domain(reverse(view, args=args, kwargs=kwargs)) - - def get(self, request, auth, *args, **kwargs): """Must be subclassed to be implemented.""" self.not_implemented('GET') @@ -158,6 +152,12 @@ class Resource(object): self.not_implemented('DELETE') + def reverse(self, view, *args, **kwargs): + """Return a fully qualified URI for a given view or resource. + Add the domain using the Sites framework if possible, otherwise fallback to using the current request.""" + return self.add_domain(reverse(view, args=args, kwargs=kwargs)) + + def not_implemented(self, operation): """Return an HTTP 500 server error if an operation is called which has been allowed by allowed_methods, but which has not been implemented.""" @@ -193,22 +193,21 @@ class Resource(object): def authenticate(self, request): - """Attempt to authenticate the request, returning an authentication context or None""" + """Attempt to authenticate the request, returning an authentication context or None. + An authentication context may be any object, although in many cases it will be a User instance.""" + + # Attempt authentication against each authenticator in turn, + # and return None if no authenticators succeed in authenticating the request. for authenticator in self.authenticators: auth_context = authenticator(self).authenticate(request) if auth_context: return auth_context + return None def check_method_allowed(self, method, auth): - """Ensure the request method is acceptable for this resource.""" - - # If anonoymous check permissions and bail with no further info if disallowed - if auth is None and not method in self.anon_allowed_methods: - raise ResponseException(status.HTTP_403_FORBIDDEN, - {'detail': 'You do not have permission to access this resource. ' + - 'You may need to login or otherwise authenticate the request.'}) + """Ensure the request method is permitted for this resource, raising a ResourceException if it is not.""" if not method in self.callmap.keys(): raise ResponseException(status.HTTP_501_NOT_IMPLEMENTED, @@ -218,13 +217,17 @@ class Resource(object): raise ResponseException(status.HTTP_405_METHOD_NOT_ALLOWED, {'detail': 'Method \'%s\' not allowed on this resource.' % method}) + if auth is None and not method in self.anon_allowed_methods: + raise ResponseException(status.HTTP_403_FORBIDDEN, + {'detail': 'You do not have permission to access this resource. ' + + 'You may need to login or otherwise authenticate the request.'}) def get_form(self, data=None): """Optionally return a Django Form instance, which may be used for validation and/or rendered by an HTML/XHTML emitter. - If data is not None the form will be bound to data. is_response indicates if data should be - treated as the input data (bind to client input) or the response data (bind to an existing object).""" + If data is not None the form will be bound to data.""" + if self.form: if data: return self.form(data) @@ -240,6 +243,7 @@ class Resource(object): Returns a tuple containing the cleaned up data, and optionally a form bound to that data. By default this uses form validation to filter the basic input into the required types.""" + if form_instance is None: return data @@ -255,7 +259,7 @@ class Resource(object): else: # Add standard field errors - details = dict((key, map(unicode, val)) for (key, val) in form_instance.errors.iteritems()) + details = dict((key, map(unicode, val)) for (key, val) in form_instance.errors.iteritems() if key != '__all__') # Add any non-field errors if form_instance.non_field_errors(): @@ -374,7 +378,8 @@ class Resource(object): def _handle_request(self, request, *args, **kwargs): - """ + """This method is the core of Resource, through which all requests are passed. + Broadly this consists of the following procedure: 0. ensure the operation is permitted |
