commonground-api-common 1.12.2__py3-none-any.whl → 2.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- commonground_api_common-1.12.2.data/scripts/patch_content_types → commonground_api_common-2.4.1.data/scripts/generate_schema +2 -4
- {commonground_api_common-1.12.2.dist-info → commonground_api_common-2.4.1.dist-info}/METADATA +47 -40
- {commonground_api_common-1.12.2.dist-info → commonground_api_common-2.4.1.dist-info}/RECORD +47 -52
- {commonground_api_common-1.12.2.dist-info → commonground_api_common-2.4.1.dist-info}/WHEEL +1 -1
- vng_api_common/__init__.py +1 -1
- vng_api_common/admin.py +1 -20
- vng_api_common/api/views.py +1 -0
- vng_api_common/apps.py +44 -26
- vng_api_common/audittrails/utils.py +44 -0
- vng_api_common/authorizations/admin.py +1 -1
- vng_api_common/authorizations/middleware.py +244 -0
- vng_api_common/authorizations/migrations/0016_remove_authorizationsconfig_api_root_and_more.py +76 -0
- vng_api_common/authorizations/models.py +62 -3
- vng_api_common/authorizations/utils.py +17 -0
- vng_api_common/authorizations/validators.py +5 -11
- vng_api_common/caching/etags.py +2 -1
- vng_api_common/client.py +61 -29
- vng_api_common/conf/api.py +33 -48
- vng_api_common/contrib/setup_configuration/models.py +32 -0
- vng_api_common/contrib/setup_configuration/steps.py +46 -0
- vng_api_common/extensions/file.py +26 -0
- vng_api_common/extensions/gegevensgroep.py +16 -0
- vng_api_common/extensions/geojson.py +270 -0
- vng_api_common/extensions/hyperlink.py +37 -0
- vng_api_common/extensions/polymorphic.py +68 -0
- vng_api_common/extensions/query.py +20 -0
- vng_api_common/filters.py +0 -1
- vng_api_common/generators.py +12 -113
- vng_api_common/middleware.py +1 -227
- vng_api_common/migrations/0006_delete_apicredential.py +120 -0
- vng_api_common/mocks.py +4 -1
- vng_api_common/models.py +10 -111
- vng_api_common/notifications/api/views.py +8 -8
- vng_api_common/notifications/handlers.py +8 -3
- vng_api_common/notifications/migrations/0011_remove_subscription_config_and_more.py +23 -0
- vng_api_common/oas.py +6 -10
- vng_api_common/pagination.py +10 -0
- vng_api_common/routers.py +3 -3
- vng_api_common/schema.py +414 -158
- vng_api_common/tests/schema.py +13 -0
- vng_api_common/utils.py +0 -22
- vng_api_common/validators.py +111 -113
- vng_api_common/views.py +35 -20
- commonground_api_common-1.12.2.data/scripts/generate_schema +0 -39
- commonground_api_common-1.12.2.data/scripts/use_external_components +0 -16
- vng_api_common/inspectors/cache.py +0 -57
- vng_api_common/inspectors/fields.py +0 -126
- vng_api_common/inspectors/files.py +0 -121
- vng_api_common/inspectors/geojson.py +0 -360
- vng_api_common/inspectors/polymorphic.py +0 -72
- vng_api_common/inspectors/query.py +0 -96
- vng_api_common/inspectors/utils.py +0 -40
- vng_api_common/inspectors/view.py +0 -547
- vng_api_common/management/commands/generate_autorisaties.py +0 -43
- vng_api_common/management/commands/generate_notificaties.py +0 -40
- vng_api_common/management/commands/generate_swagger.py +0 -197
- vng_api_common/management/commands/patch_error_contenttypes.py +0 -61
- vng_api_common/management/commands/use_external_components.py +0 -94
- vng_api_common/notifications/constants.py +0 -3
- vng_api_common/notifications/models.py +0 -97
- vng_api_common/templates/vng_api_common/api_schema_to_markdown_table.md +0 -16
- vng_api_common/templates/vng_api_common/autorisaties.md +0 -15
- vng_api_common/templates/vng_api_common/notificaties.md +0 -24
- {commonground_api_common-1.12.2.dist-info → commonground_api_common-2.4.1.dist-info}/top_level.txt +0 -0
- /vng_api_common/{inspectors → contrib}/__init__.py +0 -0
- /vng_api_common/{management → contrib/setup_configuration}/__init__.py +0 -0
- /vng_api_common/{management/commands → extensions}/__init__.py +0 -0
@@ -1,121 +0,0 @@
|
|
1
|
-
from collections import OrderedDict
|
2
|
-
|
3
|
-
from django.utils.translation import gettext as _
|
4
|
-
|
5
|
-
from drf_extra_fields.fields import Base64FieldMixin
|
6
|
-
from drf_yasg import openapi
|
7
|
-
from drf_yasg.inspectors import (
|
8
|
-
CamelCaseJSONFilter,
|
9
|
-
FieldInspector,
|
10
|
-
NotHandled,
|
11
|
-
ViewInspector,
|
12
|
-
)
|
13
|
-
from drf_yasg.utils import filter_none, get_serializer_ref_name
|
14
|
-
from rest_framework import serializers
|
15
|
-
|
16
|
-
|
17
|
-
class FileFieldInspector(CamelCaseJSONFilter):
|
18
|
-
def get_schema(self, serializer):
|
19
|
-
if self.method not in ViewInspector.body_methods:
|
20
|
-
return NotHandled
|
21
|
-
|
22
|
-
# only do this if there are base64 mixin fields
|
23
|
-
if any(
|
24
|
-
isinstance(field, Base64FieldMixin) for field in serializer.fields.values()
|
25
|
-
):
|
26
|
-
return self.probe_field_inspectors(serializer, openapi.Schema, True)
|
27
|
-
|
28
|
-
return NotHandled
|
29
|
-
|
30
|
-
def field_to_swagger_object(
|
31
|
-
self, field, swagger_object_type, use_references, **kwargs
|
32
|
-
):
|
33
|
-
if isinstance(field, serializers.Serializer):
|
34
|
-
return self._serializer_to_swagger_object(
|
35
|
-
field, swagger_object_type, use_references, **kwargs
|
36
|
-
)
|
37
|
-
|
38
|
-
if not isinstance(field, Base64FieldMixin):
|
39
|
-
return NotHandled
|
40
|
-
|
41
|
-
SwaggerType, ChildSwaggerType = self._get_partial_types(
|
42
|
-
field, swagger_object_type, use_references, **kwargs
|
43
|
-
)
|
44
|
-
|
45
|
-
type_b64 = SwaggerType(
|
46
|
-
type=openapi.TYPE_STRING,
|
47
|
-
format=openapi.FORMAT_BASE64,
|
48
|
-
description=_("Base64 encoded binary content."),
|
49
|
-
)
|
50
|
-
type_uri = SwaggerType(
|
51
|
-
type=openapi.TYPE_STRING,
|
52
|
-
read_only=True,
|
53
|
-
format=openapi.FORMAT_URI,
|
54
|
-
description=_("Download URL of the binary content."),
|
55
|
-
)
|
56
|
-
|
57
|
-
if swagger_object_type == openapi.Schema:
|
58
|
-
# on writes, it's always b64
|
59
|
-
if self.method in ViewInspector.body_methods:
|
60
|
-
return type_b64
|
61
|
-
|
62
|
-
# if not representing in base64, it's a link
|
63
|
-
return type_uri if not field.represent_in_base64 else type_b64
|
64
|
-
|
65
|
-
return NotHandled
|
66
|
-
|
67
|
-
def _serializer_to_swagger_object(
|
68
|
-
self, serializer, swagger_object_type, use_references, **kwargs
|
69
|
-
):
|
70
|
-
if self.method not in ViewInspector.body_methods:
|
71
|
-
return NotHandled
|
72
|
-
|
73
|
-
if not any(
|
74
|
-
isinstance(field, Base64FieldMixin) for field in serializer.fields.values()
|
75
|
-
):
|
76
|
-
return NotHandled
|
77
|
-
|
78
|
-
SwaggerType, ChildSwaggerType = self._get_partial_types(
|
79
|
-
serializer, swagger_object_type, use_references, **kwargs
|
80
|
-
)
|
81
|
-
|
82
|
-
ref_name = get_serializer_ref_name(serializer)
|
83
|
-
ref_name = f"{ref_name}Data" if ref_name else None
|
84
|
-
|
85
|
-
def make_schema_definition():
|
86
|
-
properties = OrderedDict()
|
87
|
-
required = []
|
88
|
-
for property_name, child in serializer.fields.items():
|
89
|
-
prop_kwargs = {"read_only": bool(child.read_only) or None}
|
90
|
-
prop_kwargs = filter_none(prop_kwargs)
|
91
|
-
|
92
|
-
child_schema = self.probe_field_inspectors(
|
93
|
-
child, ChildSwaggerType, use_references, **prop_kwargs
|
94
|
-
)
|
95
|
-
properties[property_name] = child_schema
|
96
|
-
|
97
|
-
if child.required and not getattr(child_schema, "read_only", False):
|
98
|
-
required.append(property_name)
|
99
|
-
|
100
|
-
result = SwaggerType(
|
101
|
-
type=openapi.TYPE_OBJECT,
|
102
|
-
properties=properties,
|
103
|
-
required=required or None,
|
104
|
-
)
|
105
|
-
if not ref_name and "title" in result:
|
106
|
-
# on an inline model, the title is derived from the field name
|
107
|
-
# but is visually displayed like the model name, which is confusing
|
108
|
-
# it is better to just remove title from inline models
|
109
|
-
del result.title
|
110
|
-
|
111
|
-
# Provide an option to add manual paremeters to a schema
|
112
|
-
# for example, to add examples
|
113
|
-
# self.add_manual_fields(serializer, result)
|
114
|
-
return self.process_result(result, None, None)
|
115
|
-
|
116
|
-
if not ref_name or not use_references:
|
117
|
-
return make_schema_definition()
|
118
|
-
|
119
|
-
definitions = self.components.with_scope(openapi.SCHEMA_DEFINITIONS)
|
120
|
-
definitions.setdefault(ref_name, make_schema_definition)
|
121
|
-
return openapi.SchemaRef(definitions, ref_name)
|
@@ -1,360 +0,0 @@
|
|
1
|
-
from collections import OrderedDict
|
2
|
-
|
3
|
-
from drf_yasg import openapi
|
4
|
-
from drf_yasg.inspectors import FieldInspector, NotHandled
|
5
|
-
from rest_framework import serializers
|
6
|
-
from rest_framework_gis.fields import GeometryField
|
7
|
-
|
8
|
-
from ..geo import DEFAULT_CRS, HEADER_ACCEPT, HEADER_CONTENT
|
9
|
-
|
10
|
-
REF_NAME_GEOJSON_GEOMETRY = "GeoJSONGeometry"
|
11
|
-
|
12
|
-
|
13
|
-
def register_geojson(definitions):
|
14
|
-
Geometry = openapi.Schema(
|
15
|
-
type=openapi.TYPE_OBJECT,
|
16
|
-
title="Geometry",
|
17
|
-
description="GeoJSON geometry",
|
18
|
-
required=["type"],
|
19
|
-
externalDocs=OrderedDict(url="https://tools.ietf.org/html/rfc7946#section-3.1"),
|
20
|
-
properties=OrderedDict(
|
21
|
-
(
|
22
|
-
(
|
23
|
-
"type",
|
24
|
-
openapi.Schema(
|
25
|
-
type=openapi.TYPE_STRING,
|
26
|
-
enum=[
|
27
|
-
"Point",
|
28
|
-
"MultiPoint",
|
29
|
-
"LineString",
|
30
|
-
"MultiLineString",
|
31
|
-
"Polygon",
|
32
|
-
"MultiPolygon",
|
33
|
-
"Feature",
|
34
|
-
"FeatureCollection",
|
35
|
-
"GeometryCollection",
|
36
|
-
],
|
37
|
-
description="The geometry type",
|
38
|
-
),
|
39
|
-
),
|
40
|
-
)
|
41
|
-
),
|
42
|
-
)
|
43
|
-
definitions.set("Geometry", Geometry)
|
44
|
-
|
45
|
-
Point2D = openapi.Schema(
|
46
|
-
type=openapi.TYPE_ARRAY,
|
47
|
-
title="Point2D",
|
48
|
-
description="A 2D point",
|
49
|
-
items=openapi.Schema(type=openapi.TYPE_NUMBER),
|
50
|
-
maxItems=2,
|
51
|
-
minItems=2,
|
52
|
-
)
|
53
|
-
definitions.set("Point2D", Point2D)
|
54
|
-
|
55
|
-
Point = openapi.Schema(
|
56
|
-
type=openapi.TYPE_OBJECT,
|
57
|
-
description="GeoJSON point geometry",
|
58
|
-
externalDocs=OrderedDict(
|
59
|
-
url="https://tools.ietf.org/html/rfc7946#section-3.1.2"
|
60
|
-
),
|
61
|
-
allOf=[
|
62
|
-
openapi.SchemaRef(definitions, "Geometry"),
|
63
|
-
openapi.Schema(
|
64
|
-
type=openapi.TYPE_OBJECT,
|
65
|
-
required=["coordinates"],
|
66
|
-
properties=OrderedDict(
|
67
|
-
(("coordinates", openapi.SchemaRef(definitions, "Point2D")),)
|
68
|
-
),
|
69
|
-
),
|
70
|
-
],
|
71
|
-
)
|
72
|
-
definitions.set("Point", Point)
|
73
|
-
|
74
|
-
MultiPoint = openapi.Schema(
|
75
|
-
type=openapi.TYPE_OBJECT,
|
76
|
-
description="GeoJSON multi-point geometry",
|
77
|
-
externalDocs=OrderedDict(
|
78
|
-
url="https://tools.ietf.org/html/rfc7946#section-3.1.3"
|
79
|
-
),
|
80
|
-
allOf=[
|
81
|
-
openapi.SchemaRef(definitions, "Geometry"),
|
82
|
-
openapi.Schema(
|
83
|
-
type=openapi.TYPE_OBJECT,
|
84
|
-
required=["coordinates"],
|
85
|
-
properties=OrderedDict(
|
86
|
-
(
|
87
|
-
(
|
88
|
-
"coordinates",
|
89
|
-
openapi.Schema(
|
90
|
-
type=openapi.TYPE_ARRAY,
|
91
|
-
items=openapi.SchemaRef(definitions, "Point2D"),
|
92
|
-
),
|
93
|
-
),
|
94
|
-
)
|
95
|
-
),
|
96
|
-
),
|
97
|
-
],
|
98
|
-
)
|
99
|
-
definitions.set("MultiPoint", MultiPoint)
|
100
|
-
|
101
|
-
LineString = openapi.Schema(
|
102
|
-
type=openapi.TYPE_OBJECT,
|
103
|
-
description="GeoJSON line-string geometry",
|
104
|
-
externalDocs=OrderedDict(
|
105
|
-
url="https://tools.ietf.org/html/rfc7946#section-3.1.4"
|
106
|
-
),
|
107
|
-
allOf=[
|
108
|
-
openapi.SchemaRef(definitions, "Geometry"),
|
109
|
-
openapi.Schema(
|
110
|
-
type=openapi.TYPE_OBJECT,
|
111
|
-
required=["coordinates"],
|
112
|
-
properties=OrderedDict(
|
113
|
-
(
|
114
|
-
(
|
115
|
-
"coordinates",
|
116
|
-
openapi.Schema(
|
117
|
-
type=openapi.TYPE_ARRAY,
|
118
|
-
items=openapi.SchemaRef(definitions, "Point2D"),
|
119
|
-
minItems=2,
|
120
|
-
),
|
121
|
-
),
|
122
|
-
)
|
123
|
-
),
|
124
|
-
),
|
125
|
-
],
|
126
|
-
)
|
127
|
-
definitions.set("LineString", LineString)
|
128
|
-
|
129
|
-
MultiLineString = openapi.Schema(
|
130
|
-
type=openapi.TYPE_OBJECT,
|
131
|
-
description="GeoJSON multi-line-string geometry",
|
132
|
-
externalDocs=OrderedDict(
|
133
|
-
url="https://tools.ietf.org/html/rfc7946#section-3.1.5"
|
134
|
-
),
|
135
|
-
allOf=[
|
136
|
-
openapi.SchemaRef(definitions, "Geometry"),
|
137
|
-
openapi.Schema(
|
138
|
-
type=openapi.TYPE_OBJECT,
|
139
|
-
required=["coordinates"],
|
140
|
-
properties=OrderedDict(
|
141
|
-
(
|
142
|
-
(
|
143
|
-
"coordinates",
|
144
|
-
openapi.Schema(
|
145
|
-
type=openapi.TYPE_ARRAY,
|
146
|
-
items=openapi.Schema(
|
147
|
-
type=openapi.TYPE_ARRAY,
|
148
|
-
items=openapi.SchemaRef(definitions, "Point2D"),
|
149
|
-
),
|
150
|
-
),
|
151
|
-
),
|
152
|
-
)
|
153
|
-
),
|
154
|
-
),
|
155
|
-
],
|
156
|
-
)
|
157
|
-
definitions.set("MultiLineString", MultiLineString)
|
158
|
-
|
159
|
-
Polygon = openapi.Schema(
|
160
|
-
type=openapi.TYPE_OBJECT,
|
161
|
-
description="GeoJSON polygon geometry",
|
162
|
-
externalDocs=OrderedDict(
|
163
|
-
url="https://tools.ietf.org/html/rfc7946#section-3.1.6"
|
164
|
-
),
|
165
|
-
allOf=[
|
166
|
-
openapi.SchemaRef(definitions, "Geometry"),
|
167
|
-
openapi.Schema(
|
168
|
-
type=openapi.TYPE_OBJECT,
|
169
|
-
required=["coordinates"],
|
170
|
-
properties=OrderedDict(
|
171
|
-
(
|
172
|
-
(
|
173
|
-
"coordinates",
|
174
|
-
openapi.Schema(
|
175
|
-
type=openapi.TYPE_ARRAY,
|
176
|
-
items=openapi.Schema(
|
177
|
-
type=openapi.TYPE_ARRAY,
|
178
|
-
items=openapi.SchemaRef(definitions, "Point2D"),
|
179
|
-
),
|
180
|
-
),
|
181
|
-
),
|
182
|
-
)
|
183
|
-
),
|
184
|
-
),
|
185
|
-
],
|
186
|
-
)
|
187
|
-
definitions.set("Polygon", Polygon)
|
188
|
-
|
189
|
-
MultiPolygon = openapi.Schema(
|
190
|
-
type=openapi.TYPE_OBJECT,
|
191
|
-
description="GeoJSON multi-polygon geometry",
|
192
|
-
externalDocs=OrderedDict(
|
193
|
-
url="https://tools.ietf.org/html/rfc7946#section-3.1.7"
|
194
|
-
),
|
195
|
-
allOf=[
|
196
|
-
openapi.SchemaRef(definitions, "Geometry"),
|
197
|
-
openapi.Schema(
|
198
|
-
type=openapi.TYPE_OBJECT,
|
199
|
-
required=["coordinates"],
|
200
|
-
properties=OrderedDict(
|
201
|
-
(
|
202
|
-
(
|
203
|
-
"coordinates",
|
204
|
-
openapi.Schema(
|
205
|
-
type=openapi.TYPE_ARRAY,
|
206
|
-
items=openapi.Schema(
|
207
|
-
type=openapi.TYPE_ARRAY,
|
208
|
-
items=openapi.Schema(
|
209
|
-
type=openapi.TYPE_ARRAY,
|
210
|
-
items=openapi.SchemaRef(definitions, "Point2D"),
|
211
|
-
),
|
212
|
-
),
|
213
|
-
),
|
214
|
-
),
|
215
|
-
)
|
216
|
-
),
|
217
|
-
),
|
218
|
-
],
|
219
|
-
)
|
220
|
-
definitions.set("MultiPolygon", MultiPolygon)
|
221
|
-
|
222
|
-
GeometryCollection = openapi.Schema(
|
223
|
-
type=openapi.TYPE_OBJECT,
|
224
|
-
description="GeoJSON multi-polygon geometry",
|
225
|
-
externalDocs=OrderedDict(
|
226
|
-
url="https://tools.ietf.org/html/rfc7946#section-3.1.8"
|
227
|
-
),
|
228
|
-
allOf=[
|
229
|
-
openapi.SchemaRef(definitions, "Geometry"),
|
230
|
-
openapi.Schema(
|
231
|
-
type=openapi.TYPE_OBJECT,
|
232
|
-
required=["geometries"],
|
233
|
-
properties=OrderedDict(
|
234
|
-
(
|
235
|
-
(
|
236
|
-
"geometries",
|
237
|
-
openapi.Schema(
|
238
|
-
type=openapi.TYPE_ARRAY,
|
239
|
-
items=openapi.SchemaRef(definitions, "Geometry"),
|
240
|
-
),
|
241
|
-
),
|
242
|
-
)
|
243
|
-
),
|
244
|
-
),
|
245
|
-
],
|
246
|
-
)
|
247
|
-
definitions.set("GeometryCollection", GeometryCollection)
|
248
|
-
|
249
|
-
GeoJSONGeometry = openapi.Schema(
|
250
|
-
title=REF_NAME_GEOJSON_GEOMETRY,
|
251
|
-
type=openapi.TYPE_OBJECT,
|
252
|
-
oneOf=[
|
253
|
-
openapi.SchemaRef(definitions, "Point"),
|
254
|
-
openapi.SchemaRef(definitions, "MultiPoint"),
|
255
|
-
openapi.SchemaRef(definitions, "LineString"),
|
256
|
-
openapi.SchemaRef(definitions, "MultiLineString"),
|
257
|
-
openapi.SchemaRef(definitions, "Polygon"),
|
258
|
-
openapi.SchemaRef(definitions, "MultiPolygon"),
|
259
|
-
openapi.SchemaRef(definitions, "GeometryCollection"),
|
260
|
-
],
|
261
|
-
discriminator="type",
|
262
|
-
)
|
263
|
-
definitions.set(REF_NAME_GEOJSON_GEOMETRY, GeoJSONGeometry)
|
264
|
-
|
265
|
-
|
266
|
-
class GeometryFieldInspector(FieldInspector):
|
267
|
-
def field_to_swagger_object(
|
268
|
-
self, field, swagger_object_type, use_references, **kwargs
|
269
|
-
):
|
270
|
-
if not isinstance(field, GeometryField):
|
271
|
-
return NotHandled
|
272
|
-
|
273
|
-
definitions = self.components.with_scope(openapi.SCHEMA_DEFINITIONS)
|
274
|
-
|
275
|
-
if not definitions.has("Geometry"):
|
276
|
-
register_geojson(definitions)
|
277
|
-
|
278
|
-
return openapi.SchemaRef(definitions, REF_NAME_GEOJSON_GEOMETRY)
|
279
|
-
|
280
|
-
def has_geo_fields(self, serializer) -> bool:
|
281
|
-
"""
|
282
|
-
Check if any of the serializer fields are a GeometryField.
|
283
|
-
|
284
|
-
If the serializer has nested serializers, a depth-first search is done
|
285
|
-
to check if the nested serializers has `GeometryField`\ s.
|
286
|
-
"""
|
287
|
-
for field in serializer.fields.values():
|
288
|
-
if isinstance(field, serializers.Serializer):
|
289
|
-
has_nested_geo_fields = self.probe_inspectors(
|
290
|
-
self.field_inspectors,
|
291
|
-
"has_geo_fields",
|
292
|
-
field,
|
293
|
-
{"field_inspectors": self.field_inspectors},
|
294
|
-
)
|
295
|
-
if has_nested_geo_fields:
|
296
|
-
return True
|
297
|
-
|
298
|
-
elif isinstance(field, (serializers.ListSerializer, serializers.ListField)):
|
299
|
-
field = field.child
|
300
|
-
|
301
|
-
if isinstance(field, GeometryField):
|
302
|
-
return True
|
303
|
-
|
304
|
-
return False
|
305
|
-
|
306
|
-
def get_request_header_parameters(self, serializer):
|
307
|
-
if not self.has_geo_fields(serializer):
|
308
|
-
return []
|
309
|
-
|
310
|
-
if self.method == "DELETE":
|
311
|
-
return []
|
312
|
-
|
313
|
-
# see also http://lyzidiamond.com/posts/4326-vs-3857 for difference
|
314
|
-
# between coordinate system and projected coordinate system
|
315
|
-
return [
|
316
|
-
openapi.Parameter(
|
317
|
-
name=HEADER_ACCEPT,
|
318
|
-
type=openapi.TYPE_STRING,
|
319
|
-
in_=openapi.IN_HEADER,
|
320
|
-
required=True,
|
321
|
-
description="Het gewenste 'Coordinate Reference System' (CRS) van de "
|
322
|
-
"geometrie in het antwoord (response body). Volgens de "
|
323
|
-
"GeoJSON spec is WGS84 de default (EPSG:4326 is "
|
324
|
-
"hetzelfde als WGS84).",
|
325
|
-
enum=[DEFAULT_CRS],
|
326
|
-
),
|
327
|
-
openapi.Parameter(
|
328
|
-
name=HEADER_CONTENT,
|
329
|
-
type=openapi.TYPE_STRING,
|
330
|
-
in_=openapi.IN_HEADER,
|
331
|
-
required=True,
|
332
|
-
description="Het 'Coordinate Reference System' (CRS) van de "
|
333
|
-
"geometrie in de vraag (request body). Volgens de "
|
334
|
-
"GeoJSON spec is WGS84 de default (EPSG:4326 is "
|
335
|
-
"hetzelfde als WGS84).",
|
336
|
-
enum=[DEFAULT_CRS],
|
337
|
-
),
|
338
|
-
]
|
339
|
-
|
340
|
-
def get_response_headers(self, serializer, status=None):
|
341
|
-
if not self.has_geo_fields(serializer):
|
342
|
-
return None
|
343
|
-
|
344
|
-
if int(status) != 200:
|
345
|
-
return None
|
346
|
-
|
347
|
-
return OrderedDict(
|
348
|
-
(
|
349
|
-
(
|
350
|
-
HEADER_CONTENT,
|
351
|
-
openapi.Schema(
|
352
|
-
type=openapi.TYPE_STRING,
|
353
|
-
enum=[DEFAULT_CRS],
|
354
|
-
description="Het 'Coordinate Reference System' (CRS) van de "
|
355
|
-
"antwoorddata. Volgens de GeoJSON spec is WGS84 de "
|
356
|
-
"default (EPSG:4326 is hetzelfde als WGS84).",
|
357
|
-
),
|
358
|
-
),
|
359
|
-
)
|
360
|
-
)
|
@@ -1,72 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Introspect polymorphic resources
|
3
|
-
|
4
|
-
Bulk of the code taken from https://github.com/axnsan12/drf-yasg/issues/100
|
5
|
-
"""
|
6
|
-
|
7
|
-
from drf_yasg import openapi
|
8
|
-
from drf_yasg.errors import SwaggerGenerationError
|
9
|
-
from drf_yasg.inspectors.base import NotHandled
|
10
|
-
from drf_yasg.inspectors.field import (
|
11
|
-
CamelCaseJSONFilter,
|
12
|
-
ReferencingSerializerInspector,
|
13
|
-
)
|
14
|
-
|
15
|
-
from ..polymorphism import PolymorphicSerializer
|
16
|
-
from ..utils import underscore_to_camel
|
17
|
-
|
18
|
-
|
19
|
-
class PolymorphicSerializerInspector(
|
20
|
-
CamelCaseJSONFilter, ReferencingSerializerInspector
|
21
|
-
):
|
22
|
-
def field_to_swagger_object(
|
23
|
-
self, field, swagger_object_type, use_references, **kwargs
|
24
|
-
):
|
25
|
-
SwaggerType, ChildSwaggerType = self._get_partial_types(
|
26
|
-
field, swagger_object_type, use_references, **kwargs
|
27
|
-
)
|
28
|
-
|
29
|
-
if not isinstance(field, PolymorphicSerializer):
|
30
|
-
return NotHandled
|
31
|
-
|
32
|
-
if not getattr(field, "discriminator", None):
|
33
|
-
raise SwaggerGenerationError(
|
34
|
-
"'PolymorphicSerializer' derived serializers need to have 'discriminator' set"
|
35
|
-
)
|
36
|
-
|
37
|
-
base_schema_ref = super().field_to_swagger_object(
|
38
|
-
field, swagger_object_type, use_references, **kwargs
|
39
|
-
)
|
40
|
-
if not isinstance(base_schema_ref, openapi.SchemaRef):
|
41
|
-
raise SwaggerGenerationError(
|
42
|
-
"discriminator inheritance requires model references"
|
43
|
-
)
|
44
|
-
|
45
|
-
base_schema = base_schema_ref.resolve(self.components) # type: openapi.Schema
|
46
|
-
base_schema.discriminator = underscore_to_camel(
|
47
|
-
field.discriminator.discriminator_field
|
48
|
-
)
|
49
|
-
|
50
|
-
for value, serializer in field.discriminator.mapping.items():
|
51
|
-
if serializer is None:
|
52
|
-
allof_derived = openapi.Schema(
|
53
|
-
type=openapi.TYPE_OBJECT, all_of=[base_schema_ref]
|
54
|
-
)
|
55
|
-
else:
|
56
|
-
derived_ref = self.probe_field_inspectors(
|
57
|
-
serializer, openapi.Schema, use_references=True
|
58
|
-
)
|
59
|
-
if not isinstance(derived_ref, openapi.SchemaRef):
|
60
|
-
raise SwaggerGenerationError(
|
61
|
-
"discriminator inheritance requies model references"
|
62
|
-
)
|
63
|
-
|
64
|
-
allof_derived = openapi.Schema(
|
65
|
-
type=openapi.TYPE_OBJECT, all_of=[base_schema_ref, derived_ref]
|
66
|
-
)
|
67
|
-
if not self.components.has(value, scope=openapi.SCHEMA_DEFINITIONS):
|
68
|
-
self.components.set(
|
69
|
-
value, allof_derived, scope=openapi.SCHEMA_DEFINITIONS
|
70
|
-
)
|
71
|
-
|
72
|
-
return base_schema_ref
|
@@ -1,96 +0,0 @@
|
|
1
|
-
from django.db import models
|
2
|
-
|
3
|
-
try:
|
4
|
-
from django.utils.encoding import force_str
|
5
|
-
except ImportError: # Django < 4.0
|
6
|
-
from django.utils.encoding import force_text as force_str
|
7
|
-
|
8
|
-
from django.utils.translation import gettext as _
|
9
|
-
|
10
|
-
from django_filters.filters import BaseCSVFilter, ChoiceFilter
|
11
|
-
from drf_yasg import openapi
|
12
|
-
from drf_yasg.inspectors.query import CoreAPICompatInspector
|
13
|
-
from rest_framework.filters import OrderingFilter
|
14
|
-
|
15
|
-
from ..filters import URLModelChoiceFilter
|
16
|
-
from ..utils import underscore_to_camel
|
17
|
-
from .utils import get_target_field
|
18
|
-
|
19
|
-
|
20
|
-
class FilterInspector(CoreAPICompatInspector):
|
21
|
-
"""
|
22
|
-
Filter inspector that specifies the format of URL-based fields and lists
|
23
|
-
enum options.
|
24
|
-
"""
|
25
|
-
|
26
|
-
def get_filter_parameters(self, filter_backend):
|
27
|
-
fields = super().get_filter_parameters(filter_backend)
|
28
|
-
if isinstance(filter_backend, OrderingFilter):
|
29
|
-
return fields
|
30
|
-
|
31
|
-
if fields:
|
32
|
-
queryset = self.view.get_queryset()
|
33
|
-
filter_class = filter_backend.get_filterset_class(self.view, queryset)
|
34
|
-
|
35
|
-
for parameter in fields:
|
36
|
-
filter_field = filter_class.base_filters[parameter.name]
|
37
|
-
model_field = get_target_field(queryset.model, parameter.name)
|
38
|
-
parameter._filter_field = filter_field
|
39
|
-
|
40
|
-
help_text = filter_field.extra.get(
|
41
|
-
"help_text",
|
42
|
-
getattr(model_field, "help_text", "") if model_field else "",
|
43
|
-
)
|
44
|
-
|
45
|
-
if isinstance(filter_field, BaseCSVFilter):
|
46
|
-
if "choices" in filter_field.extra:
|
47
|
-
schema = openapi.Schema(
|
48
|
-
type=openapi.TYPE_ARRAY,
|
49
|
-
items=openapi.Schema(
|
50
|
-
type=openapi.TYPE_STRING,
|
51
|
-
enum=[
|
52
|
-
choice[0]
|
53
|
-
for choice in filter_field.extra["choices"]
|
54
|
-
],
|
55
|
-
),
|
56
|
-
)
|
57
|
-
else:
|
58
|
-
schema = openapi.Schema(
|
59
|
-
type=openapi.TYPE_ARRAY,
|
60
|
-
items=openapi.Schema(type=openapi.TYPE_STRING),
|
61
|
-
)
|
62
|
-
parameter["type"] = openapi.TYPE_ARRAY
|
63
|
-
parameter["schema"] = schema
|
64
|
-
parameter["style"] = "form"
|
65
|
-
parameter["explode"] = False
|
66
|
-
elif isinstance(filter_field, URLModelChoiceFilter):
|
67
|
-
description = _("URL to the related {resource}").format(
|
68
|
-
resource=parameter.name
|
69
|
-
)
|
70
|
-
parameter.description = help_text or description
|
71
|
-
parameter.format = openapi.FORMAT_URI
|
72
|
-
elif isinstance(filter_field, ChoiceFilter):
|
73
|
-
parameter.enum = [
|
74
|
-
choice[0] for choice in filter_field.extra["choices"]
|
75
|
-
]
|
76
|
-
elif model_field and isinstance(model_field, models.URLField):
|
77
|
-
parameter.format = openapi.FORMAT_URI
|
78
|
-
|
79
|
-
if not parameter.description and help_text:
|
80
|
-
parameter.description = force_str(help_text)
|
81
|
-
|
82
|
-
if "max_length" in filter_field.extra:
|
83
|
-
parameter.max_length = filter_field.extra["max_length"]
|
84
|
-
if "min_length" in filter_field.extra:
|
85
|
-
parameter.min_length = filter_field.extra["min_length"]
|
86
|
-
|
87
|
-
return fields
|
88
|
-
|
89
|
-
def process_result(self, result, method_name, obj, **kwargs):
|
90
|
-
"""
|
91
|
-
Convert snake-case to camelCase.
|
92
|
-
"""
|
93
|
-
if result and type(result) is list:
|
94
|
-
for parameter in result:
|
95
|
-
parameter.name = underscore_to_camel(parameter.name)
|
96
|
-
return result
|
@@ -1,40 +0,0 @@
|
|
1
|
-
from typing import Optional, Type
|
2
|
-
|
3
|
-
from django.db import models
|
4
|
-
|
5
|
-
from rest_framework.utils.model_meta import get_field_info
|
6
|
-
|
7
|
-
|
8
|
-
def get_target_field(model: Type[models.Model], field: str) -> Optional[models.Field]:
|
9
|
-
"""
|
10
|
-
Retrieve the end-target that ``field`` points to.
|
11
|
-
|
12
|
-
:param field: A string containing a lookup, potentially spanning relations. E.g.:
|
13
|
-
foo__bar__lte.
|
14
|
-
:return: A Django model field instance or `None`
|
15
|
-
"""
|
16
|
-
|
17
|
-
start, *remaining = field.split("__")
|
18
|
-
field_info = get_field_info(model)
|
19
|
-
|
20
|
-
# simple, non relational field?
|
21
|
-
if start in field_info.fields:
|
22
|
-
return field_info.fields[start]
|
23
|
-
|
24
|
-
# simple relational field?
|
25
|
-
if start in field_info.forward_relations:
|
26
|
-
relation_info = field_info.forward_relations[start]
|
27
|
-
if not remaining:
|
28
|
-
return relation_info.model_field
|
29
|
-
else:
|
30
|
-
return get_target_field(relation_info.related_model, "__".join(remaining))
|
31
|
-
|
32
|
-
# check the reverse relations - note that the model name is used instead of model_name_set
|
33
|
-
# in the queries -> we can't just test for containment in field_info.reverse_relations
|
34
|
-
for relation_info in field_info.reverse_relations.values():
|
35
|
-
# not sure about this - what if there are more relations with different related names?
|
36
|
-
if relation_info.related_model._meta.model_name != start:
|
37
|
-
continue
|
38
|
-
return get_target_field(relation_info.related_model, "__".join(remaining))
|
39
|
-
|
40
|
-
return None
|