Coverage for src/backend/InvenTree/plugin/base/action/api.py: 76%
32 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
1"""APIs for action plugins."""
3from django.utils.translation import gettext_lazy as _
5from drf_spectacular.utils import OpenApiResponse, extend_schema
6from rest_framework import serializers, status
7from rest_framework.generics import GenericAPIView
8from rest_framework.response import Response
10import InvenTree.permissions
11from InvenTree.exceptions import log_error
12from plugin import PluginMixinEnum, registry
15class ActionPluginSerializer(serializers.Serializer):
16 """Serializer for the ActionPluginView responses."""
18 action = serializers.CharField()
19 data = serializers.DictField()
22class ActionPluginErrorSerializer(serializers.Serializer):
23 """Serializer for the ActionPluginView error responses."""
25 error = serializers.CharField()
26 action = serializers.CharField(required=False)
29class ActionPluginView(GenericAPIView):
30 """Endpoint for running custom action plugins."""
32 permission_classes = [InvenTree.permissions.IsAuthenticatedOrReadScope]
33 serializer_class = ActionPluginSerializer
35 @extend_schema(
36 responses={
37 200: ActionPluginSerializer,
38 400: OpenApiResponse(
39 description='No action specified',
40 response=ActionPluginErrorSerializer(),
41 ),
42 404: OpenApiResponse(
43 description='No matching action found',
44 response=ActionPluginErrorSerializer(),
45 ),
46 }
47 )
48 def post(self, request, *args, **kwargs):
49 """This function checks if all required info was submitted and then performs a plugin_action or returns an error."""
50 action = request.data.get('action', None)
52 data = request.data.get('data', None)
54 if action is None:
55 return Response(
56 {'error': _('No action specified')}, status=status.HTTP_400_BAD_REQUEST
57 )
59 action_plugins = registry.with_mixin(PluginMixinEnum.ACTION)
60 for plugin in action_plugins: 60 ↛ 61line 60 didn't jump to line 61 because the loop on line 60 never started
61 try:
62 if plugin.action_name() == action:
63 plugin.perform_action(request.user, data=data)
64 return Response(plugin.get_response(request.user, data=data))
65 except Exception:
66 log_error('perform_action', plugin=plugin.slug)
68 # If we got to here, no matching action was found
69 return Response(
70 {'error': _('No matching action found'), 'action': action},
71 status=status.HTTP_404_NOT_FOUND,
72 )