Commit 12146f87 authored by M. de Verteuil's avatar M. de Verteuil
Browse files

Added resource access filter callback mechanism

  - Adds a callback to address more granular permission schemes
  - Callback is given the request and the resource and returns boolean that
    indicates whether or not the resource should be included in the generated
parent aa7ae202
......@@ -22,6 +22,7 @@ Example:
'is_authenticated': False,
'is_superuser': False,
'permission_denied_handler': None,
'resource_access_handler': None,
'info': {
'contact': '',
......@@ -135,6 +136,68 @@ Then in app/
from django.http import HttpResponse
return HttpResponse('you have no permissions!')
custom handler for delegating access rules to the project.
Takes a callable or a string that names a callable with the following signature:
.. code-block:: python
def resource_access_handler(request, resource)
The handler must accept the following arguments:
`request` (django.http.HttpRequest): The request for documentation, providing the user and any
other relevant details about the user who is making the HTTP request.
`resource` (str): The path to the API endpoint for which to approve or reject authorization. Does not have
leading/trailing slashes.
The handler should return a truthy value when the resource is accessible in the context of the current request.
Default: :code:`None`
.. code-block:: python
'resource_access_handler': 'app.views.resource_access_handler'
Then in app/
.. code-block:: python
from django.core.urlresolvers import resolve
from .flags import flag_is_active
def resource_access_handler(request, resource):
""" Callback for resource access. Determines who can see the documentation for which API. """
# Superusers and staff can see whatever they want
if request.user.is_superuser or request.user.is_staff:
return True
if isinstance(resource, basestring):
resolver_match = resolve('/{}/'.format(resource))
view = resolver_match.func
except Exception:
return False
view = resource.callback
view_attributes = view.func_dict
feature_flag = view_attributes.get('feature_flag')
# Hide documentation for disabled features
if feature_flag and not flag_is_active(request, feature_flag):
return False
return True
......@@ -10,6 +10,7 @@ DEFAULT_SWAGGER_SETTINGS = {
'is_authenticated': False,
'is_superuser': False,
'permission_denied_handler': None,
'resource_access_handler': None,
'template_path': 'rest_framework_swagger/index.html',
'doc_expansion': 'none',
from rest_framework.views import APIView
from django.utils import six
from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated
from rest_framework.views import APIView
from .compat import import_string
from rest_framework_swagger import SWAGGER_SETTINGS
class APIDocView(APIView):
def initial(self, request, *args, **kwargs):
self.permission_classes = (self.get_permission_class(request),) = request.build_absolute_uri()
self.api_path = SWAGGER_SETTINGS['api_path']
self.api_full_uri = request.build_absolute_uri(self.api_path)
return super(APIDocView, self).initial(request, *args, **kwargs)
def get_permission_class(self, request):
......@@ -18,5 +19,12 @@ class APIDocView(APIView):
return IsAdminUser
if SWAGGER_SETTINGS['is_authenticated'] and not request.user.is_authenticated():
return IsAuthenticated
return AllowAny
def handle_resource_access(self, request, resource):
resource_access_handler = SWAGGER_SETTINGS.get('resource_access_handler')
if isinstance(resource_access_handler, six.string_types):
resource_access_handler = import_string(resource_access_handler)
if resource_access_handler:
return resource_access_handler(request, resource)
return True
......@@ -101,12 +101,12 @@ class SwaggerResourcesView(APIDocView):
def get(self, request):
apis = []
resources = self.get_resources()
resources = [resource for resource in self.get_resources()
if self.handle_resource_access(request, resource)]
for path in resources:
'path': "/%s" % path,
apis.append({'path': '/%s' % path, })
return Response({
'apiVersion': rfs.SWAGGER_SETTINGS.get('api_version', ''),
......@@ -138,16 +138,21 @@ class SwaggerResourcesView(APIDocView):
urlconf = getattr(self.request, "urlconf", None)
apis = urlparser.get_apis(
resources = urlparser.get_top_level_apis(apis)
return resources
class SwaggerApiView(APIDocView):
renderer_classes = (JSONRenderer,)
renderer_classes = (JSONRenderer, )
def get(self, request, path):
apis = self.get_api_for_resource(path)
apis = [api for api in apis
if self.handle_resource_access(request, api['pattern'])]
generator = DocumentationGenerator()
return Response({
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment