- Introduced a new public health check endpoint at `api/ping/` to verify API responsiveness. - Refactored integration response handling to utilize a unified success and error response format across various methods in `IntegrationSettingsViewSet`, improving consistency and clarity in API responses. - Updated URL patterns to include the new ping endpoint and adjusted imports accordingly.
88 lines
3.5 KiB
Python
88 lines
3.5 KiB
Python
"""
|
|
OpenAPI Schema Extensions for drf-spectacular
|
|
Custom extensions for JWT authentication and unified response format
|
|
"""
|
|
from drf_spectacular.extensions import OpenApiAuthenticationExtension
|
|
from drf_spectacular.plumbing import build_bearer_security_scheme_object
|
|
from drf_spectacular.utils import extend_schema, OpenApiResponse
|
|
from rest_framework import status
|
|
|
|
# Explicit tags we want to keep (from SPECTACULAR_SETTINGS)
|
|
EXPLICIT_TAGS = {'Authentication', 'Planner', 'Writer', 'System', 'Billing'}
|
|
|
|
|
|
def postprocess_schema_filter_tags(result, generator, request, public):
|
|
"""
|
|
Postprocessing hook to remove auto-generated tags and keep only explicit tags.
|
|
This prevents duplicate tags from URL patterns (auth, planner, etc.)
|
|
"""
|
|
# First, filter tags from all paths (operations)
|
|
if 'paths' in result:
|
|
for path, methods in result['paths'].items():
|
|
for method, operation in methods.items():
|
|
if isinstance(operation, dict) and 'tags' in operation:
|
|
# Keep only explicit tags from the operation
|
|
filtered_tags = [
|
|
tag for tag in operation['tags']
|
|
if tag in EXPLICIT_TAGS
|
|
]
|
|
|
|
# If no explicit tags found, infer from path
|
|
if not filtered_tags:
|
|
if '/ping' in path or '/system/ping/' in path:
|
|
filtered_tags = ['System'] # Health check endpoint
|
|
elif '/auth/' in path or '/api/v1/auth/' in path:
|
|
filtered_tags = ['Authentication']
|
|
elif '/planner/' in path or '/api/v1/planner/' in path:
|
|
filtered_tags = ['Planner']
|
|
elif '/writer/' in path or '/api/v1/writer/' in path:
|
|
filtered_tags = ['Writer']
|
|
elif '/system/' in path or '/api/v1/system/' in path:
|
|
filtered_tags = ['System']
|
|
elif '/billing/' in path or '/api/v1/billing/' in path:
|
|
filtered_tags = ['Billing']
|
|
|
|
operation['tags'] = filtered_tags
|
|
|
|
# Now filter the tags list - keep only explicit tag definitions
|
|
# The tags list contains tag definitions with 'name' and 'description'
|
|
if 'tags' in result and isinstance(result['tags'], list):
|
|
# Keep only tags that match our explicit tag names
|
|
result['tags'] = [
|
|
tag for tag in result['tags']
|
|
if isinstance(tag, dict) and tag.get('name') in EXPLICIT_TAGS
|
|
]
|
|
|
|
return result
|
|
|
|
|
|
class JWTAuthenticationExtension(OpenApiAuthenticationExtension):
|
|
"""
|
|
OpenAPI extension for JWT Bearer Token authentication
|
|
"""
|
|
target_class = 'igny8_core.api.authentication.JWTAuthentication'
|
|
name = 'JWTAuthentication'
|
|
|
|
def get_security_definition(self, auto_schema):
|
|
return build_bearer_security_scheme_object(
|
|
header_name='Authorization',
|
|
token_prefix='Bearer',
|
|
bearer_format='JWT'
|
|
)
|
|
|
|
|
|
class CSRFExemptSessionAuthenticationExtension(OpenApiAuthenticationExtension):
|
|
"""
|
|
OpenAPI extension for CSRF-exempt session authentication
|
|
"""
|
|
target_class = 'igny8_core.api.authentication.CSRFExemptSessionAuthentication'
|
|
name = 'SessionAuthentication'
|
|
|
|
def get_security_definition(self, auto_schema):
|
|
return {
|
|
'type': 'apiKey',
|
|
'in': 'cookie',
|
|
'name': 'sessionid'
|
|
}
|
|
|