diff --git a/README.md b/README.md index e6661c0c606f970aa6ea31c139883c09e05de637..ff9a71490304b76ded5b84d5f9ff011e7a894400 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,13 @@ hook-pre-app = exec:FLASK_APP=uffd flask db upgrade tabs. +## Config + +Uffd reads its default config from `uffd/default_config.cfg`. +You can overwrite config variables by creating a config file in the `instance` folder. +The file must be named `conifg.cfg` (Python syntax), `config.json` or `config.yml`/`config.yaml`. +You can also set a custom file name with the environment variable `CONFIG_FILENAME`. + ## Bind with service account or as user? Uffd can use a dedicated service account for LDAP operations by setting `LDAP_SERVICE_BIND_DN`. @@ -70,7 +77,6 @@ Or set `LDAP_SERVICE_USER_BIND` to use the credentials of the currently logged i If you choose to run with user credentials, some features are not available, like password resets or self signup, since in both cases, no user credentials can exist. - ## OAuth2 Single-Sign-On Provider Other services can use uffd as an OAuth2.0-based authentication provider. diff --git a/uffd/__init__.py b/uffd/__init__.py index 0ea45a235ca02783d804563e7add1dc6306f71c1..05ace003ef3fd8d7fffc2baf134aa264b4e616ac 100644 --- a/uffd/__init__.py +++ b/uffd/__init__.py @@ -18,6 +18,24 @@ from uffd.template_helper import register_template_helper from uffd.navbar import setup_navbar # pylint: enable=wrong-import-position +def load_config_file(app, cfg_name, silent=False): + cfg_path = os.path.join(app.instance_path, cfg_name) + if not os.path.exists(cfg_path): + if not silent: + raise Exception(f"Config file {cfg_path} not found") + return False + + if cfg_path.endswith(".json"): + app.config.from_json(cfg_path) + elif cfg_path.endswith(".yaml") or cfg_path.endswith(".yml"): + import yaml # pylint: disable=import-outside-toplevel disable=import-error + with open(cfg_path, encoding='utf-8') as ymlfile: + data = yaml.safe_load(ymlfile) + app.config.from_mapping(data) + else: + app.config.from_pyfile(cfg_path, silent=True) + return True + def create_app(test_config=None): # pylint: disable=too-many-locals # create and configure the app app = Flask(__name__, instance_relative_config=False) @@ -30,16 +48,19 @@ def create_app(test_config=None): # pylint: disable=too-many-locals ) app.config.from_pyfile('default_config.cfg') + # load config + if test_config is not None: + app.config.from_mapping(test_config) + elif os.environ.get("CONFIG_FILENAME"): + load_config_file(app, os.environ["CONFIG_FILENAME"], silent=False) + else: + for cfg_name in ["config.cfg", "config.json", "config.yml", "config.yaml"]: + if load_config_file(app, cfg_name, silent=True): + break + register_template_helper(app) setup_navbar(app) - if not test_config: - # load the instance config, if it exists, when not testing - app.config.from_pyfile(os.path.join(app.instance_path, 'config.cfg'), silent=True) - else: - # load the test config if passed in - app.config.from_mapping(test_config) - # ensure the instance folder exists try: os.makedirs(app.instance_path)