Skip to content
Snippets Groups Projects
Verified Commit 1c7b6eee authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Allow overriding settings from trusted (official) apps

parent 39621c77
No related branches found
Tags 2.8.1.dev0
1 merge request!993Resolve "Allow overriding settings in trusted apps"
Pipeline #59442 passed
...@@ -9,6 +9,11 @@ and this project adheres to `Semantic Versioning`_. ...@@ -9,6 +9,11 @@ and this project adheres to `Semantic Versioning`_.
Unreleased Unreleased
---------- ----------
Changed
~~~~~~~
* Official apps can now override any setting
`2.8`_ - 2022-03-11 `2.8`_ - 2022-03-11
------------------- -------------------
......
...@@ -7,7 +7,12 @@ from django.utils.translation import gettext_lazy as _ ...@@ -7,7 +7,12 @@ from django.utils.translation import gettext_lazy as _
from dynaconf import LazySettings from dynaconf import LazySettings
from .util.core_helpers import get_app_packages, merge_app_settings, monkey_patch from .util.core_helpers import (
get_app_packages,
get_app_settings_overrides,
merge_app_settings,
monkey_patch,
)
monkey_patch() monkey_patch()
...@@ -1007,3 +1012,5 @@ merge_app_settings("SHELL_PLUS_DONT_LOAD", SHELL_PLUS_DONT_LOAD) ...@@ -1007,3 +1012,5 @@ merge_app_settings("SHELL_PLUS_DONT_LOAD", SHELL_PLUS_DONT_LOAD)
# Add django-cleanup after all apps to ensure that it gets all signals as last app # Add django-cleanup after all apps to ensure that it gets all signals as last app
INSTALLED_APPS.append("django_cleanup.apps.CleanupConfig") INSTALLED_APPS.append("django_cleanup.apps.CleanupConfig")
locals().update(get_app_settings_overrides())
...@@ -3,6 +3,7 @@ from datetime import datetime, timedelta ...@@ -3,6 +3,7 @@ from datetime import datetime, timedelta
from importlib import import_module, metadata from importlib import import_module, metadata
from itertools import groupby from itertools import groupby
from operator import itemgetter from operator import itemgetter
from types import ModuleType
from typing import Any, Callable, Dict, Optional, Sequence, Union from typing import Any, Callable, Dict, Optional, Sequence, Union
from warnings import warn from warnings import warn
...@@ -59,9 +60,31 @@ def dt_show_toolbar(request: HttpRequest) -> bool: ...@@ -59,9 +60,31 @@ def dt_show_toolbar(request: HttpRequest) -> bool:
return False return False
def get_app_packages() -> Sequence[str]: def get_app_packages(only_official: bool = False) -> Sequence[str]:
"""Find all registered apps from the setuptools entrypoint.""" """Find all registered apps from the setuptools entrypoint."""
return [f"{ep.module}.{ep.attr}" for ep in metadata.entry_points().get("aleksis.app", [])] apps = []
for ep in metadata.entry_points().get("aleksis.app", []):
path = f"{ep.module}.{ep.attr}"
if path.startswith("aleksis.apps.") or not only_official:
apps.append(path)
return apps
def get_app_settings_module(app: str) -> Optional[ModuleType]:
"""Get the settings module of an app."""
pkg = ".".join(app.split(".")[:-2])
mod_settings = None
while "." in pkg:
try:
return import_module(pkg + ".settings")
except ImportError:
# Import errors are non-fatal.
pkg = ".".join(pkg.split(".")[:-1])
# The app does not have settings
return None
def merge_app_settings( def merge_app_settings(
...@@ -77,18 +100,8 @@ def merge_app_settings( ...@@ -77,18 +100,8 @@ def merge_app_settings(
potentially malicious apps! potentially malicious apps!
""" """
for app in get_app_packages(): for app in get_app_packages():
pkg = ".".join(app.split(".")[:-2]) mod_settings = get_app_settings_module(app)
mod_settings = None
while "." in pkg:
try:
mod_settings = import_module(pkg + ".settings")
except ImportError:
# Import errors are non-fatal.
pkg = ".".join(pkg.split(".")[:-1])
continue
break
if not mod_settings: if not mod_settings:
# The app does not have settings
continue continue
app_setting = getattr(mod_settings, setting, None) app_setting = getattr(mod_settings, setting, None)
...@@ -109,6 +122,26 @@ def merge_app_settings( ...@@ -109,6 +122,26 @@ def merge_app_settings(
raise TypeError("Only dict and list settings can be merged.") raise TypeError("Only dict and list settings can be merged.")
def get_app_settings_overrides() -> dict[str, Any]:
"""Get app settings overrides.
Official apps (those under the ``aleksis.apps` namespace) can override
or add settings by listing them in their ``settings.overrides``.
"""
overrides = {}
for app in get_app_packages(True):
mod_settings = get_app_settings_module(app)
if not mod_settings:
continue
if hasattr(mod_settings, "overrides"):
for name in mod_settings.overrides:
overrides[name] = getattr(mod_settings, name)
return overrides
def get_site_preferences(): def get_site_preferences():
"""Get the preferences manager of the current site.""" """Get the preferences manager of the current site."""
from django.contrib.sites.models import Site # noqa from django.contrib.sites.models import Site # noqa
......
...@@ -3,9 +3,15 @@ Merging of app settings ...@@ -3,9 +3,15 @@ Merging of app settings
AlekSIS provides features to merge app settings into main ``settings.py``. AlekSIS provides features to merge app settings into main ``settings.py``.
Third-party apps can only add values to some select existing settings.
Official apps (those under the ``aleksis.apps.`` namespace) can mark any
setting for overriding.
Currently mergable settings Currently mergable settings
--------------------------- ---------------------------
The following settings can be amended by any app:
* INSTALLED_APPS * INSTALLED_APPS
* DATABASES * DATABASES
* YARN_INSTALLED_APPS * YARN_INSTALLED_APPS
...@@ -24,3 +30,13 @@ the following into your ``settings.py``:: ...@@ -24,3 +30,13 @@ the following into your ``settings.py``::
"PORT": 5432, "PORT": 5432,
} }
} }
Overriding any setting
----------------------
Official apps only (currently) can override any setting, but need to explicitly
mark it by listing it in a list called ``overrides`` in their ``settings.py``::
PAYMENT_MODEL = "tezor.Invoice"
overrides = ["PAYMENT_MODEL"]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment