mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
update settings.py to new config panel
This commit is contained in:
parent
da079bcaaf
commit
807f5956ea
3 changed files with 81 additions and 72 deletions
|
@ -1207,6 +1207,7 @@ settings:
|
||||||
arguments:
|
arguments:
|
||||||
key:
|
key:
|
||||||
help: Settings key
|
help: Settings key
|
||||||
|
nargs: '?'
|
||||||
-f:
|
-f:
|
||||||
full: --full
|
full: --full
|
||||||
help: Display all details (meant to be used by the API)
|
help: Display all details (meant to be used by the API)
|
||||||
|
|
|
@ -73,7 +73,6 @@ name = "Security"
|
||||||
type = "tags"
|
type = "tags"
|
||||||
visible = "webadmin_allowlist_enabled"
|
visible = "webadmin_allowlist_enabled"
|
||||||
optional = true
|
optional = true
|
||||||
default = ""
|
|
||||||
|
|
||||||
[security.root_access]
|
[security.root_access]
|
||||||
name = "Change root password"
|
name = "Change root password"
|
||||||
|
@ -107,7 +106,7 @@ name = "Email"
|
||||||
[email.pop3.pop3_enabled]
|
[email.pop3.pop3_enabled]
|
||||||
type = "boolean"
|
type = "boolean"
|
||||||
default = false
|
default = false
|
||||||
|
|
||||||
[email.smtp]
|
[email.smtp]
|
||||||
name = "SMTP"
|
name = "SMTP"
|
||||||
[email.smtp.smtp_allow_ipv6]
|
[email.smtp.smtp_allow_ipv6]
|
||||||
|
@ -117,7 +116,7 @@ name = "Email"
|
||||||
[email.smtp.smtp_relay_enabled]
|
[email.smtp.smtp_relay_enabled]
|
||||||
type = "boolean"
|
type = "boolean"
|
||||||
default = false
|
default = false
|
||||||
|
|
||||||
[email.smtp.smtp_relay_host]
|
[email.smtp.smtp_relay_host]
|
||||||
type = "string"
|
type = "string"
|
||||||
default = ""
|
default = ""
|
||||||
|
@ -134,7 +133,7 @@ name = "Email"
|
||||||
default = ""
|
default = ""
|
||||||
optional = true
|
optional = true
|
||||||
visible="smtp_relay_enabled"
|
visible="smtp_relay_enabled"
|
||||||
|
|
||||||
[email.smtp.smtp_relay_password]
|
[email.smtp.smtp_relay_password]
|
||||||
type = "password"
|
type = "password"
|
||||||
default = ""
|
default = ""
|
||||||
|
|
145
src/settings.py
145
src/settings.py
|
@ -18,22 +18,27 @@
|
||||||
#
|
#
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from typing import TYPE_CHECKING, Any, Union
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.utils.config import ConfigPanel, Question
|
from yunohost.utils.configpanel import Config
|
||||||
|
from yunohost.utils.config import Question
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from yunohost.regenconf import regen_conf
|
from yunohost.regenconf import regen_conf
|
||||||
from yunohost.firewall import firewall_reload
|
from yunohost.firewall import firewall_reload
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
from yunohost.utils.legacy import translate_legacy_settings_to_configpanel_settings
|
from yunohost.utils.legacy import translate_legacy_settings_to_configpanel_settings
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from yunohost.utils.configpanel import ConfigPanel, YunoForm
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.settings")
|
logger = getActionLogger("yunohost.settings")
|
||||||
|
|
||||||
SETTINGS_PATH = "/etc/yunohost/settings.yml"
|
SETTINGS_PATH = "/etc/yunohost/settings.yml"
|
||||||
|
|
||||||
|
|
||||||
def settings_get(key="", full=False, export=False):
|
def settings_get(key=None, full=False, export=False):
|
||||||
"""
|
"""
|
||||||
Get an entry value in the settings
|
Get an entry value in the settings
|
||||||
|
|
||||||
|
@ -54,7 +59,8 @@ def settings_get(key="", full=False, export=False):
|
||||||
mode = "classic"
|
mode = "classic"
|
||||||
|
|
||||||
settings = SettingsConfigPanel()
|
settings = SettingsConfigPanel()
|
||||||
key = translate_legacy_settings_to_configpanel_settings(key)
|
if key:
|
||||||
|
key = translate_legacy_settings_to_configpanel_settings(key)
|
||||||
return settings.get(key, mode)
|
return settings.get(key, mode)
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,30 +121,60 @@ def settings_reset_all(operation_logger):
|
||||||
return settings.reset(operation_logger=operation_logger)
|
return settings.reset(operation_logger=operation_logger)
|
||||||
|
|
||||||
|
|
||||||
class SettingsConfigPanel(ConfigPanel):
|
class SettingsConfigPanel(Config):
|
||||||
entity_type = "global"
|
entity_type = "global"
|
||||||
save_path_tpl = SETTINGS_PATH
|
save_path_tpl = SETTINGS_PATH
|
||||||
save_mode = "diff"
|
save_mode = "diff"
|
||||||
virtual_settings = ["root_password", "root_password_confirm", "passwordless_sudo"]
|
virtual_settings = {"root_password", "root_password_confirm", "passwordless_sudo"}
|
||||||
|
|
||||||
def __init__(self, config_path=None, save_path=None, creation=False):
|
def __init__(self, config_path=None, save_path=None, creation=False):
|
||||||
super().__init__("settings")
|
super().__init__("settings")
|
||||||
|
|
||||||
def _apply(self):
|
def _get_config_data(
|
||||||
root_password = self.new_values.pop("root_password", None)
|
self,
|
||||||
root_password_confirm = self.new_values.pop("root_password_confirm", None)
|
panel_id: Union[str, None] = None,
|
||||||
passwordless_sudo = self.new_values.pop("passwordless_sudo", None)
|
section_id: Union[str, None] = None,
|
||||||
|
option_id: Union[str, None] = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
config_data = super()._get_config_data(panel_id, section_id, option_id)
|
||||||
|
|
||||||
self.values = {
|
# Dynamic choice list for portal themes
|
||||||
k: v for k, v in self.values.items() if k not in self.virtual_settings
|
THEMEDIR = "/usr/share/ssowat/portal/assets/themes/"
|
||||||
}
|
try:
|
||||||
self.new_values = {
|
themes = [d for d in os.listdir(THEMEDIR) if os.path.isdir(THEMEDIR + d)]
|
||||||
k: v for k, v in self.new_values.items() if k not in self.virtual_settings
|
except Exception:
|
||||||
}
|
themes = ["unsplash", "vapor", "light", "default", "clouds"]
|
||||||
|
config_data["misc"]["portal"]["portal_theme"]["choices"] = themes
|
||||||
|
|
||||||
assert all(v not in self.future_values for v in self.virtual_settings)
|
return config_data
|
||||||
|
|
||||||
if root_password and root_password.strip():
|
def _get_settings_data(self, config: "ConfigPanel"):
|
||||||
|
settings_data = super()._get_settings_data(config)
|
||||||
|
|
||||||
|
# Specific logic for those settings who are "private" settings
|
||||||
|
# and only meant to have a custom setter mapped to tools_rootpw
|
||||||
|
settings_data["root_password"] = ""
|
||||||
|
settings_data["root_password_confirm"] = ""
|
||||||
|
|
||||||
|
# Specific logic for private setting "passwordless_sudo"
|
||||||
|
try:
|
||||||
|
from yunohost.utils.ldap import _get_ldap_interface
|
||||||
|
|
||||||
|
ldap = _get_ldap_interface()
|
||||||
|
settings_data["passwordless_sudo"] = "!authenticate" in ldap.search(
|
||||||
|
"ou=sudo", "cn=admins", ["sudoOption"]
|
||||||
|
)[0].get("sudoOption", [])
|
||||||
|
except Exception:
|
||||||
|
settings_data["passwordless_sudo"] = False
|
||||||
|
|
||||||
|
return settings_data
|
||||||
|
|
||||||
|
def _apply(self, settings: "YunoForm", exclude=None):
|
||||||
|
root_password = settings.get("root_password", None)
|
||||||
|
root_password_confirm = settings.get("root_password_confirm", None)
|
||||||
|
passwordless_sudo = settings.get("passwordless_sudo", None)
|
||||||
|
|
||||||
|
if root_password is not None:
|
||||||
if root_password != root_password_confirm:
|
if root_password != root_password_confirm:
|
||||||
raise YunohostValidationError("password_confirmation_not_the_same")
|
raise YunohostValidationError("password_confirmation_not_the_same")
|
||||||
|
|
||||||
|
@ -155,70 +191,43 @@ class SettingsConfigPanel(ConfigPanel):
|
||||||
{"sudoOption": ["!authenticate"] if passwordless_sudo else []},
|
{"sudoOption": ["!authenticate"] if passwordless_sudo else []},
|
||||||
)
|
)
|
||||||
|
|
||||||
super()._apply()
|
# First save settings except virtual + default ones
|
||||||
|
super()._apply(settings, exclude=self.virtual_settings)
|
||||||
|
# Then get new values (values that have changed)
|
||||||
|
new_values = settings.dict(exclude=self.virtual_settings, exclude_unset=True)
|
||||||
|
|
||||||
settings = {
|
for setting_name, value in new_values.items():
|
||||||
k: v for k, v in self.future_values.items() if self.values.get(k) != v
|
|
||||||
}
|
|
||||||
for setting_name, value in settings.items():
|
|
||||||
try:
|
try:
|
||||||
|
# FIXME not sure why we need to provide old value?
|
||||||
|
# FIXME save old values
|
||||||
trigger_post_change_hook(
|
trigger_post_change_hook(
|
||||||
setting_name, self.values.get(setting_name), value
|
setting_name, settings[setting_name], value
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Post-change hook for setting failed : {e}")
|
logger.error(f"Post-change hook for setting failed : {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def _get_toml(self):
|
# FIXME Hum translation is auto now and "get" should returns real python types
|
||||||
toml = super()._get_toml()
|
# FIXME probably not needed anymore
|
||||||
|
# def get(self, key="", mode="classic"):
|
||||||
|
# result = super().get(key=key, mode=mode)
|
||||||
|
|
||||||
# Dynamic choice list for portal themes
|
# if mode == "full":
|
||||||
THEMEDIR = "/usr/share/ssowat/portal/assets/themes/"
|
# for panel, section, option in self._iterate():
|
||||||
try:
|
# if m18n.key_exists(self.config["i18n"] + "_" + option["id"] + "_help"):
|
||||||
themes = [d for d in os.listdir(THEMEDIR) if os.path.isdir(THEMEDIR + d)]
|
# option["help"] = m18n.n(
|
||||||
except Exception:
|
# self.config["i18n"] + "_" + option["id"] + "_help"
|
||||||
themes = ["unsplash", "vapor", "light", "default", "clouds"]
|
# )
|
||||||
toml["misc"]["portal"]["portal_theme"]["choices"] = themes
|
# return self.config
|
||||||
|
|
||||||
return toml
|
# # 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")
|
||||||
|
|
||||||
def _load_current_values(self):
|
# return result
|
||||||
super()._load_current_values()
|
|
||||||
|
|
||||||
# Specific logic for those settings who are "virtual" settings
|
|
||||||
# and only meant to have a custom setter mapped to tools_rootpw
|
|
||||||
self.values["root_password"] = ""
|
|
||||||
self.values["root_password_confirm"] = ""
|
|
||||||
|
|
||||||
# Specific logic for virtual setting "passwordless_sudo"
|
|
||||||
try:
|
|
||||||
from yunohost.utils.ldap import _get_ldap_interface
|
|
||||||
|
|
||||||
ldap = _get_ldap_interface()
|
|
||||||
self.values["passwordless_sudo"] = "!authenticate" in ldap.search(
|
|
||||||
"ou=sudo", "cn=admins", ["sudoOption"]
|
|
||||||
)[0].get("sudoOption", [])
|
|
||||||
except Exception:
|
|
||||||
self.values["passwordless_sudo"] = False
|
|
||||||
|
|
||||||
def get(self, key="", mode="classic"):
|
|
||||||
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")
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def reset(self, key="", operation_logger=None):
|
def reset(self, key="", operation_logger=None):
|
||||||
|
# FIXME integrate into base Config
|
||||||
self.filter_key = key
|
self.filter_key = key
|
||||||
|
|
||||||
# Read config panel toml
|
# Read config panel toml
|
||||||
|
|
Loading…
Add table
Reference in a new issue