1
|
6
|
import json
|
2
|
6
|
import warnings
|
3
|
|
|
4
|
6
|
from coreapi.document import Object, Link
|
5
|
|
|
6
|
6
|
from rest_framework import exceptions
|
7
|
6
|
from rest_framework.permissions import AllowAny
|
8
|
6
|
from rest_framework.renderers import CoreJSONRenderer
|
9
|
6
|
from rest_framework.response import Response
|
10
|
6
|
from rest_framework.schemas import SchemaGenerator, AutoSchema as DRFAuthSchema
|
11
|
6
|
from rest_framework.views import APIView
|
12
|
|
|
13
|
6
|
from rest_framework_swagger import renderers
|
14
|
|
|
15
|
|
|
16
|
6
|
class AutoSchema(DRFAuthSchema):
|
17
|
|
|
18
|
6
|
def get_link(self, path, method, base_url):
|
19
|
6
|
link = super(AutoSchema, self).get_link(path, method, base_url)
|
20
|
6
|
try:
|
21
|
6
|
serializer = self.view.get_serializer()
|
22
|
6
|
except Exception:
|
23
|
6
|
serializer = None
|
24
|
6
|
warnings.warn('{}.get_serializer() raised an exception during '
|
25
|
|
'schema generation. Serializer fields will not be '
|
26
|
|
'generated for {} {}.'
|
27
|
|
.format(self.view.__class__.__name__, method, path))
|
28
|
|
|
29
|
6
|
link.__dict__['deprecated'] = getattr(self.view, 'deprecated', False)
|
30
|
|
|
31
|
|
# auto-generate a topic/tag for the serializer based on its model
|
32
|
6
|
if hasattr(self.view, 'swagger_topic'):
|
33
|
6
|
link.__dict__['topic'] = str(self.view.swagger_topic).title()
|
34
|
0
|
elif serializer and hasattr(serializer, 'Meta'):
|
35
|
0
|
link.__dict__['topic'] = str(
|
36
|
|
serializer.Meta.model._meta.verbose_name_plural
|
37
|
|
).title()
|
38
|
0
|
elif hasattr(self.view, 'model'):
|
39
|
0
|
strTopic = str(self.view.model._meta.verbose_name_plural)
|
40
|
0
|
link.__dict__['topic'] = strTopic.title()
|
41
|
|
else:
|
42
|
0
|
warnings.warn('Could not determine a Swagger tag for path {}'.format(path))
|
43
|
6
|
return link
|
44
|
|
|
45
|
6
|
def get_description(self, path, method):
|
46
|
6
|
self.view._request = self.view.request
|
47
|
6
|
setattr(self.view.request, 'swagger_method', method)
|
48
|
6
|
description = super(AutoSchema, self).get_description(path, method)
|
49
|
6
|
return description
|
50
|
|
|
51
|
|
|
52
|
6
|
class SwaggerSchemaView(APIView):
|
53
|
6
|
_ignore_model_permissions = True
|
54
|
6
|
exclude_from_schema = True
|
55
|
6
|
permission_classes = [AllowAny]
|
56
|
6
|
renderer_classes = [
|
57
|
|
CoreJSONRenderer,
|
58
|
|
renderers.OpenAPIRenderer,
|
59
|
|
renderers.SwaggerUIRenderer
|
60
|
|
]
|
61
|
|
|
62
|
6
|
def get(self, request):
|
63
|
6
|
generator = SchemaGenerator(
|
64
|
|
title='CyBorgBackup API',
|
65
|
|
patterns=None,
|
66
|
|
urlconf=None
|
67
|
|
)
|
68
|
6
|
schema = generator.get_schema(request=request)
|
69
|
|
# python core-api doesn't support the deprecation yet, so track it
|
70
|
|
# ourselves and return it in a response header
|
71
|
6
|
_deprecated = []
|
72
|
|
|
73
|
|
# By default, DRF OpenAPI serialization places all endpoints in
|
74
|
|
# a single node based on their root path (/api). Instead, we want to
|
75
|
|
# group them by topic/tag so that they're categorized in the rendered
|
76
|
|
# output
|
77
|
6
|
document = schema._data.pop('api')
|
78
|
6
|
for path, node in document.items():
|
79
|
6
|
if isinstance(node, Object):
|
80
|
6
|
for action in node.values():
|
81
|
6
|
topic = getattr(action, 'topic', None)
|
82
|
6
|
if topic:
|
83
|
6
|
schema._data.setdefault(topic, Object())
|
84
|
6
|
schema._data[topic]._data[path] = node
|
85
|
|
|
86
|
|
# if isinstance(action, Object):
|
87
|
|
# for link in action.links.values():
|
88
|
|
# if link.deprecated:
|
89
|
|
# _deprecated.append(link.url)
|
90
|
|
|
91
|
6
|
elif isinstance(node, Link):
|
92
|
6
|
topic = getattr(node, 'topic', None)
|
93
|
6
|
if topic:
|
94
|
6
|
schema._data.setdefault(topic, Object())
|
95
|
6
|
schema._data[topic]._data[path] = node
|
96
|
|
|
97
|
6
|
if not schema:
|
98
|
0
|
raise exceptions.ValidationError(
|
99
|
|
'The schema generator did not return a schema Document'
|
100
|
|
)
|
101
|
|
|
102
|
6
|
return Response(
|
103
|
|
schema,
|
104
|
|
headers={'X-Deprecated-Paths': json.dumps(_deprecated)}
|
105
|
|
)
|