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
No related merge requests found
......@@ -9,6 +9,11 @@ and this project adheres to `Semantic Versioning`_.
Unreleased
----------
Changed
~~~~~~~
* Official apps can now override any setting
`2.8`_ - 2022-03-11
-------------------
......
......@@ -7,7 +7,12 @@ from django.utils.translation import gettext_lazy as _
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()
......@@ -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
INSTALLED_APPS.append("django_cleanup.apps.CleanupConfig")
locals().update(get_app_settings_overrides())
......@@ -3,6 +3,7 @@ from datetime import datetime, timedelta
from importlib import import_module, metadata
from itertools import groupby
from operator import itemgetter
from types import ModuleType
from typing import Any, Callable, Dict, Optional, Sequence, Union
from warnings import warn
......@@ -59,9 +60,31 @@ def dt_show_toolbar(request: HttpRequest) -> bool:
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."""
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(
......@@ -77,18 +100,8 @@ def merge_app_settings(
potentially malicious apps!
"""
for app in get_app_packages():
pkg = ".".join(app.split(".")[:-2])
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
mod_settings = get_app_settings_module(app)
if not mod_settings:
# The app does not have settings
continue
app_setting = getattr(mod_settings, setting, None)
......@@ -109,6 +122,26 @@ def merge_app_settings(
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():
"""Get the preferences manager of the current site."""
from django.contrib.sites.models import Site # noqa
......
......@@ -3,9 +3,15 @@ Merging of app settings
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
---------------------------
The following settings can be amended by any app:
* INSTALLED_APPS
* DATABASES
* YARN_INSTALLED_APPS
......@@ -24,3 +30,13 @@ the following into your ``settings.py``::
"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