diff --git a/InvenTree/plugin/admin.py b/InvenTree/plugin/admin.py index 839dac305a..f13444f274 100644 --- a/InvenTree/plugin/admin.py +++ b/InvenTree/plugin/admin.py @@ -4,8 +4,7 @@ from __future__ import unicode_literals from django.contrib import admin import plugin.models as models -from plugin import plugin_reg - +import plugin.registry as registry def plugin_update(queryset, new_status: bool): """general function for bulk changing plugins""" @@ -20,7 +19,7 @@ def plugin_update(queryset, new_status: bool): # reload plugins if they changed if apps_changed: - plugin_reg.reload_plugins() + registry.plugin_registry.reload_plugins() @admin.action(description='Activate plugin(s)') @@ -42,6 +41,13 @@ class PluginSettingInline(admin.TabularInline): model = models.PluginSetting + read_only_fields = [ + 'key', + ] + + def has_add_permission(self, request, obj): + return False + class PluginConfigAdmin(admin.ModelAdmin): """Custom admin with restricted id fields""" diff --git a/InvenTree/plugin/builtin/integration/mixins.py b/InvenTree/plugin/builtin/integration/mixins.py index c3437b7f8d..47e9ff630d 100644 --- a/InvenTree/plugin/builtin/integration/mixins.py +++ b/InvenTree/plugin/builtin/integration/mixins.py @@ -3,7 +3,9 @@ Plugin mixin classes """ from django.conf.urls import url, include +from django.db.utils import OperationalError, ProgrammingError +from plugin.models import PluginConfig, PluginSetting from plugin.urls import PLUGIN_BASE @@ -18,43 +20,48 @@ class SettingsMixin: def __init__(self): super().__init__() self.add_mixin('settings', 'has_settings', __class__) - self.globalsettings = getattr(self, 'SETTINGS', None) + self.settings = getattr(self, 'SETTINGS', {}) @property def has_settings(self): """ Does this plugin use custom global settings """ - return bool(self.globalsettings) + return bool(self.settings) - @property - def globalsettingspatterns(self): + def get_setting(self, key): """ - Get patterns for InvenTreeSetting defintion + Return the 'value' of the setting associated with this plugin """ - if self.has_settings: - return {f'PLUGIN_{self.slug.upper()}_{key}': value for key, value in self.globalsettings.items()} - return None - def _globalsetting_name(self, key): - """ - Get global name of setting - """ - return f'PLUGIN_{self.slug.upper()}_{key}' + # Find the plugin configuration associated with this plugin - def get_globalsetting(self, key): - """ - get plugin global setting by key - """ - from common.models import InvenTreeSetting - return InvenTreeSetting.get_setting(self._globalsetting_name(key)) + try: + plugin, _ = PluginConfig.objects.get_or_create(key=self.plugin_slug(), name=self.plugin_name()) + except (OperationalError, ProgrammingError) as error: + plugin = None + + if not plugin: + # Plugin cannot be found, return default value + return PluginSetting.get_setting_default(key, settings=self.settings) - def set_globalsetting(self, key, value, user): + return PluginSetting.get_setting(key, plugin=plugin, settings=self.settings) + + def set_setting(self, key, value, user): """ - set plugin global setting by key + Set plugin setting value by key """ - from common.models import InvenTreeSetting - return InvenTreeSetting.set_setting(self._globalsetting_name(key), value, user) + + try: + plugin, _ = PluginConfig.objects.get_or_create(key=self.plugin_slug(), name=self.plugin_name()) + except (OperationalError, ProgrammingError) as error: + plugin = None + + if not plugin: + # Cannot find associated plugin model, return + return + + PluginSetting.set_setting(key, value, user, plugin=plugin, settings=self.settings) class UrlsMixin: diff --git a/InvenTree/plugin/integration.py b/InvenTree/plugin/integration.py index 3cd8ae86d2..d66ab79c26 100644 --- a/InvenTree/plugin/integration.py +++ b/InvenTree/plugin/integration.py @@ -59,8 +59,6 @@ class IntegrationPluginBase(MixinBase, plugin.InvenTreePlugin): """ The IntegrationPluginBase class is used to integrate with 3rd party software """ - PLUGIN_SLUG = None - PLUGIN_TITLE = None AUTHOR = None DESCRIPTION = None @@ -84,11 +82,7 @@ class IntegrationPluginBase(MixinBase, plugin.InvenTreePlugin): # region properties @property def slug(self): - """slug for the plugin""" - slug = getattr(self, 'PLUGIN_SLUG', None) - if not slug: - slug = self.plugin_name() - return slugify(slug) + return self.plugin_slug() @property def human_name(self): diff --git a/InvenTree/plugin/plugin.py b/InvenTree/plugin/plugin.py index 93199df7b7..dbafda0aea 100644 --- a/InvenTree/plugin/plugin.py +++ b/InvenTree/plugin/plugin.py @@ -2,6 +2,9 @@ """Base Class for InvenTree plugins""" +from django.utils.text import slugify + + class InvenTreePlugin(): """ Base class for a plugin @@ -10,9 +13,28 @@ class InvenTreePlugin(): # Override the plugin name for each concrete plugin instance PLUGIN_NAME = '' + PLUGIN_SLUG = '' + + PLUGIN_TITLE = '' + def plugin_name(self): - """get plugin name""" + """ + Return the name of this plugin plugin + """ return self.PLUGIN_NAME + def plugin_slug(self): + + slug = getattr(self, 'PLUGIN_SLUG', None) + + if slug is None: + slug = self.plugin_name() + + return slugify(slug) + + def plugin_title(self): + + return self.PLUGIN_TITLE + def __init__(self): pass diff --git a/InvenTree/plugin/registry.py b/InvenTree/plugin/registry.py index 79892616c4..e0b25ecc65 100644 --- a/InvenTree/plugin/registry.py +++ b/InvenTree/plugin/registry.py @@ -50,7 +50,7 @@ class Plugins: # integration specific self.installed_apps = [] # Holds all added plugin_paths # mixins - self.mixins_globalsettings = {} + self.mixins_settings = {} # region public plugin functions def load_plugins(self): @@ -252,8 +252,8 @@ class Plugins: logger.info('Registering IntegrationPlugin global settings') for slug, plugin in plugins: if plugin.mixin_enabled('settings'): - plugin_setting = plugin.globalsettingspatterns - self.mixins_globalsettings[slug] = plugin_setting + plugin_setting = plugin.settings + self.mixins_settings[slug] = plugin_setting # Add to settings dir InvenTreeSetting.SETTINGS.update(plugin_setting) @@ -263,7 +263,7 @@ class Plugins: # collect all settings plugin_settings = {} - for _, plugin_setting in self.mixins_globalsettings.items(): + for _, plugin_setting in self.mixins_settings.items(): plugin_settings.update(plugin_setting) # remove settings @@ -271,7 +271,7 @@ class Plugins: InvenTreeSetting.SETTINGS.pop(setting) # clear cache - self.mixins_globalsettings = {} + self.mixins_Fsettings = {} # endregion # region integration_app diff --git a/InvenTree/plugin/samples/integration/sample.py b/InvenTree/plugin/samples/integration/sample.py index afc4a8fe8a..682726718f 100644 --- a/InvenTree/plugin/samples/integration/sample.py +++ b/InvenTree/plugin/samples/integration/sample.py @@ -44,6 +44,15 @@ class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixi 'default': True, 'validator': bool, }, + 'API_KEY': { + 'name': _('API Key'), + 'description': _('Key required for accessing external API'), + }, + 'NUMERICAL_SETTING': { + 'name': _('Numerical'), + 'description': _('A numerical setting'), + 'validator': int, + }, } NAVIGATION = [ diff --git a/InvenTree/plugin/templatetags/plugin_extras.py b/InvenTree/plugin/templatetags/plugin_extras.py index 1b4b269844..b7f4f6b6c1 100644 --- a/InvenTree/plugin/templatetags/plugin_extras.py +++ b/InvenTree/plugin/templatetags/plugin_extras.py @@ -26,9 +26,9 @@ def inactive_plugin_list(*args, **kwargs): @register.simple_tag() -def plugin_globalsettings(plugin, *args, **kwargs): - """ Return a list of all global settings for a plugin """ - return plugin_reg.mixins_globalsettings.get(plugin) +def plugin_settings(plugin, *args, **kwargs): + """ Return a list of all custom settings for a plugin """ + return plugin_reg.mixins_settings.get(plugin) @register.simple_tag() diff --git a/InvenTree/plugin/test_integration.py b/InvenTree/plugin/test_integration.py index 5cf00f7c86..f88994384a 100644 --- a/InvenTree/plugin/test_integration.py +++ b/InvenTree/plugin/test_integration.py @@ -46,15 +46,15 @@ class SettingsMixinTest(BaseMixinDefinition, TestCase): # calling settings # not existing - self.assertEqual(self.mixin.get_globalsetting('ABCD'), '') - self.assertEqual(self.mixin_nothing.get_globalsetting('ABCD'), '') + self.assertEqual(self.mixin.get_setting('ABCD'), '') + self.assertEqual(self.mixin_nothing.get_setting('ABCD'), '') # right setting - self.mixin.set_globalsetting('SETTING1', '12345', self.test_user) - self.assertEqual(self.mixin.get_globalsetting('SETTING1'), '12345') + self.mixin.set_setting('SETTING1', '12345', self.test_user) + self.assertEqual(self.mixin.get_setting('SETTING1'), '12345') # no setting - self.assertEqual(self.mixin_nothing.get_globalsetting(''), '') + self.assertEqual(self.mixin_nothing.get_setting(''), '') class UrlsMixinTest(BaseMixinDefinition, TestCase): diff --git a/InvenTree/plugin/test_plugin.py b/InvenTree/plugin/test_plugin.py index 3e0a1967db..b4e2fdaf6f 100644 --- a/InvenTree/plugin/test_plugin.py +++ b/InvenTree/plugin/test_plugin.py @@ -63,11 +63,11 @@ class PluginTagTests(TestCase): """test that all inactive plugins are listed""" self.assertEqual(plugin_tags.inactive_plugin_list(), plugin_reg.plugins_inactive) - def test_tag_plugin_globalsettings(self): + def test_tag_plugin_settings(self): """check all plugins are listed""" self.assertEqual( - plugin_tags.plugin_globalsettings(self.sample), - plugin_reg.mixins_globalsettings.get(self.sample) + plugin_tags.plugin_settings(self.sample), + plugin_reg.mixins_settings.get(self.sample) ) def test_tag_mixin_enabled(self): diff --git a/InvenTree/templates/InvenTree/settings/mixins/settings.html b/InvenTree/templates/InvenTree/settings/mixins/settings.html index 910d4bbfbb..cb136b5c4f 100644 --- a/InvenTree/templates/InvenTree/settings/mixins/settings.html +++ b/InvenTree/templates/InvenTree/settings/mixins/settings.html @@ -5,7 +5,7 @@

{% trans "Settings" %}

-{% plugin_globalsettings plugin_key as plugin_settings %} +{% plugin_settings plugin_key as plugin_settings %} diff --git a/InvenTree/templates/InvenTree/settings/setting.html b/InvenTree/templates/InvenTree/settings/setting.html index 7419b7ff34..96a8993798 100644 --- a/InvenTree/templates/InvenTree/settings/setting.html +++ b/InvenTree/templates/InvenTree/settings/setting.html @@ -13,7 +13,7 @@ {% endif %} - +
{% trans setting.name %}{{ setting.name }} {% if setting.is_bool %}
@@ -32,7 +32,7 @@
{% endif %}
- {% trans setting.description %} + {{ setting.description }}