Răsfoiți Sursa

Raise a validation error if the same tag is present in both add_tags and remove_tags

Jeremy Stretch 3 zile în urmă
părinte
comite
76c02d5aa9
2 a modificat fișierele cu 34 adăugiri și 0 ștergeri
  1. 23 0
      netbox/dcim/tests/test_api.py
  2. 11 0
      netbox/netbox/api/serializers/features.py

+ 23 - 0
netbox/dcim/tests/test_api.py

@@ -389,6 +389,29 @@ class SiteTest(APIViewTestCases.APIViewTestCase):
         response = self.client.post(self._get_list_url(), data, format='json', **self.header)
         response = self.client.post(self._get_list_url(), data, format='json', **self.header)
         self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
         self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
 
 
+    def test_add_and_remove_same_tag_error(self):
+        """
+        Including the same tag in both add_tags and remove_tags should raise a validation error.
+        """
+        site = Site.objects.first()
+        Tag.objects.bulk_create((
+            Tag(name='Alpha', slug='alpha'),
+            Tag(name='Bravo', slug='bravo'),
+        ))
+
+        obj_perm = ObjectPermission(name='Test permission', actions=['change'])
+        obj_perm.save()
+        obj_perm.users.add(self.user)
+        obj_perm.object_types.add(ObjectType.objects.get_for_model(self.model))
+
+        url = self._get_detail_url(site)
+        data = {
+            'add_tags': [{'name': 'Alpha'}, {'name': 'Bravo'}],
+            'remove_tags': [{'name': 'Alpha'}],
+        }
+        response = self.client.patch(url, data, format='json', **self.header)
+        self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
+
 
 
 class LocationTest(APIViewTestCases.APIViewTestCase):
 class LocationTest(APIViewTestCases.APIViewTestCase):
     model = Location
     model = Location

+ 11 - 0
netbox/netbox/api/serializers/features.py

@@ -60,6 +60,17 @@ class TaggableModelSerializer(serializers.Serializer):
                 'remove_tags': 'Cannot use "remove_tags" when creating a new object.'
                 'remove_tags': 'Cannot use "remove_tags" when creating a new object.'
             })
             })
 
 
+        if data.get('add_tags') and data.get('remove_tags'):
+            add_pks = {t.pk for t in data['add_tags']}
+            remove_pks = {t.pk for t in data['remove_tags']}
+            overlap = [t for t in data['add_tags'] if t.pk in (add_pks & remove_pks)]
+            if overlap:
+                raise serializers.ValidationError({
+                    'remove_tags':
+                        f'Tags may not be present in both "add_tags" and "remove_tags": '
+                        f'{", ".join(t.name for t in overlap)}'
+                })
+
         # Pop add_tags/remove_tags before calling super() to prevent them from being passed
         # Pop add_tags/remove_tags before calling super() to prevent them from being passed
         # to the model constructor during ValidatedModelSerializer validation
         # to the model constructor during ValidatedModelSerializer validation
         add_tags = data.pop('add_tags', None)
         add_tags = data.pop('add_tags', None)