diff --git a/modoboa/admin/api.py b/modoboa/admin/api.py index 2c7ee274c..7a1b04e6c 100644 --- a/modoboa/admin/api.py +++ b/modoboa/admin/api.py @@ -4,6 +4,7 @@ from django import http from django.contrib.contenttypes.models import ContentType from django.utils.translation import ugettext as _ +from drf_spectacular.utils import extend_schema, extend_schema_view from rest_framework import filters, status, viewsets from rest_framework.decorators import action from rest_framework.exceptions import ParseError @@ -16,17 +17,22 @@ from modoboa.core import sms_backends from . import lib, models, serializers +@extend_schema_view( + retrieve=extend_schema( + description="Retrieve a particular domain", + summary="Retrieve a particular domain" + ), + list=extend_schema( + description="Retrieve a list of domains", + summary="Retrieve a list of domains" + ), + create=extend_schema( + description="Create a new domain", + summary="Create a new domain" + ) +) class DomainViewSet(viewsets.ModelViewSet): - """ - retrieve: - Return the given domain. - - list: - Return a list of all existing domains. - - create: - Create a new domain instance. - """ + """Domain viewset.""" permission_classes = [IsAuthenticated, DjangoModelPermissions, ] serializer_class = serializers.DomainSerializer diff --git a/modoboa/admin/serializers.py b/modoboa/admin/serializers.py index 8a68d184e..2a66a020e 100644 --- a/modoboa/admin/serializers.py +++ b/modoboa/admin/serializers.py @@ -7,6 +7,8 @@ from django.shortcuts import get_object_or_404 from django.utils.encoding import force_text from django.utils.translation import ugettext as _, ugettext_lazy +from drf_spectacular.types import OpenApiTypes +from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from modoboa.admin import models as admin_models @@ -186,6 +188,7 @@ class AccountSerializer(serializers.ModelSerializer): if not user.is_superuser: del self.fields["master_user"] + @extend_schema_field(OpenApiTypes.STR) def get_role(self, account): """Return role.""" return account.role diff --git a/modoboa/core/commands/templates/settings.py.tpl b/modoboa/core/commands/templates/settings.py.tpl index c604ca92b..cab8a30e3 100644 --- a/modoboa/core/commands/templates/settings.py.tpl +++ b/modoboa/core/commands/templates/settings.py.tpl @@ -64,6 +64,7 @@ INSTALLED_APPS = ( 'ckeditor_uploader', 'rest_framework', 'rest_framework.authtoken', + 'drf_spectacular', 'phonenumber_field', 'django_otp', 'django_otp.plugins.otp_totp', @@ -190,6 +191,14 @@ REST_FRAMEWORK = { 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.SessionAuthentication', ), + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', +} + +SPECTACULAR_SETTINGS = { + 'SCHEMA_PATH_PREFIX': r'/api/v1', + 'TITLE': 'Modoboa API', + 'VERSION': '1.0.0', + 'SERVE_PERMISSIONS': ['rest_framework.permissions.IsAuthenticated'], } # Modoboa settings diff --git a/modoboa/core/tests/test_api.py b/modoboa/core/tests/test_api.py index ef1fe5b77..043222304 100644 --- a/modoboa/core/tests/test_api.py +++ b/modoboa/core/tests/test_api.py @@ -4,16 +4,13 @@ from modoboa.lib.tests import ModoTestCase class OpenAPITestCase(ModoTestCase): - openapi_schema_url = reverse_lazy('openapi_schema') + openapi_schema_url = reverse_lazy('schema') def test_unauthorized(self): self.client.logout() - response = self.client.get("/docs/api/") - self.assertRedirects(response, "/accounts/login/?next=/docs/api/") - response = self.client.get(self.openapi_schema_url) - self.assertEqual(response.status_code, 403) + self.assertEqual(response.status_code, 401) def test_get_schema(self): self.assertEqual(self.openapi_schema_url, "/docs/openapi.json") @@ -24,7 +21,3 @@ class OpenAPITestCase(ModoTestCase): 'title': "Modoboa API", 'version': "1.0.0", }) - - def test_get_swagger_ui(self): - response = self.client.get("/docs/api/") - self.assertContains(response, "Modoboa API") diff --git a/modoboa/core/viewsets.py b/modoboa/core/viewsets.py index 177160688..1014c2e4d 100644 --- a/modoboa/core/viewsets.py +++ b/modoboa/core/viewsets.py @@ -7,6 +7,7 @@ from django_otp.plugins.otp_static.models import StaticDevice, StaticToken from django_otp.plugins.otp_totp.models import TOTPDevice from rest_framework import permissions, response, viewsets from rest_framework.decorators import action +from drf_spectacular.utils import extend_schema from . import serializers @@ -28,6 +29,9 @@ class AccountViewSet(viewsets.ViewSet): ) return response.Response() + @extend_schema( + request=serializers.CheckTFASetupSerializer + ) @action(methods=["post"], detail=False, url_path="tfa/setup/check") def tfa_setup_check(self, request): """Check TFA setup.""" @@ -57,6 +61,7 @@ class AccountViewSet(viewsets.ViewSet): request.user.save() return response.Response() + @extend_schema(tags=['account']) @action(methods=["post"], detail=False, url_path="tfa/reset_codes") def tfa_reset_codes(self, request, *args, **kwargs): """Reset recovery codes.""" diff --git a/modoboa/templates/swagger-ui.html b/modoboa/templates/swagger-ui.html deleted file mode 100644 index efbd02f35..000000000 --- a/modoboa/templates/swagger-ui.html +++ /dev/null @@ -1,57 +0,0 @@ - -{% load static %} - -
- - -