*: fix static response descriptions

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-05-16 13:26:58 +02:00
parent 1324d03815
commit 0bac738090
22 changed files with 136 additions and 64 deletions

View file

@ -26,7 +26,7 @@ lint:
pylint authentik tests lifecycle
gen:
./manage.py spectacular --file schema.yml
./manage.py spectacular --file schema.yaml --validate --fail-on-warn
docker run \
--rm -v ${PWD}:/local \
openapitools/openapi-generator-cli generate \

View file

@ -4,7 +4,7 @@ from importlib import import_module
from django.contrib import messages
from django.http.response import Http404
from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import CharField, ChoiceField, DateTimeField, ListField
from rest_framework.permissions import IsAdminUser
@ -34,8 +34,14 @@ class TaskViewSet(ViewSet):
"""Read-only view set that returns all background tasks"""
permission_classes = [IsAdminUser]
serializer_class = TaskSerializer
@extend_schema(responses={200: TaskSerializer(many=False), 404: "Task not found"})
@extend_schema(
responses={
200: TaskSerializer(many=False),
404: OpenApiResponse(description="Task not found"),
}
)
# pylint: disable=invalid-name
def retrieve(self, request: Request, pk=None) -> Response:
"""Get a single system task"""
@ -52,9 +58,9 @@ class TaskViewSet(ViewSet):
@extend_schema(
responses={
204: "Task retried successfully",
404: "Task not found",
500: "Failed to retry task",
204: OpenApiResponse(description="Task retried successfully"),
404: OpenApiResponse(description="Task not found"),
500: OpenApiResponse(description="Failed to retry task"),
}
)
@action(detail=True, methods=["post"])

View file

@ -3,11 +3,11 @@ from base64 import b64decode
from binascii import Error
from typing import Any, Optional, Union
from drf_spectacular.authentication import OpenApiAuthenticationExtension
from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.request import Request
from structlog.stdlib import get_logger
from drf_spectacular.authentication import OpenApiAuthenticationExtension
from authentik.core.models import Token, TokenIntents, User
@ -60,11 +60,11 @@ class AuthentikTokenAuthentication(BaseAuthentication):
class TokenSchema(OpenApiAuthenticationExtension):
target_class = AuthentikTokenAuthentication
name = 'authentik'
name = "authentik"
def get_security_definition(self, auto_schema):
return {
'type': 'apiKey',
'in': 'header',
'name': 'Authorization',
"type": "apiKey",
"in": "header",
"name": "Authorization",
}

View file

@ -6,7 +6,7 @@ from django.db.models import QuerySet
from django.http.response import HttpResponseBadRequest
from django.shortcuts import get_object_or_404
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import SerializerMethodField
from rest_framework.parsers import MultiPartParser
@ -94,8 +94,8 @@ class ApplicationViewSet(ModelViewSet):
@extend_schema(
responses={
204: "Access granted",
403: "Access denied",
204: OpenApiResponse(description="Access granted"),
403: OpenApiResponse(description="Access denied"),
}
)
@action(detail=True, methods=["GET"])
@ -161,7 +161,10 @@ class ApplicationViewSet(ModelViewSet):
required=True,
)
],
responses={200: "Success", 400: "Bad request"},
responses={
200: OpenApiResponse(description="Success"),
400: OpenApiResponse(description="Bad request"),
},
)
@action(
detail=True,

View file

@ -2,7 +2,7 @@
from json import dumps
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework import mixins
from rest_framework.decorators import action
@ -102,7 +102,10 @@ class PropertyMappingViewSet(
@permission_required("authentik_core.view_propertymapping")
@extend_schema(
request=PolicyTestSerializer(),
responses={200: PropertyMappingTestResultSerializer, 400: "Invalid parameters"},
responses={
200: PropertyMappingTestResultSerializer,
400: OpenApiResponse(description="Invalid parameters"),
},
parameters=[
OpenApiParameter(
name="format_result",

View file

@ -22,7 +22,7 @@ class ProviderSerializer(ModelSerializer, MetaNameSerializer):
component = SerializerMethodField()
def get_component(self, obj: Provider): # pragma: no cover
def get_component(self, obj: Provider) -> str: # pragma: no cover
"""Get object component so that we know how to edit the object"""
# pyright: reportGeneralTypeIssues=false
if obj.__class__ == Provider:

View file

@ -24,7 +24,7 @@ class SourceSerializer(ModelSerializer, MetaNameSerializer):
component = SerializerMethodField()
def get_component(self, obj: Source):
def get_component(self, obj: Source) -> str:
"""Get object component so that we know how to edit the object"""
# pyright: reportGeneralTypeIssues=false
if obj.__class__ == Source:

View file

@ -1,6 +1,6 @@
"""Tokens API Viewset"""
from django.http.response import Http404
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import CharField
from rest_framework.request import Request
@ -70,7 +70,7 @@ class TokenViewSet(ModelViewSet):
@extend_schema(
responses={
200: TokenViewSerializer(many=False),
404: "Token not found or expired",
404: OpenApiResponse(description="Token not found or expired"),
}
)
@action(detail=True, pagination_class=None, filter_backends=[])

View file

@ -7,7 +7,7 @@ from django.urls import reverse_lazy
from django.utils.http import urlencode
from django_filters.filters import BooleanFilter, CharFilter
from django_filters.filterset import FilterSet
from drf_spectacular.utils import extend_schema, extend_schema_field
from drf_spectacular.utils import OpenApiResponse, extend_schema, extend_schema_field
from guardian.utils import get_anonymous_user
from rest_framework.decorators import action
from rest_framework.fields import CharField, JSONField, SerializerMethodField
@ -170,7 +170,10 @@ class UserViewSet(ModelViewSet):
@permission_required("authentik_core.reset_user_password")
@extend_schema(
responses={"200": LinkSerializer(many=False), "404": "No recovery flow found."},
responses={
"200": LinkSerializer(many=False),
"404": OpenApiResponse(description="No recovery flow found."),
},
)
@action(detail=True, pagination_class=None, filter_backends=[])
# pylint: disable=invalid-name, unused-argument

View file

@ -6,7 +6,7 @@ from cryptography.x509 import load_pem_x509_certificate
from django.http.response import HttpResponse
from django.utils.translation import gettext_lazy as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import (
CharField,
@ -127,7 +127,10 @@ class CertificateKeyPairViewSet(ModelViewSet):
@permission_required(None, ["authentik_crypto.add_certificatekeypair"])
@extend_schema(
request=CertificateGenerationSerializer(),
responses={200: CertificateKeyPairSerializer, 400: "Bad request"},
responses={
200: CertificateKeyPairSerializer,
400: OpenApiResponse(description="Bad request"),
},
)
@action(detail=False, methods=["POST"])
def generate(self, request: Request) -> Response:

View file

@ -1,8 +1,8 @@
"""Events API Views"""
from drf_spectacular.types import OpenApiTypes
import django_filters
from django.db.models.aggregates import Count
from django.db.models.fields.json import KeyTextTransform
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action
@ -116,7 +116,7 @@ class EventViewSet(ReadOnlyModelViewSet):
location=OpenApiParameter.QUERY,
required=False,
)
]
],
)
@action(detail=False, methods=["GET"])
def top_per_user(self, request: Request):

View file

@ -1,6 +1,6 @@
"""NotificationTransport API Views"""
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import CharField, ListField, SerializerMethodField
from rest_framework.request import Request
@ -23,7 +23,7 @@ class NotificationTransportSerializer(ModelSerializer):
mode_verbose = SerializerMethodField()
def get_mode_verbose(self, instance: NotificationTransport):
def get_mode_verbose(self, instance: NotificationTransport) -> str:
"""Return selected mode with a UI Label"""
return TransportMode(instance.mode).label
@ -62,7 +62,7 @@ class NotificationTransportViewSet(ModelViewSet):
@extend_schema(
responses={
200: NotificationTransportTestSerializer(many=False),
503: "Failed to test transport",
500: OpenApiResponse(description="Failed to test transport"),
},
request=OpenApiTypes.NONE,
)
@ -84,4 +84,4 @@ class NotificationTransportViewSet(ModelViewSet):
response.is_valid()
return Response(response.data)
except NotificationTransportError as exc:
return Response(str(exc.__cause__ or None), status=503)
return Response(str(exc.__cause__ or None), status=500)

View file

@ -7,12 +7,7 @@ from django.http.response import HttpResponseBadRequest, JsonResponse
from django.urls import reverse
from django.utils.translation import gettext as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import (
OpenApiParameter,
OpenApiResponse,
OpenApiSchemaBase,
extend_schema,
)
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action
from rest_framework.parsers import MultiPartParser
@ -46,7 +41,7 @@ class FlowSerializer(ModelSerializer):
cache_count = SerializerMethodField()
def get_cache_count(self, flow: Flow):
def get_cache_count(self, flow: Flow) -> int:
"""Get count of cached flows"""
return len(cache.keys(f"{cache_key(flow)}*"))
@ -111,7 +106,10 @@ class FlowViewSet(ModelViewSet):
@permission_required(None, ["authentik_flows.clear_flow_cache"])
@extend_schema(
request=OpenApiTypes.NONE,
responses={204: "Successfully cleared cache", 400: "Bad request"},
responses={
204: OpenApiResponse(description="Successfully cleared cache"),
400: OpenApiResponse(description="Bad request"),
},
)
@action(detail=False, methods=["POST"])
def cache_clear(self, request: Request) -> Response:
@ -148,7 +146,10 @@ class FlowViewSet(ModelViewSet):
required=True,
)
],
responses={204: "Successfully imported flow", 400: "Bad request"},
responses={
204: OpenApiResponse(description="Successfully imported flow"),
400: OpenApiResponse(description="Bad request"),
},
)
@action(detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
def import_flow(self, request: Request) -> Response:
@ -178,9 +179,7 @@ class FlowViewSet(ModelViewSet):
)
@extend_schema(
responses={
"200": OpenApiResponse(
response=OpenApiParameter("File Attachment", type=OpenApiTypes.BINARY)
),
"200": OpenApiResponse(response=OpenApiTypes.BINARY),
},
)
@action(detail=True, pagination_class=None, filter_backends=[])
@ -274,7 +273,10 @@ class FlowViewSet(ModelViewSet):
required=True,
)
],
responses={200: "Success", 400: "Bad request"},
responses={
200: OpenApiResponse(description="Success"),
400: OpenApiResponse(description="Bad request"),
},
)
@action(
detail=True,
@ -295,7 +297,10 @@ class FlowViewSet(ModelViewSet):
return Response({})
@extend_schema(
responses={200: LinkSerializer(many=False), 400: "Flow not applicable"},
responses={
200: LinkSerializer(many=False),
400: OpenApiResponse(description="Flow not applicable"),
},
)
@action(detail=True, pagination_class=None, filter_backends=[])
# pylint: disable=unused-argument

View file

@ -11,7 +11,7 @@ from django.utils.decorators import method_decorator
from django.views.decorators.clickjacking import xframe_options_sameorigin
from django.views.generic import View
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.permissions import AllowAny
from rest_framework.views import APIView
from sentry_sdk import capture_exception
@ -128,7 +128,9 @@ class FlowExecutorView(APIView):
@extend_schema(
responses={
200: Challenge(),
404: "No Token found", # This error can be raised by the email stage
404: OpenApiResponse(
description="No Token found"
), # This error can be raised by the email stage
},
request=OpenApiTypes.NONE,
parameters=[

View file

@ -1,7 +1,7 @@
"""policy API Views"""
from django.core.cache import cache
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import OpenApiResponse, extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework import mixins
from rest_framework.decorators import action
@ -124,7 +124,10 @@ class PolicyViewSet(
@permission_required(None, ["authentik_policies.clear_policy_cache"])
@extend_schema(
request=OpenApiTypes.NONE,
responses={204: "Successfully cleared cache", 400: "Bad request"},
responses={
204: OpenApiResponse(description="Successfully cleared cache"),
400: OpenApiResponse(description="Bad request"),
},
)
@action(detail=False, methods=["POST"])
def cache_clear(self, request: Request) -> Response:
@ -140,7 +143,10 @@ class PolicyViewSet(
@permission_required("authentik_policies.view_policy")
@extend_schema(
request=PolicyTestSerializer(),
responses={200: PolicyTestResultSerializer(), 400: "Invalid parameters"},
responses={
200: PolicyTestResultSerializer(),
400: OpenApiResponse(description="Invalid parameters"),
},
)
@action(detail=True, pagination_class=None, filter_backends=[], methods=["POST"])
# pylint: disable=unused-argument, invalid-name

View file

@ -2,7 +2,7 @@
from django.db.models.base import Model
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.fields import ReadOnlyField
from rest_framework.generics import get_object_or_404
@ -61,9 +61,6 @@ class OAuth2ProviderSetupURLs(PassiveSerializer):
provider_info = ReadOnlyField()
logout = ReadOnlyField()
class Meta:
model = Model
class OAuth2ProviderViewSet(ModelViewSet):
"""OAuth2Provider Viewset"""
@ -74,7 +71,7 @@ class OAuth2ProviderViewSet(ModelViewSet):
@extend_schema(
responses={
200: OAuth2ProviderSetupURLs,
404: "Provider has no application assigned",
404: OpenApiResponse(description="Provider has no application assigned"),
}
)
@action(methods=["GET"], detail=True)

View file

@ -6,7 +6,7 @@ from django.http.response import HttpResponse
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext_lazy as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema, extend_schema_field
from rest_framework.decorators import action
from rest_framework.fields import CharField, FileField, ReadOnlyField
from rest_framework.parsers import MultiPartParser
@ -83,7 +83,7 @@ class SAMLProviderViewSet(ModelViewSet):
@extend_schema(
responses={
200: SAMLMetadataSerializer(many=False),
404: "Provider has no application assigned",
404: OpenApiResponse(description="Provider has no application assigned"),
},
parameters=[
OpenApiParameter(
@ -120,7 +120,10 @@ class SAMLProviderViewSet(ModelViewSet):
)
@extend_schema(
request=SAMLProviderImportSerializer(),
responses={204: "Successfully imported provider", 400: "Bad request"},
responses={
204: OpenApiResponse(description="Successfully imported provider"),
400: OpenApiResponse(description="Bad request"),
},
)
@action(detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
def import_metadata(self, request: Request) -> Response:

View file

@ -151,6 +151,9 @@ SPECTACULAR_SETTINGS = {
"name": "GNU GPLv3",
"url": "https://github.com/goauthentik/authentik/blob/master/LICENSE",
},
"ENUM_NAME_OVERRIDES": {
"ChallengeChoices": "authentik.flows.challenge.ChallengeTypes"
},
}
REST_FRAMEWORK = {

View file

@ -1,7 +1,7 @@
"""Source API Views"""
from django.http.response import Http404
from django.utils.text import slugify
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.response import Response
@ -48,7 +48,12 @@ class LDAPSourceViewSet(ModelViewSet):
serializer_class = LDAPSourceSerializer
lookup_field = "slug"
@extend_schema(responses={200: TaskSerializer(many=False), 404: "Task not found"})
@extend_schema(
responses={
200: TaskSerializer(many=False),
404: OpenApiResponse(description="Task not found"),
}
)
@action(methods=["GET"], detail=True)
# pylint: disable=unused-argument
def sync_status(self, request: Request, slug: str) -> Response:

View file

@ -1,7 +1,7 @@
"""Plex Source Serializer"""
from django.shortcuts import get_object_or_404
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied
from rest_framework.fields import CharField
@ -54,8 +54,8 @@ class PlexSourceViewSet(ModelViewSet):
request=PlexTokenRedeemSerializer(),
responses={
200: RedirectChallenge(),
400: "Token not found",
403: "Access denied",
400: OpenApiResponse(description="Token not found"),
403: OpenApiResponse(description="Access denied"),
},
parameters=[
OpenApiParameter(

View file

@ -34,7 +34,6 @@ class StaticDeviceSerializer(ModelSerializer):
model = StaticDevice
fields = ["name", "token_set", "pk"]
depth = 2
class StaticDeviceViewSet(ModelViewSet):

View file

@ -105,6 +105,18 @@ paths:
required: true
tags:
- admin
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TaskRequest'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/TaskRequest'
multipart/form-data:
schema:
$ref: '#/components/schemas/TaskRequest'
required: true
security:
- authentik: []
- cookieAuth: []
@ -21190,6 +21202,28 @@ components:
- task_description
- task_finish_timestamp
- task_name
TaskRequest:
type: object
description: Serialize TaskInfo and TaskResult
properties:
task_name:
type: string
task_description:
type: string
task_finish_timestamp:
type: string
format: date-time
status:
$ref: '#/components/schemas/StatusEnum'
messages:
type: array
items: {}
required:
- messages
- status
- task_description
- task_finish_timestamp
- task_name
Token:
type: object
description: Token Serializer