*: initial migration to openapi v3
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
34e2bbc41d
commit
1324d03815
4
Makefile
4
Makefile
|
@ -26,11 +26,11 @@ lint:
|
|||
pylint authentik tests lifecycle
|
||||
|
||||
gen:
|
||||
./manage.py generate_swagger -o swagger.yaml -f yaml
|
||||
./manage.py spectacular --file schema.yml
|
||||
docker run \
|
||||
--rm -v ${PWD}:/local \
|
||||
openapitools/openapi-generator-cli generate \
|
||||
-i /local/swagger.yaml \
|
||||
-i /local/schema.yml \
|
||||
-g typescript-fetch \
|
||||
-o /local/web/api \
|
||||
--additional-properties=typescriptThreePlus=true,supportsES6=true,npmName=authentik-api,npmVersion=1.0.0
|
||||
|
|
1
Pipfile
1
Pipfile
|
@ -44,6 +44,7 @@ urllib3 = {extras = ["secure"],version = "*"}
|
|||
uvicorn = {extras = ["standard"],version = "*"}
|
||||
webauthn = "*"
|
||||
xmlsec = "*"
|
||||
drf-spectacular = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
|
|
73
Pipfile.lock
generated
73
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "8a32708c1c04f8da03c817df973de28c37c97ee773f571ce0b3f3f834e1b7094"
|
||||
"sha256": "f38fd1bd4336a968ebb88f80874dd0d683b79f962551e4aff536322360a90b0d"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -122,18 +122,19 @@
|
|||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:3317722a1e9acbfc0d30cdf273d1708c823ceb19309e9cd91cac8a3604762341",
|
||||
"sha256:ee3317fd79b443ef102469fac393a1ffb650ea51ac4fc27464013872c5e1ce31"
|
||||
"sha256:13cfe0e3ae1bdc7baf4272b1814a7e760fbb508b19d6ac3f472a6bbd64baad61",
|
||||
"sha256:ce08b88a2d7a0ad8edb385f84ea4914296fee6813c66ebf0def956d5278de793"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.17.72"
|
||||
"version": "==1.17.73"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:0fa93a2e2daad5791c63ee526ada66896cc483d04cb2d32bfcadfeb881203453"
|
||||
"sha256:4b4aa58c61d4b125bc6ec1597924b2749e19de8f2c9a374ac087aa2561e71828",
|
||||
"sha256:69dc0b6fdc0855f5a4f8b1d29c96b9cec44e71054fea0f968e5904d6ccfd4fd9"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.20.72"
|
||||
"version": "==1.20.73"
|
||||
},
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
|
@ -415,6 +416,14 @@
|
|||
"index": "pypi",
|
||||
"version": "==5.0.0"
|
||||
},
|
||||
"drf-spectacular": {
|
||||
"hashes": [
|
||||
"sha256:4a77c233c99e028b8905cd2cf05388524838ade97b95d5c6e4861e0c3c95af31",
|
||||
"sha256:d7f64b97e8940b143a0e8d1de20523e8d7d5fe8ec557aec574513282c413b0b3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.16.0"
|
||||
},
|
||||
"drf-yasg": {
|
||||
"hashes": [
|
||||
"sha256:8b72e5b1875931a8d11af407be3a9a5ba8776541492947a0df5bafda6b7f8267",
|
||||
|
@ -614,11 +623,11 @@
|
|||
},
|
||||
"ldap3": {
|
||||
"hashes": [
|
||||
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57",
|
||||
"sha256:18c3ee656a6775b9b0d60f7c6c5b094d878d1d90fc03d56731039f0a4b546a91",
|
||||
"sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59",
|
||||
"sha256:8c949edbad2be8a03e719ba48bd6779f327ec156929562814b3e84ab56889c8c",
|
||||
"sha256:afc6fc0d01f02af82cd7bfabd3bbfd5dc96a6ae91e97db0a2dab8a0f1b436056",
|
||||
"sha256:4139c91f0eef9782df7b77c8cbc6243086affcb6a8a249b768a9658438e5da59"
|
||||
"sha256:c1df41d89459be6f304e0ceec4b00fdea533dbbcd83c802b1272dcdb94620b57"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.9"
|
||||
|
@ -873,37 +882,37 @@
|
|||
},
|
||||
"pyasn1": {
|
||||
"hashes": [
|
||||
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
|
||||
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
|
||||
"sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf",
|
||||
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
|
||||
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
|
||||
"sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00",
|
||||
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
|
||||
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
|
||||
"sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359",
|
||||
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3",
|
||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
|
||||
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
|
||||
"sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576",
|
||||
"sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8",
|
||||
"sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7",
|
||||
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"
|
||||
"sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86",
|
||||
"sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12",
|
||||
"sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776",
|
||||
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba",
|
||||
"sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2",
|
||||
"sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"
|
||||
],
|
||||
"version": "==0.4.8"
|
||||
},
|
||||
"pyasn1-modules": {
|
||||
"hashes": [
|
||||
"sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
|
||||
"sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
|
||||
"sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
|
||||
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
|
||||
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
|
||||
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
|
||||
"sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8",
|
||||
"sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199",
|
||||
"sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811",
|
||||
"sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
|
||||
"sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4",
|
||||
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
|
||||
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74",
|
||||
"sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb",
|
||||
"sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405",
|
||||
"sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed",
|
||||
"sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199"
|
||||
"sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45",
|
||||
"sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd",
|
||||
"sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0",
|
||||
"sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d",
|
||||
"sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"
|
||||
],
|
||||
"version": "==0.2.8"
|
||||
},
|
||||
|
@ -1602,11 +1611,11 @@
|
|||
},
|
||||
"gitpython": {
|
||||
"hashes": [
|
||||
"sha256:2bfcd25e6b81fe431fa3ab1f0975986cfddabf7870a323c183f3afbc9447c0c5",
|
||||
"sha256:37ac36cacf2e2be5e88f0810187c5833e71c1a2a8cf81588f5699d1b70183baa"
|
||||
"sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135",
|
||||
"sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==3.1.16"
|
||||
"version": "==3.1.17"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
|
@ -1752,11 +1761,11 @@
|
|||
},
|
||||
"pytest-django": {
|
||||
"hashes": [
|
||||
"sha256:80f8875226ec4dc0b205f0578072034563879d98d9b1bec143a80b9045716cb0",
|
||||
"sha256:a51150d8962200250e850c6adcab670779b9c2aa07271471059d1fb92a843fa9"
|
||||
"sha256:d1c6758a592fb0ef8abaa2fe12dd28858c1dcfc3d466102ffe52aa8934733dca",
|
||||
"sha256:f96c4556f4e7b15d987dd1dcc1d1526df81d40c1548d31ce840d597ed2be8c46"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.2.0"
|
||||
"version": "==4.3.0"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""Meta API"""
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.request import Request
|
||||
|
@ -22,7 +22,7 @@ class AppsViewSet(ViewSet):
|
|||
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
@swagger_auto_schema(responses={200: AppSerializer(many=True)})
|
||||
@extend_schema(responses={200: AppSerializer(many=True)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""List current messages and pass into Serializer"""
|
||||
data = []
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.db.models import Count, ExpressionWrapper, F
|
|||
from django.db.models.fields import DurationField
|
||||
from django.db.models.functions import ExtractHour
|
||||
from django.utils.timezone import now
|
||||
from drf_yasg.utils import swagger_auto_schema, swagger_serializer_method
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_field
|
||||
from rest_framework.fields import IntegerField, SerializerMethodField
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.request import Request
|
||||
|
@ -58,12 +58,12 @@ class LoginMetricsSerializer(PassiveSerializer):
|
|||
logins_per_1h = SerializerMethodField()
|
||||
logins_failed_per_1h = SerializerMethodField()
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_logins_per_1h(self, _):
|
||||
"""Get successful logins per hour for the last 24 hours"""
|
||||
return get_events_per_1h(action=EventAction.LOGIN)
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_logins_failed_per_1h(self, _):
|
||||
"""Get failed logins per hour for the last 24 hours"""
|
||||
return get_events_per_1h(action=EventAction.LOGIN_FAILED)
|
||||
|
@ -74,7 +74,7 @@ class AdministrationMetricsViewSet(ViewSet):
|
|||
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
@swagger_auto_schema(responses={200: LoginMetricsSerializer(many=False)})
|
||||
@extend_schema(responses={200: LoginMetricsSerializer(many=False)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""Login Metrics per 1h"""
|
||||
serializer = LoginMetricsSerializer(True)
|
||||
|
|
|
@ -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_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, ChoiceField, DateTimeField, ListField
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
|
@ -35,9 +35,7 @@ class TaskViewSet(ViewSet):
|
|||
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={200: TaskSerializer(many=False), 404: "Task not found"}
|
||||
)
|
||||
@extend_schema(responses={200: TaskSerializer(many=False), 404: "Task not found"})
|
||||
# pylint: disable=invalid-name
|
||||
def retrieve(self, request: Request, pk=None) -> Response:
|
||||
"""Get a single system task"""
|
||||
|
@ -46,13 +44,13 @@ class TaskViewSet(ViewSet):
|
|||
raise Http404
|
||||
return Response(TaskSerializer(task, many=False).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: TaskSerializer(many=True)})
|
||||
@extend_schema(responses={200: TaskSerializer(many=True)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""List system tasks"""
|
||||
tasks = sorted(TaskInfo.all().values(), key=lambda task: task.task_name)
|
||||
return Response(TaskSerializer(tasks, many=True).data)
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
204: "Task retried successfully",
|
||||
404: "Task not found",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from os import environ
|
||||
|
||||
from django.core.cache import cache
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from packaging.version import parse
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from rest_framework.mixins import ListModelMixin
|
||||
|
@ -57,7 +57,7 @@ class VersionViewSet(ListModelMixin, GenericViewSet):
|
|||
def get_queryset(self): # pragma: no cover
|
||||
return None
|
||||
|
||||
@swagger_auto_schema(responses={200: VersionSerializer(many=False)})
|
||||
@extend_schema(responses={200: VersionSerializer(many=False)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""Get running and latest version."""
|
||||
return Response(VersionSerializer(True).data)
|
||||
|
|
|
@ -7,6 +7,7 @@ from rest_framework.authentication import BaseAuthentication, get_authorization_
|
|||
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
|
||||
|
||||
|
@ -55,3 +56,15 @@ class AuthentikTokenAuthentication(BaseAuthentication):
|
|||
return None
|
||||
|
||||
return (token.user, None) # pragma: no cover
|
||||
|
||||
|
||||
class TokenSchema(OpenApiAuthenticationExtension):
|
||||
target_class = AuthentikTokenAuthentication
|
||||
name = 'authentik'
|
||||
|
||||
def get_security_definition(self, auto_schema):
|
||||
return {
|
||||
'type': 'apiKey',
|
||||
'in': 'header',
|
||||
'name': 'Authorization',
|
||||
}
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
"""Swagger Pagination Schema class"""
|
||||
from typing import OrderedDict
|
||||
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.inspectors import PaginatorInspector
|
||||
|
||||
|
||||
class PaginationInspector(PaginatorInspector):
|
||||
"""Swagger Pagination Schema class"""
|
||||
|
||||
def get_paginated_response(self, paginator, response_schema):
|
||||
"""
|
||||
:param BasePagination paginator: the paginator
|
||||
:param openapi.Schema response_schema: the response schema that must be paged.
|
||||
:rtype: openapi.Schema
|
||||
"""
|
||||
|
||||
return openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties=OrderedDict(
|
||||
(
|
||||
(
|
||||
"pagination",
|
||||
openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties=OrderedDict(
|
||||
(
|
||||
("next", openapi.Schema(type=openapi.TYPE_NUMBER)),
|
||||
(
|
||||
"previous",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
("count", openapi.Schema(type=openapi.TYPE_NUMBER)),
|
||||
(
|
||||
"current",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
(
|
||||
"total_pages",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
(
|
||||
"start_index",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
(
|
||||
"end_index",
|
||||
openapi.Schema(type=openapi.TYPE_NUMBER),
|
||||
),
|
||||
)
|
||||
),
|
||||
required=[
|
||||
"next",
|
||||
"previous",
|
||||
"count",
|
||||
"current",
|
||||
"total_pages",
|
||||
"start_index",
|
||||
"end_index",
|
||||
],
|
||||
),
|
||||
),
|
||||
("results", response_schema),
|
||||
)
|
||||
),
|
||||
required=["results", "pagination"],
|
||||
)
|
||||
|
||||
def get_paginator_parameters(self, paginator):
|
||||
"""
|
||||
Get the pagination parameters for a single paginator **instance**.
|
||||
|
||||
Should return :data:`.NotHandled` if this inspector
|
||||
does not know how to handle the given `paginator`.
|
||||
|
||||
:param BasePagination paginator: the paginator
|
||||
:rtype: list[openapi.Parameter]
|
||||
"""
|
||||
|
||||
return [
|
||||
openapi.Parameter(
|
||||
"page",
|
||||
openapi.IN_QUERY,
|
||||
"Page Index",
|
||||
False,
|
||||
None,
|
||||
openapi.TYPE_INTEGER,
|
||||
),
|
||||
openapi.Parameter(
|
||||
"page_size",
|
||||
openapi.IN_QUERY,
|
||||
"Page Size",
|
||||
False,
|
||||
None,
|
||||
openapi.TYPE_INTEGER,
|
||||
),
|
||||
]
|
|
@ -1,102 +0,0 @@
|
|||
"""Error Response schema, from https://github.com/axnsan12/drf-yasg/issues/224"""
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.inspectors.view import SwaggerAutoSchema
|
||||
from drf_yasg.utils import force_real_str, is_list_view
|
||||
from rest_framework import exceptions, status
|
||||
from rest_framework.settings import api_settings
|
||||
|
||||
|
||||
class ErrorResponseAutoSchema(SwaggerAutoSchema):
|
||||
"""Inspector which includes an error schema"""
|
||||
|
||||
def get_generic_error_schema(self):
|
||||
"""Get a generic error schema"""
|
||||
return openapi.Schema(
|
||||
"Generic API Error",
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
"detail": openapi.Schema(
|
||||
type=openapi.TYPE_STRING, description="Error details"
|
||||
),
|
||||
"code": openapi.Schema(
|
||||
type=openapi.TYPE_STRING, description="Error code"
|
||||
),
|
||||
},
|
||||
required=["detail"],
|
||||
)
|
||||
|
||||
def get_validation_error_schema(self):
|
||||
"""Get a generic validation error schema"""
|
||||
return openapi.Schema(
|
||||
"Validation Error",
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
api_settings.NON_FIELD_ERRORS_KEY: openapi.Schema(
|
||||
description="List of validation errors not related to any field",
|
||||
type=openapi.TYPE_ARRAY,
|
||||
items=openapi.Schema(type=openapi.TYPE_STRING),
|
||||
),
|
||||
},
|
||||
additional_properties=openapi.Schema(
|
||||
description=(
|
||||
"A list of error messages for each "
|
||||
"field that triggered a validation error"
|
||||
),
|
||||
type=openapi.TYPE_ARRAY,
|
||||
items=openapi.Schema(type=openapi.TYPE_STRING),
|
||||
),
|
||||
)
|
||||
|
||||
def get_response_serializers(self):
|
||||
responses = super().get_response_serializers()
|
||||
definitions = self.components.with_scope(
|
||||
openapi.SCHEMA_DEFINITIONS
|
||||
) # type: openapi.ReferenceResolver
|
||||
|
||||
definitions.setdefault("GenericError", self.get_generic_error_schema)
|
||||
definitions.setdefault("ValidationError", self.get_validation_error_schema)
|
||||
definitions.setdefault("APIException", self.get_generic_error_schema)
|
||||
|
||||
if self.get_request_serializer() or self.get_query_serializer():
|
||||
responses.setdefault(
|
||||
exceptions.ValidationError.status_code,
|
||||
openapi.Response(
|
||||
description=force_real_str(
|
||||
exceptions.ValidationError.default_detail
|
||||
),
|
||||
schema=openapi.SchemaRef(definitions, "ValidationError"),
|
||||
),
|
||||
)
|
||||
|
||||
security = self.get_security()
|
||||
if security is None or len(security) > 0:
|
||||
# Note: 401 error codes are coerced into 403 see
|
||||
# rest_framework/views.py:433:handle_exception
|
||||
# This is b/c the API uses token auth which doesn't have WWW-Authenticate header
|
||||
responses.setdefault(
|
||||
status.HTTP_403_FORBIDDEN,
|
||||
openapi.Response(
|
||||
description="Authentication credentials were invalid, absent or insufficient.",
|
||||
schema=openapi.SchemaRef(definitions, "GenericError"),
|
||||
),
|
||||
)
|
||||
if not is_list_view(self.path, self.method, self.view):
|
||||
responses.setdefault(
|
||||
exceptions.PermissionDenied.status_code,
|
||||
openapi.Response(
|
||||
description="Permission denied.",
|
||||
schema=openapi.SchemaRef(definitions, "APIException"),
|
||||
),
|
||||
)
|
||||
responses.setdefault(
|
||||
exceptions.NotFound.status_code,
|
||||
openapi.Response(
|
||||
description=(
|
||||
"Object does not exist or caller "
|
||||
"has insufficient permissions to access it."
|
||||
),
|
||||
schema=openapi.SchemaRef(definitions, "APIException"),
|
||||
),
|
||||
)
|
||||
|
||||
return responses
|
|
@ -1,5 +1,5 @@
|
|||
"""core Configs API"""
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.fields import BooleanField, CharField, ListField
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.request import Request
|
||||
|
@ -34,7 +34,7 @@ class ConfigsViewSet(ViewSet):
|
|||
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
@swagger_auto_schema(responses={200: ConfigSerializer(many=False)})
|
||||
@extend_schema(responses={200: ConfigSerializer(many=False)})
|
||||
def list(self, request: Request) -> Response:
|
||||
"""Retrive public configuration options"""
|
||||
config = ConfigSerializer(
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""api v2 urls"""
|
||||
from django.urls import path, re_path
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.views import get_schema_view
|
||||
from drf_spectacular.views import SpectacularAPIView
|
||||
from rest_framework import routers
|
||||
from rest_framework.permissions import AllowAny
|
||||
|
||||
|
@ -196,17 +195,6 @@ router.register("stages/user_write", UserWriteStageViewSet)
|
|||
router.register("stages/dummy", DummyStageViewSet)
|
||||
router.register("policies/dummy", DummyPolicyViewSet)
|
||||
|
||||
info = openapi.Info(
|
||||
title="authentik API",
|
||||
default_version="v2beta",
|
||||
contact=openapi.Contact(email="hello@beryju.org"),
|
||||
license=openapi.License(
|
||||
name="GNU GPLv3",
|
||||
url="https://github.com/goauthentik/authentik/blob/master/LICENSE",
|
||||
),
|
||||
)
|
||||
SchemaView = get_schema_view(info, public=True, permission_classes=(AllowAny,))
|
||||
|
||||
urlpatterns = (
|
||||
[
|
||||
path("", SwaggerView.as_view(), name="swagger"),
|
||||
|
@ -218,10 +206,6 @@ urlpatterns = (
|
|||
FlowExecutorView.as_view(),
|
||||
name="flow-executor",
|
||||
),
|
||||
re_path(
|
||||
r"^swagger(?P<format>\.json|\.yaml)$",
|
||||
SchemaView.without_ui(cache_timeout=0),
|
||||
name="schema-json",
|
||||
),
|
||||
path("schema/", SpectacularAPIView.as_view(), name="schema"),
|
||||
]
|
||||
)
|
||||
|
|
|
@ -5,8 +5,8 @@ from django.core.cache import cache
|
|||
from django.db.models import QuerySet
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
|
@ -92,7 +92,7 @@ class ApplicationViewSet(ModelViewSet):
|
|||
applications.append(application)
|
||||
return applications
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
204: "Access granted",
|
||||
403: "Access denied",
|
||||
|
@ -111,12 +111,12 @@ class ApplicationViewSet(ModelViewSet):
|
|||
return Response(status=204)
|
||||
return Response(status=403)
|
||||
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="superuser_full_list",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
@ -151,13 +151,13 @@ class ApplicationViewSet(ModelViewSet):
|
|||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
@permission_required("authentik_core.change_application")
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="file",
|
||||
in_=openapi.IN_FORM,
|
||||
type=openapi.TYPE_FILE,
|
||||
location=OpenApiParameter.QUERY, # TODO: In Form
|
||||
type=OpenApiTypes.BINARY,
|
||||
required=True,
|
||||
)
|
||||
],
|
||||
|
@ -184,7 +184,7 @@ class ApplicationViewSet(ModelViewSet):
|
|||
@permission_required(
|
||||
"authentik_core.view_application", ["authentik_events.view_event"]
|
||||
)
|
||||
@swagger_auto_schema(responses={200: CoordinateSerializer(many=True)})
|
||||
@extend_schema(responses={200: CoordinateSerializer(many=True)})
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=unused-argument
|
||||
def metrics(self, request: Request, slug: str):
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"""PropertyMapping API Views"""
|
||||
from json import dumps
|
||||
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
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 import mixins
|
||||
from rest_framework.decorators import action
|
||||
|
@ -81,7 +81,7 @@ class PropertyMappingViewSet(
|
|||
def get_queryset(self):
|
||||
return PropertyMapping.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable property-mapping types"""
|
||||
|
@ -100,14 +100,14 @@ class PropertyMappingViewSet(
|
|||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@permission_required("authentik_core.view_propertymapping")
|
||||
@swagger_auto_schema(
|
||||
request_body=PolicyTestSerializer(),
|
||||
@extend_schema(
|
||||
request=PolicyTestSerializer(),
|
||||
responses={200: PropertyMappingTestResultSerializer, 400: "Invalid parameters"},
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="format_result",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Provider API Views"""
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import ReadOnlyField
|
||||
|
@ -66,7 +66,7 @@ class ProviderViewSet(
|
|||
def get_queryset(self):
|
||||
return Provider.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable provider types"""
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Source API Views"""
|
||||
from typing import Iterable
|
||||
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
|
@ -64,7 +64,7 @@ class SourceViewSet(
|
|||
def get_queryset(self):
|
||||
return Source.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable source types"""
|
||||
|
@ -87,7 +87,7 @@ class SourceViewSet(
|
|||
)
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: UserSettingSerializer(many=True)})
|
||||
@extend_schema(responses={200: UserSettingSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def user_settings(self, request: Request) -> Response:
|
||||
"""Get all sources the user can configure"""
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Tokens API Viewset"""
|
||||
from django.http.response import Http404
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.request import Request
|
||||
|
@ -67,7 +67,7 @@ class TokenViewSet(ModelViewSet):
|
|||
serializer.save(user=self.request.user, intent=TokenIntents.INTENT_API)
|
||||
|
||||
@permission_required("authentik_core.view_token_key")
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: TokenViewSerializer(many=False),
|
||||
404: "Token not found or expired",
|
||||
|
|
|
@ -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_yasg.utils import swagger_auto_schema, swagger_serializer_method
|
||||
from drf_spectacular.utils import 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
|
||||
|
@ -77,13 +77,13 @@ class UserMetricsSerializer(PassiveSerializer):
|
|||
logins_failed_per_1h = SerializerMethodField()
|
||||
authorizations_per_1h = SerializerMethodField()
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_logins_per_1h(self, _):
|
||||
"""Get successful logins per hour for the last 24 hours"""
|
||||
user = self.context["user"]
|
||||
return get_events_per_1h(action=EventAction.LOGIN, user__pk=user.pk)
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_logins_failed_per_1h(self, _):
|
||||
"""Get failed logins per hour for the last 24 hours"""
|
||||
user = self.context["user"]
|
||||
|
@ -91,7 +91,7 @@ class UserMetricsSerializer(PassiveSerializer):
|
|||
action=EventAction.LOGIN_FAILED, context__username=user.username
|
||||
)
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True))
|
||||
@extend_schema_field(CoordinateSerializer(many=True))
|
||||
def get_authorizations_per_1h(self, _):
|
||||
"""Get failed logins per hour for the last 24 hours"""
|
||||
user = self.context["user"]
|
||||
|
@ -142,7 +142,7 @@ class UserViewSet(ModelViewSet):
|
|||
def get_queryset(self):
|
||||
return User.objects.all().exclude(pk=get_anonymous_user().pk)
|
||||
|
||||
@swagger_auto_schema(responses={200: SessionUserSerializer(many=False)})
|
||||
@extend_schema(responses={200: SessionUserSerializer(many=False)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=invalid-name
|
||||
def me(self, request: Request) -> Response:
|
||||
|
@ -158,7 +158,7 @@ class UserViewSet(ModelViewSet):
|
|||
return Response(serializer.data)
|
||||
|
||||
@permission_required("authentik_core.view_user", ["authentik_events.view_event"])
|
||||
@swagger_auto_schema(responses={200: UserMetricsSerializer(many=False)})
|
||||
@extend_schema(responses={200: UserMetricsSerializer(many=False)})
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
def metrics(self, request: Request, pk: int) -> Response:
|
||||
|
@ -169,7 +169,7 @@ class UserViewSet(ModelViewSet):
|
|||
return Response(serializer.data)
|
||||
|
||||
@permission_required("authentik_core.reset_user_password")
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={"200": LinkSerializer(many=False), "404": "No recovery flow found."},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
|
|
|
@ -28,6 +28,9 @@ class PassiveSerializer(Serializer):
|
|||
) -> Model: # pragma: no cover
|
||||
return Model()
|
||||
|
||||
class Meta:
|
||||
model = Model
|
||||
|
||||
|
||||
class MetaNameSerializer(PassiveSerializer):
|
||||
"""Add verbose names to response"""
|
||||
|
|
|
@ -5,8 +5,8 @@ from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
|||
from cryptography.x509 import load_pem_x509_certificate
|
||||
from django.http.response import HttpResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import (
|
||||
CharField,
|
||||
|
@ -125,8 +125,8 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
|||
filterset_class = CertificateKeyPairFilter
|
||||
|
||||
@permission_required(None, ["authentik_crypto.add_certificatekeypair"])
|
||||
@swagger_auto_schema(
|
||||
request_body=CertificateGenerationSerializer(),
|
||||
@extend_schema(
|
||||
request=CertificateGenerationSerializer(),
|
||||
responses={200: CertificateKeyPairSerializer, 400: "Bad request"},
|
||||
)
|
||||
@action(detail=False, methods=["POST"])
|
||||
|
@ -147,12 +147,12 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
|||
serializer = self.get_serializer(instance)
|
||||
return Response(serializer.data)
|
||||
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
],
|
||||
responses={200: CertificateDataSerializer(many=False)},
|
||||
|
@ -180,12 +180,12 @@ class CertificateKeyPairViewSet(ModelViewSet):
|
|||
CertificateDataSerializer({"data": certificate.certificate_data}).data
|
||||
)
|
||||
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
],
|
||||
responses={200: CertificateDataSerializer(many=False)},
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
"""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_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, DictField, IntegerField
|
||||
|
@ -38,12 +39,6 @@ class EventSerializer(ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class EventTopPerUserParams(PassiveSerializer):
|
||||
"""Query params for top_per_user"""
|
||||
|
||||
top_n = IntegerField(default=15)
|
||||
|
||||
|
||||
class EventTopPerUserSerializer(PassiveSerializer):
|
||||
"""Response object of Event's top_per_user"""
|
||||
|
||||
|
@ -111,10 +106,17 @@ class EventViewSet(ReadOnlyModelViewSet):
|
|||
]
|
||||
filterset_class = EventsFilter
|
||||
|
||||
@swagger_auto_schema(
|
||||
method="GET",
|
||||
@extend_schema(
|
||||
methods=["GET"],
|
||||
responses={200: EventTopPerUserSerializer(many=True)},
|
||||
query_serializer=EventTopPerUserParams,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
"top_n",
|
||||
type=OpenApiTypes.INT,
|
||||
location=OpenApiParameter.QUERY,
|
||||
required=False,
|
||||
)
|
||||
]
|
||||
)
|
||||
@action(detail=False, methods=["GET"])
|
||||
def top_per_user(self, request: Request):
|
||||
|
@ -134,7 +136,7 @@ class EventViewSet(ReadOnlyModelViewSet):
|
|||
.order_by("-counted_events")[:top_n]
|
||||
)
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def actions(self, request: Request) -> Response:
|
||||
"""Get all actions"""
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"""NotificationTransport API Views"""
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
||||
from rest_framework.request import Request
|
||||
|
@ -58,12 +59,12 @@ class NotificationTransportViewSet(ModelViewSet):
|
|||
serializer_class = NotificationTransportSerializer
|
||||
|
||||
@permission_required("authentik_events.change_notificationtransport")
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: NotificationTransportTestSerializer(many=False),
|
||||
503: "Failed to test transport",
|
||||
},
|
||||
request_body=no_body,
|
||||
request=OpenApiTypes.NONE,
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[], methods=["post"])
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
|
|
|
@ -6,8 +6,13 @@ from django.db.models import Model
|
|||
from django.http.response import HttpResponseBadRequest, JsonResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import (
|
||||
OpenApiParameter,
|
||||
OpenApiResponse,
|
||||
OpenApiSchemaBase,
|
||||
extend_schema,
|
||||
)
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
|
@ -97,15 +102,15 @@ class FlowViewSet(ModelViewSet):
|
|||
filterset_fields = ["flow_uuid", "name", "slug", "designation"]
|
||||
|
||||
@permission_required(None, ["authentik_flows.view_flow_cache"])
|
||||
@swagger_auto_schema(responses={200: CacheSerializer(many=False)})
|
||||
@extend_schema(responses={200: CacheSerializer(many=False)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def cache_info(self, request: Request) -> Response:
|
||||
"""Info about cached flows"""
|
||||
return Response(data={"count": len(cache.keys("flow_*"))})
|
||||
|
||||
@permission_required(None, ["authentik_flows.clear_flow_cache"])
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
responses={204: "Successfully cleared cache", 400: "Bad request"},
|
||||
)
|
||||
@action(detail=False, methods=["POST"])
|
||||
|
@ -133,13 +138,13 @@ class FlowViewSet(ModelViewSet):
|
|||
"authentik_stages_prompt.change_prompt",
|
||||
],
|
||||
)
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="file",
|
||||
in_=openapi.IN_FORM,
|
||||
type=openapi.TYPE_FILE,
|
||||
location=OpenApiParameter.QUERY, # TODO: Form
|
||||
type=OpenApiTypes.BINARY,
|
||||
required=True,
|
||||
)
|
||||
],
|
||||
|
@ -171,10 +176,10 @@ class FlowViewSet(ModelViewSet):
|
|||
"authentik_stages_prompt.view_prompt",
|
||||
],
|
||||
)
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
"200": openapi.Response(
|
||||
"File Attachment", schema=openapi.Schema(type=openapi.TYPE_FILE)
|
||||
"200": OpenApiResponse(
|
||||
response=OpenApiParameter("File Attachment", type=OpenApiTypes.BINARY)
|
||||
),
|
||||
},
|
||||
)
|
||||
|
@ -188,7 +193,7 @@ class FlowViewSet(ModelViewSet):
|
|||
response["Content-Disposition"] = f'attachment; filename="{flow.slug}.akflow"'
|
||||
return response
|
||||
|
||||
@swagger_auto_schema(responses={200: FlowDiagramSerializer()})
|
||||
@extend_schema(responses={200: FlowDiagramSerializer()})
|
||||
@action(detail=True, pagination_class=None, filter_backends=[], methods=["get"])
|
||||
# pylint: disable=unused-argument
|
||||
def diagram(self, request: Request, slug: str) -> Response:
|
||||
|
@ -259,13 +264,13 @@ class FlowViewSet(ModelViewSet):
|
|||
return Response({"diagram": diagram})
|
||||
|
||||
@permission_required("authentik_flows.change_flow")
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="file",
|
||||
in_=openapi.IN_FORM,
|
||||
type=openapi.TYPE_FILE,
|
||||
location=OpenApiParameter.QUERY, # TODO: Form
|
||||
type=OpenApiTypes.BINARY,
|
||||
required=True,
|
||||
)
|
||||
],
|
||||
|
@ -289,7 +294,7 @@ class FlowViewSet(ModelViewSet):
|
|||
app.save()
|
||||
return Response({})
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={200: LinkSerializer(many=False), 400: "Flow not applicable"},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Flow Stage API Views"""
|
||||
from typing import Iterable
|
||||
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField
|
||||
|
@ -68,7 +68,7 @@ class StageViewSet(
|
|||
def get_queryset(self):
|
||||
return Stage.objects.select_subclasses()
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable stage types"""
|
||||
|
@ -86,7 +86,7 @@ class StageViewSet(
|
|||
data = sorted(data, key=lambda x: x["name"])
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: StageUserSettingSerializer(many=True)})
|
||||
@extend_schema(responses={200: StageUserSettingSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def user_settings(self, request: Request) -> Response:
|
||||
"""Get all stages the user can configure"""
|
||||
|
|
|
@ -10,8 +10,8 @@ from django.template.response import TemplateResponse
|
|||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
||||
from django.views.generic import View
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.views import APIView
|
||||
from sentry_sdk import capture_exception
|
||||
|
@ -125,19 +125,19 @@ class FlowExecutorView(APIView):
|
|||
self.current_stage_view.request = request
|
||||
return super().dispatch(request)
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: Challenge(),
|
||||
404: "No Token found", # This error can be raised by the email stage
|
||||
},
|
||||
request_body=no_body,
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
"query",
|
||||
openapi.IN_QUERY,
|
||||
request=OpenApiTypes.NONE,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="query",
|
||||
location=OpenApiParameter.QUERY,
|
||||
required=True,
|
||||
description="Querystring as received",
|
||||
type=openapi.TYPE_STRING,
|
||||
type=OpenApiTypes.STR,
|
||||
)
|
||||
],
|
||||
operation_id="flows_executor_get",
|
||||
|
@ -157,16 +157,16 @@ class FlowExecutorView(APIView):
|
|||
self._logger.warning(exc)
|
||||
return to_stage_response(request, FlowErrorResponse(request, exc))
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={200: Challenge()},
|
||||
request_body=ChallengeResponse(),
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
"query",
|
||||
openapi.IN_QUERY,
|
||||
request=ChallengeResponse(),
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="query",
|
||||
location=OpenApiParameter.QUERY,
|
||||
required=True,
|
||||
description="Querystring as received",
|
||||
type=openapi.TYPE_STRING,
|
||||
type=OpenApiTypes.STR,
|
||||
)
|
||||
],
|
||||
operation_id="flows_executor_solve",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from dataclasses import asdict
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from kubernetes.client.configuration import Configuration
|
||||
from kubernetes.config.config_exception import ConfigException
|
||||
from kubernetes.config.kube_config import load_kube_config_from_dict
|
||||
|
@ -69,7 +69,7 @@ class ServiceConnectionViewSet(
|
|||
search_fields = ["name"]
|
||||
filterset_fields = ["name"]
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable service connection types"""
|
||||
|
@ -87,7 +87,7 @@ class ServiceConnectionViewSet(
|
|||
)
|
||||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: ServiceConnectionStateSerializer(many=False)})
|
||||
@extend_schema(responses={200: ServiceConnectionStateSerializer(many=False)})
|
||||
@action(detail=True, pagination_class=None, filter_backends=[])
|
||||
# pylint: disable=unused-argument, invalid-name
|
||||
def state(self, request: Request, pk: str) -> Response:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Outpost API Views"""
|
||||
from dacite.core import from_dict
|
||||
from dacite.exceptions import DaciteError
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField, CharField, DateTimeField
|
||||
from rest_framework.request import Request
|
||||
|
@ -72,7 +72,7 @@ class OutpostViewSet(ModelViewSet):
|
|||
]
|
||||
ordering = ["name"]
|
||||
|
||||
@swagger_auto_schema(responses={200: OutpostHealthSerializer(many=True)})
|
||||
@extend_schema(responses={200: OutpostHealthSerializer(many=True)})
|
||||
@action(methods=["GET"], detail=True)
|
||||
# pylint: disable=invalid-name, unused-argument
|
||||
def health(self, request: Request, pk: int) -> Response:
|
||||
|
@ -90,7 +90,7 @@ class OutpostViewSet(ModelViewSet):
|
|||
)
|
||||
return Response(OutpostHealthSerializer(states, many=True).data)
|
||||
|
||||
@swagger_auto_schema(responses={200: OutpostDefaultConfigSerializer(many=False)})
|
||||
@extend_schema(responses={200: OutpostDefaultConfigSerializer(many=False)})
|
||||
@action(detail=False, methods=["GET"])
|
||||
def default_settings(self, request: Request) -> Response:
|
||||
"""Global default outpost config"""
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""policy API Views"""
|
||||
from django.core.cache import cache
|
||||
from drf_yasg.utils import no_body, swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
|
@ -96,7 +97,7 @@ class PolicyViewSet(
|
|||
"bindings", "promptstage_set"
|
||||
)
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def types(self, request: Request) -> Response:
|
||||
"""Get all creatable policy types"""
|
||||
|
@ -114,15 +115,15 @@ class PolicyViewSet(
|
|||
return Response(TypeCreateSerializer(data, many=True).data)
|
||||
|
||||
@permission_required(None, ["authentik_policies.view_policy_cache"])
|
||||
@swagger_auto_schema(responses={200: CacheSerializer(many=False)})
|
||||
@extend_schema(responses={200: CacheSerializer(many=False)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def cache_info(self, request: Request) -> Response:
|
||||
"""Info about cached policies"""
|
||||
return Response(data={"count": len(cache.keys("policy_*"))})
|
||||
|
||||
@permission_required(None, ["authentik_policies.clear_policy_cache"])
|
||||
@swagger_auto_schema(
|
||||
request_body=no_body,
|
||||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
responses={204: "Successfully cleared cache", 400: "Bad request"},
|
||||
)
|
||||
@action(detail=False, methods=["POST"])
|
||||
|
@ -137,8 +138,8 @@ class PolicyViewSet(
|
|||
return Response(status=204)
|
||||
|
||||
@permission_required("authentik_policies.view_policy")
|
||||
@swagger_auto_schema(
|
||||
request_body=PolicyTestSerializer(),
|
||||
@extend_schema(
|
||||
request=PolicyTestSerializer(),
|
||||
responses={200: PolicyTestResultSerializer(), 400: "Invalid parameters"},
|
||||
)
|
||||
@action(detail=True, pagination_class=None, filter_backends=[], methods=["POST"])
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
"""OAuth2Provider API Views"""
|
||||
from django.db.models.base import Model
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import ReadOnlyField
|
||||
from rest_framework.generics import get_object_or_404
|
||||
|
@ -60,6 +61,9 @@ class OAuth2ProviderSetupURLs(PassiveSerializer):
|
|||
provider_info = ReadOnlyField()
|
||||
logout = ReadOnlyField()
|
||||
|
||||
class Meta:
|
||||
model = Model
|
||||
|
||||
|
||||
class OAuth2ProviderViewSet(ModelViewSet):
|
||||
"""OAuth2Provider Viewset"""
|
||||
|
@ -67,9 +71,9 @@ class OAuth2ProviderViewSet(ModelViewSet):
|
|||
queryset = OAuth2Provider.objects.all()
|
||||
serializer_class = OAuth2ProviderSerializer
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: OAuth2ProviderSetupURLs(many=False),
|
||||
200: OAuth2ProviderSetupURLs,
|
||||
404: "Provider has no application assigned",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""ProxyProvider API Views"""
|
||||
from typing import Any
|
||||
|
||||
from drf_yasg.utils import swagger_serializer_method
|
||||
from drf_spectacular.utils import extend_schema_field
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
|
@ -107,7 +107,7 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
|
|||
"forward_auth_mode",
|
||||
]
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=OpenIDConnectConfigurationSerializer)
|
||||
@extend_schema_field(OpenIDConnectConfigurationSerializer)
|
||||
def get_oidc_configuration(self, obj: ProxyProvider):
|
||||
"""Embed OpenID Connect provider information"""
|
||||
return ProviderInfoView(request=self.context["request"]._request).get_info(obj)
|
||||
|
|
|
@ -5,8 +5,8 @@ from defusedxml.ElementTree import fromstring
|
|||
from django.http.response import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, FileField, ReadOnlyField
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
|
@ -80,16 +80,16 @@ class SAMLProviderViewSet(ModelViewSet):
|
|||
queryset = SAMLProvider.objects.all()
|
||||
serializer_class = SAMLProviderSerializer
|
||||
|
||||
@swagger_auto_schema(
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: SAMLMetadataSerializer(many=False),
|
||||
404: "Provider has no application assigned",
|
||||
},
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="download",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_BOOLEAN,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.BOOL,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
@ -118,8 +118,8 @@ class SAMLProviderViewSet(ModelViewSet):
|
|||
"authentik_crypto.add_certificatekeypair",
|
||||
],
|
||||
)
|
||||
@swagger_auto_schema(
|
||||
request_body=SAMLProviderImportSerializer(),
|
||||
@extend_schema(
|
||||
request=SAMLProviderImportSerializer(),
|
||||
responses={204: "Successfully imported provider", 400: "Bad request"},
|
||||
)
|
||||
@action(detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
|
||||
|
|
|
@ -130,7 +130,7 @@ INSTALLED_APPS = [
|
|||
"authentik.stages.user_write",
|
||||
"rest_framework",
|
||||
"django_filters",
|
||||
"drf_yasg",
|
||||
"drf_spectacular",
|
||||
"guardian",
|
||||
"django_prometheus",
|
||||
"channels",
|
||||
|
@ -139,14 +139,17 @@ INSTALLED_APPS = [
|
|||
|
||||
GUARDIAN_MONKEY_PATCH = False
|
||||
|
||||
SWAGGER_SETTINGS = {
|
||||
"DEFAULT_AUTO_SCHEMA_CLASS": "authentik.api.schema.ErrorResponseAutoSchema",
|
||||
"DEFAULT_INFO": "authentik.api.v2.urls.info",
|
||||
"DEFAULT_PAGINATOR_INSPECTORS": [
|
||||
"authentik.api.pagination_schema.PaginationInspector",
|
||||
],
|
||||
"SECURITY_DEFINITIONS": {
|
||||
"Bearer": {"type": "apiKey", "name": "Authorization", "in": "header"}
|
||||
SPECTACULAR_SETTINGS = {
|
||||
"TITLE": "authentik",
|
||||
"DESCRIPTION": "Making authentication simple.",
|
||||
"VERSION": __version__,
|
||||
"COMPONENT_SPLIT_REQUEST": True,
|
||||
"CONTACT": {
|
||||
"email": "hello@beryju.org",
|
||||
},
|
||||
"LICENSE": {
|
||||
"name": "GNU GPLv3",
|
||||
"url": "https://github.com/goauthentik/authentik/blob/master/LICENSE",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -169,6 +172,7 @@ REST_FRAMEWORK = {
|
|||
"DEFAULT_RENDERER_CLASSES": [
|
||||
"rest_framework.renderers.JSONRenderer",
|
||||
],
|
||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||
}
|
||||
|
||||
CACHES = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Source API Views"""
|
||||
from django.http.response import Http404
|
||||
from django.utils.text import slugify
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
@ -48,9 +48,7 @@ class LDAPSourceViewSet(ModelViewSet):
|
|||
serializer_class = LDAPSourceSerializer
|
||||
lookup_field = "slug"
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={200: TaskSerializer(many=False), 404: "Task not found"}
|
||||
)
|
||||
@extend_schema(responses={200: TaskSerializer(many=False), 404: "Task not found"})
|
||||
@action(methods=["GET"], detail=True)
|
||||
# pylint: disable=unused-argument
|
||||
def sync_status(self, request: Request, slug: str) -> Response:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""OAuth Source Serializer"""
|
||||
from django.urls.base import reverse_lazy
|
||||
from drf_yasg.utils import swagger_auto_schema, swagger_serializer_method
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_field
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import BooleanField, CharField, SerializerMethodField
|
||||
from rest_framework.request import Request
|
||||
|
@ -43,7 +43,7 @@ class OAuthSourceSerializer(SourceSerializer):
|
|||
|
||||
type = SerializerMethodField()
|
||||
|
||||
@swagger_serializer_method(serializer_or_field=SourceTypeSerializer)
|
||||
@extend_schema_field(SourceTypeSerializer)
|
||||
def get_type(self, instace: OAuthSource) -> SourceTypeSerializer:
|
||||
"""Get source's type configuration"""
|
||||
return SourceTypeSerializer(instace.type).data
|
||||
|
@ -85,7 +85,7 @@ class OAuthSourceViewSet(ModelViewSet):
|
|||
serializer_class = OAuthSourceSerializer
|
||||
lookup_field = "slug"
|
||||
|
||||
@swagger_auto_schema(responses={200: SourceTypeSerializer(many=True)})
|
||||
@extend_schema(responses={200: SourceTypeSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def source_types(self, request: Request) -> Response:
|
||||
"""Get all creatable source types"""
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Plex Source Serializer"""
|
||||
from django.shortcuts import get_object_or_404
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.fields import CharField
|
||||
|
@ -50,18 +50,18 @@ class PlexSourceViewSet(ModelViewSet):
|
|||
lookup_field = "slug"
|
||||
|
||||
@permission_required(None)
|
||||
@swagger_auto_schema(
|
||||
request_body=PlexTokenRedeemSerializer(),
|
||||
@extend_schema(
|
||||
request=PlexTokenRedeemSerializer(),
|
||||
responses={
|
||||
200: RedirectChallenge(),
|
||||
400: "Token not found",
|
||||
403: "Access denied",
|
||||
},
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="slug",
|
||||
in_=openapi.IN_QUERY,
|
||||
type=openapi.TYPE_STRING,
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.STR,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""SAMLSource API Views"""
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
@ -39,7 +39,7 @@ class SAMLSourceViewSet(ModelViewSet):
|
|||
serializer_class = SAMLSourceSerializer
|
||||
lookup_field = "slug"
|
||||
|
||||
@swagger_auto_schema(responses={200: SAMLMetadataSerializer(many=False)})
|
||||
@extend_schema(responses={200: SAMLMetadataSerializer(many=False)})
|
||||
@action(methods=["GET"], detail=True)
|
||||
# pylint: disable=unused-argument
|
||||
def metadata(self, request: Request, slug: str) -> Response:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""EmailStage API Views"""
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
@ -52,7 +52,7 @@ class EmailStageViewSet(ModelViewSet):
|
|||
queryset = EmailStage.objects.all()
|
||||
serializer_class = EmailStageSerializer
|
||||
|
||||
@swagger_auto_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@extend_schema(responses={200: TypeCreateSerializer(many=True)})
|
||||
@action(detail=False, pagination_class=None, filter_backends=[])
|
||||
def templates(self, request: Request) -> Response:
|
||||
"""Get all available templates, including custom templates"""
|
||||
|
|
21751
schema.yml
Normal file
21751
schema.yml
Normal file
File diff suppressed because it is too large
Load diff
Reference in a new issue