ソースを参照

refactor(api): merge DomainDetail and DomainList into DomainViewSet

Peter Thomassen 5 年 前
コミット
33342565ab
3 ファイル変更19 行追加64 行削除
  1. 5 43
      api/desecapi/tests/test_domains.py
  2. 4 2
      api/desecapi/urls/version_1.py
  3. 10 19
      api/desecapi/views.py

+ 5 - 43
api/desecapi/tests/test_domains.py

@@ -1,12 +1,10 @@
-import re
-
 from django.conf import settings
 from django.core import mail
 from django.core.exceptions import ValidationError
 from psl_dns.exceptions import UnsupportedRule
 from rest_framework import status
 
-from desecapi.models import Domain, Token
+from desecapi.models import Domain
 from desecapi.pdns_change_tracker import PDNSChangeTracker
 from desecapi.tests.base import DesecTestCase, DomainOwnerTestCase, PublicSuffixMockMixin
 
@@ -183,51 +181,15 @@ class DomainOwnerTestCase1(DomainOwnerTestCase):
             response = self.client.get(self.reverse('v1:domain-detail', name=domain.name))
             self.assertStatus(response, status.HTTP_404_NOT_FOUND)
 
-    def test_update_my_domain_name(self):
+    def test_update_domain(self):
         url = self.reverse('v1:domain-detail', name=self.my_domain.name)
         with self.assertPdnsRequests(self.request_pdns_zone_retrieve_crypto_keys(name=self.my_domain.name)):
             response = self.client.get(url)
             self.assertStatus(response, status.HTTP_200_OK)
 
-        response.data['name'] = self.random_domain_name()
-        response = self.client.put(url, response.data, format='json')
-        self.assertStatus(response, status.HTTP_400_BAD_REQUEST)
-
-        with self.assertPdnsRequests(self.request_pdns_zone_retrieve_crypto_keys(name=self.my_domain.name)):
-            response = self.client.get(url)
-            self.assertStatus(response, status.HTTP_200_OK)
-            self.assertEqual(response.data['name'], self.my_domain.name)
-
-    def test_update_my_domain_immutable(self):
-        url = self.reverse('v1:domain-detail', name=self.my_domain.name)
-        with self.assertPdnsRequests(self.request_pdns_zone_retrieve_crypto_keys(name=self.my_domain.name)):
-            response = self.client.get(url)
-            self.assertStatus(response, status.HTTP_200_OK)
-
-        created = response.data['created']
-        keys = response.data['keys']
-        published = response.data['published']
-
-        response.data['created'] = '2019-08-07T18:34:39.249227Z'
-        response.data['published'] = '2019-08-07T18:34:39.249227Z'
-        response.data['keys'] = [{'dnskey': '257 3 13 badefefe'}]
-
-        self.assertNotEqual(response.data['created'], created)
-        self.assertNotEqual(response.data['published'], published)
-        self.assertNotEqual(response.data['keys'], keys)
-
-        with self.assertPdnsRequests(self.request_pdns_zone_retrieve_crypto_keys(name=self.my_domain.name)):
-            response = self.client.put(url, response.data, format='json')
-        self.assertStatus(response, status.HTTP_200_OK)
-
-        self.assertEqual(response.data['created'], created)
-        self.assertEqual(response.data['published'], published)
-        self.assertEqual(response.data['keys'], keys)
-
-    def test_update_other_domains(self):
-        url = self.reverse('v1:domain-detail', name=self.other_domain.name)
-        response = self.client.put(url, {}, format='json')
-        self.assertStatus(response, status.HTTP_404_NOT_FOUND)
+        for method in [self.client.patch, self.client.put]:
+            response = method(url, response.data, format='json')
+            self.assertStatus(response, status.HTTP_405_METHOD_NOT_ALLOWED)
 
     def test_create_domains(self):
         self.owner.limit_domains = 100

+ 4 - 2
api/desecapi/urls/version_1.py

@@ -20,13 +20,15 @@ auth_urls = [
     path('tokens/', include(tokens_router.urls)),
 ]
 
+domains_router = SimpleRouter()
+domains_router.register(r'', views.DomainViewSet, basename='domain')
+
 api_urls = [
     # API home
     path('', views.Root.as_view(), name='root'),
 
     # Domain and RRSet management
-    path('domains/', views.DomainList.as_view(), name='domain-list'),
-    path('domains/<name>/', views.DomainDetail.as_view(), name='domain-detail'),
+    path('domains/', include(domains_router.urls)),
     path('domains/<name>/rrsets/', views.RRsetList.as_view(), name='rrsets'),
     path('domains/<name>/rrsets/.../<type>/', views.RRsetDetail.as_view(), kwargs={'subname': ''}),
     re_path(r'^domains/(?P<name>[^/]+)/rrsets/(?P<subname>[^/]*)\.\.\./(?P<type>[^/]+)/$',

+ 10 - 19
api/desecapi/views.py

@@ -1,7 +1,6 @@
 import base64
 import binascii
 
-import django.core.exceptions
 from django.conf import settings
 from django.contrib.auth import user_logged_in
 from django.contrib.auth.hashers import is_password_usable
@@ -73,12 +72,19 @@ class TokenViewSet(IdempotentDestroy,
         serializer.save(user=self.request.user)
 
 
-class DomainList(generics.ListCreateAPIView):
+class DomainViewSet(IdempotentDestroy,
+                    mixins.CreateModelMixin,
+                    mixins.RetrieveModelMixin,
+                    mixins.DestroyModelMixin,
+                    mixins.ListModelMixin,
+                    GenericViewSet):
     serializer_class = serializers.DomainSerializer
     permission_classes = (IsAuthenticated, IsOwner, WithinDomainLimitOnPOST)
+    lookup_field = 'name'
+    lookup_value_regex = r'[^/]+'
 
     def get_queryset(self):
-        return models.Domain.objects.filter(owner=self.request.user.pk)
+        return self.request.user.domains
 
     def perform_create(self, serializer):
         with PDNSChangeTracker():
@@ -93,12 +99,6 @@ class DomainList(generics.ListCreateAPIView):
             parent_domain = models.Domain.objects.get(name=domain.parent_domain_name)
             parent_domain.update_delegation(domain)
 
-
-class DomainDetail(IdempotentDestroy, generics.RetrieveUpdateDestroyAPIView):
-    serializer_class = serializers.DomainSerializer
-    permission_classes = (IsAuthenticated, IsOwner,)
-    lookup_field = 'name'
-
     def perform_destroy(self, instance: models.Domain):
         with PDNSChangeTracker():
             instance.delete()
@@ -107,15 +107,6 @@ class DomainDetail(IdempotentDestroy, generics.RetrieveUpdateDestroyAPIView):
             with PDNSChangeTracker():
                 parent_domain.update_delegation(instance)
 
-    def get_queryset(self):
-        return models.Domain.objects.filter(owner=self.request.user.pk)
-
-    def update(self, request, *args, **kwargs):
-        try:
-            return super().update(request, *args, **kwargs)
-        except django.core.exceptions.ValidationError as e:
-            raise ValidationError(detail={"detail": e.message})
-
 
 class RRsetDetail(IdempotentDestroy, DomainView, generics.RetrieveUpdateDestroyAPIView):
     serializer_class = serializers.RRsetSerializer
@@ -594,7 +585,7 @@ class AuthenticatedActivateUserActionView(AuthenticatedActionView):
     def _finalize_with_domain(self, domain):
         if domain.is_locally_registrable:
             # TODO the following line raises Domain.DoesNotExist under unknown conditions
-            PDNSChangeTracker.track(lambda: DomainList.auto_delegate(domain))
+            PDNSChangeTracker.track(lambda: DomainViewSet.auto_delegate(domain))
             token = models.Token.objects.create(user=domain.owner, name='dyndns')
             return Response({
                 'detail': 'Success! Here is the password ("token") to configure your router (or any other dynDNS '