2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-10-14 21:22:20 +00:00

Add schema representation for plugin action error responses (#10538)

* Define error serializer and codes for schema

* Bump api version

* Update integration test status code check
This commit is contained in:
Joe Rogers
2025-10-09 18:13:24 -04:00
committed by GitHub
parent 8ff5b1965d
commit b36f452ac1
4 changed files with 36 additions and 7 deletions

View File

@@ -1,12 +1,15 @@
"""InvenTree API version information."""
# InvenTree API version
INVENTREE_API_VERSION = 406
INVENTREE_API_VERSION = 407
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
v407 -> 2025-10-09: https://github.com/inventree/InvenTree/pull/10538
- Breaking: Set error status code for plugin action call instead of just returning error data
v406 -> 2025-10-08: https://github.com/inventree/InvenTree/pull/10532
- Set return type for background task overview
- Implement serializer for part serial number detail

View File

@@ -2,7 +2,8 @@
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework import serializers, status
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
@@ -18,12 +19,32 @@ class ActionPluginSerializer(serializers.Serializer):
data = serializers.DictField()
class ActionPluginErrorSerializer(serializers.Serializer):
"""Serializer for the ActionPluginView error responses."""
error = serializers.CharField()
action = serializers.CharField(required=False)
class ActionPluginView(GenericAPIView):
"""Endpoint for running custom action plugins."""
permission_classes = [InvenTree.permissions.IsAuthenticatedOrReadScope]
serializer_class = ActionPluginSerializer
@extend_schema(
responses={
200: ActionPluginSerializer,
400: OpenApiResponse(
description='No action specified',
response=ActionPluginErrorSerializer(),
),
404: OpenApiResponse(
description='No matching action found',
response=ActionPluginErrorSerializer(),
),
}
)
def post(self, request, *args, **kwargs):
"""This function checks if all required info was submitted and then performs a plugin_action or returns an error."""
action = request.data.get('action', None)
@@ -31,7 +52,9 @@ class ActionPluginView(GenericAPIView):
data = request.data.get('data', None)
if action is None:
return Response({'error': _('No action specified')})
return Response(
{'error': _('No action specified')}, status=status.HTTP_400_BAD_REQUEST
)
action_plugins = registry.with_mixin(PluginMixinEnum.ACTION)
for plugin in action_plugins:
@@ -43,4 +66,7 @@ class ActionPluginView(GenericAPIView):
log_error('perform_action', plugin=plugin.slug)
# If we got to here, no matching action was found
return Response({'error': _('No matching action found'), 'action': action})
return Response(
{'error': _('No matching action found'), 'action': action},
status=status.HTTP_404_NOT_FOUND,
)

View File

@@ -83,12 +83,12 @@ class APITests(InvenTreeTestCase):
"""Check the possible errors with post."""
# Test empty request
response = self.client.post('/api/action/')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.data, {'error': 'No action specified'})
# Test non-existing action
response = self.client.post('/api/action/', data={'action': 'nonexisting'})
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, 404)
self.assertEqual(
response.data,
{'error': 'No matching action found', 'action': 'nonexisting'},

View File

@@ -27,7 +27,7 @@ class SimpleActionPluginTests(InvenTreeTestCase):
self.set_plugin_state(False)
response = self.client.post('/api/action/', data=data)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, 404)
self.assertIn('error', response.data)
# Now enable the plugin