Просмотр исходного кода

Fixes #22513: Make JournalEntry.created_by immutable after creation (#22547)

mburggraf 1 неделя назад
Родитель
Сommit
ad054fc694

+ 9 - 0
netbox/extras/api/serializers_/journaling.py

@@ -38,6 +38,15 @@ class JournalEntrySerializer(NetBoxModelSerializer):
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'created')
         brief_fields = ('id', 'url', 'display', 'created')
 
 
+    def get_fields(self):
+        fields = super().get_fields()
+
+        # Make created_by field read-only if updating an existing JournalEntry.
+        if self.instance is not None:
+            fields['created_by'].read_only = True
+
+        return fields
+
     def validate(self, data):
     def validate(self, data):
 
 
         # Validate that the parent object exists
         # Validate that the parent object exists

+ 6 - 0
netbox/extras/forms/bulk_import.py

@@ -344,6 +344,12 @@ class JournalEntryImportForm(NetBoxModelImportForm):
             'assigned_object_type', 'assigned_object_id', 'created_by', 'kind', 'comments', 'tags'
             'assigned_object_type', 'assigned_object_id', 'created_by', 'kind', 'comments', 'tags'
         )
         )
 
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        # If not creating a new JournalEntry, disable the created_by field
+        if self.instance and not self.instance._state.adding:
+            self.fields['created_by'].disabled = True
+
 
 
 class NotificationGroupImportForm(CSVModelForm):
 class NotificationGroupImportForm(CSVModelForm):
     users = CSVModelMultipleChoiceField(
     users = CSVModelMultipleChoiceField(

+ 1 - 1
netbox/extras/tests/query_counts.json

@@ -19,7 +19,7 @@
   "exporttemplate:list_objects_with_permission": 19,
   "exporttemplate:list_objects_with_permission": 19,
   "imageattachment:api_list_objects": 11,
   "imageattachment:api_list_objects": 11,
   "imageattachment:list_objects_with_permission": 21,
   "imageattachment:list_objects_with_permission": 21,
-  "journalentry:api_list_objects": 15,
+  "journalentry:api_list_objects": 16,
   "journalentry:list_objects_with_permission": 24,
   "journalentry:list_objects_with_permission": 24,
   "notification:api_list_objects": 12,
   "notification:api_list_objects": 12,
   "notificationgroup:api_list_objects": 11,
   "notificationgroup:api_list_objects": 11,

+ 25 - 0
netbox/extras/tests/test_api.py

@@ -926,6 +926,12 @@ class JournalEntryTestCase(APIViewTestCases.APIViewTestCase):
 
 
     @classmethod
     @classmethod
     def setUpTestData(cls):
     def setUpTestData(cls):
+        users = (
+            User(username='User 1'),
+            User(username='User 2'),
+        )
+        User.objects.bulk_create(users)
+
         user = User.objects.first()
         user = User.objects.first()
         site = Site.objects.create(name='Site 1', slug='site-1')
         site = Site.objects.create(name='Site 1', slug='site-1')
 
 
@@ -966,6 +972,25 @@ class JournalEntryTestCase(APIViewTestCases.APIViewTestCase):
             },
             },
         ]
         ]
 
 
+    def test_immutable_created_by(self):
+        """
+        Verify that created_by can't be changed for existing objects
+        """
+        entry = JournalEntry.objects.first()
+        created_by_before = entry.created_by_id
+        # select user different from the one currently set
+        change_user = User.objects.exclude(pk=created_by_before).only('id').first()
+
+        url = reverse('extras-api:journalentry-detail', kwargs={'pk': entry.pk})
+        self.add_permissions('extras.change_journalentry')
+        response = self.client.patch(url, {'created_by': change_user.id}, format='json', **self.header)
+
+        self.assertEqual(response.status_code, 200)
+
+        entry.refresh_from_db()
+        created_by_after = entry.created_by_id
+        self.assertEqual(created_by_before, created_by_after)
+
 
 
 class ConfigContextProfileTestCase(APIViewTestCases.APIViewTestCase):
 class ConfigContextProfileTestCase(APIViewTestCases.APIViewTestCase):
     model = ConfigContextProfile
     model = ConfigContextProfile