config: rework get method

This commit is contained in:
axolotle 2023-04-18 16:11:14 +02:00
parent 80dbd6dac4
commit a92e22b653
3 changed files with 62 additions and 86 deletions

View file

@ -652,22 +652,9 @@ class DomainConfigPanel(ConfigPanel):
save_path_tpl = f"{DOMAIN_SETTINGS_DIR}/{{entity}}.yml"
save_mode = "diff"
def get(self, key="", mode="classic"):
result = super().get(key=key, mode=mode)
if mode == "full":
for panel, section, option in self._iterate():
# This injects:
# i18n: domain_config_cert_renew_help
# i18n: domain_config_default_app_help
# i18n: domain_config_xmpp_help
if m18n.key_exists(self.config["i18n"] + "_" + option["id"] + "_help"):
option["help"] = m18n.n(
self.config["i18n"] + "_" + option["id"] + "_help"
)
return self.config
return result
# i18n: domain_config_cert_renew_help
# i18n: domain_config_default_app_help
# i18n: domain_config_xmpp_help
def _get_raw_config(self) -> "RawConfig":
# TODO add mechanism to share some settings with other domains on the same zone

View file

@ -19,7 +19,7 @@
import os
import subprocess
from logging import getLogger
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any, Union
from moulinette import m18n
from yunohost.utils.error import YunohostError, YunohostValidationError
@ -31,7 +31,12 @@ from yunohost.log import is_unit_operation
from yunohost.utils.legacy import translate_legacy_settings_to_configpanel_settings
if TYPE_CHECKING:
from yunohost.utils.configpanel import ConfigPanelModel, RawConfig, RawSettings
from yunohost.utils.configpanel import (
ConfigPanelGetMode,
ConfigPanelModel,
RawConfig,
RawSettings,
)
logger = getLogger("yunohost.settings")
@ -129,17 +134,11 @@ class SettingsConfigPanel(ConfigPanel):
def __init__(self, config_path=None, save_path=None, creation=False):
super().__init__("settings")
def get(self, key="", mode="classic"):
def get(
self, key: Union[str, None] = None, mode: "ConfigPanelGetMode" = "classic"
) -> Any:
result = super().get(key=key, mode=mode)
if mode == "full":
for panel, section, option in self._iterate():
if m18n.key_exists(self.config["i18n"] + "_" + option["id"] + "_help"):
option["help"] = m18n.n(
self.config["i18n"] + "_" + option["id"] + "_help"
)
return self.config
# Dirty hack to let settings_get() to work from a python script
if isinstance(result, str) and result in ["True", "False"]:
result = bool(result == "True")

View file

@ -31,6 +31,7 @@ from moulinette.interfaces.cli import colorize
from moulinette.utils.filesystem import mkdir, read_toml, read_yaml, write_to_yaml
from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.utils.form import (
AnyOption,
BaseInputOption,
BaseOption,
BaseReadonlyOption,
@ -190,6 +191,13 @@ class ConfigPanelModel(BaseModel):
for option in section.options:
yield option
def get_option(self, option_id) -> Union[AnyOption, None]:
for option in self.options:
if option.id == option_id:
return option
# FIXME raise error?
return None
def iter_children(
self,
@ -236,6 +244,7 @@ if TYPE_CHECKING:
FilterKey = Sequence[Union[str, None]]
RawConfig = OrderedDict[str, Any]
RawSettings = dict[str, Any]
ConfigPanelGetMode = Literal["classic", "full", "export"]
def parse_filter_key(key: Union[str, None] = None) -> "FilterKey":
@ -310,78 +319,59 @@ class ConfigPanel:
and re.match("^(validate|post_ask)__", func)
}
def get(self, key="", mode="classic"):
self.filter_key = key or ""
def get(
self, key: Union[str, None] = None, mode: "ConfigPanelGetMode" = "classic"
) -> Any:
self.filter_key = parse_filter_key(key)
self.config, self.form = self._get_config_panel(prevalidate=False)
# Read config panel toml
self._get_config_panel()
if not self.config:
raise YunohostValidationError("config_no_panel")
# Read or get values and hydrate the config
self._get_raw_settings()
self._hydrate()
panel_id, section_id, option_id = self.filter_key
# In 'classic' mode, we display the current value if key refer to an option
if self.filter_key.count(".") == 2 and mode == "classic":
option = self.filter_key.split(".")[-1]
value = self.values.get(option, None)
if option_id and mode == "classic":
option = self.config.get_option(option_id)
option_type = None
for _, _, option_ in self._iterate():
if option_["id"] == option:
option_type = OPTIONS[option_["type"]]
break
if option is None:
# FIXME i18n
raise YunohostValidationError(
f"Couldn't find any option with id {option_id}"
)
return option_type.normalize(value) if option_type else value
if isinstance(option, BaseReadonlyOption):
return None
return self.form[option_id]
# Format result in 'classic' or 'export' mode
self.config.translate()
logger.debug(f"Formating result in '{mode}' mode")
result = {}
for panel, section, option in self._iterate():
if section["is_action_section"] and mode != "full":
continue
result = OrderedDict()
for panel in self.config.panels:
for section in panel.sections:
if section.is_action_section and mode != "full":
continue
key = f"{panel['id']}.{section['id']}.{option['id']}"
if mode == "export":
result[option["id"]] = option.get("current_value")
continue
for option in section.options:
if mode == "export":
if isinstance(option, BaseInputOption):
result[option.id] = self.form[option.id]
continue
ask = None
if "ask" in option:
ask = _value_for_locale(option["ask"])
elif "i18n" in self.config:
ask = m18n.n(self.config["i18n"] + "_" + option["id"])
if mode == "classic":
key = f"{panel.id}.{section.id}.{option.id}"
result[key] = {"ask": option.ask}
if mode == "full":
option["ask"] = ask
question_class = OPTIONS[option.get("type", OptionType.string)]
# FIXME : maybe other properties should be taken from the question, not just choices ?.
if issubclass(question_class, BaseChoicesOption):
option["choices"] = question_class(option).choices
if issubclass(question_class, BaseInputOption):
option["default"] = question_class(option).default
option["pattern"] = question_class(option).pattern
else:
result[key] = {"ask": ask}
if "current_value" in option:
question_class = OPTIONS[option.get("type", OptionType.string)]
if hasattr(question_class, "humanize"):
result[key]["value"] = question_class.humanize(
option["current_value"], option
)
else:
result[key]["value"] = option["current_value"]
# FIXME: semantics, technically here this is not about a prompt...
if getattr(question_class, "hide_user_input_in_prompt", None):
result[key][
"value"
] = "**************" # Prevent displaying password in `config get`
if isinstance(option, BaseInputOption):
result[key]["value"] = option.humanize(
self.form[option.id], option
)
if option.type is OptionType.password:
result[key][
"value"
] = "**************" # Prevent displaying password in `config get`
if mode == "full":
return self.config
return self.config.dict(exclude_none=True)
else:
return result