From ae1f0c9b5b9b30b2885c3fcd6fdb9cc646ea4c82 Mon Sep 17 00:00:00 2001 From: Camille Harang Date: Fri, 10 Feb 2012 22:22:01 +0100 Subject: [PATCH] Permissions can be checked with arbitrary HTTP methods, only views on which the user has write access display forms --- djangorestframework/mixins.py | 4 ++-- djangorestframework/permissions.py | 21 ++++++++++++--------- djangorestframework/renderers.py | 8 ++++++++ djangorestframework/templates/renderer.html | 4 ++-- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py index f4a9c998a..1cb7d5f13 100644 --- a/djangorestframework/mixins.py +++ b/djangorestframework/mixins.py @@ -361,14 +361,14 @@ class AuthMixin(object): return AnonymousUser() # TODO: wrap this behavior around dispatch() - def _check_permissions(self): + def _check_permissions(self, test_methods=None): """ Check user permissions and either raise an ``ErrorResponse`` or return. """ user = self.user for permission_cls in self.permissions: permission = permission_cls(self) - permission.check_permission(user) + permission.check_permission(user, test_methods=test_methods) ########## Resource Mixin ########## diff --git a/djangorestframework/permissions.py b/djangorestframework/permissions.py index dfe55ce94..a6edb1919 100644 --- a/djangorestframework/permissions.py +++ b/djangorestframework/permissions.py @@ -41,7 +41,7 @@ class BasePermission(object): """ self.view = view - def check_permission(self, auth): + def check_permission(self, auth, test_methods=None, **kwargs): """ Should simply return, or raise an :exc:`response.ErrorResponse`. """ @@ -53,7 +53,7 @@ class FullAnonAccess(BasePermission): Allows full access. """ - def check_permission(self, user): + def check_permission(self, user, test_methods=None, **kwargs): pass @@ -62,7 +62,7 @@ class IsAuthenticated(BasePermission): Allows access only to authenticated users. """ - def check_permission(self, user): + def check_permission(self, user, test_methods=None, **kwargs): if not user.is_authenticated(): raise _403_FORBIDDEN_RESPONSE @@ -72,7 +72,7 @@ class IsAdminUser(BasePermission): Allows access only to admin users. """ - def check_permission(self, user): + def check_permission(self, user, test_methods=None, **kwargs): if not user.is_staff: raise _403_FORBIDDEN_RESPONSE @@ -82,10 +82,9 @@ class IsUserOrIsAnonReadOnly(BasePermission): The request is authenticated as a user, or is a read-only request. """ - def check_permission(self, user): - if (not user.is_authenticated() and - self.view.method != 'GET' and - self.view.method != 'HEAD'): + def check_permission(self, user, test_methods=None, **kwargs): + if not test_methods: test_methods = [self.view.method] + if not user.is_authenticated() and not set(['GET', 'HEAD']).issuperset(test_methods): raise _403_FORBIDDEN_RESPONSE @@ -113,11 +112,15 @@ class BaseThrottle(BasePermission): """ pass - def check_permission(self, auth): + def check_permission(self, auth, test_methods=None, **kwargs): """ Check the throttling. Return `None` or raise an :exc:`.ErrorResponse`. """ + + # Return if just testing the permission. + if test_methods: return + num, period = getattr(self.view, self.attr_name, self.default).split('/') self.num_requests = int(num) self.duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]] diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py index bb0f789aa..aab6a20ba 100644 --- a/djangorestframework/renderers.py +++ b/djangorestframework/renderers.py @@ -17,6 +17,7 @@ from djangorestframework.utils import dict2xml, url_resolves from djangorestframework.utils.breadcrumbs import get_breadcrumbs from djangorestframework.utils.mediatypes import get_media_type_params, add_media_type_param, media_type_matches from djangorestframework import VERSION +from djangorestframework.response import ErrorResponse import string from urllib import quote_plus @@ -232,6 +233,13 @@ class DocumentingTemplateRenderer(BaseRenderer): provide a form that can be used to submit arbitrary content. """ + # Return no form if user doesn't have write access to this view + if hasattr(view, '_check_permissions'): + try: + view._check_permissions(test_methods=('POST', 'PUT', 'DELETE', 'PATCH',)) + except ErrorResponse: + return None + # Get the form instance if we have one bound to the input form_instance = None if method == getattr(view, 'method', view.request.method).lower(): diff --git a/djangorestframework/templates/renderer.html b/djangorestframework/templates/renderer.html index e396a58f5..5b80f11da 100644 --- a/djangorestframework/templates/renderer.html +++ b/djangorestframework/templates/renderer.html @@ -65,7 +65,7 @@ {# Only display the POST/PUT/DELETE forms if method tunneling via POST forms is enabled and the user has permissions on this view. #} {% if METHOD_PARAM and response.status != 403 %} - {% if 'POST' in view.allowed_methods %} + {% if 'POST' in view.allowed_methods and post_form %}

POST {{ name }}

@@ -86,7 +86,7 @@ {% endif %} - {% if 'PUT' in view.allowed_methods %} + {% if 'PUT' in view.allowed_methods and put_form %}

PUT {{ name }}