100 lines
3.2 KiB
Python
100 lines
3.2 KiB
Python
"""
|
|
Bedrijfslogica rond modules: status uitlezen en veilig aan/uit zetten,
|
|
met respect voor onderlinge afhankelijkheden.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from .models import ModuleState
|
|
from .registry import ModuleSpec, registry
|
|
|
|
|
|
class ModuleError(Exception):
|
|
"""Een aan/uit-actie is niet toegestaan."""
|
|
|
|
|
|
def _state_map() -> dict[str, bool]:
|
|
return {s.key: s.enabled for s in ModuleState.objects.all()}
|
|
|
|
|
|
def is_enabled(key: str) -> bool:
|
|
spec = registry.get(key)
|
|
if spec is None:
|
|
return False
|
|
if spec.core:
|
|
return True
|
|
state = ModuleState.objects.filter(key=key).first()
|
|
return bool(state and state.enabled)
|
|
|
|
|
|
def sync_states() -> None:
|
|
"""Zorg dat elke geregistreerde module een rij in de database heeft."""
|
|
existing = set(ModuleState.objects.values_list("key", flat=True))
|
|
for spec in registry.all():
|
|
if spec.core:
|
|
continue
|
|
if spec.key not in existing:
|
|
ModuleState.objects.create(key=spec.key, enabled=spec.default_enabled)
|
|
|
|
|
|
def describe_all() -> list[dict]:
|
|
"""Alle modules met metadata + actuele status, voor de API/het beheerscherm."""
|
|
states = _state_map()
|
|
result: list[dict] = []
|
|
for spec in registry.all():
|
|
enabled = True if spec.core else states.get(spec.key, spec.default_enabled)
|
|
result.append(
|
|
{
|
|
"key": spec.key,
|
|
"name": spec.name,
|
|
"description": spec.description,
|
|
"version": spec.version,
|
|
"category": spec.category,
|
|
"core": spec.core,
|
|
"enabled": enabled,
|
|
"depends_on": list(spec.depends_on),
|
|
"menu_items": [
|
|
{
|
|
"label": m.label,
|
|
"path": m.path,
|
|
"icon": m.icon,
|
|
"order": m.order,
|
|
}
|
|
for m in spec.menu_items
|
|
]
|
|
if enabled
|
|
else [],
|
|
}
|
|
)
|
|
return result
|
|
|
|
|
|
def set_enabled(key: str, enabled: bool) -> ModuleSpec:
|
|
"""Zet een module aan of uit, met controle op afhankelijkheden."""
|
|
spec = registry.get(key)
|
|
if spec is None:
|
|
raise ModuleError(f"Onbekende module: {key}")
|
|
if spec.core:
|
|
raise ModuleError(f"Kernmodule '{key}' kan niet worden uitgeschakeld.")
|
|
|
|
if enabled:
|
|
# Vereiste modules moeten ook aan staan.
|
|
for dep in spec.depends_on:
|
|
if not is_enabled(dep):
|
|
dep_spec = registry.get(dep)
|
|
dep_name = dep_spec.name if dep_spec else dep
|
|
raise ModuleError(
|
|
f"Module '{spec.name}' vereist eerst '{dep_name}'."
|
|
)
|
|
else:
|
|
# Modules die hiervan afhangen mogen niet meer aan staan.
|
|
for dependent in registry.dependents_of(key):
|
|
if is_enabled(dependent.key):
|
|
raise ModuleError(
|
|
f"'{dependent.name}' heeft '{spec.name}' nodig; "
|
|
f"schakel die eerst uit."
|
|
)
|
|
|
|
state, _ = ModuleState.objects.get_or_create(key=key)
|
|
state.enabled = enabled
|
|
state.save(update_fields=["enabled", "updated_at"])
|
|
return spec
|