From 3777686c924238893062dbb0d7cb97ca6395aff8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 16:34:50 +1000 Subject: [PATCH 01/15] 503 page was missing inventree_extras (cherry picked from commit 1a8fd7878ea253f7cdfd50f54850827e634fcb0f) --- InvenTree/templates/503.html | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/templates/503.html b/InvenTree/templates/503.html index 7b5b25d611..606fc03ff0 100644 --- a/InvenTree/templates/503.html +++ b/InvenTree/templates/503.html @@ -1,5 +1,6 @@ {% extends "skeleton.html" %} {% load static %} +{% load inventree_extras %} {% load i18n %} {% block head %} From 5d4972d981d0429b4bd775de54f4e655c618080f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 19:46:17 +1000 Subject: [PATCH 02/15] Convert settings to 'native' values before running callable valiators --- InvenTree/common/models.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index f1cd8bc09a..84f9a4277d 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -455,7 +455,14 @@ class BaseInvenTreeSetting(models.Model): if callable(validator): # We can accept function validators with a single argument - validator(self.value) + + if self.is_bool(): + value = self.as_bool() + + if self.is_int(): + value = self.as_int() + + validator(value) def validate_unique(self, exclude=None, **kwargs): """ From 75fa0bed260bf051e74d8366d82cf91dc1207d8d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 19:51:08 +1000 Subject: [PATCH 03/15] Render "native value" in serializer --- InvenTree/common/models.py | 14 ++++++++++++++ InvenTree/common/serializers.py | 5 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 84f9a4277d..299549be49 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -398,6 +398,17 @@ class BaseInvenTreeSetting(models.Model): def units(self): return self.__class__.get_setting_units(self.key) + @property + def native_value(self): + + if self.is_bool(): + return self.as_bool() + + if self.is_int(): + return self.as_int() + + return self.value + def clean(self, **kwargs): """ If a validator (or multiple validators) are defined for a particular setting key, @@ -636,6 +647,9 @@ class BaseInvenTreeSetting(models.Model): return setting.get('protected', False) + @property + def protected(self): + return self.__class__.is_protected(self.key) def settings_group_options(): """ diff --git a/InvenTree/common/serializers.py b/InvenTree/common/serializers.py index 71ccac8a4d..86d45cd881 100644 --- a/InvenTree/common/serializers.py +++ b/InvenTree/common/serializers.py @@ -50,11 +50,12 @@ class SettingsSerializer(InvenTreeModelSerializer): """ Make sure protected values are not returned """ - result = obj.value # never return protected values - if obj.is_protected: + if obj.protected: result = '***' + else: + result = obj.value return result From eabe082f0a1976617cd46a29ec9b6b20cd7a9770 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 20:20:32 +1000 Subject: [PATCH 04/15] Add unit tests for boolean user settings (via the API) --- .../migrations/0029_auto_20210601_1525.py | 6 +- InvenTree/common/models.py | 3 + InvenTree/common/tests.py | 97 ++++++++++++++++++- 3 files changed, 100 insertions(+), 6 deletions(-) diff --git a/InvenTree/build/migrations/0029_auto_20210601_1525.py b/InvenTree/build/migrations/0029_auto_20210601_1525.py index 12ec66960c..5470416dcd 100644 --- a/InvenTree/build/migrations/0029_auto_20210601_1525.py +++ b/InvenTree/build/migrations/0029_auto_20210601_1525.py @@ -17,8 +17,6 @@ def assign_bom_items(apps, schema_editor): BuildItem = apps.get_model('build', 'builditem') BomItem = apps.get_model('part', 'bomitem') Part = apps.get_model('part', 'part') - - logger.info("Assigning BomItems to existing BuildItem objects") count_valid = 0 count_total = 0 @@ -29,6 +27,10 @@ def assign_bom_items(apps, schema_editor): # Note: Before this migration, variant stock assignment was not allowed, # so BomItem lookup should be pretty easy + if count_total == 0: + # First time around + logger.info("Assigning BomItems to existing BuildItem objects") + count_total += 1 try: diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 299549be49..5865b3ce70 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -417,6 +417,9 @@ class BaseInvenTreeSetting(models.Model): super().clean() + # Encode as native values + self.value = self.native_value + validator = self.__class__.get_setting_validator(self.key, **kwargs) if validator is not None: diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index c3ce4f9e51..b91403cc34 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -9,7 +9,9 @@ from django.contrib.auth import get_user_model from django.urls import reverse from InvenTree.api_tester import InvenTreeAPITestCase -from .models import InvenTreeSetting, WebhookEndpoint, WebhookMessage, NotificationEntry +from InvenTree.helpers import str2bool + +from .models import InvenTreeSetting, InvenTreeUserSetting, WebhookEndpoint, WebhookMessage, NotificationEntry from .api import WebhookView CONTENT_TYPE_JSON = 'application/json' @@ -158,10 +160,97 @@ class SettingsTest(TestCase): class SettingsApiTest(InvenTreeAPITestCase): - def test_settings_api(self): - # test setting with choice + def test_global_settings_api_list(self): + """ + Test list URL for global settings + """ + url = reverse('api-global-setting-list') + + response = self.get(url, expected_code=200) + + def test_user_settings_api_list(self): + """ + Test list URL for user settings + """ url = reverse('api-user-setting-list') - self.get(url, expected_code=200) + # test setting with choice + response = self.get(url, expected_code=200) + + def test_user_setting_boolean(self): + """ + Test a boolean user setting value + """ + + # Ensure we have a boolean setting available + setting = InvenTreeUserSetting.get_setting_object( + 'SEARCH_PREVIEW_SHOW_PARTS', + user=self.user + ) + + # Check default values + self.assertEqual(setting.native_value, True) + + # Fetch via API + url = reverse('api-user-setting-detail', kwargs={'pk': setting.pk}) + + response = self.get(url, expected_code=200) + + self.assertEqual(response.data['pk'], setting.pk) + self.assertEqual(response.data['key'], 'SEARCH_PREVIEW_SHOW_PARTS') + self.assertEqual(response.data['description'], 'Display parts in search preview window') + self.assertEqual(response.data['type'], 'boolean') + self.assertEqual(len(response.data['choices']), 0) + self.assertTrue(str2bool(response.data['value'])) + + # Assign some truthy values + for v in ['true', True, 1, 'y', 'TRUE']: + self.patch( + url, + { + 'value': str(v), + }, + expected_code=200, + ) + + response = self.get(url, expected_code=200) + + self.assertTrue(str2bool(response.data['value'])) + + # Assign some falsey values + for v in ['false', False, '0', 'n', 'FalSe']: + self.patch( + url, + { + 'value': str(v), + }, + expected_code=200, + ) + + response = self.get(url, expected_code=200) + + self.assertFalse(str2bool(response.data['value'])) + + # Assign some invalid values + for v in ['x', '', 'invalid', None, '-1', 'abcde']: + response = self.patch( + url, + { + 'value': str(v), + }, + expected_code=200 + ) + + # Invalid values evaluate to False + self.assertFalse(str2bool(response.data['value'])) + + def test_user_setting_string(self): + ... + + def test_user_setting_choice(self): + ... + + def test_user_setting_integer(self): + ... class WebhookMessageTests(TestCase): From f9725512460cf5d76e047f761b3758e62b9f0eb3 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:07:16 +1000 Subject: [PATCH 05/15] Add unit test for multiple-choice setting type --- InvenTree/common/tests.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index b91403cc34..921e1ee9b7 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -247,7 +247,43 @@ class SettingsApiTest(InvenTreeAPITestCase): ... def test_user_setting_choice(self): - ... + + setting = InvenTreeUserSetting.get_setting_object( + 'DATE_DISPLAY_FORMAT', + user=self.user + ) + + url = reverse('api-user-setting-detail', kwargs={'pk': setting.pk}) + + # Check default value + self.assertEqual(setting.value, 'YYYY-MM-DD') + + # Check that a valid option can be assigned via the API + for opt in ['YYYY-MM-DD', 'DD-MM-YYYY', 'MM/DD/YYYY']: + + self.patch( + url, + { + 'value': opt, + }, + expected_code=200, + ) + + setting.refresh_from_db() + self.assertEqual(setting.value, opt) + + # Send an invalid option + for opt in ['cat', 'dog', 12345]: + + response = self.patch( + url, + { + 'value': opt, + }, + expected_code=400, + ) + + self.assertIn('Chosen value is not a valid option', str(response.data)) def test_user_setting_integer(self): ... From 0f8f9f3e5e24c47ed56e67b617f4f04bdd6e98c1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:21:57 +1000 Subject: [PATCH 06/15] Add unit test for integer settings with validator --- InvenTree/common/models.py | 35 +++++++++++++++++++++++++--- InvenTree/common/tests.py | 47 ++++++++++++++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 5865b3ce70..a7a75fa180 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -1035,48 +1035,56 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'default': True, 'validator': bool, }, + 'LOGIN_ENABLE_REG': { 'name': _('Enable registration'), 'description': _('Enable self-registration for users on the login pages'), 'default': False, 'validator': bool, }, + 'LOGIN_ENABLE_SSO': { 'name': _('Enable SSO'), 'description': _('Enable SSO on the login pages'), 'default': False, 'validator': bool, }, + 'LOGIN_MAIL_REQUIRED': { 'name': _('Email required'), 'description': _('Require user to supply mail on signup'), 'default': False, 'validator': bool, }, + 'LOGIN_SIGNUP_SSO_AUTO': { 'name': _('Auto-fill SSO users'), 'description': _('Automatically fill out user-details from SSO account-data'), 'default': True, 'validator': bool, }, + 'LOGIN_SIGNUP_MAIL_TWICE': { 'name': _('Mail twice'), 'description': _('On signup ask users twice for their mail'), 'default': False, 'validator': bool, }, + 'LOGIN_SIGNUP_PWD_TWICE': { 'name': _('Password twice'), 'description': _('On signup ask users twice for their password'), 'default': True, 'validator': bool, }, + 'SIGNUP_GROUP': { 'name': _('Group on signup'), 'description': _('Group to which new users are assigned on registration'), 'default': '', 'choices': settings_group_options }, + 'LOGIN_ENFORCE_MFA': { 'name': _('Enforce MFA'), 'description': _('Users must use multifactor security.'), @@ -1091,6 +1099,7 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'validator': bool, 'requires_restart': True, }, + # Settings for plugin mixin features 'ENABLE_PLUGINS_URL': { 'name': _('Enable URL integration'), @@ -1099,6 +1108,7 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'validator': bool, 'requires_restart': True, }, + 'ENABLE_PLUGINS_NAVIGATION': { 'name': _('Enable navigation integration'), 'description': _('Enable plugins to integrate into navigation'), @@ -1106,6 +1116,7 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'validator': bool, 'requires_restart': True, }, + 'ENABLE_PLUGINS_APP': { 'name': _('Enable app integration'), 'description': _('Enable plugins to add apps'), @@ -1113,6 +1124,7 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'validator': bool, 'requires_restart': True, }, + 'ENABLE_PLUGINS_SCHEDULE': { 'name': _('Enable schedule integration'), 'description': _('Enable plugins to run scheduled tasks'), @@ -1120,6 +1132,7 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'validator': bool, 'requires_restart': True, }, + 'ENABLE_PLUGINS_EVENTS': { 'name': _('Enable event integration'), 'description': _('Enable plugins to respond to internal events'), @@ -1173,18 +1186,21 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): 'default': True, 'validator': bool, }, + 'HOMEPAGE_CATEGORY_STARRED': { 'name': _('Show subscribed categories'), 'description': _('Show subscribed part categories on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_PART_LATEST': { 'name': _('Show latest parts'), 'description': _('Show latest parts on the homepage'), 'default': True, 'validator': bool, }, + 'PART_RECENT_COUNT': { 'name': _('Recent Part Count'), 'description': _('Number of recent parts to display on index page'), @@ -1198,78 +1214,91 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): 'default': True, 'validator': bool, }, + 'HOMEPAGE_STOCK_RECENT': { 'name': _('Show recent stock changes'), 'description': _('Show recently changed stock items on the homepage'), 'default': True, 'validator': bool, }, + 'STOCK_RECENT_COUNT': { 'name': _('Recent Stock Count'), 'description': _('Number of recent stock items to display on index page'), 'default': 10, 'validator': [int, MinValueValidator(1)] }, + 'HOMEPAGE_STOCK_LOW': { 'name': _('Show low stock'), 'description': _('Show low stock items on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_STOCK_DEPLETED': { 'name': _('Show depleted stock'), 'description': _('Show depleted stock items on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_STOCK_NEEDED': { 'name': _('Show needed stock'), 'description': _('Show stock items needed for builds on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_STOCK_EXPIRED': { 'name': _('Show expired stock'), 'description': _('Show expired stock items on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_STOCK_STALE': { 'name': _('Show stale stock'), 'description': _('Show stale stock items on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_BUILD_PENDING': { 'name': _('Show pending builds'), 'description': _('Show pending builds on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_BUILD_OVERDUE': { 'name': _('Show overdue builds'), 'description': _('Show overdue builds on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_PO_OUTSTANDING': { 'name': _('Show outstanding POs'), 'description': _('Show outstanding POs on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_PO_OVERDUE': { 'name': _('Show overdue POs'), 'description': _('Show overdue POs on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_SO_OUTSTANDING': { 'name': _('Show outstanding SOs'), 'description': _('Show outstanding SOs on the homepage'), 'default': True, 'validator': bool, }, + 'HOMEPAGE_SO_OVERDUE': { 'name': _('Show overdue SOs'), 'description': _('Show overdue SOs on the homepage'), @@ -1367,7 +1396,7 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): 'default': False, 'validator': bool, }, - + 'PART_SHOW_QUANTITY_IN_FORMS': { 'name': _('Show Quantity in Forms'), 'description': _('Display available part quantity in some forms'), @@ -1381,7 +1410,7 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): 'default': False, 'validator': bool, }, - + 'STICKY_HEADER': { 'name': _('Fixed Navbar'), 'description': _('The navbar position is fixed to the top of the screen'), @@ -1403,7 +1432,7 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): ('MMM DD YYYY', 'Feb 22 2022'), ] }, - + 'DISPLAY_SCHEDULE_TAB': { 'name': _('Part Scheduling'), 'description': _('Display part scheduling information'), diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index 921e1ee9b7..6f983d0009 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -243,9 +243,6 @@ class SettingsApiTest(InvenTreeAPITestCase): # Invalid values evaluate to False self.assertFalse(str2bool(response.data['value'])) - def test_user_setting_string(self): - ... - def test_user_setting_choice(self): setting = InvenTreeUserSetting.get_setting_object( @@ -286,7 +283,49 @@ class SettingsApiTest(InvenTreeAPITestCase): self.assertIn('Chosen value is not a valid option', str(response.data)) def test_user_setting_integer(self): - ... + + setting = InvenTreeUserSetting.get_setting_object( + 'SEARCH_PREVIEW_RESULTS', + user=self.user + ) + + url = reverse('api-user-setting-detail', kwargs={'pk': setting.pk}) + + # Check default value for this setting + self.assertEqual(setting.value, 10) + + for v in [1, 9, 99]: + setting.value = v + setting.save() + + response = self.get(url) + + self.assertEqual(response.data['value'], str(v)) + + # Set valid options via the api + for v in [5, 15, 25]: + self.patch( + url, + { + 'value': v, + }, + expected_code=200, + ) + + setting.refresh_from_db() + self.assertEqual(setting.native_value, v) + + # Set invalid options via the API + # Note that this particular setting has a MinValueValidator(1) associated with it + for v in [0, -1, -5]: + + response = self.patch( + url, + { + 'value': v, + }, + expected_code=400, + ) class WebhookMessageTests(TestCase): From f794d91e5ccea0b278ab46cbf8c499cc80e940bf Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:26:51 +1000 Subject: [PATCH 07/15] Adds more unit tests for global settings objects --- InvenTree/common/tests.py | 52 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index 6f983d0009..dd98a79bc7 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -158,7 +158,11 @@ class SettingsTest(TestCase): raise ValueError(f'Non-boolean default value specified for {key}') # pragma: no cover -class SettingsApiTest(InvenTreeAPITestCase): + +class GlobalSettingsApiTest(InvenTreeAPITestCase): + """ + Tests for the global settings API + """ def test_global_settings_api_list(self): """ @@ -166,8 +170,54 @@ class SettingsApiTest(InvenTreeAPITestCase): """ url = reverse('api-global-setting-list') + # Read out each of the global settings value, to ensure they are instantiated in the database + for key in InvenTreeSetting.SETTINGS: + InvenTreeSetting.get_setting_object(key) + response = self.get(url, expected_code=200) + # Number of results should match the number of settings + self.assertEqual(len(response.data), len(InvenTreeSetting.SETTINGS.keys())) + + def test_company_name(self): + + setting = InvenTreeSetting.get_setting_object('INVENTREE_COMPANY_NAME') + + # Check default value + self.assertEqual(setting.value, 'My company name') + + url = reverse('api-global-setting-detail', kwargs={'pk': setting.pk}) + + # Test getting via the API + for val in ['test', '123', 'My company nam3']: + setting.value = val + setting.save() + + response = self.get(url, expected_code=200) + + self.assertEqual(response.data['value'], val) + + # Test setting via the API + for val in ['cat', 'hat', 'bat', 'mat']: + response = self.patch( + url, + { + 'value': val, + }, + expected_code=200 + ) + + self.assertEqual(response.data['value'], val) + + setting.refresh_from_db() + self.assertEqual(setting.value, val) + + +class UserSettingsApiTest(InvenTreeAPITestCase): + """ + Tests for the user settings API + """ + def test_user_settings_api_list(self): """ Test list URL for user settings From d72efc3757310461524148cd21c7aa56bcb0d939 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:30:24 +1000 Subject: [PATCH 08/15] Small tweaks - Factor out native_value property (not needed!) - PEP fixes --- InvenTree/common/models.py | 15 ++------------- InvenTree/common/tests.py | 5 ++--- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index a7a75fa180..543451b35e 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -398,17 +398,6 @@ class BaseInvenTreeSetting(models.Model): def units(self): return self.__class__.get_setting_units(self.key) - @property - def native_value(self): - - if self.is_bool(): - return self.as_bool() - - if self.is_int(): - return self.as_int() - - return self.value - def clean(self, **kwargs): """ If a validator (or multiple validators) are defined for a particular setting key, @@ -418,7 +407,7 @@ class BaseInvenTreeSetting(models.Model): super().clean() # Encode as native values - self.value = self.native_value + self.value = self.to_native_value() validator = self.__class__.get_setting_validator(self.key, **kwargs) @@ -1432,7 +1421,7 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): ('MMM DD YYYY', 'Feb 22 2022'), ] }, - + 'DISPLAY_SCHEDULE_TAB': { 'name': _('Part Scheduling'), 'description': _('Display part scheduling information'), diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index dd98a79bc7..a8948fd29d 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -158,7 +158,6 @@ class SettingsTest(TestCase): raise ValueError(f'Non-boolean default value specified for {key}') # pragma: no cover - class GlobalSettingsApiTest(InvenTreeAPITestCase): """ Tests for the global settings API @@ -238,7 +237,7 @@ class UserSettingsApiTest(InvenTreeAPITestCase): ) # Check default values - self.assertEqual(setting.native_value, True) + self.assertEqual(setting.to_native_value(), True) # Fetch via API url = reverse('api-user-setting-detail', kwargs={'pk': setting.pk}) @@ -363,7 +362,7 @@ class UserSettingsApiTest(InvenTreeAPITestCase): ) setting.refresh_from_db() - self.assertEqual(setting.native_value, v) + self.assertEqual(setting.to_native_value(), v) # Set invalid options via the API # Note that this particular setting has a MinValueValidator(1) associated with it From 0a3613476ceb9175beaab529212c0b5f2d56aec3 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:34:03 +1000 Subject: [PATCH 09/15] Fix empty translation string --- InvenTree/templates/js/translated/order.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js index c971a4d694..4aad54a65a 100644 --- a/InvenTree/templates/js/translated/order.js +++ b/InvenTree/templates/js/translated/order.js @@ -2413,7 +2413,7 @@ function showAllocationSubTable(index, row, element, options) { }, { field: 'buttons', - title: '{% trans "" %}', + title: '', formatter: function(value, row, index, field) { var html = `
`; From ef530956a8dbb6185e12b3067195e373f3b74b56 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:38:18 +1000 Subject: [PATCH 10/15] Run translation as part of the update process --- tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks.py b/tasks.py index 34528e2609..0578f69acd 100644 --- a/tasks.py +++ b/tasks.py @@ -236,7 +236,7 @@ def translate(c): manage(c, "compilemessages") -@task(pre=[install, migrate, translate_stats, static, clean_settings]) +@task(pre=[install, migrate, translate, static, clean_settings]) def update(c): """ Update InvenTree installation. From 8abc96a79afeac9ed0779162e6be3823dab9a7a9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:42:25 +1000 Subject: [PATCH 11/15] Ignore .mo files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 6532442dc7..56d4180482 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,6 @@ maintenance_mode_state.txt # plugin dev directory plugins/ + +# Compiled translation files +*.mo From 9e469a949f5d27cff3a7e6a1d991344e0f84aa80 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:43:25 +1000 Subject: [PATCH 12/15] Push from latest master to l10 branch --- .github/workflows/translations.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/translations.yml b/.github/workflows/translations.yml index 24106c028e..044187e135 100644 --- a/.github/workflows/translations.yml +++ b/.github/workflows/translations.yml @@ -38,19 +38,11 @@ jobs: - name: Make Translations run: | invoke translate - - name: stash changes - run: | - git stash - - name: Checkout Translation Branch - uses: actions/checkout@v2.3.4 - with: - ref: l10 - name: Commit files run: | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" git config --local user.name "github-actions[bot]" - git checkout stash -- . - git reset + git checkout -b l10_local git add "*.po" git commit -m "updated translation base" - name: Push changes From e3c3ed28da6f1b54d2ee89ea52551c30d2d8ff77 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:46:50 +1000 Subject: [PATCH 13/15] PEP fixes --- InvenTree/common/models.py | 13 +++++++------ InvenTree/common/tests.py | 12 ++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 543451b35e..a6ddbd5a96 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -461,7 +461,7 @@ class BaseInvenTreeSetting(models.Model): if self.is_bool(): value = self.as_bool() - + if self.is_int(): value = self.as_int() @@ -643,6 +643,7 @@ class BaseInvenTreeSetting(models.Model): def protected(self): return self.__class__.is_protected(self.key) + def settings_group_options(): """ Build up group tuple for settings based on your choices @@ -1066,7 +1067,7 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'default': True, 'validator': bool, }, - + 'SIGNUP_GROUP': { 'name': _('Group on signup'), 'description': _('Group to which new users are assigned on registration'), @@ -1121,7 +1122,7 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'validator': bool, 'requires_restart': True, }, - + 'ENABLE_PLUGINS_EVENTS': { 'name': _('Enable event integration'), 'description': _('Enable plugins to respond to internal events'), @@ -1203,7 +1204,7 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): 'default': True, 'validator': bool, }, - + 'HOMEPAGE_STOCK_RECENT': { 'name': _('Show recent stock changes'), 'description': _('Show recently changed stock items on the homepage'), @@ -1385,7 +1386,7 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): 'default': False, 'validator': bool, }, - + 'PART_SHOW_QUANTITY_IN_FORMS': { 'name': _('Show Quantity in Forms'), 'description': _('Display available part quantity in some forms'), @@ -1399,7 +1400,7 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): 'default': False, 'validator': bool, }, - + 'STICKY_HEADER': { 'name': _('Fixed Navbar'), 'description': _('The navbar position is fixed to the top of the screen'), diff --git a/InvenTree/common/tests.py b/InvenTree/common/tests.py index a8948fd29d..e2966fb8d5 100644 --- a/InvenTree/common/tests.py +++ b/InvenTree/common/tests.py @@ -222,8 +222,8 @@ class UserSettingsApiTest(InvenTreeAPITestCase): Test list URL for user settings """ url = reverse('api-user-setting-list') - # test setting with choice - response = self.get(url, expected_code=200) + + self.get(url, expected_code=200) def test_user_setting_boolean(self): """ @@ -293,7 +293,7 @@ class UserSettingsApiTest(InvenTreeAPITestCase): self.assertFalse(str2bool(response.data['value'])) def test_user_setting_choice(self): - + setting = InvenTreeUserSetting.get_setting_object( 'DATE_DISPLAY_FORMAT', user=self.user @@ -303,10 +303,10 @@ class UserSettingsApiTest(InvenTreeAPITestCase): # Check default value self.assertEqual(setting.value, 'YYYY-MM-DD') - + # Check that a valid option can be assigned via the API for opt in ['YYYY-MM-DD', 'DD-MM-YYYY', 'MM/DD/YYYY']: - + self.patch( url, { @@ -332,7 +332,7 @@ class UserSettingsApiTest(InvenTreeAPITestCase): self.assertIn('Chosen value is not a valid option', str(response.data)) def test_user_setting_integer(self): - + setting = InvenTreeUserSetting.get_setting_object( 'SEARCH_PREVIEW_RESULTS', user=self.user From 526571c062cb0139c413bea26f1159a0c7425f0c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 22:50:56 +1000 Subject: [PATCH 14/15] Prevent recursion --- InvenTree/common/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index a6ddbd5a96..89febf3713 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -407,7 +407,11 @@ class BaseInvenTreeSetting(models.Model): super().clean() # Encode as native values - self.value = self.to_native_value() + if self.is_int(): + self.value = self.as_int() + + elif self.is_bool(): + self.value = self.as_bool() validator = self.__class__.get_setting_validator(self.key, **kwargs) From 8635cb82675fc5219d019a0bb9ca0640c1c0aef4 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 1 May 2022 23:21:49 +1000 Subject: [PATCH 15/15] Fix CI --- .github/workflows/translations.yml | 58 ++++++++++++++---------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/.github/workflows/translations.yml b/.github/workflows/translations.yml index 044187e135..108bee2132 100644 --- a/.github/workflows/translations.yml +++ b/.github/workflows/translations.yml @@ -19,34 +19,30 @@ jobs: INVENTREE_STATIC_ROOT: ./static steps: - - uses: actions/checkout@v2 - - name: Get Current Translations - run: | - git fetch - git checkout origin/l10 -- `git ls-tree origin/l10 -r --name-only | grep ".po"` - git reset - - name: Set up Python 3.7 - uses: actions/setup-python@v1 - with: - python-version: 3.7 - - name: Install Dependencies - run: | - sudo apt-get update - sudo apt-get install -y gettext - pip3 install invoke - invoke install - - name: Make Translations - run: | - invoke translate - - name: Commit files - run: | - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot]" - git checkout -b l10_local - git add "*.po" - git commit -m "updated translation base" - - name: Push changes - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - branch: l10 + - name: Checkout Code + uses: actions/checkout@v2 + - name: Set up Python 3.7 + uses: actions/setup-python@v1 + with: + python-version: 3.7 + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y gettext + pip3 install invoke + invoke install + - name: Make Translations + run: | + invoke translate + - name: Commit files + run: | + git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git checkout -b l10_local + git add "*.po" + git commit -m "updated translation base" + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: l10