diff --git a/netbox/extras/api/views.py b/netbox/extras/api/views.py index 9c395a0fb..0144949b9 100644 --- a/netbox/extras/api/views.py +++ b/netbox/extras/api/views.py @@ -306,10 +306,13 @@ class ScriptViewSet(ModelViewSet): context={'request': request}, ) serializer.is_valid(raise_exception=True) - serializer.save() + self.perform_create(serializer) return Response(serializer.data, status=status.HTTP_201_CREATED) + # PUT and PATCH are intentionally unsupported: ScriptSerializer has no writable fields + # and there is no implementation for replacing the underlying module file via these methods. + # They remain registered by ModelViewSet and return 405 rather than 404. def update(self, request, *args, **kwargs): raise MethodNotAllowed(request.method) @@ -317,8 +320,8 @@ class ScriptViewSet(ModelViewSet): raise MethodNotAllowed(request.method) def destroy(self, request, *args, **kwargs): - if not request.user.has_perm('extras.delete_scriptmodule'): - raise PermissionDenied(_("This user does not have permission to delete script modules.")) + if not request.user.has_perm('extras.delete_script'): + raise PermissionDenied(_("This user does not have permission to delete scripts.")) return super().destroy(request, *args, **kwargs) def _get_script(self, pk): diff --git a/netbox/extras/tests/test_api.py b/netbox/extras/tests/test_api.py index 254920f43..7e4c49c77 100644 --- a/netbox/extras/tests/test_api.py +++ b/netbox/extras/tests/test_api.py @@ -1411,6 +1411,7 @@ class ScriptUploadTest(APITestCase): script_content = b"from extras.scripts import Script\nclass TestScript(Script):\n pass\n" upload_file = SimpleUploadedFile('test_upload.py', script_content, content_type='text/plain') mock_storage = MagicMock() + mock_storage.save.return_value = 'test_upload.py' with patch('extras.api.serializers_.scripts.storages') as mock_storages: mock_storages.create_storage.return_value = mock_storage mock_storages.backends = {'scripts': {}} @@ -1423,6 +1424,7 @@ class ScriptUploadTest(APITestCase): self.assertHttpStatus(response, status.HTTP_201_CREATED) self.assertEqual(response.data['file_path'], 'test_upload.py') mock_storage.save.assert_called_once() + self.assertTrue(ScriptModule.objects.filter(file_path='test_upload.py').exists()) def test_upload_script_module_without_file_fails(self): self.add_permissions('extras.add_scriptmodule', 'core.add_managedfile')