From dc9e25ebad12ee9fe23903d4bd8ac06df033d3b1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 2 Jan 2022 14:12:34 +1100 Subject: [PATCH] Adds API endpoints for viewing and updating plugin settings A lot of code updates / refactoring here to get this to work as expected --- InvenTree/InvenTree/version.py | 6 +- InvenTree/common/models.py | 26 ++++---- .../part/templatetags/inventree_extras.py | 13 +++- InvenTree/plugin/__init__.py | 8 ++- InvenTree/plugin/admin.py | 1 + InvenTree/plugin/api.py | 42 ++++++++++++- InvenTree/plugin/apps.py | 8 +-- .../plugin/builtin/integration/mixins.py | 17 +++-- InvenTree/plugin/helpers.py | 8 +-- InvenTree/plugin/integration.py | 1 - InvenTree/plugin/loader.py | 4 +- InvenTree/plugin/models.py | 62 +++++++++++++++++-- InvenTree/plugin/plugin.py | 30 +++++++-- InvenTree/plugin/registry.py | 23 +++---- .../plugin/samples/integration/sample.py | 12 ++++ InvenTree/plugin/serializers.py | 25 +++++++- .../plugin/templatetags/plugin_extras.py | 10 +-- InvenTree/plugin/test_api.py | 4 +- InvenTree/plugin/test_plugin.py | 10 +-- InvenTree/plugin/urls.py | 4 +- .../InvenTree/settings/mixins/settings.html | 2 +- .../templates/InvenTree/settings/setting.html | 8 ++- InvenTree/templates/js/dynamic/settings.js | 6 +- 23 files changed, 250 insertions(+), 80 deletions(-) diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 79bc44bc0e..1f8e372d39 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -12,11 +12,15 @@ import common.models INVENTREE_SW_VERSION = "0.6.0 dev" # InvenTree API version -INVENTREE_API_VERSION = 22 +INVENTREE_API_VERSION = 23 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v23 -> 2022-02-02 + - Adds API endpoints for managing plugin classes + - Adds API endpoints for managing plugin settings + v22 -> 2021-12-20 - Adds API endpoint to "merge" multiple stock items diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index ecddd17de8..048a968d1a 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -71,7 +71,7 @@ class BaseInvenTreeSetting(models.Model): super().save() @classmethod - def allValues(cls, user=None, plugin=None, exclude_hidden=False): + def allValues(cls, user=None, exclude_hidden=False): """ Return a dict of "all" defined global settings. @@ -86,10 +86,6 @@ class BaseInvenTreeSetting(models.Model): if user is not None: results = results.filter(user=user) - # Optionally filter by plugin - if plugin is not None: - results = results.filter(plugin=plugin) - # Query the database settings = {} @@ -238,16 +234,12 @@ class BaseInvenTreeSetting(models.Model): settings = cls.objects.all() + # Filter by user user = kwargs.get('user', None) if user is not None: settings = settings.filter(user=user) - plugin = kwargs.get('plugin', None) - - if plugin is not None: - settings = settings.filter(plugin=plugin) - try: setting = settings.filter(**cls.get_filters(key, **kwargs)).first() except (ValueError, cls.DoesNotExist): @@ -255,6 +247,16 @@ class BaseInvenTreeSetting(models.Model): except (IntegrityError, OperationalError): setting = None + plugin = kwargs.pop('plugin', None) + + if plugin: + from plugin import InvenTreePlugin + + if issubclass(plugin.__class__, InvenTreePlugin): + plugin = plugin.plugin_config() + + kwargs['plugin'] = plugin + # Setting does not exist! (Try to create it) if not setting: @@ -554,7 +556,9 @@ class BaseInvenTreeSetting(models.Model): def settings_group_options(): - """build up group tuple for settings based on gour choices""" + """ + Build up group tuple for settings based on your choices + """ return [('', _('No group')), *[(str(a.id), str(a)) for a in Group.objects.all()]] diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index 9dc09535fa..9c0b0e691f 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -""" This module provides template tags for extra functionality +""" +This module provides template tags for extra functionality, over and above the built-in Django tags. """ @@ -22,6 +23,8 @@ import InvenTree.helpers from common.models import InvenTreeSetting, ColorTheme, InvenTreeUserSetting from common.settings import currency_code_default +from plugin.models import PluginSetting + register = template.Library() @@ -223,8 +226,16 @@ def setting_object(key, *args, **kwargs): if a user-setting was requested return that """ + if 'plugin' in kwargs: + # Note, 'plugin' is an instance of an InvenTreePlugin class + + plugin = kwargs['plugin'] + + return PluginSetting.get_setting_object(key, plugin=plugin) + if 'user' in kwargs: return InvenTreeUserSetting.get_setting_object(key, user=kwargs['user']) + return InvenTreeSetting.get_setting_object(key) diff --git a/InvenTree/plugin/__init__.py b/InvenTree/plugin/__init__.py index 973d341171..b3dc3a2fd0 100644 --- a/InvenTree/plugin/__init__.py +++ b/InvenTree/plugin/__init__.py @@ -1,7 +1,11 @@ -from .registry import plugins as plugin_reg +from .registry import plugin_registry +from .plugin import InvenTreePlugin from .integration import IntegrationPluginBase from .action import ActionPlugin __all__ = [ - 'plugin_reg', 'IntegrationPluginBase', 'ActionPlugin', + 'ActionPlugin', + 'IntegrationPluginBase', + 'InvenTreePlugin', + 'plugin_registry', ] diff --git a/InvenTree/plugin/admin.py b/InvenTree/plugin/admin.py index f13444f274..e27c499479 100644 --- a/InvenTree/plugin/admin.py +++ b/InvenTree/plugin/admin.py @@ -6,6 +6,7 @@ from django.contrib import admin import plugin.models as models import plugin.registry as registry + def plugin_update(queryset, new_status: bool): """general function for bulk changing plugins""" apps_changed = False diff --git a/InvenTree/plugin/api.py b/InvenTree/plugin/api.py index 4aecd6bb24..9ab3b96724 100644 --- a/InvenTree/plugin/api.py +++ b/InvenTree/plugin/api.py @@ -11,7 +11,8 @@ from rest_framework import generics from rest_framework import status from rest_framework.response import Response -from plugin.models import PluginConfig +from common.api import GlobalSettingsPermissions +from plugin.models import PluginConfig, PluginSetting import plugin.serializers as PluginSerializers @@ -76,7 +77,46 @@ class PluginInstall(generics.CreateAPIView): return serializer.save() +class PluginSettingList(generics.ListAPIView): + """ + List endpoint for all plugin related settings. + + - read only + - only accessible by staff users + """ + + queryset = PluginSetting.objects.all() + serializer_class = PluginSerializers.PluginSettingSerializer + + permission_classes = [ + GlobalSettingsPermissions, + ] + + +class PluginSettingDetail(generics.RetrieveUpdateAPIView): + """ + Detail endpoint for a plugin-specific setting. + + Note that these cannot be created or deleted via the API + """ + + queryset = PluginSetting.objects.all() + serializer_class = PluginSerializers.PluginSettingSerializer + + # Staff permission required + permission_classes = [ + GlobalSettingsPermissions, + ] + + plugin_api_urls = [ + + # Plugin settings URLs + url(r'^settings/', include([ + url(r'^(?P\d+)/', PluginSettingDetail.as_view(), name='api-plugin-setting-detail'), + url(r'^.*$', PluginSettingList.as_view(), name='api-plugin-setting-list'), + ])), + # Detail views for a single PluginConfig item url(r'^(?P\d+)/', include([ url(r'^.*$', PluginDetail.as_view(), name='api-plugin-detail'), diff --git a/InvenTree/plugin/apps.py b/InvenTree/plugin/apps.py index 8a3cd97889..cca9dee91c 100644 --- a/InvenTree/plugin/apps.py +++ b/InvenTree/plugin/apps.py @@ -4,17 +4,17 @@ from __future__ import unicode_literals from django.apps import AppConfig from maintenance_mode.core import set_maintenance_mode -from plugin.registry import plugins +from plugin import plugin_registry class PluginAppConfig(AppConfig): name = 'plugin' def ready(self): - if not plugins.is_loading: + if not plugin_registry.is_loading: # this is the first startup - plugins.collect_plugins() - plugins.load_plugins() + plugin_registry.collect_plugins() + plugin_registry.load_plugins() # drop out of maintenance # makes sure we did not have an error in reloading and maintenance is still active diff --git a/InvenTree/plugin/builtin/integration/mixins.py b/InvenTree/plugin/builtin/integration/mixins.py index 47e9ff630d..30f3cd8551 100644 --- a/InvenTree/plugin/builtin/integration/mixins.py +++ b/InvenTree/plugin/builtin/integration/mixins.py @@ -36,17 +36,14 @@ class SettingsMixin: # Find the plugin configuration associated with this plugin - 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 = self.plugin_config() + + if plugin: + return PluginSetting.get_setting(key, plugin=plugin, settings=self.settings) + else: # Plugin cannot be found, return default value return PluginSetting.get_setting_default(key, settings=self.settings) - return PluginSetting.get_setting(key, plugin=plugin, settings=self.settings) - def set_setting(self, key, value, user): """ Set plugin setting value by key @@ -54,12 +51,12 @@ class SettingsMixin: try: plugin, _ = PluginConfig.objects.get_or_create(key=self.plugin_slug(), name=self.plugin_name()) - except (OperationalError, ProgrammingError) as error: + except (OperationalError, ProgrammingError): plugin = None if not plugin: # Cannot find associated plugin model, return - return + return PluginSetting.set_setting(key, value, user, plugin=plugin, settings=self.settings) diff --git a/InvenTree/plugin/helpers.py b/InvenTree/plugin/helpers.py index 003ca707b4..fb46df8927 100644 --- a/InvenTree/plugin/helpers.py +++ b/InvenTree/plugin/helpers.py @@ -10,14 +10,14 @@ from django.conf import settings # region logging / errors def log_plugin_error(error, reference: str = 'general'): - from plugin import plugin_reg + from plugin import plugin_registry # make sure the registry is set up - if reference not in plugin_reg.errors: - plugin_reg.errors[reference] = [] + if reference not in plugin_registry.errors: + plugin_registry.errors[reference] = [] # add error to stack - plugin_reg.errors[reference].append(error) + plugin_registry.errors[reference].append(error) class IntegrationPluginError(Exception): diff --git a/InvenTree/plugin/integration.py b/InvenTree/plugin/integration.py index d66ab79c26..2c593291d3 100644 --- a/InvenTree/plugin/integration.py +++ b/InvenTree/plugin/integration.py @@ -9,7 +9,6 @@ import pathlib from django.urls.base import reverse from django.conf import settings -from django.utils.text import slugify from django.utils.translation import ugettext_lazy as _ import plugin.plugin as plugin diff --git a/InvenTree/plugin/loader.py b/InvenTree/plugin/loader.py index 2491336a51..2d17f8c36f 100644 --- a/InvenTree/plugin/loader.py +++ b/InvenTree/plugin/loader.py @@ -4,7 +4,7 @@ load templates for loaded plugins from django.template.loaders.filesystem import Loader as FilesystemLoader from pathlib import Path -from plugin import plugin_reg +from plugin import plugin_registry class PluginTemplateLoader(FilesystemLoader): @@ -12,7 +12,7 @@ class PluginTemplateLoader(FilesystemLoader): def get_dirs(self): dirname = 'templates' template_dirs = [] - for plugin in plugin_reg.plugins.values(): + for plugin in plugin_registry.plugins.values(): new_path = Path(plugin.path) / dirname if Path(new_path).is_dir(): template_dirs.append(new_path) diff --git a/InvenTree/plugin/models.py b/InvenTree/plugin/models.py index b001798544..f477df5c27 100644 --- a/InvenTree/plugin/models.py +++ b/InvenTree/plugin/models.py @@ -10,7 +10,7 @@ from django.db import models import common.models -from plugin import plugin_reg +from plugin import InvenTreePlugin, plugin_registry class PluginConfig(models.Model): @@ -72,7 +72,7 @@ class PluginConfig(models.Model): self.__org_active = self.active # append settings from registry - self.plugin = plugin_reg.plugins.get(self.key, None) + self.plugin = plugin_registry.plugins.get(self.key, None) def get_plugin_meta(name): if self.plugin: @@ -95,10 +95,10 @@ class PluginConfig(models.Model): if not reload: if self.active is False and self.__org_active is True: - plugin_reg.reload_plugins() + plugin_registry.reload_plugins() elif self.active is True and self.__org_active is False: - plugin_reg.reload_plugins() + plugin_registry.reload_plugins() return ret @@ -113,6 +113,58 @@ class PluginSetting(common.models.BaseInvenTreeSetting): ('plugin', 'key'), ] + """ + We override the following class methods, + so that we can pass the plugin instance + """ + + @property + def name(self): + return self.__class__.get_setting_name(self.key, plugin=self.plugin) + + @property + def default_value(self): + return self.__class__.get_setting_default(self.key, plugin=self.plugin) + + @property + def description(self): + return self.__class__.get_setting_description(self.key, plugin=self.plugin) + + @property + def units(self): + return self.__class__.get_setting_units(self.key, plugin=self.plugin) + + def choices(self): + return self.__class__.get_setting_choices(self.key, plugin=self.plugin) + + @classmethod + def get_setting_definition(cls, key, **kwargs): + """ + In the BaseInvenTreeSetting class, we have a class attribute named 'SETTINGS', + which is a dict object that fully defines all the setting parameters. + + Here, unlike the BaseInvenTreeSetting, we do not know the definitions of all settings + 'ahead of time' (as they are defined externally in the plugins). + + Settings can be provided by the caller, as kwargs['settings']. + + If not provided, we'll look at the plugin registry to see what settings are available, + (if the plugin is specified!) + """ + + if 'settings' not in kwargs: + + plugin = kwargs.pop('plugin', None) + + if plugin: + + if issubclass(plugin.__class__, InvenTreePlugin): + plugin = plugin.plugin_config() + + kwargs['settings'] = plugin_registry.mixins_settings.get(plugin.key, {}) + + return super().get_setting_definition(key, **kwargs) + @classmethod def get_filters(cls, key, **kwargs): """ @@ -124,6 +176,8 @@ class PluginSetting(common.models.BaseInvenTreeSetting): plugin = kwargs.get('plugin', None) if plugin: + if issubclass(plugin.__class__, InvenTreePlugin): + plugin = plugin.plugin_config() filters['plugin'] = plugin return filters diff --git a/InvenTree/plugin/plugin.py b/InvenTree/plugin/plugin.py index dbafda0aea..0cf8082b7f 100644 --- a/InvenTree/plugin/plugin.py +++ b/InvenTree/plugin/plugin.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- -"""Base Class for InvenTree plugins""" - +""" +Base Class for InvenTree plugins +""" +from django.db.utils import OperationalError, ProgrammingError from django.utils.text import slugify @@ -10,6 +12,9 @@ class InvenTreePlugin(): Base class for a plugin """ + def __init__(self): + pass + # Override the plugin name for each concrete plugin instance PLUGIN_NAME = '' @@ -36,5 +41,22 @@ class InvenTreePlugin(): return self.PLUGIN_TITLE - def __init__(self): - pass + def plugin_config(self, raise_error=False): + """ + Return the PluginConfig object associated with this plugin + """ + + try: + import plugin.models + + cfg, _ = plugin.models.PluginConfig.objects.get_or_create( + key=self.plugin_slug(), + name=self.plugin_name(), + ) + except (OperationalError, ProgrammingError) as error: + cfg = None + + if raise_error: + raise error + + return cfg diff --git a/InvenTree/plugin/registry.py b/InvenTree/plugin/registry.py index e0b25ecc65..30dbad5f95 100644 --- a/InvenTree/plugin/registry.py +++ b/InvenTree/plugin/registry.py @@ -33,7 +33,7 @@ from .helpers import get_plugin_error, IntegrationPluginError logger = logging.getLogger('inventree') -class Plugins: +class PluginsRegistry: def __init__(self) -> None: # plugin registry self.plugins = {} @@ -225,7 +225,8 @@ class Plugins: self.plugins_inactive[plug_key] = plugin_db_setting def _activate_plugins(self, force_reload=False): - """run integration functions for all plugins + """ + Run integration functions for all plugins :param force_reload: force reload base apps, defaults to False :type force_reload: bool, optional @@ -238,13 +239,13 @@ class Plugins: self.activate_integration_app(plugins, force_reload=force_reload) def _deactivate_plugins(self): - """run integration deactivation functions for all plugins""" + """ + Run integration deactivation functions for all plugins + """ self.deactivate_integration_app() self.deactivate_integration_globalsettings() # endregion - # region specific integrations - # region integration_globalsettings def activate_integration_globalsettings(self, plugins): from common.models import InvenTreeSetting @@ -255,24 +256,16 @@ class Plugins: plugin_setting = plugin.settings self.mixins_settings[slug] = plugin_setting - # Add to settings dir - InvenTreeSetting.SETTINGS.update(plugin_setting) - def deactivate_integration_globalsettings(self): - from common.models import InvenTreeSetting # collect all settings plugin_settings = {} + for _, plugin_setting in self.mixins_settings.items(): plugin_settings.update(plugin_setting) - # remove settings - for setting in plugin_settings: - InvenTreeSetting.SETTINGS.pop(setting) - # clear cache self.mixins_Fsettings = {} - # endregion # region integration_app def activate_integration_app(self, plugins, force_reload=False): @@ -452,4 +445,4 @@ class Plugins: # endregion -plugins = Plugins() +plugin_registry = PluginsRegistry() diff --git a/InvenTree/plugin/samples/integration/sample.py b/InvenTree/plugin/samples/integration/sample.py index 682726718f..a05e804def 100644 --- a/InvenTree/plugin/samples/integration/sample.py +++ b/InvenTree/plugin/samples/integration/sample.py @@ -52,6 +52,18 @@ class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixi 'name': _('Numerical'), 'description': _('A numerical setting'), 'validator': int, + 'default': 123, + }, + 'CHOICE_SETTING': { + 'name': _("Choice Setting"), + 'description': _('A setting with multiple choices'), + 'choices': [ + ('A', 'Anaconda'), + ('B', 'Bat'), + ('C', 'Cat'), + ('D', 'Dog'), + ], + 'default': 'A', }, } diff --git a/InvenTree/plugin/serializers.py b/InvenTree/plugin/serializers.py index e25e253498..da171a604d 100644 --- a/InvenTree/plugin/serializers.py +++ b/InvenTree/plugin/serializers.py @@ -14,7 +14,9 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers -from plugin.models import PluginConfig +from common.serializers import SettingsSerializer + +from plugin.models import PluginConfig, PluginSetting class PluginConfigSerializer(serializers.ModelSerializer): @@ -117,3 +119,24 @@ class PluginConfigInstallSerializer(serializers.Serializer): # TODO return ret + + +class PluginSettingSerializer(SettingsSerializer): + """ + Serializer for the PluginSetting model + """ + + plugin = serializers.PrimaryKeyRelatedField(read_only=True) + + class Meta: + model = PluginSetting + fields = [ + 'pk', + 'key', + 'value', + 'name', + 'description', + 'type', + 'choices', + 'plugin', + ] diff --git a/InvenTree/plugin/templatetags/plugin_extras.py b/InvenTree/plugin/templatetags/plugin_extras.py index b7f4f6b6c1..7852133ebb 100644 --- a/InvenTree/plugin/templatetags/plugin_extras.py +++ b/InvenTree/plugin/templatetags/plugin_extras.py @@ -7,7 +7,7 @@ from django import template from django.urls import reverse from common.models import InvenTreeSetting -from plugin import plugin_reg +from plugin import plugin_registry register = template.Library() @@ -16,19 +16,19 @@ register = template.Library() @register.simple_tag() def plugin_list(*args, **kwargs): """ Return a list of all installed integration plugins """ - return plugin_reg.plugins + return plugin_registry.plugins @register.simple_tag() def inactive_plugin_list(*args, **kwargs): """ Return a list of all inactive integration plugins """ - return plugin_reg.plugins_inactive + return plugin_registry.plugins_inactive @register.simple_tag() def plugin_settings(plugin, *args, **kwargs): """ Return a list of all custom settings for a plugin """ - return plugin_reg.mixins_settings.get(plugin) + return plugin_registry.mixins_settings.get(plugin) @register.simple_tag() @@ -57,4 +57,4 @@ def safe_url(view_name, *args, **kwargs): @register.simple_tag() def plugin_errors(*args, **kwargs): """Return all plugin errors""" - return plugin_reg.errors + return plugin_registry.errors diff --git a/InvenTree/plugin/test_api.py b/InvenTree/plugin/test_api.py index 0bb5f7789b..fe1e9802bf 100644 --- a/InvenTree/plugin/test_api.py +++ b/InvenTree/plugin/test_api.py @@ -64,14 +64,14 @@ class PluginDetailAPITest(InvenTreeAPITestCase): Test the PluginConfig action commands """ from plugin.models import PluginConfig - from plugin import plugin_reg + from plugin import plugin_registry url = reverse('admin:plugin_pluginconfig_changelist') fixtures = PluginConfig.objects.all() # check if plugins were registered -> in some test setups the startup has no db access if not fixtures: - plugin_reg.reload_plugins() + plugin_registry.reload_plugins() fixtures = PluginConfig.objects.all() print([str(a) for a in fixtures]) diff --git a/InvenTree/plugin/test_plugin.py b/InvenTree/plugin/test_plugin.py index b4e2fdaf6f..5724bdb0a9 100644 --- a/InvenTree/plugin/test_plugin.py +++ b/InvenTree/plugin/test_plugin.py @@ -8,7 +8,7 @@ from plugin.samples.integration.sample import SampleIntegrationPlugin from plugin.samples.integration.another_sample import WrongIntegrationPlugin, NoIntegrationPlugin # from plugin.plugins import load_action_plugins, load_barcode_plugins import plugin.templatetags.plugin_extras as plugin_tags -from plugin import plugin_reg +from plugin import plugin_registry class InvenTreePluginTests(TestCase): @@ -57,17 +57,17 @@ class PluginTagTests(TestCase): def test_tag_plugin_list(self): """test that all plugins are listed""" - self.assertEqual(plugin_tags.plugin_list(), plugin_reg.plugins) + self.assertEqual(plugin_tags.plugin_list(), plugin_registry.plugins) def test_tag_incative_plugin_list(self): """test that all inactive plugins are listed""" - self.assertEqual(plugin_tags.inactive_plugin_list(), plugin_reg.plugins_inactive) + self.assertEqual(plugin_tags.inactive_plugin_list(), plugin_registry.plugins_inactive) def test_tag_plugin_settings(self): """check all plugins are listed""" self.assertEqual( plugin_tags.plugin_settings(self.sample), - plugin_reg.mixins_settings.get(self.sample) + plugin_registry.mixins_settings.get(self.sample) ) def test_tag_mixin_enabled(self): @@ -89,4 +89,4 @@ class PluginTagTests(TestCase): def test_tag_plugin_errors(self): """test that all errors are listed""" - self.assertEqual(plugin_tags.plugin_errors(), plugin_reg.errors) + self.assertEqual(plugin_tags.plugin_errors(), plugin_registry.errors) diff --git a/InvenTree/plugin/urls.py b/InvenTree/plugin/urls.py index 419dce5a88..46cdfd8a84 100644 --- a/InvenTree/plugin/urls.py +++ b/InvenTree/plugin/urls.py @@ -3,7 +3,7 @@ URL lookup for plugin app """ from django.conf.urls import url, include -from plugin import plugin_reg +from plugin import plugin_registry PLUGIN_BASE = 'plugin' # Constant for links @@ -12,7 +12,7 @@ PLUGIN_BASE = 'plugin' # Constant for links def get_plugin_urls(): """returns a urlpattern that can be integrated into the global urls""" urls = [] - for plugin in plugin_reg.plugins.values(): + for plugin in plugin_registry.plugins.values(): if plugin.mixin_enabled('urls'): urls.append(plugin.urlpatterns) return url(f'^{PLUGIN_BASE}/', include((urls, 'plugin'))) diff --git a/InvenTree/templates/InvenTree/settings/mixins/settings.html b/InvenTree/templates/InvenTree/settings/mixins/settings.html index cb136b5c4f..57218b3699 100644 --- a/InvenTree/templates/InvenTree/settings/mixins/settings.html +++ b/InvenTree/templates/InvenTree/settings/mixins/settings.html @@ -10,7 +10,7 @@ {% for setting in plugin_settings %} - {% include "InvenTree/settings/setting.html" with key=setting%} + {% include "InvenTree/settings/setting.html" with key=setting plugin=plugin %} {% endfor %}
\ No newline at end of file diff --git a/InvenTree/templates/InvenTree/settings/setting.html b/InvenTree/templates/InvenTree/settings/setting.html index 96a8993798..91d03849ce 100644 --- a/InvenTree/templates/InvenTree/settings/setting.html +++ b/InvenTree/templates/InvenTree/settings/setting.html @@ -1,10 +1,12 @@ {% load inventree_extras %} {% load i18n %} -{% if user_setting %} - {% setting_object key user=request.user as setting %} +{% if plugin %} +{% setting_object key plugin=plugin as setting %} +{% elif user_setting %} +{% setting_object key user=request.user as setting %} {% else %} - {% setting_object key as setting %} +{% setting_object key as setting %} {% endif %} diff --git a/InvenTree/templates/js/dynamic/settings.js b/InvenTree/templates/js/dynamic/settings.js index e19bba6501..133edfba20 100644 --- a/InvenTree/templates/js/dynamic/settings.js +++ b/InvenTree/templates/js/dynamic/settings.js @@ -28,9 +28,13 @@ function editSetting(pk, options={}) { // Is this a global setting or a user setting? var global = options.global || false; + var plugin = options.plugin; + var url = ''; - if (global) { + if (plugin) { + url = `/api/plugin/settings/${pk}/`; + } else if (global) { url = `/api/settings/global/${pk}/`; } else { url = `/api/settings/user/${pk}/`;