From 4d6e44657f137bffb7a26a330258afe42cd6a675 Mon Sep 17 00:00:00 2001 From: ManishShah120 Date: Sat, 26 Dec 2020 22:01:35 +0530 Subject: [PATCH] [api] Added ScopedThrottling #34 closes #34 --- openwisp_ipam/api/views.py | 42 +++++++++++++------------------------ openwisp_ipam/apps.py | 9 +++++++- tests/openwisp2/settings.py | 1 + 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/openwisp_ipam/api/views.py b/openwisp_ipam/api/views.py index 19487ca..7d20c8e 100644 --- a/openwisp_ipam/api/views.py +++ b/openwisp_ipam/api/views.py @@ -33,6 +33,12 @@ Subnet = swapper.load_model('openwisp_ipam', 'Subnet') +class ProtectedAPIMixin(object): + authentication_classes = [BearerAuthentication, SessionAuthentication] + permission_classes = [DjangoModelPermissions] + throttle_scope = 'ipam' + + class ListViewPagination(pagination.PageNumberPagination): page_size = 10 page_size_query_param = 'page_size' @@ -137,22 +143,18 @@ def index_of(self, address): return index -class AvailableIpView(RetrieveAPIView): +class AvailableIpView(ProtectedAPIMixin, RetrieveAPIView): subnet_model = Subnet queryset = IpAddress.objects.none() - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (DjangoModelPermissions,) def get(self, request, *args, **kwargs): subnet = get_object_or_404(self.subnet_model, pk=self.kwargs['subnet_id']) return Response(subnet.get_next_available_ip()) -class IpAddressListCreateView(ListCreateAPIView): +class IpAddressListCreateView(ProtectedAPIMixin, ListCreateAPIView): subnet_model = Subnet serializer_class = IpAddressSerializer - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (DjangoModelPermissions,) pagination_class = ListViewPagination def get_queryset(self): @@ -160,34 +162,26 @@ def get_queryset(self): return subnet.ipaddress_set.all().order_by('ip_address') -class SubnetListCreateView(ListCreateAPIView): +class SubnetListCreateView(ProtectedAPIMixin, ListCreateAPIView): serializer_class = SubnetSerializer - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (DjangoModelPermissions,) pagination_class = ListViewPagination queryset = Subnet.objects.all() -class SubnetView(RetrieveUpdateDestroyAPIView): +class SubnetView(ProtectedAPIMixin, RetrieveUpdateDestroyAPIView): serializer_class = SubnetSerializer - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (DjangoModelPermissions,) queryset = Subnet.objects.all() -class IpAddressView(RetrieveUpdateDestroyAPIView): +class IpAddressView(ProtectedAPIMixin, RetrieveUpdateDestroyAPIView): serializer_class = IpAddressSerializer - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (DjangoModelPermissions,) queryset = IpAddress.objects.all() -class RequestIPView(CreateAPIView): +class RequestIPView(ProtectedAPIMixin, CreateAPIView): subnet_model = Subnet queryset = IpAddress.objects.none() serializer_class = IpRequestSerializer - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (DjangoModelPermissions,) def post(self, request, *args, **kwargs): options = {'description': request.data.get('description')} @@ -202,12 +196,10 @@ def post(self, request, *args, **kwargs): return Response(None) -class ImportSubnetView(CreateAPIView): +class ImportSubnetView(ProtectedAPIMixin, CreateAPIView): subnet_model = Subnet queryset = Subnet.objects.none() serializer_class = ImportSubnetSerializer - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (DjangoModelPermissions,) def post(self, request, *args, **kwargs): file = request.FILES['csvfile'] @@ -220,12 +212,10 @@ def post(self, request, *args, **kwargs): return Response({'detail': _('Data imported successfully.')}) -class ExportSubnetView(CreateAPIView): +class ExportSubnetView(ProtectedAPIMixin, CreateAPIView): subnet_model = Subnet queryset = Subnet.objects.none() serializer_class = serializers.Serializer - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (DjangoModelPermissions,) def post(self, request, *args, **kwargs): response = HttpResponse(content_type='text/csv') @@ -235,12 +225,10 @@ def post(self, request, *args, **kwargs): return response -class SubnetHostsView(ListAPIView): +class SubnetHostsView(ProtectedAPIMixin, ListAPIView): subnet_model = Subnet queryset = Subnet.objects.none() serializer_class = HostsResponseSerializer - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (DjangoModelPermissions,) pagination_class = HostsListPagination def get_queryset(self): diff --git a/openwisp_ipam/apps.py b/openwisp_ipam/apps.py index 751a015..cc5778e 100644 --- a/openwisp_ipam/apps.py +++ b/openwisp_ipam/apps.py @@ -1,5 +1,6 @@ +from django.conf import settings from openwisp_utils.api.apps import ApiAppConfig -from openwisp_utils.utils import register_menu_items +from openwisp_utils.utils import default_or_test, register_menu_items from swapper import get_model_name from .compat import patch_ipaddress_lib @@ -9,7 +10,13 @@ class OpenWispIpamConfig(ApiAppConfig): name = 'openwisp_ipam' verbose_name = 'IPAM' + API_ENABLED = getattr(settings, 'OPENWISP_IPAM_API') + REST_FRAMEWORK_SETTINGS = { + 'DEFAULT_THROTTLE_RATES': {'ipam': default_or_test('400/hour', None)}, + } + def ready(self, *args, **kwargs): + super().ready(*args, **kwargs) patch_ipaddress_lib() items = [ {'model': get_model_name('openwisp_ipam', 'Subnet')}, diff --git a/tests/openwisp2/settings.py b/tests/openwisp2/settings.py index 52ed1d1..ec5acea 100644 --- a/tests/openwisp2/settings.py +++ b/tests/openwisp2/settings.py @@ -85,6 +85,7 @@ STATIC_URL = '/static/' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' OPENWISP_USERS_AUTH_API = True +OPENWISP_IPAM_API = True if TESTING: OPENWISP_ORGANIZATION_USER_ADMIN = True