Repository: openwisp/openwisp-network-topology (language: python)

Issue:
[change] Migrate to openwisp-users REST API filters
Replace plain django-filters with the multi-tenant capable filters being added in https://github.com/openwisp/openwisp-users/pull/347 (once this is merged).
[change] Migrate to openwisp-users REST API filters
Replace plain django-filters with the multi-tenant capable filters being added in https://github.com/openwisp/openwisp-users/pull/347 (once this is merged).


Discussion / hints:

Fix patch:
diff --git a/README.rst b/README.rst
index eccd99bd..6ae1c844 100644
--- a/README.rst
+++ b/README.rst
@@ -629,6 +629,8 @@ Available filters:
   E.g. ``?parser=<topology_parsers>``.
 - ``organization``: Filter topologies based on their organization.
   E.g. ``?organization=<topology_organization_id>``.
+- ``organization_slug``: Filter topologies based on their organization slug.
+  E.g. ``?organization_slug=<topology_organization_slug>``.
 
 You can use multiple filters in one request, e.g.:
 
@@ -721,6 +723,8 @@ Available filters:
   E.g. ``?topology=<topology_id>``.
 - ``organization``: Filter links belonging to an organization.
   E.g. ``?organization=<organization_id>``.
+- ``organization_slug``: Filter links based on their organization slug.
+  E.g. ``?organization_slug=<organization_slug>``.
 - ``status``: Filter links based on their status (``up`` or ``down``).
   E.g. ``?status=<link_status>``.
 
@@ -778,6 +782,8 @@ Available filters:
   E.g. ``?topology=<topology_id>``.
 - ``organization``: Filter nodes belonging to an organization.
   E.g. ``?organization=<organization_id>``.
+- ``organization_slug``: Filter nodes based on their organization slug.
+  E.g. ``?organization_slug=<organization_slug>``.
 
 You can use multiple filters in one request, e.g.:
 
diff --git a/openwisp_network_topology/api/filters.py b/openwisp_network_topology/api/filters.py
new file mode 100644
index 00000000..e77fdc14
--- /dev/null
+++ b/openwisp_network_topology/api/filters.py
@@ -0,0 +1,25 @@
+from swapper import load_model
+
+from openwisp_users.api.filters import OrganizationManagedFilter
+
+Node = load_model('topology', 'Node')
+Link = load_model('topology', 'Link')
+Topology = load_model('topology', 'Topology')
+
+
+class NetworkCollectionFilter(OrganizationManagedFilter):
+    class Meta(OrganizationManagedFilter.Meta):
+        model = Topology
+        fields = OrganizationManagedFilter.Meta.fields + ['strategy', 'parser']
+
+
+class NodeFilter(OrganizationManagedFilter):
+    class Meta(OrganizationManagedFilter.Meta):
+        model = Node
+        fields = OrganizationManagedFilter.Meta.fields + ['topology']
+
+
+class LinkFilter(OrganizationManagedFilter):
+    class Meta(OrganizationManagedFilter.Meta):
+        model = Link
+        fields = OrganizationManagedFilter.Meta.fields + ['topology', 'status']
diff --git a/openwisp_network_topology/api/views.py b/openwisp_network_topology/api/views.py
index 4fb28da6..fe8f89e9 100644
--- a/openwisp_network_topology/api/views.py
+++ b/openwisp_network_topology/api/views.py
@@ -18,6 +18,7 @@
 
 from .. import settings as app_settings
 from ..utils import get_object_or_404
+from .filters import LinkFilter, NetworkCollectionFilter, NodeFilter
 from .parsers import TextParser
 from .serializers import (
     LinkSerializer,
@@ -76,7 +77,7 @@ class NetworkCollectionView(
     serializer_class = NetworkGraphSerializer
     queryset = Topology.objects.select_related('organization')
     filter_backends = (DjangoFilterBackend,)
-    filterset_fields = ('strategy', 'parser', 'organization')
+    filterset_class = NetworkCollectionFilter
 
     def list(self, request, *args, **kwargs):
         self.check_permissions(request)
@@ -184,7 +185,7 @@ class NodeListCreateView(
     serializer_class = NodeSerializer
     pagination_class = ListViewPagination
     filter_backends = (DjangoFilterBackend,)
-    filterset_fields = ('topology', 'organization')
+    filterset_class = NodeFilter
 
 
 class NodeDetailView(
@@ -207,7 +208,7 @@ class LinkListCreateView(
     serializer_class = LinkSerializer
     pagination_class = ListViewPagination
     filter_backends = (DjangoFilterBackend,)
-    filterset_fields = ('topology', 'organization', 'status')
+    filterset_class = LinkFilter
 
 
 class LinkDetailView(


Test patch:
diff --git a/openwisp_network_topology/tests/test_api.py b/openwisp_network_topology/tests/test_api.py
index 59e51de0..68134fb6 100644
--- a/openwisp_network_topology/tests/test_api.py
+++ b/openwisp_network_topology/tests/test_api.py
@@ -114,6 +114,10 @@ def test_list_topology_filter(self):
             response = self.client.get(f'{self.list_url}?organization={org2.pk}')
             self.assertEqual(len(response.data['collection']), 1)
 
+        with self.subTest('Test filter with organization slug'):
+            response = self.client.get(f'{self.list_url}?organization_slug={org2.slug}')
+            self.assertEqual(len(response.data['collection']), 1)
+
         with self.subTest('Test filter with strategy'):
             response = self.client.get(f'{self.list_url}?strategy=receive')
             self.assertEqual(len(response.data['collection']), 1)
@@ -668,6 +672,10 @@ def test_node_list_filter(self):
             response = self.client.get(f'{path}?organization={org1.pk}')
             self.assertEqual(response.data['count'], 2)
 
+        with self.subTest('Test filter by organization slug'):
+            response = self.client.get(f'{path}?organization_slug={org1.slug}')
+            self.assertEqual(response.data['count'], 2)
+
         with self.subTest('Test filter by topology'):
             response = self.client.get(f'{path}?topology={t2.pk}')
             self.assertEqual(response.data['count'], 1)
@@ -785,6 +793,10 @@ def test_link_list_filters(self):
             response = self.client.get(f'{path}?organization={org1.pk}')
             self.assertEqual(response.data['count'], 1)
 
+        with self.subTest('Test filter by organization slug'):
+            response = self.client.get(f'{path}?organization_slug={org1.slug}')
+            self.assertEqual(response.data['count'], 1)
+
         with self.subTest('Test filter by topology'):
             response = self.client.get(f'{path}?topology={t2.pk}')
             self.assertEqual(response.data['count'], 1)