mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
* Hide protected setting in settings view
* Implement custom serializer for setting value
- Return '***' if the setting is protected
* Implement to_internal_value
* Stringify
* Add protected setting to sample plugin
* Unit tests for plugin settings API
* Update unit test
(cherry picked from commit 01f2aa5f74
)
Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
parent
cf5d637678
commit
9b5e828b87
@ -13,6 +13,25 @@ from InvenTree.serializers import (InvenTreeImageSerializerField,
|
|||||||
InvenTreeModelSerializer)
|
InvenTreeModelSerializer)
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsValueField(serializers.Field):
|
||||||
|
"""Custom serializer field for a settings value."""
|
||||||
|
|
||||||
|
def get_attribute(self, instance):
|
||||||
|
"""Return the object instance, not the attribute value."""
|
||||||
|
return instance
|
||||||
|
|
||||||
|
def to_representation(self, instance):
|
||||||
|
"""Return the value of the setting:
|
||||||
|
|
||||||
|
- Protected settings are returned as '***'
|
||||||
|
"""
|
||||||
|
return '***' if instance.protected else str(instance.value)
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
"""Return the internal value of the setting"""
|
||||||
|
return str(data)
|
||||||
|
|
||||||
|
|
||||||
class SettingsSerializer(InvenTreeModelSerializer):
|
class SettingsSerializer(InvenTreeModelSerializer):
|
||||||
"""Base serializer for a settings object."""
|
"""Base serializer for a settings object."""
|
||||||
|
|
||||||
@ -30,6 +49,8 @@ class SettingsSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
api_url = serializers.CharField(read_only=True)
|
api_url = serializers.CharField(read_only=True)
|
||||||
|
|
||||||
|
value = SettingsValueField()
|
||||||
|
|
||||||
def get_choices(self, obj):
|
def get_choices(self, obj):
|
||||||
"""Returns the choices available for a given item."""
|
"""Returns the choices available for a given item."""
|
||||||
results = []
|
results = []
|
||||||
@ -45,16 +66,6 @@ class SettingsSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def get_value(self, obj):
|
|
||||||
"""Make sure protected values are not returned."""
|
|
||||||
# never return protected values
|
|
||||||
if obj.protected:
|
|
||||||
result = '***'
|
|
||||||
else:
|
|
||||||
result = obj.value
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
class GlobalSettingsSerializer(SettingsSerializer):
|
class GlobalSettingsSerializer(SettingsSerializer):
|
||||||
"""Serializer for the InvenTreeSetting model."""
|
"""Serializer for the InvenTreeSetting model."""
|
||||||
|
@ -72,6 +72,12 @@ class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixi
|
|||||||
'description': 'Select a part object from the database',
|
'description': 'Select a part object from the database',
|
||||||
'model': 'part.part',
|
'model': 'part.part',
|
||||||
},
|
},
|
||||||
|
'PROTECTED_SETTING': {
|
||||||
|
'name': 'Protected Setting',
|
||||||
|
'description': 'A protected setting, hidden from the UI',
|
||||||
|
'default': 'ABC-123',
|
||||||
|
'protected': True,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NAVIGATION = [
|
NAVIGATION = [
|
||||||
|
@ -193,3 +193,76 @@ class PluginDetailAPITest(PluginMixin, InvenTreeAPITestCase):
|
|||||||
with self.assertRaises(NotFound) as exc:
|
with self.assertRaises(NotFound) as exc:
|
||||||
check_plugin(plugin_slug=None, plugin_pk='123')
|
check_plugin(plugin_slug=None, plugin_pk='123')
|
||||||
self.assertEqual(str(exc.exception.detail), "Plugin '123' not installed")
|
self.assertEqual(str(exc.exception.detail), "Plugin '123' not installed")
|
||||||
|
|
||||||
|
def test_plugin_settings(self):
|
||||||
|
"""Test plugin settings access via the API"""
|
||||||
|
|
||||||
|
# Ensure we have superuser permissions
|
||||||
|
self.user.is_superuser = True
|
||||||
|
self.user.save()
|
||||||
|
|
||||||
|
# Activate the 'sample' plugin via the API
|
||||||
|
cfg = PluginConfig.objects.filter(key='sample').first()
|
||||||
|
url = reverse('api-plugin-detail-activate', kwargs={'pk': cfg.pk})
|
||||||
|
self.client.patch(url, {}, expected_code=200)
|
||||||
|
|
||||||
|
# Valid plugin settings endpoints
|
||||||
|
valid_settings = [
|
||||||
|
'SELECT_PART',
|
||||||
|
'API_KEY',
|
||||||
|
'NUMERICAL_SETTING',
|
||||||
|
]
|
||||||
|
|
||||||
|
for key in valid_settings:
|
||||||
|
response = self.get(
|
||||||
|
reverse('api-plugin-setting-detail', kwargs={
|
||||||
|
'plugin': 'sample',
|
||||||
|
'key': key
|
||||||
|
}))
|
||||||
|
|
||||||
|
self.assertEqual(response.data['key'], key)
|
||||||
|
|
||||||
|
# Test that an invalid setting key raises a 404 error
|
||||||
|
response = self.get(
|
||||||
|
reverse('api-plugin-setting-detail', kwargs={
|
||||||
|
'plugin': 'sample',
|
||||||
|
'key': 'INVALID_SETTING'
|
||||||
|
}),
|
||||||
|
expected_code=404
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test that a protected setting returns hidden value
|
||||||
|
response = self.get(
|
||||||
|
reverse('api-plugin-setting-detail', kwargs={
|
||||||
|
'plugin': 'sample',
|
||||||
|
'key': 'PROTECTED_SETTING'
|
||||||
|
}),
|
||||||
|
expected_code=200
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.data['value'], '***')
|
||||||
|
|
||||||
|
# Test that we can update a setting value
|
||||||
|
response = self.patch(
|
||||||
|
reverse('api-plugin-setting-detail', kwargs={
|
||||||
|
'plugin': 'sample',
|
||||||
|
'key': 'NUMERICAL_SETTING'
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
'value': 456
|
||||||
|
},
|
||||||
|
expected_code=200
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.data['value'], '456')
|
||||||
|
|
||||||
|
# Retrieve the value again
|
||||||
|
response = self.get(
|
||||||
|
reverse('api-plugin-setting-detail', kwargs={
|
||||||
|
'plugin': 'sample',
|
||||||
|
'key': 'NUMERICAL_SETTING'
|
||||||
|
}),
|
||||||
|
expected_code=200
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.data['value'], '456')
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
{{ setting.description }}
|
{{ setting.description }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if setting.is_bool %}
|
{% if setting.protected %}
|
||||||
|
<span style='color: red;'>***</span> <span class='fas fa-lock icon-red'></span>
|
||||||
|
{% elif setting.is_bool %}
|
||||||
{% include "InvenTree/settings/setting_boolean.html" %}
|
{% include "InvenTree/settings/setting_boolean.html" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div id='setting-{{ setting.pk }}'>
|
<div id='setting-{{ setting.pk }}'>
|
||||||
|
Loading…
Reference in New Issue
Block a user