Преглед на файлове

Fixes #2994: Prevent modifying termination points of existing cable to ensure end-to-end path integrity

Jeremy Stretch преди 5 години
родител
ревизия
b362c6a967
променени са 2 файла, в които са добавени 33 реда и са изтрити 0 реда
  1. 1 0
      docs/release-notes/version-2.8.md
  2. 32 0
      netbox/dcim/models/__init__.py

+ 1 - 0
docs/release-notes/version-2.8.md

@@ -8,6 +8,7 @@
 
 ### Bug Fixes
 
+* [#2994](https://github.com/netbox-community/netbox/issues/2994) - Prevent modifying termination points of existing cable to ensure end-to-end path integrity
 * [#4361](https://github.com/netbox-community/netbox/issues/4361) - Fix Type of `connection_state` in Swagger schema
 * [#4388](https://github.com/netbox-community/netbox/issues/4388) - Fix detection of connected endpoints when connecting rear ports
 * [#4489](https://github.com/netbox-community/netbox/issues/4489) - Fix display of parent/child role on device type view

+ 32 - 0
netbox/dcim/models/__init__.py

@@ -2070,6 +2070,20 @@ class Cable(ChangeLoggedModel):
         # A copy of the PK to be used by __str__ in case the object is deleted
         self._pk = self.pk
 
+    @classmethod
+    def from_db(cls, db, field_names, values):
+        """
+        Cache the original A and B terminations of existing Cable instances for later reference inside clean().
+        """
+        instance = super().from_db(db, field_names, values)
+
+        instance._orig_termination_a_type = instance.termination_a_type
+        instance._orig_termination_a_id = instance.termination_a_id
+        instance._orig_termination_b_type = instance.termination_b_type
+        instance._orig_termination_b_id = instance.termination_b_id
+
+        return instance
+
     def __str__(self):
         return self.label or '#{}'.format(self._pk)
 
@@ -2098,6 +2112,24 @@ class Cable(ChangeLoggedModel):
                 'termination_b': 'Invalid ID for type {}'.format(self.termination_b_type)
             })
 
+        # If editing an existing Cable instance, check that neither termination has been modified.
+        if self.pk:
+            err_msg = 'Cable termination points may not be modified. Delete and recreate the cable instead.'
+            if (
+                self.termination_a_type != self._orig_termination_a_type or
+                self.termination_a_id != self._orig_termination_a_id
+            ):
+                raise ValidationError({
+                    'termination_a': err_msg
+                })
+            if (
+                self.termination_b_type != self._orig_termination_b_type or
+                self.termination_b_id != self._orig_termination_b_id
+            ):
+                raise ValidationError({
+                    'termination_b': err_msg
+                })
+
         type_a = self.termination_a_type.model
         type_b = self.termination_b_type.model