Commit ebe1c912 authored by ariovistus's avatar ariovistus
Browse files

Merge pull request #307 from mverteuil/resource_access_callback

Added resource access filter callback mechanism
parents 4f40219f 36157bad
......@@ -8,21 +8,22 @@ Example:
.. code-block:: python
SWAGGER_SETTINGS = {
'exclude_namespaces': [],
'api_version': '0.1',
'api_path': '/',
'enabled_methods': [
'exclude_namespaces': [],
'api_version': '0.1',
'api_path': '/',
'enabled_methods': [
'get',
'post',
'put',
'patch',
'delete'
],
'api_key': '',
'is_authenticated': False,
'is_superuser': False,
'api_key': '',
'is_authenticated': False,
'is_superuser': False,
'permission_denied_handler': None,
'base_path':'helloreverb.com/docs',
'resource_access_handler': None,
'base_path':'helloreverb.com/docs',
'info': {
'contact': 'apiteam@wordnik.com',
'description': 'This is a sample server Petstore server. '
......@@ -44,7 +45,7 @@ Example:
api_version
------------------------
version of your api.
version of your api.
Defaults to :code:`''`
......@@ -135,6 +136,68 @@ Then in app/views.py:
from django.http import HttpResponse
return HttpResponse('you have no permissions!')
resource_access_handler
-------------------------
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`
Example:
.. code-block:: python
SWAGGER_SETTINGS = {
'resource_access_handler': 'app.views.resource_access_handler'
}
Then in app/views.py:
.. 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
else:
if isinstance(resource, basestring):
try:
resolver_match = resolve('/{}/'.format(resource))
view = resolver_match.func
except Exception:
return False
else:
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
else:
return True
token_type
----------
......
......@@ -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),)
self.host = 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:
apis.append({
'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(
urlconf=urlconf,
exclude_namespaces=rfs.SWAGGER_SETTINGS.get('exclude_namespaces'))
exclude_namespaces=rfs.SWAGGER_SETTINGS.get('exclude_namespaces')
)
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