From 31f40454652077c0d4b2af2b6f2227f0fce2f3f8 Mon Sep 17 00:00:00 2001 From: Philipp Fruck Date: Thu, 2 Mar 2023 23:47:15 +0000 Subject: [PATCH] Fix parsing dict variables from env (#4438) * fix parsing dict variables from env The INVENTREE_SOCIAL_PROVIDERS variable has been parsed as a string from the environment which resulted in an attribute error as dict was the expected variable type. To circumvent this error, parsing JSON strings as dictionary values from the environment has been added * add unit tests for env typecasting to dict --- InvenTree/InvenTree/config.py | 27 +++++++++++++++++++++++++++ InvenTree/InvenTree/settings.py | 5 +---- InvenTree/InvenTree/tests.py | 11 +++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) 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."""