mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
perf: improve perf for a bunch of operations by lazy import + lazy define of config-panel related stuff
This commit is contained in:
parent
650c0136f2
commit
3dda3bc4d5
2 changed files with 259 additions and 233 deletions
176
src/app.py
176
src/app.py
|
@ -17,11 +17,11 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import time
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import yaml
|
import yaml
|
||||||
import time
|
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
|
@ -45,13 +45,6 @@ from moulinette.utils.filesystem import (
|
||||||
chmod,
|
chmod,
|
||||||
)
|
)
|
||||||
|
|
||||||
from yunohost.utils.configpanel import ConfigPanel
|
|
||||||
from yunohost.utils.form import (
|
|
||||||
DomainOption,
|
|
||||||
WebPathOption,
|
|
||||||
ask_questions_and_parse_answers,
|
|
||||||
parse_raw_options,
|
|
||||||
)
|
|
||||||
from yunohost.utils.i18n import _value_for_locale
|
from yunohost.utils.i18n import _value_for_locale
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.utils.system import (
|
from yunohost.utils.system import (
|
||||||
|
@ -414,6 +407,7 @@ def app_change_url(operation_logger, app, domain, path):
|
||||||
path -- New path at which the application will be move
|
path -- New path at which the application will be move
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from yunohost.utils.form import DomainOption, WebPathOption
|
||||||
from yunohost.hook import hook_exec_with_script_debug_if_failure, hook_callback
|
from yunohost.hook import hook_exec_with_script_debug_if_failure, hook_callback
|
||||||
from yunohost.service import service_reload_or_restart
|
from yunohost.service import service_reload_or_restart
|
||||||
|
|
||||||
|
@ -964,6 +958,8 @@ def app_upgrade(
|
||||||
|
|
||||||
|
|
||||||
def app_manifest(app, with_screenshot=False):
|
def app_manifest(app, with_screenshot=False):
|
||||||
|
from yunohost.utils.form import parse_raw_options
|
||||||
|
|
||||||
manifest, extracted_app_folder = _extract_app(app)
|
manifest, extracted_app_folder = _extract_app(app)
|
||||||
|
|
||||||
manifest["install"] = parse_raw_options(manifest.get("install", {}), serialize=True)
|
manifest["install"] = parse_raw_options(manifest.get("install", {}), serialize=True)
|
||||||
|
@ -1060,6 +1056,7 @@ def app_install(
|
||||||
)
|
)
|
||||||
from yunohost.regenconf import manually_modified_files
|
from yunohost.regenconf import manually_modified_files
|
||||||
from yunohost.utils.legacy import _patch_legacy_php_versions, _patch_legacy_helpers
|
from yunohost.utils.legacy import _patch_legacy_php_versions, _patch_legacy_helpers
|
||||||
|
from yunohost.utils.form import ask_questions_and_parse_answers
|
||||||
|
|
||||||
# Check if disk space available
|
# Check if disk space available
|
||||||
if free_space_in_directory("/") <= 512 * 1000 * 1000:
|
if free_space_in_directory("/") <= 512 * 1000 * 1000:
|
||||||
|
@ -1393,7 +1390,7 @@ def app_remove(operation_logger, app, purge=False, force_workdir=None):
|
||||||
permission_delete,
|
permission_delete,
|
||||||
permission_sync_to_user,
|
permission_sync_to_user,
|
||||||
)
|
)
|
||||||
from yunohost.domain import domain_list, domain_config_get, domain_config_set
|
from yunohost.domain import domain_list, domain_config_set, _get_raw_domain_settings
|
||||||
|
|
||||||
if not _is_installed(app):
|
if not _is_installed(app):
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
|
@ -1471,7 +1468,7 @@ def app_remove(operation_logger, app, purge=False, force_workdir=None):
|
||||||
hook_remove(app)
|
hook_remove(app)
|
||||||
|
|
||||||
for domain in domain_list()["domains"]:
|
for domain in domain_list()["domains"]:
|
||||||
if domain_config_get(domain, "feature.app.default_app") == app:
|
if _get_raw_domain_settings(domain).get("default_app") == app:
|
||||||
domain_config_set(domain, "feature.app.default_app", "_none")
|
domain_config_set(domain, "feature.app.default_app", "_none")
|
||||||
|
|
||||||
if ret == 0:
|
if ret == 0:
|
||||||
|
@ -1572,6 +1569,7 @@ def app_register_url(app, domain, path):
|
||||||
domain -- The domain on which the app should be registered (e.g. your.domain.tld)
|
domain -- The domain on which the app should be registered (e.g. your.domain.tld)
|
||||||
path -- The path to be registered (e.g. /coffee)
|
path -- The path to be registered (e.g. /coffee)
|
||||||
"""
|
"""
|
||||||
|
from yunohost.utils.form import DomainOption, WebPathOption
|
||||||
from yunohost.permission import (
|
from yunohost.permission import (
|
||||||
permission_url,
|
permission_url,
|
||||||
user_permission_update,
|
user_permission_update,
|
||||||
|
@ -1614,7 +1612,7 @@ def app_ssowatconf():
|
||||||
"""
|
"""
|
||||||
from yunohost.domain import (
|
from yunohost.domain import (
|
||||||
domain_list,
|
domain_list,
|
||||||
domain_config_get,
|
_get_raw_domain_settings,
|
||||||
_get_domain_portal_dict,
|
_get_domain_portal_dict,
|
||||||
)
|
)
|
||||||
from yunohost.permission import user_permission_list
|
from yunohost.permission import user_permission_list
|
||||||
|
@ -1654,8 +1652,8 @@ def app_ssowatconf():
|
||||||
# FIXME : this could be handled by nginx's regen conf to further simplify ssowat's code ...
|
# FIXME : this could be handled by nginx's regen conf to further simplify ssowat's code ...
|
||||||
redirected_urls = {}
|
redirected_urls = {}
|
||||||
for domain in domains:
|
for domain in domains:
|
||||||
default_app = domain_config_get(domain, "feature.app.default_app")
|
default_app = _get_raw_domain_settings(domain).get("default_app")
|
||||||
if default_app != "_none" and _is_installed(default_app):
|
if default_app not in ["_none", None] and _is_installed(default_app):
|
||||||
app_settings = _get_app_settings(default_app)
|
app_settings = _get_app_settings(default_app)
|
||||||
app_domain = app_settings["domain"]
|
app_domain = app_settings["domain"]
|
||||||
app_path = app_settings["path"]
|
app_path = app_settings["path"]
|
||||||
|
@ -1753,11 +1751,13 @@ def app_change_label(app, new_label):
|
||||||
|
|
||||||
|
|
||||||
def app_action_list(app):
|
def app_action_list(app):
|
||||||
|
AppConfigPanel = _get_AppConfigPanel()
|
||||||
return AppConfigPanel(app).list_actions()
|
return AppConfigPanel(app).list_actions()
|
||||||
|
|
||||||
|
|
||||||
@is_unit_operation()
|
@is_unit_operation()
|
||||||
def app_action_run(operation_logger, app, action, args=None, args_file=None):
|
def app_action_run(operation_logger, app, action, args=None, args_file=None):
|
||||||
|
AppConfigPanel = _get_AppConfigPanel()
|
||||||
return AppConfigPanel(app).run_action(
|
return AppConfigPanel(app).run_action(
|
||||||
action, args=args, args_file=args_file, operation_logger=operation_logger
|
action, args=args, args_file=args_file, operation_logger=operation_logger
|
||||||
)
|
)
|
||||||
|
@ -1779,6 +1779,7 @@ def app_config_get(app, key="", full=False, export=False):
|
||||||
else:
|
else:
|
||||||
mode = "classic"
|
mode = "classic"
|
||||||
|
|
||||||
|
AppConfigPanel = _get_AppConfigPanel()
|
||||||
try:
|
try:
|
||||||
config_ = AppConfigPanel(app)
|
config_ = AppConfigPanel(app)
|
||||||
return config_.get(key, mode)
|
return config_.get(key, mode)
|
||||||
|
@ -1798,91 +1799,97 @@ def app_config_set(
|
||||||
Apply a new app configuration
|
Apply a new app configuration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
AppConfigPanel = _get_AppConfigPanel()
|
||||||
config_ = AppConfigPanel(app)
|
config_ = AppConfigPanel(app)
|
||||||
|
|
||||||
return config_.set(key, value, args, args_file, operation_logger=operation_logger)
|
return config_.set(key, value, args, args_file, operation_logger=operation_logger)
|
||||||
|
|
||||||
|
|
||||||
class AppConfigPanel(ConfigPanel):
|
def _get_AppConfigPanel():
|
||||||
entity_type = "app"
|
from yunohost.utils.configpanel import ConfigPanel
|
||||||
save_path_tpl = os.path.join(APPS_SETTING_PATH, "{entity}/settings.yml")
|
|
||||||
config_path_tpl = os.path.join(APPS_SETTING_PATH, "{entity}/config_panel.toml")
|
|
||||||
settings_must_be_defined: bool = True
|
|
||||||
|
|
||||||
def _get_raw_settings(self) -> "RawSettings":
|
class AppConfigPanel(ConfigPanel):
|
||||||
return self._call_config_script("show")
|
entity_type = "app"
|
||||||
|
save_path_tpl = os.path.join(APPS_SETTING_PATH, "{entity}/settings.yml")
|
||||||
|
config_path_tpl = os.path.join(APPS_SETTING_PATH, "{entity}/config_panel.toml")
|
||||||
|
settings_must_be_defined: bool = True
|
||||||
|
|
||||||
def _apply(
|
def _get_raw_settings(self) -> "RawSettings":
|
||||||
self,
|
return self._call_config_script("show")
|
||||||
form: "FormModel",
|
|
||||||
previous_settings: dict[str, Any],
|
|
||||||
exclude: Union["AbstractSetIntStr", "MappingIntStrAny", None] = None,
|
|
||||||
) -> None:
|
|
||||||
env = {key: str(value) for key, value in form.dict().items()}
|
|
||||||
return_content = self._call_config_script("apply", env=env)
|
|
||||||
|
|
||||||
# If the script returned validation error
|
def _apply(
|
||||||
# raise a ValidationError exception using
|
self,
|
||||||
# the first key
|
form: "FormModel",
|
||||||
errors = return_content.get("validation_errors")
|
previous_settings: dict[str, Any],
|
||||||
if errors:
|
exclude: Union["AbstractSetIntStr", "MappingIntStrAny", None] = None,
|
||||||
for key, message in errors.items():
|
) -> None:
|
||||||
raise YunohostValidationError(
|
env = {key: str(value) for key, value in form.dict().items()}
|
||||||
"app_argument_invalid",
|
return_content = self._call_config_script("apply", env=env)
|
||||||
name=key,
|
|
||||||
error=message,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _run_action(self, form: "FormModel", action_id: str) -> None:
|
# If the script returned validation error
|
||||||
env = {key: str(value) for key, value in form.dict().items()}
|
# raise a ValidationError exception using
|
||||||
self._call_config_script(action_id, env=env)
|
# the first key
|
||||||
|
errors = return_content.get("validation_errors")
|
||||||
|
if errors:
|
||||||
|
for key, message in errors.items():
|
||||||
|
raise YunohostValidationError(
|
||||||
|
"app_argument_invalid",
|
||||||
|
name=key,
|
||||||
|
error=message,
|
||||||
|
)
|
||||||
|
|
||||||
def _call_config_script(
|
def _run_action(self, form: "FormModel", action_id: str) -> None:
|
||||||
self, action: str, env: Union[dict[str, Any], None] = None
|
env = {key: str(value) for key, value in form.dict().items()}
|
||||||
) -> dict[str, Any]:
|
self._call_config_script(action_id, env=env)
|
||||||
from yunohost.hook import hook_exec
|
|
||||||
|
|
||||||
if env is None:
|
def _call_config_script(
|
||||||
env = {}
|
self, action: str, env: Union[dict[str, Any], None] = None
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
from yunohost.hook import hook_exec
|
||||||
|
|
||||||
# Add default config script if needed
|
if env is None:
|
||||||
config_script = os.path.join(
|
env = {}
|
||||||
APPS_SETTING_PATH, self.entity, "scripts", "config"
|
|
||||||
)
|
|
||||||
if not os.path.exists(config_script):
|
|
||||||
logger.debug("Adding a default config script")
|
|
||||||
default_script = """#!/bin/bash
|
|
||||||
source /usr/share/yunohost/helpers
|
|
||||||
ynh_abort_if_errors
|
|
||||||
ynh_app_config_run $1
|
|
||||||
"""
|
|
||||||
write_to_file(config_script, default_script)
|
|
||||||
|
|
||||||
# Call config script to extract current values
|
# Add default config script if needed
|
||||||
logger.debug(f"Calling '{action}' action from config script")
|
config_script = os.path.join(
|
||||||
app = self.entity
|
APPS_SETTING_PATH, self.entity, "scripts", "config"
|
||||||
app_id, app_instance_nb = _parse_app_instance_name(app)
|
)
|
||||||
settings = _get_app_settings(app)
|
if not os.path.exists(config_script):
|
||||||
env.update(
|
logger.debug("Adding a default config script")
|
||||||
{
|
default_script = """#!/bin/bash
|
||||||
"app_id": app_id,
|
source /usr/share/yunohost/helpers
|
||||||
"app": app,
|
ynh_abort_if_errors
|
||||||
"app_instance_nb": str(app_instance_nb),
|
ynh_app_config_run $1
|
||||||
"final_path": settings.get("final_path", ""),
|
"""
|
||||||
"install_dir": settings.get("install_dir", ""),
|
write_to_file(config_script, default_script)
|
||||||
"YNH_APP_BASEDIR": os.path.join(APPS_SETTING_PATH, app),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
ret, values = hook_exec(config_script, args=[action], env=env)
|
# Call config script to extract current values
|
||||||
if ret != 0:
|
logger.debug(f"Calling '{action}' action from config script")
|
||||||
if action == "show":
|
app = self.entity
|
||||||
raise YunohostError("app_config_unable_to_read")
|
app_id, app_instance_nb = _parse_app_instance_name(app)
|
||||||
elif action == "apply":
|
settings = _get_app_settings(app)
|
||||||
raise YunohostError("app_config_unable_to_apply")
|
env.update(
|
||||||
else:
|
{
|
||||||
raise YunohostError("app_action_failed", action=action, app=app)
|
"app_id": app_id,
|
||||||
return values
|
"app": app,
|
||||||
|
"app_instance_nb": str(app_instance_nb),
|
||||||
|
"final_path": settings.get("final_path", ""),
|
||||||
|
"install_dir": settings.get("install_dir", ""),
|
||||||
|
"YNH_APP_BASEDIR": os.path.join(APPS_SETTING_PATH, app),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
ret, values = hook_exec(config_script, args=[action], env=env)
|
||||||
|
if ret != 0:
|
||||||
|
if action == "show":
|
||||||
|
raise YunohostError("app_config_unable_to_read")
|
||||||
|
elif action == "apply":
|
||||||
|
raise YunohostError("app_config_unable_to_apply")
|
||||||
|
else:
|
||||||
|
raise YunohostError("app_action_failed", action=action, app=app)
|
||||||
|
return values
|
||||||
|
|
||||||
|
return AppConfigPanel
|
||||||
|
|
||||||
|
|
||||||
def _get_app_settings(app):
|
def _get_app_settings(app):
|
||||||
|
@ -2782,6 +2789,7 @@ def _get_conflicting_apps(domain, path, ignore_app=None):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from yunohost.domain import _assert_domain_exists
|
from yunohost.domain import _assert_domain_exists
|
||||||
|
from yunohost.utils.form import DomainOption, WebPathOption
|
||||||
|
|
||||||
domain = DomainOption.normalize(domain)
|
domain = DomainOption.normalize(domain)
|
||||||
path = WebPathOption.normalize(path)
|
path = WebPathOption.normalize(path)
|
||||||
|
|
316
src/domain.py
316
src/domain.py
|
@ -34,17 +34,8 @@ from moulinette.utils.filesystem import (
|
||||||
write_to_yaml,
|
write_to_yaml,
|
||||||
)
|
)
|
||||||
|
|
||||||
from yunohost.app import (
|
|
||||||
app_ssowatconf,
|
|
||||||
_installed_apps,
|
|
||||||
_get_app_settings,
|
|
||||||
_get_conflicting_apps,
|
|
||||||
)
|
|
||||||
from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf
|
from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf
|
||||||
from yunohost.utils.configpanel import ConfigPanel
|
|
||||||
from yunohost.utils.form import BaseOption
|
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.utils.dns import is_yunohost_dyndns_domain
|
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -191,7 +182,7 @@ def domain_info(domain):
|
||||||
domain -- Domain to be checked
|
domain -- Domain to be checked
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from yunohost.app import app_info
|
from yunohost.app import app_info, _installed_apps, _get_app_settings
|
||||||
from yunohost.dns import _get_registar_settings
|
from yunohost.dns import _get_registar_settings
|
||||||
from yunohost.certificate import certificate_status
|
from yunohost.certificate import certificate_status
|
||||||
|
|
||||||
|
@ -268,6 +259,7 @@ def domain_add(
|
||||||
from yunohost.utils.ldap import _get_ldap_interface
|
from yunohost.utils.ldap import _get_ldap_interface
|
||||||
from yunohost.utils.password import assert_password_is_strong_enough
|
from yunohost.utils.password import assert_password_is_strong_enough
|
||||||
from yunohost.certificate import _certificate_install_selfsigned
|
from yunohost.certificate import _certificate_install_selfsigned
|
||||||
|
from yunohost.utils.dns import is_yunohost_dyndns_domain
|
||||||
|
|
||||||
if dyndns_recovery_password:
|
if dyndns_recovery_password:
|
||||||
operation_logger.data_to_redact.append(dyndns_recovery_password)
|
operation_logger.data_to_redact.append(dyndns_recovery_password)
|
||||||
|
@ -383,8 +375,15 @@ def domain_remove(
|
||||||
"""
|
"""
|
||||||
import glob
|
import glob
|
||||||
from yunohost.hook import hook_callback
|
from yunohost.hook import hook_callback
|
||||||
from yunohost.app import app_ssowatconf, app_info, app_remove
|
from yunohost.app import (
|
||||||
|
app_ssowatconf,
|
||||||
|
app_info,
|
||||||
|
app_remove,
|
||||||
|
_get_app_settings,
|
||||||
|
_installed_apps,
|
||||||
|
)
|
||||||
from yunohost.utils.ldap import _get_ldap_interface
|
from yunohost.utils.ldap import _get_ldap_interface
|
||||||
|
from yunohost.utils.dns import is_yunohost_dyndns_domain
|
||||||
|
|
||||||
if dyndns_recovery_password:
|
if dyndns_recovery_password:
|
||||||
operation_logger.data_to_redact.append(dyndns_recovery_password)
|
operation_logger.data_to_redact.append(dyndns_recovery_password)
|
||||||
|
@ -566,6 +565,7 @@ def domain_main_domain(operation_logger, new_main_domain=None):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from yunohost.tools import _set_hostname
|
from yunohost.tools import _set_hostname
|
||||||
|
from yunohost.app import app_ssowatconf
|
||||||
|
|
||||||
# If no new domain specified, we return the current main domain
|
# If no new domain specified, we return the current main domain
|
||||||
if not new_main_domain:
|
if not new_main_domain:
|
||||||
|
@ -614,6 +614,8 @@ def domain_url_available(domain, path):
|
||||||
path -- The path to check (e.g. /coffee)
|
path -- The path to check (e.g. /coffee)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from yunohost.app import _get_conflicting_apps
|
||||||
|
|
||||||
return len(_get_conflicting_apps(domain, path)) == 0
|
return len(_get_conflicting_apps(domain, path)) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -623,7 +625,8 @@ def _get_raw_domain_settings(domain):
|
||||||
so the file may be completely empty
|
so the file may be completely empty
|
||||||
"""
|
"""
|
||||||
_assert_domain_exists(domain)
|
_assert_domain_exists(domain)
|
||||||
path = DomainConfigPanel.save_path_tpl.format(entity=domain)
|
# NB: this corresponds to save_path_tpl in DomainConfigPanel
|
||||||
|
path = f"{DOMAIN_SETTINGS_DIR}/{domain}.yml"
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
return read_yaml(path)
|
return read_yaml(path)
|
||||||
|
|
||||||
|
@ -647,6 +650,7 @@ def domain_config_get(domain, key="", full=False, export=False):
|
||||||
else:
|
else:
|
||||||
mode = "classic"
|
mode = "classic"
|
||||||
|
|
||||||
|
DomainConfigPanel = _get_DomainConfigPanel()
|
||||||
config = DomainConfigPanel(domain)
|
config = DomainConfigPanel(domain)
|
||||||
return config.get(key, mode)
|
return config.get(key, mode)
|
||||||
|
|
||||||
|
@ -658,175 +662,189 @@ def domain_config_set(
|
||||||
"""
|
"""
|
||||||
Apply a new domain configuration
|
Apply a new domain configuration
|
||||||
"""
|
"""
|
||||||
|
from yunohost.utils.form import BaseOption
|
||||||
|
|
||||||
|
DomainConfigPanel = _get_DomainConfigPanel()
|
||||||
BaseOption.operation_logger = operation_logger
|
BaseOption.operation_logger = operation_logger
|
||||||
config = DomainConfigPanel(domain)
|
config = DomainConfigPanel(domain)
|
||||||
return config.set(key, value, args, args_file, operation_logger=operation_logger)
|
return config.set(key, value, args, args_file, operation_logger=operation_logger)
|
||||||
|
|
||||||
|
|
||||||
class DomainConfigPanel(ConfigPanel):
|
def _get_DomainConfigPanel():
|
||||||
entity_type = "domain"
|
from yunohost.utils.configpanel import ConfigPanel
|
||||||
save_path_tpl = f"{DOMAIN_SETTINGS_DIR}/{{entity}}.yml"
|
|
||||||
save_mode = "diff"
|
|
||||||
|
|
||||||
# i18n: domain_config_cert_renew_help
|
class DomainConfigPanel(ConfigPanel):
|
||||||
# i18n: domain_config_default_app_help
|
entity_type = "domain"
|
||||||
# i18n: domain_config_xmpp_help
|
save_path_tpl = f"{DOMAIN_SETTINGS_DIR}/{{entity}}.yml"
|
||||||
|
save_mode = "diff"
|
||||||
|
|
||||||
def _get_raw_config(self) -> "RawConfig":
|
# i18n: domain_config_cert_renew_help
|
||||||
# TODO add mechanism to share some settings with other domains on the same zone
|
# i18n: domain_config_default_app_help
|
||||||
raw_config = super()._get_raw_config()
|
# i18n: domain_config_xmpp_help
|
||||||
|
|
||||||
any_filter = all(self.filter_key)
|
def _get_raw_config(self) -> "RawConfig":
|
||||||
panel_id, section_id, option_id = self.filter_key
|
# TODO add mechanism to share some settings with other domains on the same zone
|
||||||
|
raw_config = super()._get_raw_config()
|
||||||
|
|
||||||
raw_config["feature"]["xmpp"]["xmpp"]["default"] = (
|
any_filter = all(self.filter_key)
|
||||||
1 if self.entity == _get_maindomain() else 0
|
panel_id, section_id, option_id = self.filter_key
|
||||||
)
|
|
||||||
|
|
||||||
# Portal settings are only available on "topest" domains
|
raw_config["feature"]["xmpp"]["xmpp"]["default"] = (
|
||||||
if _get_parent_domain_of(self.entity, topest=True) is not None:
|
1 if self.entity == _get_maindomain() else 0
|
||||||
del raw_config["feature"]["portal"]
|
|
||||||
|
|
||||||
# Optimize wether or not to load the DNS section,
|
|
||||||
# e.g. we don't want to trigger the whole _get_registary_config_section
|
|
||||||
# when just getting the current value from the feature section
|
|
||||||
if not any_filter or panel_id == "dns":
|
|
||||||
from yunohost.dns import _get_registrar_config_section
|
|
||||||
|
|
||||||
raw_config["dns"]["registrar"] = _get_registrar_config_section(self.entity)
|
|
||||||
|
|
||||||
# Cert stuff
|
|
||||||
if not any_filter or panel_id == "cert":
|
|
||||||
from yunohost.certificate import certificate_status
|
|
||||||
|
|
||||||
status = certificate_status([self.entity], full=True)["certificates"][
|
|
||||||
self.entity
|
|
||||||
]
|
|
||||||
|
|
||||||
raw_config["cert"]["cert"]["cert_summary"]["style"] = status["style"]
|
|
||||||
|
|
||||||
# i18n: domain_config_cert_summary_expired
|
|
||||||
# i18n: domain_config_cert_summary_selfsigned
|
|
||||||
# i18n: domain_config_cert_summary_abouttoexpire
|
|
||||||
# i18n: domain_config_cert_summary_ok
|
|
||||||
# i18n: domain_config_cert_summary_letsencrypt
|
|
||||||
raw_config["cert"]["cert"]["cert_summary"]["ask"] = m18n.n(
|
|
||||||
f"domain_config_cert_summary_{status['summary']}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for option_id, status_key in [
|
# Portal settings are only available on "topest" domains
|
||||||
("cert_validity", "validity"),
|
if _get_parent_domain_of(self.entity, topest=True) is not None:
|
||||||
("cert_issuer", "CA_type"),
|
del raw_config["feature"]["portal"]
|
||||||
("acme_eligible", "ACME_eligible"),
|
|
||||||
# FIXME not sure why "summary" was injected in settings values
|
|
||||||
# ("summary", "summary")
|
|
||||||
]:
|
|
||||||
raw_config["cert"]["cert"][option_id]["default"] = status[status_key]
|
|
||||||
|
|
||||||
# Other specific strings used in config panels
|
# Optimize wether or not to load the DNS section,
|
||||||
# i18n: domain_config_cert_renew_help
|
# e.g. we don't want to trigger the whole _get_registary_config_section
|
||||||
|
# when just getting the current value from the feature section
|
||||||
|
if not any_filter or panel_id == "dns":
|
||||||
|
from yunohost.dns import _get_registrar_config_section
|
||||||
|
|
||||||
return raw_config
|
raw_config["dns"]["registrar"] = _get_registrar_config_section(
|
||||||
|
self.entity
|
||||||
def _apply(
|
|
||||||
self,
|
|
||||||
form: "FormModel",
|
|
||||||
previous_settings: dict[str, Any],
|
|
||||||
exclude: Union["AbstractSetIntStr", "MappingIntStrAny", None] = None,
|
|
||||||
) -> None:
|
|
||||||
next_settings = {
|
|
||||||
k: v for k, v in form.dict().items() if previous_settings.get(k) != v
|
|
||||||
}
|
|
||||||
|
|
||||||
if "default_app" in next_settings:
|
|
||||||
from yunohost.app import app_ssowatconf, app_map
|
|
||||||
|
|
||||||
if "/" in app_map(raw=True).get(self.entity, {}):
|
|
||||||
raise YunohostValidationError(
|
|
||||||
"app_make_default_location_already_used",
|
|
||||||
app=next_settings["default_app"],
|
|
||||||
domain=self.entity,
|
|
||||||
other_app=app_map(raw=True)[self.entity]["/"]["id"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if next_settings.get("recovery_password", None):
|
# Cert stuff
|
||||||
domain_dyndns_set_recovery_password(
|
if not any_filter or panel_id == "cert":
|
||||||
self.entity, next_settings["recovery_password"]
|
from yunohost.certificate import certificate_status
|
||||||
)
|
|
||||||
|
|
||||||
portal_options = [
|
status = certificate_status([self.entity], full=True)["certificates"][
|
||||||
"default_app",
|
self.entity
|
||||||
"show_other_domains_apps",
|
]
|
||||||
"portal_title",
|
|
||||||
"portal_logo",
|
|
||||||
"portal_theme",
|
|
||||||
"portal_user_intro",
|
|
||||||
"portal_public_intro",
|
|
||||||
]
|
|
||||||
|
|
||||||
if _get_parent_domain_of(self.entity, topest=True) is None and any(
|
raw_config["cert"]["cert"]["cert_summary"]["style"] = status["style"]
|
||||||
option in next_settings for option in portal_options
|
|
||||||
):
|
|
||||||
from yunohost.portal import PORTAL_SETTINGS_DIR
|
|
||||||
|
|
||||||
# Portal options are also saved in a `domain.portal.yml` file
|
# i18n: domain_config_cert_summary_expired
|
||||||
# that can be read by the portal API.
|
# i18n: domain_config_cert_summary_selfsigned
|
||||||
# FIXME remove those from the config panel saved values?
|
# i18n: domain_config_cert_summary_abouttoexpire
|
||||||
|
# i18n: domain_config_cert_summary_ok
|
||||||
|
# i18n: domain_config_cert_summary_letsencrypt
|
||||||
|
raw_config["cert"]["cert"]["cert_summary"]["ask"] = m18n.n(
|
||||||
|
f"domain_config_cert_summary_{status['summary']}"
|
||||||
|
)
|
||||||
|
|
||||||
portal_values = form.dict(include=set(portal_options))
|
for option_id, status_key in [
|
||||||
# Remove logo from values else filename will replace b64 content
|
("cert_validity", "validity"),
|
||||||
portal_values.pop("portal_logo")
|
("cert_issuer", "CA_type"),
|
||||||
|
("acme_eligible", "ACME_eligible"),
|
||||||
|
# FIXME not sure why "summary" was injected in settings values
|
||||||
|
# ("summary", "summary")
|
||||||
|
]:
|
||||||
|
raw_config["cert"]["cert"][option_id]["default"] = status[
|
||||||
|
status_key
|
||||||
|
]
|
||||||
|
|
||||||
if "portal_logo" in next_settings:
|
# Other specific strings used in config panels
|
||||||
if previous_settings.get("portal_logo"):
|
# i18n: domain_config_cert_renew_help
|
||||||
try:
|
|
||||||
os.remove(previous_settings["portal_logo"])
|
|
||||||
except FileNotFoundError:
|
|
||||||
logger.warning(
|
|
||||||
f"Coulnd't remove previous logo file, maybe the file was already deleted, path: {previous_settings['portal_logo']}"
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
portal_values["portal_logo"] = ""
|
|
||||||
|
|
||||||
if next_settings["portal_logo"]:
|
return raw_config
|
||||||
# Save the file content as `{mimetype}:{base64content}` in portal settings
|
|
||||||
# while keeping the file path in the domain settings
|
|
||||||
from base64 import b64encode
|
|
||||||
from magic import Magic
|
|
||||||
|
|
||||||
file_content = Path(next_settings["portal_logo"]).read_bytes()
|
def _apply(
|
||||||
mimetype = Magic(mime=True).from_buffer(file_content)
|
self,
|
||||||
portal_values["portal_logo"] = (
|
form: "FormModel",
|
||||||
mimetype + ":" + b64encode(file_content).decode("utf-8")
|
previous_settings: dict[str, Any],
|
||||||
|
exclude: Union["AbstractSetIntStr", "MappingIntStrAny", None] = None,
|
||||||
|
) -> None:
|
||||||
|
next_settings = {
|
||||||
|
k: v for k, v in form.dict().items() if previous_settings.get(k) != v
|
||||||
|
}
|
||||||
|
|
||||||
|
if "default_app" in next_settings:
|
||||||
|
from yunohost.app import app_map
|
||||||
|
|
||||||
|
if "/" in app_map(raw=True).get(self.entity, {}):
|
||||||
|
raise YunohostValidationError(
|
||||||
|
"app_make_default_location_already_used",
|
||||||
|
app=next_settings["default_app"],
|
||||||
|
domain=self.entity,
|
||||||
|
other_app=app_map(raw=True)[self.entity]["/"]["id"],
|
||||||
)
|
)
|
||||||
|
|
||||||
portal_settings_path = Path(f"{PORTAL_SETTINGS_DIR}/{self.entity}.json")
|
if next_settings.get("recovery_password", None):
|
||||||
portal_settings: dict[str, Any] = {"apps": {}}
|
domain_dyndns_set_recovery_password(
|
||||||
|
self.entity, next_settings["recovery_password"]
|
||||||
|
)
|
||||||
|
|
||||||
if portal_settings_path.exists():
|
portal_options = [
|
||||||
portal_settings.update(read_json(str(portal_settings_path)))
|
"default_app",
|
||||||
|
"show_other_domains_apps",
|
||||||
|
"portal_title",
|
||||||
|
"portal_logo",
|
||||||
|
"portal_theme",
|
||||||
|
"portal_user_intro",
|
||||||
|
"portal_public_intro",
|
||||||
|
]
|
||||||
|
|
||||||
# Merge settings since this config file is shared with `app_ssowatconf()` which populate the `apps` key.
|
if _get_parent_domain_of(self.entity, topest=True) is None and any(
|
||||||
portal_settings.update(portal_values)
|
option in next_settings for option in portal_options
|
||||||
write_to_json(
|
):
|
||||||
str(portal_settings_path), portal_settings, sort_keys=True, indent=4
|
from yunohost.portal import PORTAL_SETTINGS_DIR
|
||||||
)
|
|
||||||
|
|
||||||
super()._apply(form, previous_settings, exclude={"recovery_password"})
|
# Portal options are also saved in a `domain.portal.yml` file
|
||||||
|
# that can be read by the portal API.
|
||||||
|
# FIXME remove those from the config panel saved values?
|
||||||
|
|
||||||
# Reload ssowat if default app changed
|
portal_values = form.dict(include=set(portal_options))
|
||||||
if "default_app" in next_settings:
|
# Remove logo from values else filename will replace b64 content
|
||||||
app_ssowatconf()
|
portal_values.pop("portal_logo")
|
||||||
|
|
||||||
stuff_to_regen_conf = set()
|
if "portal_logo" in next_settings:
|
||||||
if "xmpp" in next_settings:
|
if previous_settings.get("portal_logo"):
|
||||||
stuff_to_regen_conf.update({"nginx", "metronome"})
|
try:
|
||||||
|
os.remove(previous_settings["portal_logo"])
|
||||||
|
except FileNotFoundError:
|
||||||
|
logger.warning(
|
||||||
|
f"Coulnd't remove previous logo file, maybe the file was already deleted, path: {previous_settings['portal_logo']}"
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
portal_values["portal_logo"] = ""
|
||||||
|
|
||||||
if "mail_in" in next_settings or "mail_out" in next_settings:
|
if next_settings["portal_logo"]:
|
||||||
stuff_to_regen_conf.update({"nginx", "postfix", "dovecot", "rspamd"})
|
# Save the file content as `{mimetype}:{base64content}` in portal settings
|
||||||
|
# while keeping the file path in the domain settings
|
||||||
|
from base64 import b64encode
|
||||||
|
from magic import Magic
|
||||||
|
|
||||||
if stuff_to_regen_conf:
|
file_content = Path(next_settings["portal_logo"]).read_bytes()
|
||||||
regen_conf(names=list(stuff_to_regen_conf))
|
mimetype = Magic(mime=True).from_buffer(file_content)
|
||||||
|
portal_values["portal_logo"] = (
|
||||||
|
mimetype + ":" + b64encode(file_content).decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
portal_settings_path = Path(f"{PORTAL_SETTINGS_DIR}/{self.entity}.json")
|
||||||
|
portal_settings: dict[str, Any] = {"apps": {}}
|
||||||
|
|
||||||
|
if portal_settings_path.exists():
|
||||||
|
portal_settings.update(read_json(str(portal_settings_path)))
|
||||||
|
|
||||||
|
# Merge settings since this config file is shared with `app_ssowatconf()` which populate the `apps` key.
|
||||||
|
portal_settings.update(portal_values)
|
||||||
|
write_to_json(
|
||||||
|
str(portal_settings_path), portal_settings, sort_keys=True, indent=4
|
||||||
|
)
|
||||||
|
|
||||||
|
super()._apply(form, previous_settings, exclude={"recovery_password"})
|
||||||
|
|
||||||
|
# Reload ssowat if default app changed
|
||||||
|
if "default_app" in next_settings:
|
||||||
|
from yunohost.app import app_ssowatconf
|
||||||
|
|
||||||
|
app_ssowatconf()
|
||||||
|
|
||||||
|
stuff_to_regen_conf = set()
|
||||||
|
if "xmpp" in next_settings:
|
||||||
|
stuff_to_regen_conf.update({"nginx", "metronome"})
|
||||||
|
|
||||||
|
if "mail_in" in next_settings or "mail_out" in next_settings:
|
||||||
|
stuff_to_regen_conf.update({"nginx", "postfix", "dovecot", "rspamd"})
|
||||||
|
|
||||||
|
if stuff_to_regen_conf:
|
||||||
|
regen_conf(names=list(stuff_to_regen_conf))
|
||||||
|
|
||||||
|
return DomainConfigPanel
|
||||||
|
|
||||||
|
|
||||||
def domain_action_run(domain, action, args=None):
|
def domain_action_run(domain, action, args=None):
|
||||||
|
|
Loading…
Add table
Reference in a new issue