diff --git a/InvenTree/InvenTree/api.py b/InvenTree/InvenTree/api.py index 41f292b7b2..0183c12c20 100644 --- a/InvenTree/InvenTree/api.py +++ b/InvenTree/InvenTree/api.py @@ -152,6 +152,7 @@ class InfoView(AjaxView): 'worker_running': is_worker_running(), 'worker_pending_tasks': self.worker_pending_tasks(), 'plugins_enabled': settings.PLUGINS_ENABLED, + 'plugins_install_disabled': settings.PLUGINS_INSTALL_DISABLED, 'active_plugins': plugins_info(), 'email_configured': is_email_configured(), 'debug_mode': settings.DEBUG, diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index 4985687484..d8a6b94100 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -1,11 +1,14 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 175 +INVENTREE_API_VERSION = 176 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v176 - 2024-02-26 : https://github.com/inventree/InvenTree/pull/6535 + - Adds the field "plugins_install_disabled" to the Server info API endpoint + v175 - 2024-02-21 : https://github.com/inventree/InvenTree/pull/6538 - Adds "parts" count to PartParameterTemplate serializer diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 9e7c94f8ad..a89c856883 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -1136,6 +1136,9 @@ MAINTENANCE_MODE_STATE_BACKEND = 'InvenTree.backends.InvenTreeMaintenanceModeBac PLUGINS_ENABLED = get_boolean_setting( 'INVENTREE_PLUGINS_ENABLED', 'plugins_enabled', False ) +PLUGINS_INSTALL_DISABLED = get_boolean_setting( + 'INVENTREE_PLUGIN_NOINSTALL', 'plugin_noinstall', False +) PLUGIN_FILE = config.get_plugin_file() diff --git a/InvenTree/InvenTree/templatetags/inventree_extras.py b/InvenTree/InvenTree/templatetags/inventree_extras.py index aa67af3fef..48fbe7ba99 100644 --- a/InvenTree/InvenTree/templatetags/inventree_extras.py +++ b/InvenTree/InvenTree/templatetags/inventree_extras.py @@ -155,6 +155,12 @@ def plugins_enabled(*args, **kwargs): return djangosettings.PLUGINS_ENABLED +@register.simple_tag() +def plugins_install_disabled(*args, **kwargs): + """Return True if plugin install is disabled for the server instance.""" + return djangosettings.PLUGINS_INSTALL_DISABLED + + @register.simple_tag() def plugins_info(*args, **kwargs): """Return information about activated plugins.""" diff --git a/InvenTree/config_template.yaml b/InvenTree/config_template.yaml index c302a7c195..0b4f753670 100644 --- a/InvenTree/config_template.yaml +++ b/InvenTree/config_template.yaml @@ -152,6 +152,7 @@ sentry_enabled: False # Set this variable to True to enable InvenTree Plugins # Alternatively, use the environment variable INVENTREE_PLUGINS_ENABLED plugins_enabled: False +#plugin_noinstall: True #plugin_file: '/path/to/plugins.txt' #plugin_dir: '/path/to/plugins/' diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index c267043855..98f9dc5410 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -55,6 +55,10 @@ class TemplateTagTest(InvenTreeTestCase): """Test the plugins_enabled tag.""" self.assertEqual(inventree_extras.plugins_enabled(), True) + def test_plugins_install_disabled(self): + """Test the plugins_install_disabled tag.""" + self.assertEqual(inventree_extras.plugins_install_disabled(), False) + def test_inventree_instance_name(self): """Test the 'instance name' setting.""" self.assertEqual(inventree_extras.inventree_instance_name(), 'InvenTree') diff --git a/InvenTree/plugin/installer.py b/InvenTree/plugin/installer.py index b7e7c772a2..8edcfd7159 100644 --- a/InvenTree/plugin/installer.py +++ b/InvenTree/plugin/installer.py @@ -193,6 +193,9 @@ def install_plugin(url=None, packagename=None, user=None, version=None): if user and not user.is_staff: raise ValidationError(_('Only staff users can administer plugins')) + if settings.PLUGINS_INSTALL_DISABLED: + raise ValidationError(_('Plugin installation is disabled')) + logger.info('install_plugin: %s, %s', url, packagename) # Check if we are running in a virtual environment @@ -292,6 +295,9 @@ def uninstall_plugin(cfg: plugin.models.PluginConfig, user=None, delete_config=T """ from plugin.registry import registry + if settings.PLUGINS_INSTALL_DISABLED: + raise ValidationError(_('Plugin uninstalling is disabled')) + if cfg.active: raise ValidationError( _('Plugin cannot be uninstalled as it is currently active') diff --git a/InvenTree/plugin/test_api.py b/InvenTree/plugin/test_api.py index a28379a592..a0474c551d 100644 --- a/InvenTree/plugin/test_api.py +++ b/InvenTree/plugin/test_api.py @@ -1,5 +1,6 @@ """Tests for general API tests for the plugin app.""" +from django.conf import settings from django.urls import reverse from rest_framework.exceptions import NotFound @@ -81,6 +82,11 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase): data['confirm'][0].title().upper(), 'Installation not confirmed'.upper() ) + # install disabled + settings.PLUGINS_INSTALL_DISABLED = True + self.post(url, {}, expected_code=400) + settings.PLUGINS_INSTALL_DISABLED = False + def test_plugin_activate(self): """Test the plugin activate.""" test_plg = self.plugin_confs.first() diff --git a/InvenTree/templates/InvenTree/settings/plugin.html b/InvenTree/templates/InvenTree/settings/plugin.html index fe6a296536..ea1cc4341a 100644 --- a/InvenTree/templates/InvenTree/settings/plugin.html +++ b/InvenTree/templates/InvenTree/settings/plugin.html @@ -29,6 +29,7 @@ {% plugins_enabled as plug %} +{% plugins_install_disabled as plug_disabled %}