mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-03 22:55:43 +00:00 
			
		
		
		
	@@ -1802,10 +1802,8 @@ class WebhookEndpoint(models.Model):
 | 
				
			|||||||
    def process_webhook(self):
 | 
					    def process_webhook(self):
 | 
				
			||||||
        if self.token:
 | 
					        if self.token:
 | 
				
			||||||
            self.verify = VerificationMethod.TOKEN
 | 
					            self.verify = VerificationMethod.TOKEN
 | 
				
			||||||
            # TODO make a object-setting
 | 
					 | 
				
			||||||
        if self.secret:
 | 
					        if self.secret:
 | 
				
			||||||
            self.verify = VerificationMethod.HMAC
 | 
					            self.verify = VerificationMethod.HMAC
 | 
				
			||||||
            # TODO make a object-setting
 | 
					 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate_token(self, payload, headers, request):
 | 
					    def validate_token(self, payload, headers, request):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,12 +31,8 @@ class ActionPluginView(APIView):
 | 
				
			|||||||
        action_plugins = registry.with_mixin('action')
 | 
					        action_plugins = registry.with_mixin('action')
 | 
				
			||||||
        for plugin in action_plugins:
 | 
					        for plugin in action_plugins:
 | 
				
			||||||
            if plugin.action_name() == action:
 | 
					            if plugin.action_name() == action:
 | 
				
			||||||
                # TODO @matmair use easier syntax once InvenTree 0.7.0 is released
 | 
					                plugin.perform_action(request.user, data=data)
 | 
				
			||||||
                plugin.init(request.user, data=data)
 | 
					                return Response(plugin.get_response(request.user, data=data))
 | 
				
			||||||
 | 
					 | 
				
			||||||
                plugin.perform_action()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return Response(plugin.get_response())
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # If we got to here, no matching action was found
 | 
					        # If we got to here, no matching action was found
 | 
				
			||||||
        return Response({
 | 
					        return Response({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,10 +15,9 @@ class ActionMixin:
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        MIXIN_NAME = 'Actions'
 | 
					        MIXIN_NAME = 'Actions'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, user=None, data=None):
 | 
					    def __init__(self):
 | 
				
			||||||
        super().__init__()
 | 
					        super().__init__()
 | 
				
			||||||
        self.add_mixin('action', True, __class__)
 | 
					        self.add_mixin('action', True, __class__)
 | 
				
			||||||
        self.init(user, data)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def action_name(self):
 | 
					    def action_name(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -31,19 +30,12 @@ class ActionMixin:
 | 
				
			|||||||
            return self.ACTION_NAME
 | 
					            return self.ACTION_NAME
 | 
				
			||||||
        return self.name
 | 
					        return self.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def init(self, user, data=None):
 | 
					    def perform_action(self, user=None, data=None):
 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        An action plugin takes a user reference, and an optional dataset (dict)
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        self.user = user
 | 
					 | 
				
			||||||
        self.data = data
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def perform_action(self):
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Override this method to perform the action!
 | 
					        Override this method to perform the action!
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_result(self):
 | 
					    def get_result(self, user=None, data=None):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Result of the action?
 | 
					        Result of the action?
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -51,19 +43,19 @@ class ActionMixin:
 | 
				
			|||||||
        # Re-implement this for cutsom actions
 | 
					        # Re-implement this for cutsom actions
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_info(self):
 | 
					    def get_info(self, user=None, data=None):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Extra info? Can be a string / dict / etc
 | 
					        Extra info? Can be a string / dict / etc
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_response(self):
 | 
					    def get_response(self, user=None, data=None):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return a response. Default implementation is a simple response
 | 
					        Return a response. Default implementation is a simple response
 | 
				
			||||||
        which can be overridden.
 | 
					        which can be overridden.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            "action": self.action_name(),
 | 
					            "action": self.action_name(),
 | 
				
			||||||
            "result": self.get_result(),
 | 
					            "result": self.get_result(user, data),
 | 
				
			||||||
            "info": self.get_info(),
 | 
					            "info": self.get_info(user, data),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,27 +14,27 @@ class ActionMixinTests(TestCase):
 | 
				
			|||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        class SimplePlugin(ActionMixin, InvenTreePlugin):
 | 
					        class SimplePlugin(ActionMixin, InvenTreePlugin):
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
        self.plugin = SimplePlugin('user')
 | 
					        self.plugin = SimplePlugin()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class TestActionPlugin(ActionMixin, InvenTreePlugin):
 | 
					        class TestActionPlugin(ActionMixin, InvenTreePlugin):
 | 
				
			||||||
            """a action plugin"""
 | 
					            """a action plugin"""
 | 
				
			||||||
            ACTION_NAME = 'abc123'
 | 
					            ACTION_NAME = 'abc123'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            def perform_action(self):
 | 
					            def perform_action(self, user=None, data=None):
 | 
				
			||||||
                return ActionMixinTests.ACTION_RETURN + 'action'
 | 
					                return ActionMixinTests.ACTION_RETURN + 'action'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            def get_result(self):
 | 
					            def get_result(self, user=None, data=None):
 | 
				
			||||||
                return ActionMixinTests.ACTION_RETURN + 'result'
 | 
					                return ActionMixinTests.ACTION_RETURN + 'result'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            def get_info(self):
 | 
					            def get_info(self, user=None, data=None):
 | 
				
			||||||
                return ActionMixinTests.ACTION_RETURN + 'info'
 | 
					                return ActionMixinTests.ACTION_RETURN + 'info'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.action_plugin = TestActionPlugin('user')
 | 
					        self.action_plugin = TestActionPlugin()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class NameActionPlugin(ActionMixin, InvenTreePlugin):
 | 
					        class NameActionPlugin(ActionMixin, InvenTreePlugin):
 | 
				
			||||||
            NAME = 'Aplugin'
 | 
					            NAME = 'Aplugin'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.action_name = NameActionPlugin('user')
 | 
					        self.action_name = NameActionPlugin()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_action_name(self):
 | 
					    def test_action_name(self):
 | 
				
			||||||
        """check the name definition possibilities"""
 | 
					        """check the name definition possibilities"""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,7 +63,6 @@ class BarcodeScan(APIView):
 | 
				
			|||||||
        plugin = None
 | 
					        plugin = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for current_plugin in plugins:
 | 
					        for current_plugin in plugins:
 | 
				
			||||||
            # TODO @matmair make simpler after InvenTree 0.7.0 release
 | 
					 | 
				
			||||||
            current_plugin.init(barcode_data)
 | 
					            current_plugin.init(barcode_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if current_plugin.validate():
 | 
					            if current_plugin.validate():
 | 
				
			||||||
@@ -168,7 +167,6 @@ class BarcodeAssign(APIView):
 | 
				
			|||||||
        plugin = None
 | 
					        plugin = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for current_plugin in plugins:
 | 
					        for current_plugin in plugins:
 | 
				
			||||||
            # TODO @matmair make simpler after InvenTree 0.7.0 release
 | 
					 | 
				
			||||||
            current_plugin.init(barcode_data)
 | 
					            current_plugin.init(barcode_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if current_plugin.validate():
 | 
					            if current_plugin.validate():
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,14 +13,14 @@ class SimpleActionPlugin(ActionMixin, InvenTreePlugin):
 | 
				
			|||||||
    NAME = "SimpleActionPlugin"
 | 
					    NAME = "SimpleActionPlugin"
 | 
				
			||||||
    ACTION_NAME = "simple"
 | 
					    ACTION_NAME = "simple"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def perform_action(self):
 | 
					    def perform_action(self, user=None, data=None):
 | 
				
			||||||
        print("Action plugin in action!")
 | 
					        print("Action plugin in action!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_info(self):
 | 
					    def get_info(self, user, data=None):
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            "user": self.user.username,
 | 
					            "user": user.username,
 | 
				
			||||||
            "hello": "world",
 | 
					            "hello": "world",
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_result(self):
 | 
					    def get_result(self, user=None, data=None):
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ class SimpleActionPluginTests(TestCase):
 | 
				
			|||||||
        self.test_user = user.objects.create_user('testuser', 'test@testing.com', 'password')
 | 
					        self.test_user = user.objects.create_user('testuser', 'test@testing.com', 'password')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.client.login(username='testuser', password='password')
 | 
					        self.client.login(username='testuser', password='password')
 | 
				
			||||||
        self.plugin = SimpleActionPlugin(user=self.test_user)
 | 
					        self.plugin = SimpleActionPlugin()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_name(self):
 | 
					    def test_name(self):
 | 
				
			||||||
        """check plugn names """
 | 
					        """check plugn names """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -133,7 +133,6 @@ class PluginsRegistry:
 | 
				
			|||||||
                if retry_counter <= 0:  # pragma: no cover
 | 
					                if retry_counter <= 0:  # pragma: no cover
 | 
				
			||||||
                    if settings.PLUGIN_TESTING:
 | 
					                    if settings.PLUGIN_TESTING:
 | 
				
			||||||
                        print('[PLUGIN] Max retries, breaking loading')
 | 
					                        print('[PLUGIN] Max retries, breaking loading')
 | 
				
			||||||
                    # TODO error for server status
 | 
					 | 
				
			||||||
                    break
 | 
					                    break
 | 
				
			||||||
                if settings.PLUGIN_TESTING:
 | 
					                if settings.PLUGIN_TESTING:
 | 
				
			||||||
                    print(f'[PLUGIN] Above error occured during testing - {retry_counter}/{settings.PLUGIN_RETRY} retries left')
 | 
					                    print(f'[PLUGIN] Above error occured during testing - {retry_counter}/{settings.PLUGIN_RETRY} retries left')
 | 
				
			||||||
@@ -301,7 +300,6 @@ class PluginsRegistry:
 | 
				
			|||||||
                        # Errors are bad so disable the plugin in the database
 | 
					                        # Errors are bad so disable the plugin in the database
 | 
				
			||||||
                        if not settings.PLUGIN_TESTING:  # pragma: no cover
 | 
					                        if not settings.PLUGIN_TESTING:  # pragma: no cover
 | 
				
			||||||
                            plugin_db_setting.active = False
 | 
					                            plugin_db_setting.active = False
 | 
				
			||||||
                            # TODO save the error to the plugin
 | 
					 | 
				
			||||||
                            plugin_db_setting.save(no_reload=True)
 | 
					                            plugin_db_setting.save(no_reload=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        # Add to inactive plugins so it shows up in the ui
 | 
					                        # Add to inactive plugins so it shows up in the ui
 | 
				
			||||||
@@ -310,8 +308,6 @@ class PluginsRegistry:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                # Initialize package
 | 
					                # Initialize package
 | 
				
			||||||
                # now we can be sure that an admin has activated the plugin
 | 
					                # now we can be sure that an admin has activated the plugin
 | 
				
			||||||
                # TODO check more stuff -> as of Nov 2021 there are not many checks in place
 | 
					 | 
				
			||||||
                # but we could enhance those to check signatures, run the plugin against a whitelist etc.
 | 
					 | 
				
			||||||
                logger.info(f'Loading plugin {plug_name}')
 | 
					                logger.info(f'Loading plugin {plug_name}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user