fi(api): improve auth/preferences schema generation
Applying recommendation from https://github.com/tfranzel/drf-spectacular/issues/874
This commit is contained in:
parent
9bfc83f0e4
commit
8f65318d32
|
@ -1,35 +1,97 @@
|
|||
import os
|
||||
|
||||
from drf_spectacular.contrib.django_oauth_toolkit import OpenApiAuthenticationExtension
|
||||
from drf_spectacular.plumbing import build_bearer_security_scheme_object
|
||||
from drf_spectacular.contrib.django_oauth_toolkit import (
|
||||
DjangoOAuthToolkitScheme,
|
||||
OpenApiAuthenticationExtension,
|
||||
)
|
||||
from drf_spectacular.extensions import (
|
||||
OpenApiSerializerExtension,
|
||||
OpenApiSerializerFieldExtension,
|
||||
)
|
||||
from drf_spectacular.plumbing import (
|
||||
OpenApiTypes,
|
||||
build_basic_type,
|
||||
build_bearer_security_scheme_object,
|
||||
)
|
||||
|
||||
|
||||
class CustomOAuthExt(OpenApiAuthenticationExtension):
|
||||
class CustomRelatedFieldScheme(OpenApiSerializerFieldExtension):
|
||||
target_class = "funkwhale_api.common.serializers.RelatedField"
|
||||
match_subclasses = True
|
||||
|
||||
def map_serializer_field(self, auto_schema, direction):
|
||||
if direction == "request":
|
||||
return build_basic_type(OpenApiTypes.UUID)
|
||||
elif direction == "response" and self.target.serializer:
|
||||
component = auto_schema.resolve_serializer(
|
||||
self.target.serializer, direction
|
||||
)
|
||||
return component.ref
|
||||
else:
|
||||
# happens for
|
||||
# UserViewSet: UserWriteSerializer: not sure how this works for: avatar
|
||||
# AlbumViewSet: AlbumCreateSerializer: not sure how this works for: artist
|
||||
return build_basic_type(OpenApiTypes.UUID)
|
||||
|
||||
|
||||
class PreferenceSerializerScheme(OpenApiSerializerExtension):
|
||||
target_class = "dynamic_preferences.api.serializers.PreferenceSerializer"
|
||||
match_subclasses = True
|
||||
|
||||
def map_serializer(self, auto_schema, direction):
|
||||
from dynamic_preferences.api.serializers import PreferenceSerializer
|
||||
|
||||
class Fix(PreferenceSerializer):
|
||||
def get_default(self, o) -> str:
|
||||
pass
|
||||
|
||||
def get_verbose_name(self, o) -> str:
|
||||
pass
|
||||
|
||||
def get_identifier(self, o) -> str:
|
||||
pass
|
||||
|
||||
def get_help_text(self, o) -> str:
|
||||
pass
|
||||
|
||||
def get_additional_data(self, o) -> dict:
|
||||
pass
|
||||
|
||||
def get_field(self, o) -> dict:
|
||||
pass
|
||||
|
||||
return auto_schema._map_serializer(Fix, direction, bypass_extensions=True)
|
||||
|
||||
|
||||
class CustomOAuthScheme(DjangoOAuthToolkitScheme):
|
||||
target_class = "funkwhale_api.common.authentication.OAuth2Authentication"
|
||||
name = "oauth2"
|
||||
|
||||
def get_security_definition(self, auto_schema):
|
||||
from drf_spectacular.settings import spectacular_settings
|
||||
from oauth2_provider.scopes import get_scopes_backend
|
||||
def get_security_requirement(self, auto_schema):
|
||||
from funkwhale_api.users.oauth.permissions import (
|
||||
METHOD_SCOPE_MAPPING,
|
||||
ScopePermission,
|
||||
)
|
||||
|
||||
flows = {}
|
||||
for flow_type in spectacular_settings.OAUTH2_FLOWS:
|
||||
flows[flow_type] = {}
|
||||
if flow_type in ("implicit", "authorizationCode"):
|
||||
flows[flow_type][
|
||||
"authorizationUrl"
|
||||
] = spectacular_settings.OAUTH2_AUTHORIZATION_URL
|
||||
if flow_type in ("password", "clientCredentials", "authorizationCode"):
|
||||
flows[flow_type]["tokenUrl"] = spectacular_settings.OAUTH2_TOKEN_URL
|
||||
if spectacular_settings.OAUTH2_REFRESH_URL:
|
||||
flows[flow_type]["refreshUrl"] = spectacular_settings.OAUTH2_REFRESH_URL
|
||||
scope_backend = get_scopes_backend()
|
||||
flows[flow_type]["scopes"] = scope_backend.get_all_scopes()
|
||||
for permission in auto_schema.view.get_permissions():
|
||||
if isinstance(permission, ScopePermission):
|
||||
scope_config = getattr(auto_schema.view, "required_scope", "noopscope")
|
||||
|
||||
return {"type": "oauth2", "flows": flows}
|
||||
if isinstance(scope_config, str):
|
||||
scope_config = {
|
||||
"read": f"read:{scope_config}",
|
||||
"write": f"write:{scope_config}",
|
||||
}
|
||||
action = METHOD_SCOPE_MAPPING[
|
||||
auto_schema.view.request.method.lower()
|
||||
]
|
||||
required_scope = scope_config[action]
|
||||
else:
|
||||
required_scope = scope_config[auto_schema.view.action]
|
||||
|
||||
return {self.name: [required_scope]}
|
||||
|
||||
|
||||
class CustomApplicationTokenExt(OpenApiAuthenticationExtension):
|
||||
class CustomApplicationTokenScheme(OpenApiAuthenticationExtension):
|
||||
target_class = "funkwhale_api.common.authentication.ApplicationTokenAuthentication"
|
||||
name = "ApplicationToken"
|
||||
|
||||
|
|
Loading…
Reference in New Issue