diff --git a/InvenTree/InvenTree/config.py b/InvenTree/InvenTree/config.py index 703b0097da..720e7bd6eb 100644 --- a/InvenTree/InvenTree/config.py +++ b/InvenTree/InvenTree/config.py @@ -1,6 +1,7 @@ """Helper functions for loading InvenTree configuration options.""" import datetime +import json import logging import os import random @@ -32,6 +33,28 @@ def to_list(value, delimiter=','): return [x.strip() for x in value.split(delimiter)] +def to_dict(value): + """Take a configuration setting and make sure it is a dict. + + For example, we might have a configuration setting taken from the .config file, + which is already an object/dict. + + However, the same setting may be specified via an environment variable, + using a valid JSON string! + """ + if value is None: + return {} + + if type(value) == dict: + return value + + try: + return json.loads(value) + except Exception as error: + logger.error(f"Failed to parse value '{value}' as JSON with error {error}. Ensure value is a valid JSON string.") + return {} + + def is_true(x): """Shortcut function to determine if a value "looks" like a boolean""" return str(x).strip().lower() in ['1', 'y', 'yes', 't', 'true', 'on'] @@ -125,6 +148,10 @@ def get_setting(env_var=None, config_key=None, default_value=None, typecast=None if typecast is list: value = to_list(value) + # Valid JSON string is required + elif typecast is dict: + value = to_dict(value) + elif typecast is not None: # Try to typecast the value try: diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 1bd14925bf..1aab68d5d6 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -816,10 +816,7 @@ SOCIAL_BACKENDS = get_setting('INVENTREE_SOCIAL_BACKENDS', 'social_backends', [] for app in SOCIAL_BACKENDS: INSTALLED_APPS.append(app) # pragma: no cover -SOCIALACCOUNT_PROVIDERS = get_setting('INVENTREE_SOCIAL_PROVIDERS', 'social_providers', None) - -if SOCIALACCOUNT_PROVIDERS is None: - SOCIALACCOUNT_PROVIDERS = {} +SOCIALACCOUNT_PROVIDERS = get_setting('INVENTREE_SOCIAL_PROVIDERS', 'social_providers', None, typecast=dict) SOCIALACCOUNT_STORE_TOKENS = True diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index feb57d6469..23bb69cd53 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -830,6 +830,17 @@ class TestSettings(helpers.InvenTreeTestCase): with self.in_env_context({TEST_ENV_NAME: '321'}): self.assertEqual(config.get_setting(TEST_ENV_NAME, None), '321') + # test typecasting to dict - None should be mapped to empty dict + self.assertEqual(config.get_setting(TEST_ENV_NAME, None, None), {}) + + # test typecasting to dict - valid JSON string should be mapped to corresponding dict + with self.in_env_context({TEST_ENV_NAME: '{"a": 1}'}): + self.assertEqual(config.get_setting(TEST_ENV_NAME, None), {"a": 1}) + + # test typecasting to dict - invalid JSON string should be mapped to empty dict + with self.in_env_context({TEST_ENV_NAME: "{'a': 1}"}): + self.assertEqual(config.get_setting(TEST_ENV_NAME, None), {}) + class TestInstanceName(helpers.InvenTreeTestCase): """Unit tests for instance name."""