From 30983a4efd89585b778257df695fb636616876bf Mon Sep 17 00:00:00 2001 From: Tagada <36127788+Tagadda@users.noreply.github.com> Date: Sat, 8 Jan 2022 00:12:45 +0100 Subject: [PATCH 01/36] [enh] Manage default applications with DomainConfigPanel [enh] makedefault with domain_config_set() [enh] Allow webadmin to reverse makedefault [legacy] translate legacy redirections to new domain config --- locales/en.json | 1 + share/actionsmap.yml | 4 +++ share/config_domain.toml | 5 ++++ src/app.py | 61 ++++++++++++++++++++-------------------- src/domain.py | 15 ++++++++++ src/utils/config.py | 19 +++++++++++++ src/utils/legacy.py | 46 ++++++++++++++++++++++++++++++ 7 files changed, 120 insertions(+), 31 deletions(-) diff --git a/locales/en.json b/locales/en.json index 91db42cb5..72aca192f 100644 --- a/locales/en.json +++ b/locales/en.json @@ -310,6 +310,7 @@ "domain_config_auth_key": "Authentication key", "domain_config_auth_secret": "Authentication secret", "domain_config_auth_token": "Authentication token", + "domain_config_default_app": "Default app", "domain_config_features_disclaimer": "So far, enabling/disabling mail or XMPP features only impact the recommended and automatic DNS configuration, not system configurations!", "domain_config_mail_in": "Incoming emails", "domain_config_mail_out": "Outgoing emails", diff --git a/share/actionsmap.yml b/share/actionsmap.yml index 9eee48716..ce395942f 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -896,6 +896,10 @@ app: -d: full: --domain help: Specific domain to put app on (the app domain by default) + -u: + full: --undo + help: Undo redirection + action: store_true ### app_ssowatconf() ssowatconf: diff --git a/share/config_domain.toml b/share/config_domain.toml index 93551458b..b0131f1c1 100644 --- a/share/config_domain.toml +++ b/share/config_domain.toml @@ -11,6 +11,11 @@ i18n = "domain_config" # [feature] + [feature.app] + [feature.app.default_app] + type = "app" + filters = ["is_webapp"] + default = "_none" [feature.mail] #services = ['postfix', 'dovecot'] diff --git a/src/app.py b/src/app.py index af13765e3..beee7799b 100644 --- a/src/app.py +++ b/src/app.py @@ -117,6 +117,7 @@ def app_info(app, full=False): Get info for a specific app """ from yunohost.permission import user_permission_list + from yunohost.domain import domain_config_get _assert_is_installed(app) @@ -153,6 +154,9 @@ def app_info(app, full=False): ret["is_webapp"] = "domain" in settings and "path" in settings + if ret["is_webapp"]: + ret["is_default"] = domain_config_get(settings["domain"], "feature.app.default_app") == app + ret["supports_change_url"] = os.path.exists( os.path.join(setting_path, "scripts", "change_url") ) @@ -989,6 +993,7 @@ def app_remove(operation_logger, app, purge=False): permission_delete, permission_sync_to_user, ) + from yunohost.domain import domain_list, domain_config_get, domain_config_set if not _is_installed(app): raise YunohostValidationError( @@ -1048,12 +1053,16 @@ def app_remove(operation_logger, app, purge=False): hook_remove(app) + for domain in domain_list()["domains"]: + if (domain_config_get(domain, "feature.app.default_app") == app): + domain_config_set(domain, "feature.app.default_app", "_none") + permission_sync_to_user() _assert_system_is_sane_for_app(manifest, "post") @is_unit_operation() -def app_makedefault(operation_logger, app, domain=None): +def app_makedefault(operation_logger, app, domain=None, undo=False): """ Redirect domain root to an app @@ -1062,11 +1071,10 @@ def app_makedefault(operation_logger, app, domain=None): domain """ - from yunohost.domain import _assert_domain_exists + from yunohost.domain import _assert_domain_exists, domain_config_set app_settings = _get_app_settings(app) app_domain = app_settings["domain"] - app_path = app_settings["path"] if domain is None: domain = app_domain @@ -1075,36 +1083,12 @@ def app_makedefault(operation_logger, app, domain=None): operation_logger.related_to.append(("domain", domain)) - if "/" in app_map(raw=True)[domain]: - raise YunohostValidationError( - "app_make_default_location_already_used", - app=app, - domain=app_domain, - other_app=app_map(raw=True)[domain]["/"]["id"], - ) - operation_logger.start() - # TODO / FIXME : current trick is to add this to conf.json.persisten - # This is really not robust and should be improved - # e.g. have a flag in /etc/yunohost/apps/$app/ to say that this is the - # default app or idk... - if not os.path.exists("/etc/ssowat/conf.json.persistent"): - ssowat_conf = {} + if undo: + domain_config_set(domain, 'feature.app.default_app', "_none") else: - ssowat_conf = read_json("/etc/ssowat/conf.json.persistent") - - if "redirected_urls" not in ssowat_conf: - ssowat_conf["redirected_urls"] = {} - - ssowat_conf["redirected_urls"][domain + "/"] = app_domain + app_path - - write_to_json( - "/etc/ssowat/conf.json.persistent", ssowat_conf, sort_keys=True, indent=4 - ) - chmod("/etc/ssowat/conf.json.persistent", 0o644) - - logger.success(m18n.n("ssowat_conf_updated")) + domain_config_set(domain, 'feature.app.default_app', app) def app_setting(app, key, value=None, delete=False): @@ -1303,7 +1287,7 @@ def app_ssowatconf(): """ - from yunohost.domain import domain_list, _get_maindomain + from yunohost.domain import domain_list, _get_maindomain, domain_config_get from yunohost.permission import user_permission_list main_domain = _get_maindomain() @@ -1341,6 +1325,21 @@ def app_ssowatconf(): redirected_urls.update(app_settings.get("redirected_urls", {})) redirected_regex.update(app_settings.get("redirected_regex", {})) + from .utils.legacy import translate_legacy_default_app_in_ssowant_conf_json_persistent + + translate_legacy_default_app_in_ssowant_conf_json_persistent() + + for domain in domains: + default_app = domain_config_get(domain, "feature.app.default_app") + if default_app != "_none" and _is_installed(default_app): + app_settings = _get_app_settings(default_app) + app_domain = app_settings["domain"] + app_path = app_settings["path"] + + # Prevent infinite redirect loop... + if domain + "/" != app_domain + app_path: + redirected_urls[domain + "/"] = app_domain + app_path + # New permission system for perm_name, perm_info in all_permissions.items(): diff --git a/src/domain.py b/src/domain.py index 6fd1724b4..f2e7fd7f4 100644 --- a/src/domain.py +++ b/src/domain.py @@ -456,6 +456,21 @@ class DomainConfigPanel(ConfigPanel): save_path_tpl = f"{DOMAIN_SETTINGS_DIR}/{{entity}}.yml" save_mode = "diff" + def _apply(self): + if ("default_app" in self.future_values and self.future_values["default_app"] != self.values["default_app"]): + from yunohost.app import app_ssowatconf, app_map + + if "/" in app_map(raw=True)[self.entity]: + raise YunohostValidationError( + "app_make_default_location_already_used", + app=self.future_values["default_app"], + domain=self.entity, + other_app=app_map(raw=True)[self.entity]["/"]["id"], + ) + + super()._apply() + app_ssowatconf() + def _get_toml(self): from yunohost.dns import _get_registrar_config_section diff --git a/src/utils/config.py b/src/utils/config.py index 99a002404..f3c8f8177 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -438,6 +438,7 @@ class ConfigPanel: "step", "accept", "redact", + "filters", ], "defaults": {}, }, @@ -703,6 +704,7 @@ class Question: self.ask = question.get("ask", {"en": self.name}) self.help = question.get("help") self.redact = question.get("redact", False) + self.filters = question.get("filters", []) # .current_value is the currently stored value self.current_value = question.get("current_value") # .value is the "proposed" value which we got from the user @@ -1123,6 +1125,22 @@ class DomainQuestion(Question): return value +class AppQuestion(Question): + argument_type = "app" + + def __init__( + self, question, context: Mapping[str, Any] = {}, hooks: Dict[str, Callable] = {} + ): + from yunohost.app import app_list + + super().__init__(question, context, hooks) + + apps = app_list(full=True)["apps"] + for _filter in self.filters: + print(_filter) + apps = [ app for app in apps if _filter in app and app[_filter] ] + + self.choices = ["_none"] + [app['id'] for app in apps] class UserQuestion(Question): argument_type = "user" @@ -1315,6 +1333,7 @@ ARGUMENTS_TYPE_PARSERS = { "alert": DisplayTextQuestion, "markdown": DisplayTextQuestion, "file": FileQuestion, + "app": AppQuestion, } diff --git a/src/utils/legacy.py b/src/utils/legacy.py index 306fcc87f..7a8a4540a 100644 --- a/src/utils/legacy.py +++ b/src/utils/legacy.py @@ -68,6 +68,52 @@ def legacy_permission_label(app, permission_type): ) +def translate_legacy_default_app_in_ssowant_conf_json_persistent(): + from yunohost.app import app_list + from yunohost.domain import domain_config_set + + persistent_file_name = "/etc/ssowat/conf.json.persistent" + if not os.path.exists(persistent_file_name): + return + + # Ugly hack because for some reason so many people have tabs in their conf.json.persistent ... + os.system(r"sed -i 's/\t/ /g' /etc/ssowat/conf.json.persistent") + + # Ugly hack to try not to misarably fail migration + persistent = read_yaml(persistent_file_name) + + if "redirected_urls" not in persistent: + return + + redirected_urls = persistent["redirected_urls"] + + if not any(from_url.count('/') == 1 and from_url.endswith('/') for from_url in redirected_urls): + return + + apps = app_list()['apps'] + + if not any('domain_path' in app and app['domain_path'] in redirected_urls.values() for app in apps): + return + + for from_url, dest_url in redirected_urls.items(): + # Not a root domain, skip + if from_url.count('/') != 1 or not from_url.endswith('/'): + continue + for app in apps: + if 'domain_path' not in app or app['domain_path'] is not dest_url: + continue + domain_config_set(from_url.strip('/'), "feature.app.default", app['id']) + del redirected_urls[from_url] + + persistent["redirected_urls"] = redirected_urls + + write_to_json(persistent_file_name, persistent, sort_keys=True, indent=4) + + logger.warning( + "YunoHost automatically translated some legacy redirections in /etc/ssowat/conf.json.persistent to match the new default application using domain configuration" + ) + + LEGACY_PHP_VERSION_REPLACEMENTS = [ ("/etc/php5", "/etc/php/7.4"), ("/etc/php/7.0", "/etc/php/7.4"), From cb7bfe7a669943e0a0cbaf9ce5cd8b92da22f0d1 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Thu, 20 Jan 2022 20:23:32 +0000 Subject: [PATCH 02/36] fix for bullseye --- src/utils/config.py | 1 - src/utils/legacy.py | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utils/config.py b/src/utils/config.py index f3c8f8177..837416ab5 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -1137,7 +1137,6 @@ class AppQuestion(Question): apps = app_list(full=True)["apps"] for _filter in self.filters: - print(_filter) apps = [ app for app in apps if _filter in app and app[_filter] ] self.choices = ["_none"] + [app['id'] for app in apps] diff --git a/src/utils/legacy.py b/src/utils/legacy.py index 7a8a4540a..3d42af20b 100644 --- a/src/utils/legacy.py +++ b/src/utils/legacy.py @@ -7,6 +7,7 @@ from moulinette.utils.filesystem import ( read_file, write_to_file, write_to_yaml, + write_to_json, read_yaml, ) @@ -92,17 +93,17 @@ def translate_legacy_default_app_in_ssowant_conf_json_persistent(): apps = app_list()['apps'] - if not any('domain_path' in app and app['domain_path'] in redirected_urls.values() for app in apps): + if not any(app.get('domain_path') in redirected_urls.values() for app in apps): return - for from_url, dest_url in redirected_urls.items(): + for from_url, dest_url in redirected_urls.copy().items(): # Not a root domain, skip if from_url.count('/') != 1 or not from_url.endswith('/'): continue for app in apps: - if 'domain_path' not in app or app['domain_path'] is not dest_url: + if app.get('domain_path') != dest_url: continue - domain_config_set(from_url.strip('/'), "feature.app.default", app['id']) + domain_config_set(from_url.strip('/'), "feature.app.default_app", app['id']) del redirected_urls[from_url] persistent["redirected_urls"] = redirected_urls From 5565e6c55c4ca640bcd3354577c8b4a24eadde6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M?= Date: Fri, 21 Jan 2022 08:16:53 +0000 Subject: [PATCH 03/36] Translated using Weblate (Galician) Currently translated at 100.0% (686 of 686 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/gl/ --- locales/gl.json | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/locales/gl.json b/locales/gl.json index 5ac7ea9da..e25c698c0 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -676,5 +676,13 @@ "migration_description_0021_migrate_to_bullseye": "Actualizar o sistema a Debian Bullseye e YunoHost 11.x", "migration_0021_system_not_fully_up_to_date": "O teu sistema non está completamente actualizado. Fai unha actualización normal antes de executar a migración a Bullseye.", "migration_0021_general_warning": "Ten en conta que a migración é unha operación delicada. O equipo de YunoHost fixo todo o que puido para revisalo e probalo, pero aínda así poderían acontecer fallos no sistema ou apps.\n\nAsí as cousas, é recomendable:\n - Facer unha copia de apoio dos datos e apps importantes. Máis info en https://yunohost.org/backup;\n - Ter paciencia unha vez inicias a migración: dependendo da túa conexión a internet e hardware, podería levarlle varias horas completar o proceso.", - "global_settings_setting_security_ssh_password_authentication": "Permitir autenticación con contrasinal para SSH" -} \ No newline at end of file + "global_settings_setting_security_ssh_password_authentication": "Permitir autenticación con contrasinal para SSH", + "tools_upgrade_failed": "Non se actualizaron os paquetes: {packages_list}", + "migration_0023_not_enough_space": "Crear espazo suficiente en {path} para realizar a migración.", + "migration_0023_postgresql_11_not_installed": "PostgreSQL non estaba instalado no sistema. Nada que facer.", + "migration_0023_postgresql_13_not_installed": "PostgreSQL 11 está instalado, pero PostgreSQL 13 non!? Algo raro debeu pasarlle ao teu sistema :(...", + "migration_description_0022_php73_to_php74_pools": "Migrar ficheiros de configuración de php7.3-fpm 'pool' a php7.4", + "migration_description_0023_postgresql_11_to_13": "Migrar bases de datos de PostgreSQL 11 a 13", + "service_description_postgresql": "Almacena datos da app (Base datos SQL)", + "tools_upgrade": "Actualizando paquetes do sistema" +} From 2f7ec5b368b5b393dcc166077e970eda96281baf Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 21 Jan 2022 20:05:59 +0100 Subject: [PATCH 04/36] configpanels: config_get should return possible choices for domain, user questions (and other dynamic-choices questions) --- src/utils/config.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/utils/config.py b/src/utils/config.py index 99a002404..90bc0be9f 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -285,8 +285,10 @@ class ConfigPanel: ask = m18n.n(self.config["i18n"] + "_" + option["id"]) if mode == "full": - # edit self.config directly option["ask"] = ask + question_class = ARGUMENTS_TYPE_PARSERS[option.get("type", "string")] + # FIXME : maybe other properties should be taken from the question, not just choices ?. + option["choices"] = question_class(option).choices else: result[key] = {"ask": ask} if "current_value" in option: @@ -1109,7 +1111,7 @@ class DomainQuestion(Question): if self.default is None: self.default = _get_maindomain() - self.choices = domain_list()["domains"] + self.choices = {domain: domain + ' ★' if domain == self.default else '' for domain in domain_list()['domains']} @staticmethod def normalize(value, option={}): @@ -1134,7 +1136,9 @@ class UserQuestion(Question): from yunohost.domain import _get_maindomain super().__init__(question, context, hooks) - self.choices = list(user_list()["users"].keys()) + + self.choices = {username: f"{infos['fullname']} ({infos['mail']})" + for username, infos in user_list()["users"].items()} if not self.choices: raise YunohostValidationError( From dfa021fbf7482243f30b1d0e50df92ba099f2bc4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 22 Jan 2022 15:44:37 +0100 Subject: [PATCH 05/36] Fix tests --- src/tests/test_app_config.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tests/test_app_config.py b/src/tests/test_app_config.py index 8de03bfd5..d6cf8045d 100644 --- a/src/tests/test_app_config.py +++ b/src/tests/test_app_config.py @@ -19,6 +19,7 @@ from yunohost.app import ( app_config_set, app_ssowatconf, ) +from yunohost.user import user_create, user_delete from yunohost.utils.error import YunohostError, YunohostValidationError @@ -101,6 +102,8 @@ def config_app(request): def test_app_config_get(config_app): + user_create("alice", "Alice", "White", _get_maindomain(), "test123Ynh") + assert isinstance(app_config_get(config_app), dict) assert isinstance(app_config_get(config_app, full=True), dict) assert isinstance(app_config_get(config_app, export=True), dict) @@ -108,6 +111,8 @@ def test_app_config_get(config_app): assert isinstance(app_config_get(config_app, "main.components"), dict) assert app_config_get(config_app, "main.components.boolean") == "0" + user_delete("alice") + def test_app_config_nopanel(legacy_app): From fde01fafd7c3375dd6323c449e39ea33419f8224 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 24 Jan 2022 18:31:04 +0100 Subject: [PATCH 06/36] app questions in config panel: handle choices with nice display names for webadmin --- src/utils/config.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/utils/config.py b/src/utils/config.py index 79d73b6ec..1ba38c604 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -1127,6 +1127,7 @@ class DomainQuestion(Question): return value + class AppQuestion(Question): argument_type = "app" @@ -1139,9 +1140,15 @@ class AppQuestion(Question): apps = app_list(full=True)["apps"] for _filter in self.filters: - apps = [ app for app in apps if _filter in app and app[_filter] ] + apps = [app for app in apps if _filter in app and app[_filter]] + + def _app_display(app): + domain_path = f" ({app['domain_path']})" if 'domain_path' in app else "" + return app["label"] + domain_path + + self.choices = {"_none": "---"} + self.choices.update({app['id']: _app_display(app) for app in apps}) - self.choices = ["_none"] + [app['id'] for app in apps] class UserQuestion(Question): argument_type = "user" From 71e73c7cf2f77d7ea83157e26afb37632bfb5f8d Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Mon, 24 Jan 2022 18:16:08 +0000 Subject: [PATCH 07/36] [CI] Format code with Black --- src/app.py | 16 ++++++++++------ src/diagnosis.py | 7 ++++--- src/domain.py | 7 +++++-- src/utils/config.py | 15 ++++++++++----- src/utils/legacy.py | 17 ++++++++++------- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/app.py b/src/app.py index 22946eabc..a75f25bc4 100644 --- a/src/app.py +++ b/src/app.py @@ -155,7 +155,9 @@ def app_info(app, full=False): ret["is_webapp"] = "domain" in settings and "path" in settings if ret["is_webapp"]: - ret["is_default"] = domain_config_get(settings["domain"], "feature.app.default_app") == app + ret["is_default"] = ( + domain_config_get(settings["domain"], "feature.app.default_app") == app + ) ret["supports_change_url"] = os.path.exists( os.path.join(setting_path, "scripts", "change_url") @@ -1054,7 +1056,7 @@ def app_remove(operation_logger, app, purge=False): hook_remove(app) for domain in domain_list()["domains"]: - if (domain_config_get(domain, "feature.app.default_app") == app): + if domain_config_get(domain, "feature.app.default_app") == app: domain_config_set(domain, "feature.app.default_app", "_none") permission_sync_to_user() @@ -1086,9 +1088,9 @@ def app_makedefault(operation_logger, app, domain=None, undo=False): operation_logger.start() if undo: - domain_config_set(domain, 'feature.app.default_app', "_none") + domain_config_set(domain, "feature.app.default_app", "_none") else: - domain_config_set(domain, 'feature.app.default_app', app) + domain_config_set(domain, "feature.app.default_app", app) def app_setting(app, key, value=None, delete=False): @@ -1325,8 +1327,10 @@ def app_ssowatconf(): redirected_urls.update(app_settings.get("redirected_urls", {})) redirected_regex.update(app_settings.get("redirected_regex", {})) - from .utils.legacy import translate_legacy_default_app_in_ssowant_conf_json_persistent - + from .utils.legacy import ( + translate_legacy_default_app_in_ssowant_conf_json_persistent, + ) + translate_legacy_default_app_in_ssowant_conf_json_persistent() for domain in domains: diff --git a/src/diagnosis.py b/src/diagnosis.py index 34bdd2e54..007719dfc 100644 --- a/src/diagnosis.py +++ b/src/diagnosis.py @@ -656,9 +656,10 @@ class Diagnoser: def _list_diagnosis_categories(): paths = glob.glob(os.path.dirname(__file__) + "/diagnosers/??-*.py") - names = [name.split("-")[-1] for name in sorted( - [os.path.basename(path)[: -len(".py")] for path in paths] - )] + names = [ + name.split("-")[-1] + for name in sorted([os.path.basename(path)[: -len(".py")] for path in paths]) + ] return names diff --git a/src/domain.py b/src/domain.py index 1fdded817..e73d6ed5f 100644 --- a/src/domain.py +++ b/src/domain.py @@ -455,7 +455,10 @@ class DomainConfigPanel(ConfigPanel): save_mode = "diff" def _apply(self): - if ("default_app" in self.future_values and self.future_values["default_app"] != self.values["default_app"]): + if ( + "default_app" in self.future_values + and self.future_values["default_app"] != self.values["default_app"] + ): from yunohost.app import app_ssowatconf, app_map if "/" in app_map(raw=True)[self.entity]: @@ -468,7 +471,7 @@ class DomainConfigPanel(ConfigPanel): super()._apply() app_ssowatconf() - + def _get_toml(self): from yunohost.dns import _get_registrar_config_section diff --git a/src/utils/config.py b/src/utils/config.py index 1ba38c604..56c45d5f8 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -1113,7 +1113,10 @@ class DomainQuestion(Question): if self.default is None: self.default = _get_maindomain() - self.choices = {domain: domain + ' ★' if domain == self.default else '' for domain in domain_list()['domains']} + self.choices = { + domain: domain + " ★" if domain == self.default else "" + for domain in domain_list()["domains"] + } @staticmethod def normalize(value, option={}): @@ -1143,11 +1146,11 @@ class AppQuestion(Question): apps = [app for app in apps if _filter in app and app[_filter]] def _app_display(app): - domain_path = f" ({app['domain_path']})" if 'domain_path' in app else "" + domain_path = f" ({app['domain_path']})" if "domain_path" in app else "" return app["label"] + domain_path self.choices = {"_none": "---"} - self.choices.update({app['id']: _app_display(app) for app in apps}) + self.choices.update({app["id"]: _app_display(app) for app in apps}) class UserQuestion(Question): @@ -1161,8 +1164,10 @@ class UserQuestion(Question): super().__init__(question, context, hooks) - self.choices = {username: f"{infos['fullname']} ({infos['mail']})" - for username, infos in user_list()["users"].items()} + self.choices = { + username: f"{infos['fullname']} ({infos['mail']})" + for username, infos in user_list()["users"].items() + } if not self.choices: raise YunohostValidationError( diff --git a/src/utils/legacy.py b/src/utils/legacy.py index 4c61edb05..85898f28d 100644 --- a/src/utils/legacy.py +++ b/src/utils/legacy.py @@ -88,24 +88,27 @@ def translate_legacy_default_app_in_ssowant_conf_json_persistent(): redirected_urls = persistent["redirected_urls"] - if not any(from_url.count('/') == 1 and from_url.endswith('/') for from_url in redirected_urls): + if not any( + from_url.count("/") == 1 and from_url.endswith("/") + for from_url in redirected_urls + ): return - apps = app_list()['apps'] + apps = app_list()["apps"] - if not any(app.get('domain_path') in redirected_urls.values() for app in apps): + if not any(app.get("domain_path") in redirected_urls.values() for app in apps): return for from_url, dest_url in redirected_urls.copy().items(): # Not a root domain, skip - if from_url.count('/') != 1 or not from_url.endswith('/'): + if from_url.count("/") != 1 or not from_url.endswith("/"): continue for app in apps: - if app.get('domain_path') != dest_url: + if app.get("domain_path") != dest_url: continue - domain_config_set(from_url.strip('/'), "feature.app.default_app", app['id']) + domain_config_set(from_url.strip("/"), "feature.app.default_app", app["id"]) del redirected_urls[from_url] - + persistent["redirected_urls"] = redirected_urls write_to_json(persistent_file_name, persistent, sort_keys=True, indent=4) From 07396b8b34c29b582c5fd16a57fcc0ceee8f4579 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 25 Jan 2022 13:04:06 +0100 Subject: [PATCH 08/36] [fix] When no main app permission found, fallback to default label instead of having a 'None' label to prevent the webadmin from displaying an empty app list --- src/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app.py b/src/app.py index a75f25bc4..3b6b0a5aa 100644 --- a/src/app.py +++ b/src/app.py @@ -177,6 +177,7 @@ def app_info(app, full=False): if not ret["label"]: logger.warning(f"Failed to get label for app {app} ?") + ret["label"] = local_manifest["name"] return ret From 9b89f66bba2465c57ad82d841a64882e446ee6f9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 25 Jan 2022 13:09:19 +0100 Subject: [PATCH 09/36] Update changelog for 11.0.3 --- debian/changelog | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/debian/changelog b/debian/changelog index cbc6cfc99..b0229fe8d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,18 @@ +yunohost (11.0.3) testing; urgency=low + + - [enh] mail: Add SNI support for postfix and dovecot ([#1413](https://github.com/YunoHost/yunohost/pull/1413)) + - [fix] services: fix a couple edge cases (4571c5b2) + - [fix] services: Do not save php-fpm services in services.yml (5d0f8021) + - [fix] diagnosis: diagnosers were run in a funky order ([#1418](https://github.com/YunoHost/yunohost/pull/1418)) + - [fix] configpanels: config_get should return possible choices for domain, user questions (and other dynamic-choices questions) ([#1420](https://github.com/YunoHost/yunohost/pull/1420)) + - [enh] apps/domain: Clarify the default app mecanism, handle it fron domain config panel ([#1406](https://github.com/YunoHost/yunohost/pull/1406)) + - [fix] apps: When no main app permission found, fallback to default label instead of having a 'None' label to prevent the webadmin from displaying an empty app list (07396b8b) + - [i18n] Translations updated for Galician + + Thanks to all contributors <3 ! (José M, Kay0u, Tagadda, tituspijean) + + -- Alexandre Aubin Tue, 25 Jan 2022 13:06:10 +0100 + yunohost (11.0.2) testing; urgency=low - [mod] Various tweaks for Python 3.9, PHP 7.4, PostgreSQL 13, and other changes related to Buster->Bullseye ecosystem From dcf1a892bfb530ee782546d2f0f852a164f9ef3d Mon Sep 17 00:00:00 2001 From: Kay0u Date: Wed, 26 Jan 2022 14:19:09 +0100 Subject: [PATCH 10/36] fix bash_completion --- debian/install | 2 +- doc/generate_bash_completion.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/debian/install b/debian/install index db88462ab..5169d0b62 100644 --- a/debian/install +++ b/debian/install @@ -5,6 +5,6 @@ helpers/* /usr/share/yunohost/helpers.d/ conf/* /usr/share/yunohost/conf/ locales/* /usr/share/yunohost/locales/ doc/yunohost.8.gz /usr/share/man/man8/ -doc/bash-completion.sh /etc/bash_completion.d/yunohost +doc/bash_completion.d/* /etc/bash_completion.d/ conf/metronome/modules/* /usr/lib/metronome/modules/ src/* /usr/lib/python3/dist-packages/yunohost/ diff --git a/doc/generate_bash_completion.py b/doc/generate_bash_completion.py index 72a524210..d55973010 100644 --- a/doc/generate_bash_completion.py +++ b/doc/generate_bash_completion.py @@ -13,7 +13,8 @@ import yaml THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) ACTIONSMAP_FILE = THIS_SCRIPT_DIR + "/../share/actionsmap.yml" -BASH_COMPLETION_FILE = THIS_SCRIPT_DIR + "/bash-completion.sh" +BASH_COMPLETION_FOLDER = THIS_SCRIPT_DIR + "/bash_completion.d" +BASH_COMPLETION_FILE = BASH_COMPLETION_FOLDER + "/yunohost" def get_dict_actions(OPTION_SUBTREE, category): @@ -61,6 +62,8 @@ with open(ACTIONSMAP_FILE, "r") as stream: OPTION_TREE[category]["subcategories"], subcategory ) + os.makedirs(BASH_COMPLETION_FOLDER, exist_ok=True) + with open(BASH_COMPLETION_FILE, "w") as generated_file: # header of the file From 4b78e8e32796ef412499e525c8bb49ea40d908fb Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 26 Jan 2022 14:28:45 +0100 Subject: [PATCH 11/36] [mod] certificate: drop unused 'staging' LE mode --- share/actionsmap.yml | 12 ---------- src/certificate.py | 52 +++++++++----------------------------------- src/domain.py | 8 +++---- 3 files changed, 14 insertions(+), 58 deletions(-) diff --git a/share/actionsmap.yml b/share/actionsmap.yml index ce395942f..43b610a9d 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -531,9 +531,6 @@ domain: --self-signed: help: Install self-signed certificate instead of Let's Encrypt action: store_true - --staging: - help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure. - action: store_true ### certificate_renew() cert-renew: @@ -552,9 +549,6 @@ domain: --no-checks: help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended) action: store_true - --staging: - help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure. - action: store_true ### domain_url_available() url-available: @@ -677,9 +671,6 @@ domain: --self-signed: help: Install self-signed certificate instead of Let's Encrypt action: store_true - --staging: - help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure. - action: store_true ### certificate_renew() renew: @@ -698,9 +689,6 @@ domain: --no-checks: help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended) action: store_true - --staging: - help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure. - action: store_true ############################# diff --git a/src/certificate.py b/src/certificate.py index 2ad294605..308b79f1c 100644 --- a/src/certificate.py +++ b/src/certificate.py @@ -60,8 +60,6 @@ KEY_SIZE = 3072 VALIDITY_LIMIT = 15 # days -# For tests -STAGING_CERTIFICATION_AUTHORITY = "https://acme-staging-v02.api.letsencrypt.org" # For prod PRODUCTION_CERTIFICATION_AUTHORITY = "https://acme-v02.api.letsencrypt.org" @@ -114,7 +112,7 @@ def certificate_status(domains, full=False): def certificate_install( - domain_list, force=False, no_checks=False, self_signed=False, staging=False + domain_list, force=False, no_checks=False, self_signed=False ): """ Install a Let's Encrypt certificate for given domains (all by default) @@ -130,7 +128,7 @@ def certificate_install( if self_signed: _certificate_install_selfsigned(domain_list, force) else: - _certificate_install_letsencrypt(domain_list, force, no_checks, staging) + _certificate_install_letsencrypt(domain_list, force, no_checks) def _certificate_install_selfsigned(domain_list, force=False): @@ -234,7 +232,7 @@ def _certificate_install_selfsigned(domain_list, force=False): def _certificate_install_letsencrypt( - domains, force=False, no_checks=False, staging=False + domains, force=False, no_checks=False ): from yunohost.domain import domain_list, _assert_domain_exists @@ -264,11 +262,6 @@ def _certificate_install_letsencrypt( "certmanager_domain_cert_not_selfsigned", domain=domain ) - if staging: - logger.warning( - "Please note that you used the --staging option, and that no new certificate will actually be enabled !" - ) - # Actual install steps for domain in domains: @@ -284,12 +277,12 @@ def _certificate_install_letsencrypt( operation_logger = OperationLogger( "letsencrypt_cert_install", [("domain", domain)], - args={"force": force, "no_checks": no_checks, "staging": staging}, + args={"force": force, "no_checks": no_checks}, ) operation_logger.start() try: - _fetch_and_enable_new_certificate(domain, staging, no_checks=no_checks) + _fetch_and_enable_new_certificate(domain, no_checks=no_checks) except Exception as e: msg = f"Certificate installation for {domain} failed !\nException: {e}" logger.error(msg) @@ -305,7 +298,7 @@ def _certificate_install_letsencrypt( def certificate_renew( - domains, force=False, no_checks=False, email=False, staging=False + domains, force=False, no_checks=False, email=False ): """ Renew Let's Encrypt certificate for given domains (all by default) @@ -373,11 +366,6 @@ def certificate_renew( "certmanager_acme_not_configured_for_domain", domain=domain ) - if staging: - logger.warning( - "Please note that you used the --staging option, and that no new certificate will actually be enabled !" - ) - # Actual renew steps for domain in domains: @@ -399,14 +387,13 @@ def certificate_renew( args={ "force": force, "no_checks": no_checks, - "staging": staging, "email": email, }, ) operation_logger.start() try: - _fetch_and_enable_new_certificate(domain, staging, no_checks=no_checks) + _fetch_and_enable_new_certificate(domain, no_checks=no_checks) except Exception as e: import traceback from io import StringIO @@ -473,7 +460,7 @@ def _check_acme_challenge_configuration(domain): return "include /etc/nginx/conf.d/acme-challenge.conf.inc" in read_file(domain_conf) -def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False): +def _fetch_and_enable_new_certificate(domain, no_checks=False): if not os.path.exists(ACCOUNT_KEY_FILE): _generate_account_key() @@ -507,11 +494,6 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False): domain_csr_file = f"{TMP_FOLDER}/{domain}.csr" - if staging: - certification_authority = STAGING_CERTIFICATION_AUTHORITY - else: - certification_authority = PRODUCTION_CERTIFICATION_AUTHORITY - try: signed_certificate = sign_certificate( ACCOUNT_KEY_FILE, @@ -519,7 +501,7 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False): WEBROOT_FOLDER, log=logger, disable_check=no_checks, - CA=certification_authority, + CA=PRODUCTION_CERTIFICATION_AUTHORITY, ) except ValueError as e: if "urn:acme:error:rateLimited" in str(e): @@ -539,12 +521,7 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False): # Create corresponding directory date_tag = datetime.utcnow().strftime("%Y%m%d.%H%M%S") - if staging: - folder_flag = "staging" - else: - folder_flag = "letsencrypt" - - new_cert_folder = f"{CERT_FOLDER}/{domain}-history/{date_tag}-{folder_flag}" + new_cert_folder = f"{CERT_FOLDER}/{domain}-history/{date_tag}-letsencrypt" os.makedirs(new_cert_folder) @@ -563,9 +540,6 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False): _set_permissions(domain_cert_file, "root", "ssl-cert", 0o640) - if staging: - return - _enable_certificate(domain, new_cert_folder) # Check the status of the certificate is now good @@ -677,12 +651,6 @@ def _get_status(domain): "verbose": "Let's Encrypt", } - elif cert_issuer.startswith("Fake LE"): - CA_type = { - "code": "fake-lets-encrypt", - "verbose": "Fake Let's Encrypt", - } - else: CA_type = { "code": "other-unknown", diff --git a/src/domain.py b/src/domain.py index e73d6ed5f..7481e4088 100644 --- a/src/domain.py +++ b/src/domain.py @@ -528,19 +528,19 @@ def domain_cert_status(domain_list, full=False): def domain_cert_install( - domain_list, force=False, no_checks=False, self_signed=False, staging=False + domain_list, force=False, no_checks=False, self_signed=False ): from yunohost.certificate import certificate_install - return certificate_install(domain_list, force, no_checks, self_signed, staging) + return certificate_install(domain_list, force, no_checks, self_signed) def domain_cert_renew( - domain_list, force=False, no_checks=False, email=False, staging=False + domain_list, force=False, no_checks=False, email=False ): from yunohost.certificate import certificate_renew - return certificate_renew(domain_list, force, no_checks, email, staging) + return certificate_renew(domain_list, force, no_checks, email) def domain_dns_conf(domain): From 67cce15d0276e3f1a916540c06ad77274a53aa46 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 26 Jan 2022 20:59:56 +0000 Subject: [PATCH 12/36] Enhance yunomdns service startup Make it rely on network-online.target instead of network.target Co-authored-by: Alexandre Aubin --- conf/mdns/yunomdns.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conf/mdns/yunomdns.service b/conf/mdns/yunomdns.service index 1102f18f6..5fc98afbd 100644 --- a/conf/mdns/yunomdns.service +++ b/conf/mdns/yunomdns.service @@ -1,6 +1,7 @@ [Unit] Description=YunoHost mDNS service -After=network.target +Wants=network-online.target +After=network-online.target [Service] User=mdns From 377558b54e75ea372930e2096266f238f7fcd7f5 Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Thu, 27 Jan 2022 12:15:09 +0100 Subject: [PATCH 13/36] Fix typo --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 4a8f2c1b2..e902ecc2a 100644 --- a/locales/en.json +++ b/locales/en.json @@ -501,7 +501,7 @@ "migration_0021_yunohost_upgrade": "Starting YunoHost core upgrade...", "migration_0023_not_enough_space": "Make sufficient space available in {path} to run the migration.", "migration_0023_postgresql_11_not_installed": "PostgreSQL was not installed on your system. Nothing to do.", - "migration_0023_postgresql_13_not_installed": "PostgreSQL 11 is installed, but not postgresql 13!? Something weird might have happened on your system :(...", + "migration_0023_postgresql_13_not_installed": "PostgreSQL 11 is installed, but not PostgreSQL 13!? Something weird might have happened on your system :(...", "migration_description_0021_migrate_to_bullseye": "Upgrade the system to Debian Bullseye and YunoHost 11.x", "migration_description_0022_php73_to_php74_pools": "Migrate php7.3-fpm 'pool' conf files to php7.4", "migration_description_0023_postgresql_11_to_13": "Migrate databases from PostgreSQL 11 to 13", From 740eaa43aef51c1125851b99005185c826e363d2 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Fri, 28 Jan 2022 02:39:02 +0000 Subject: [PATCH 14/36] typos --- src/utils/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/config.py b/src/utils/config.py index 56c45d5f8..f3b906f00 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -1114,7 +1114,7 @@ class DomainQuestion(Question): self.default = _get_maindomain() self.choices = { - domain: domain + " ★" if domain == self.default else "" + domain: domain + " ★" if domain == self.default else domain for domain in domain_list()["domains"] } @@ -1178,7 +1178,7 @@ class UserQuestion(Question): if self.default is None: root_mail = "root@%s" % _get_maindomain() - for user in self.choices: + for user in self.choices.keys(): if root_mail in user_info(user).get("mail-aliases", []): self.default = user break From 9486931674230f65a5fe87f036ebcf231f309c4d Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Fri, 28 Jan 2022 02:39:20 +0000 Subject: [PATCH 15/36] Hydrate manifest with choices --- src/app.py | 4 ++++ src/utils/config.py | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/app.py b/src/app.py index 3b6b0a5aa..d7310c0ea 100644 --- a/src/app.py +++ b/src/app.py @@ -57,6 +57,7 @@ from yunohost.utils.config import ( ask_questions_and_parse_answers, DomainQuestion, PathQuestion, + hydrate_questions_with_choices, ) from yunohost.utils.i18n import _value_for_locale from yunohost.utils.error import YunohostError, YunohostValidationError @@ -678,6 +679,9 @@ def app_manifest(app): shutil.rmtree(extracted_app_folder) + raw_questions = manifest.get("arguments", {}).get("install", []) + manifest['arguments']['install'] = hydrate_questions_with_choices(raw_questions) + return manifest diff --git a/src/utils/config.py b/src/utils/config.py index f3b906f00..f44fe5c22 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -1396,3 +1396,15 @@ def ask_questions_and_parse_answers( out.append(question) return out + +def hydrate_questions_with_choices(raw_questions: List) -> List: + out = [] + + for raw_question in raw_questions: + question = ARGUMENTS_TYPE_PARSERS[raw_question.get("type", "string")](raw_question) + if question.choices: + raw_question["choices"] = question.choices + raw_question["default"] = question.default + out.append(raw_question) + + return out From 49b444e4809b927b54af6ec9e5ef563dad04a524 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 14:36:10 +0100 Subject: [PATCH 16/36] tools_upgrade: raise a Yunohost error, not a raw exception, when misusing args --- src/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools.py b/src/tools.py index 28b4457b4..f85d0abdf 100644 --- a/src/tools.py +++ b/src/tools.py @@ -453,7 +453,7 @@ def tools_upgrade(operation_logger, target=None): raise YunohostValidationError("dpkg_lock_not_available") if target not in ["apps", "system"]: - raise Exception( + raise YunohostValidationError( "Uhoh ?! tools_upgrade should have 'apps' or 'system' value for argument target" ) From fc3834bff56917df6e3d791b938873b821e77d74 Mon Sep 17 00:00:00 2001 From: Tymofii-Lytvynenko Date: Tue, 25 Jan 2022 01:28:28 +0000 Subject: [PATCH 17/36] Translated using Weblate (Ukrainian) Currently translated at 100.0% (687 of 687 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/uk/ --- locales/uk.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/locales/uk.json b/locales/uk.json index 1f99ba1b4..ae363bd35 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -676,5 +676,14 @@ "migration_0021_system_not_fully_up_to_date": "Ваша система не повністю оновлена. Будь ласка, виконайте регулярне оновлення перед запуском міграції на Bullseye.", "migration_0021_general_warning": "Будь ласка, зверніть увагу, що ця міграція є делікатною операцією. Команда YunoHost зробила все можливе, щоб перевірити і протестувати її, але міграція все ще може порушити частину системи або її застосунків.\n\nТому рекомендовано:\n - Виконати резервне копіювання всіх важливих даних або застосунків. Подробиці на сайті https://yunohost.org/backup; \n - Наберіться терпіння після запуску міграції: В залежності від вашого з'єднання з Інтернетом і апаратного забезпечення, оновлення може зайняти до декількох годин.", "migration_description_0021_migrate_to_bullseye": "Оновлення системи до Debian Bullseye і YunoHost 11.x", - "global_settings_setting_security_ssh_password_authentication": "Дозволити автентифікацію паролем для SSH" -} \ No newline at end of file + "global_settings_setting_security_ssh_password_authentication": "Дозволити автентифікацію паролем для SSH", + "service_description_postgresql": "Зберігає дані застосунків (база даних SQL)", + "domain_config_default_app": "Типовий застосунок", + "migration_0023_postgresql_13_not_installed": "PostgreSQL 11 встановлено, але не PostgreSQL 13!? У вашій системі могло статися щось неприємне :(...", + "migration_description_0023_postgresql_11_to_13": "Перенесення баз даних з PostgreSQL 11 на 13", + "tools_upgrade": "Оновлення системних пакетів", + "tools_upgrade_failed": "Не вдалося оновити наступні пакети: {packages_list}", + "migration_0023_not_enough_space": "Звільніть достатньо місця в {path} для виконання міграції.", + "migration_0023_postgresql_11_not_installed": "PostgreSQL не було встановлено у вашій системі. Нічого робити.", + "migration_description_0022_php73_to_php74_pools": "Перенесення конфігураційних файлів php7.3-fpm 'pool' на php7.4" +} From c9606d353bc095077769ce0aaae18dc02c4df33e Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 26 Jan 2022 13:41:52 +0000 Subject: [PATCH 18/36] Added translation using Weblate (Danish) --- locales/da.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 locales/da.json diff --git a/locales/da.json b/locales/da.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/locales/da.json @@ -0,0 +1 @@ +{} From d79e3618de1204216f29f4c869030f51bc0c0b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= Date: Thu, 27 Jan 2022 11:07:18 +0000 Subject: [PATCH 19/36] Translated using Weblate (French) Currently translated at 100.0% (687 of 687 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index de88b79f8..a14850b8b 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -676,5 +676,14 @@ "migration_0021_patch_yunohost_conflicts": "Application du correctif pour contourner le problème de conflit...", "migration_0021_not_buster": "La distribution Debian actuelle n'est pas Buster !", "migration_description_0021_migrate_to_bullseye": "Mise à niveau du système vers Debian Bullseye et YunoHost 11.x", - "global_settings_setting_security_ssh_password_authentication": "Autoriser l'authentification par mot de passe pour SSH" -} \ No newline at end of file + "global_settings_setting_security_ssh_password_authentication": "Autoriser l'authentification par mot de passe pour SSH", + "domain_config_default_app": "Application par défaut", + "migration_description_0022_php73_to_php74_pools": "Migration des fichiers de configuration php7.3-fpm 'pool' vers php7.4", + "migration_description_0023_postgresql_11_to_13": "Migration des bases de données de PostgreSQL 11 vers 13", + "service_description_postgresql": "Stocke les données d'application (base de données SQL)", + "tools_upgrade": "Mise à niveau des packages système", + "migration_0023_postgresql_13_not_installed": "PostgreSQL 11 est installé, mais pas PostgreSQL 13 ! ? Quelque chose d'anormal s'est peut-être produit sur votre système :(...", + "tools_upgrade_failed": "Impossible de mettre à jour les paquets : {packages_list}", + "migration_0023_not_enough_space": "Prévoyez suffisamment d'espace disponible dans {path} pour exécuter la migration.", + "migration_0023_postgresql_11_not_installed": "PostgreSQL n'a pas été installé sur votre système. Il n'y a rien à faire." +} From bccff1b4421eaa68d2da45493eaf99517233e5aa Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 15:52:16 +0100 Subject: [PATCH 20/36] regenconf: make some systemctl enable/disable quiet --- hooks/conf_regen/01-yunohost | 2 +- hooks/conf_regen/37-mdns | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hooks/conf_regen/01-yunohost b/hooks/conf_regen/01-yunohost index 1f6c143a6..ceab4b2f6 100755 --- a/hooks/conf_regen/01-yunohost +++ b/hooks/conf_regen/01-yunohost @@ -62,7 +62,7 @@ do_init_regen() { systemctl daemon-reload - systemctl enable yunohost-api.service + systemctl enable yunohost-api.service --quiet systemctl start yunohost-api.service # Yunohost-firewall is enabled only during postinstall, not init, not 100% sure why diff --git a/hooks/conf_regen/37-mdns b/hooks/conf_regen/37-mdns index 246b5b469..b99584863 100755 --- a/hooks/conf_regen/37-mdns +++ b/hooks/conf_regen/37-mdns @@ -27,7 +27,7 @@ _generate_config() { do_init_regen() { do_pre_regen do_post_regen /etc/systemd/system/yunomdns.service - systemctl enable yunomdns + systemctl enable yunomdns --quiet } do_pre_regen() { @@ -53,12 +53,12 @@ do_post_regen() { systemctl daemon-reload fi - systemctl disable avahi-daemon.socket --now 2>&1|| true - systemctl disable avahi-daemon --now 2>&1 || true + systemctl disable avahi-daemon.socket --quiet --now 2>&1 || true + systemctl disable avahi-daemon --quiet --now 2>&1 || true # Legacy stuff to enable the new yunomdns service on legacy systems if [[ -e /etc/avahi/avahi-daemon.conf ]] && grep -q 'yunohost' /etc/avahi/avahi-daemon.conf; then - systemctl enable yunomdns --now + systemctl enable yunomdns --now --quiet sleep 2 fi From 345e50ae0098e4fc6f45a52b783bf6acca46a373 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 16:49:03 +0100 Subject: [PATCH 21/36] =?UTF-8?q?regenconf:=20make=20some=20systemctl=20en?= =?UTF-8?q?able/disable=20quiet=C2=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hooks/conf_regen/37-mdns | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hooks/conf_regen/37-mdns b/hooks/conf_regen/37-mdns index b99584863..3a877970b 100755 --- a/hooks/conf_regen/37-mdns +++ b/hooks/conf_regen/37-mdns @@ -53,8 +53,8 @@ do_post_regen() { systemctl daemon-reload fi - systemctl disable avahi-daemon.socket --quiet --now 2>&1 || true - systemctl disable avahi-daemon --quiet --now 2>&1 || true + systemctl disable avahi-daemon.socket --quiet --now 2>/dev/null || true + systemctl disable avahi-daemon --quiet --now 2>/dev/null || true # Legacy stuff to enable the new yunomdns service on legacy systems if [[ -e /etc/avahi/avahi-daemon.conf ]] && grep -q 'yunohost' /etc/avahi/avahi-daemon.conf; then From 3ca302b85dd4d4a86d1a406b8f56d8a9b0e95526 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 16:54:27 +0100 Subject: [PATCH 22/36] Tmp fix to try to debug the CI @_@ --- src/domain.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/domain.py b/src/domain.py index 7481e4088..c4c8d0160 100644 --- a/src/domain.py +++ b/src/domain.py @@ -389,7 +389,11 @@ def domain_main_domain(operation_logger, new_main_domain=None): raise YunohostError("main_domain_change_failed") # Generate SSOwat configuration file - app_ssowatconf() + try: + app_ssowatconf() + except Exception as e: + logger.warning(str(e), exc_info=1) + raise YunohostError("main_domain_change_failed") # Regen configurations if os.path.exists("/etc/yunohost/installed"): From 16946372cca69c12fa3f6a2f0069206aa6911964 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 17:18:24 +0100 Subject: [PATCH 23/36] Moar tmp tweaks to try to debug the CI --- src/domain.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/domain.py b/src/domain.py index c4c8d0160..974a8d72c 100644 --- a/src/domain.py +++ b/src/domain.py @@ -385,6 +385,8 @@ def domain_main_domain(operation_logger, new_main_domain=None): domain_list_cache = {} _set_hostname(new_main_domain) except Exception as e: + import traceback + traceback.print_exc() logger.warning(str(e), exc_info=1) raise YunohostError("main_domain_change_failed") @@ -392,6 +394,8 @@ def domain_main_domain(operation_logger, new_main_domain=None): try: app_ssowatconf() except Exception as e: + import traceback + traceback.print_exc() logger.warning(str(e), exc_info=1) raise YunohostError("main_domain_change_failed") From bf6252ac1db0247637f8978d0a2b71a95dd4c822 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 17:49:45 +0100 Subject: [PATCH 24/36] configpanels: optimize _get_toml for domains to not load the whole DNS section stuff when just getting a simple info from another section --- src/domain.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/domain.py b/src/domain.py index 974a8d72c..a773bcaad 100644 --- a/src/domain.py +++ b/src/domain.py @@ -481,18 +481,24 @@ class DomainConfigPanel(ConfigPanel): app_ssowatconf() def _get_toml(self): - from yunohost.dns import _get_registrar_config_section toml = super()._get_toml() toml["feature"]["xmpp"]["xmpp"]["default"] = ( 1 if self.entity == _get_maindomain() else 0 ) - toml["dns"]["registrar"] = _get_registrar_config_section(self.entity) - # FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ... - self.registar_id = toml["dns"]["registrar"]["registrar"]["value"] - del toml["dns"]["registrar"]["registrar"]["value"] + # 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 + filter_key = self.filter_key.split(".") if self.filter_key != "" else [] + if not filter_key or filter_key[0] == "dns": + from yunohost.dns import _get_registrar_config_section + toml["dns"]["registrar"] = _get_registrar_config_section(self.entity) + + # FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ... + self.registar_id = toml["dns"]["registrar"]["registrar"]["value"] + del toml["dns"]["registrar"]["registrar"]["value"] return toml @@ -502,7 +508,8 @@ class DomainConfigPanel(ConfigPanel): super()._load_current_values() # FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ... - self.values["registrar"] = self.registar_id + if self.hasattr("registrar_id"): + self.values["registrar"] = self.registar_id def _get_domain_settings(domain: str) -> dict: From 74e73c470f6ad4c8f078eb6506e5b0797f582ac5 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 17:49:59 +0100 Subject: [PATCH 25/36] Revert "Moar tmp tweaks to try to debug the CI" This reverts commit 16946372cca69c12fa3f6a2f0069206aa6911964. --- src/domain.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/domain.py b/src/domain.py index a773bcaad..1e869c985 100644 --- a/src/domain.py +++ b/src/domain.py @@ -385,8 +385,6 @@ def domain_main_domain(operation_logger, new_main_domain=None): domain_list_cache = {} _set_hostname(new_main_domain) except Exception as e: - import traceback - traceback.print_exc() logger.warning(str(e), exc_info=1) raise YunohostError("main_domain_change_failed") @@ -394,8 +392,6 @@ def domain_main_domain(operation_logger, new_main_domain=None): try: app_ssowatconf() except Exception as e: - import traceback - traceback.print_exc() logger.warning(str(e), exc_info=1) raise YunohostError("main_domain_change_failed") From 73777983855d51c11da398ff5634d2b4ce7ef920 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 17:50:03 +0100 Subject: [PATCH 26/36] Revert "Tmp fix to try to debug the CI @_@" This reverts commit 3ca302b85dd4d4a86d1a406b8f56d8a9b0e95526. --- src/domain.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/domain.py b/src/domain.py index 1e869c985..ad3eaaed2 100644 --- a/src/domain.py +++ b/src/domain.py @@ -389,11 +389,7 @@ def domain_main_domain(operation_logger, new_main_domain=None): raise YunohostError("main_domain_change_failed") # Generate SSOwat configuration file - try: - app_ssowatconf() - except Exception as e: - logger.warning(str(e), exc_info=1) - raise YunohostError("main_domain_change_failed") + app_ssowatconf() # Regen configurations if os.path.exists("/etc/yunohost/installed"): From e46fe6b77b05704b3dab6f98de25722912a47a72 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 18:05:23 +0100 Subject: [PATCH 27/36] Typo: self.hasattr is not a thing /o\ --- src/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domain.py b/src/domain.py index ad3eaaed2..594c18d27 100644 --- a/src/domain.py +++ b/src/domain.py @@ -500,7 +500,7 @@ class DomainConfigPanel(ConfigPanel): super()._load_current_values() # FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ... - if self.hasattr("registrar_id"): + if hasattr(self, "registrar_id"): self.values["registrar"] = self.registar_id From adb0e67b25d8385dea8f1b2b319321b11157faf1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 18:28:07 +0100 Subject: [PATCH 28/36] Aaand hasattr not working as expected --- src/domain.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/domain.py b/src/domain.py index 594c18d27..338abc21b 100644 --- a/src/domain.py +++ b/src/domain.py @@ -500,7 +500,8 @@ class DomainConfigPanel(ConfigPanel): super()._load_current_values() # FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ... - if hasattr(self, "registrar_id"): + filter_key = self.filter_key.split(".") if self.filter_key != "" else [] + if not filter_key or filter_key[0] == "dns": self.values["registrar"] = self.registar_id From e1ffe57282dc39a0ac9759011d68cb6ca086df1e Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Sat, 29 Jan 2022 17:48:05 +0000 Subject: [PATCH 29/36] [CI] Format code with Black --- src/app.py | 2 +- src/certificate.py | 12 +++--------- src/domain.py | 9 +++------ src/utils/config.py | 5 ++++- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/app.py b/src/app.py index d7310c0ea..c200a66c6 100644 --- a/src/app.py +++ b/src/app.py @@ -680,7 +680,7 @@ def app_manifest(app): shutil.rmtree(extracted_app_folder) raw_questions = manifest.get("arguments", {}).get("install", []) - manifest['arguments']['install'] = hydrate_questions_with_choices(raw_questions) + manifest["arguments"]["install"] = hydrate_questions_with_choices(raw_questions) return manifest diff --git a/src/certificate.py b/src/certificate.py index 308b79f1c..2a9fb4ce9 100644 --- a/src/certificate.py +++ b/src/certificate.py @@ -111,9 +111,7 @@ def certificate_status(domains, full=False): return {"certificates": certificates} -def certificate_install( - domain_list, force=False, no_checks=False, self_signed=False -): +def certificate_install(domain_list, force=False, no_checks=False, self_signed=False): """ Install a Let's Encrypt certificate for given domains (all by default) @@ -231,9 +229,7 @@ def _certificate_install_selfsigned(domain_list, force=False): operation_logger.error(msg) -def _certificate_install_letsencrypt( - domains, force=False, no_checks=False -): +def _certificate_install_letsencrypt(domains, force=False, no_checks=False): from yunohost.domain import domain_list, _assert_domain_exists if not os.path.exists(ACCOUNT_KEY_FILE): @@ -297,9 +293,7 @@ def _certificate_install_letsencrypt( operation_logger.success() -def certificate_renew( - domains, force=False, no_checks=False, email=False -): +def certificate_renew(domains, force=False, no_checks=False, email=False): """ Renew Let's Encrypt certificate for given domains (all by default) diff --git a/src/domain.py b/src/domain.py index 338abc21b..ab6ce54a5 100644 --- a/src/domain.py +++ b/src/domain.py @@ -486,6 +486,7 @@ class DomainConfigPanel(ConfigPanel): filter_key = self.filter_key.split(".") if self.filter_key != "" else [] if not filter_key or filter_key[0] == "dns": from yunohost.dns import _get_registrar_config_section + toml["dns"]["registrar"] = _get_registrar_config_section(self.entity) # FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ... @@ -535,17 +536,13 @@ def domain_cert_status(domain_list, full=False): return certificate_status(domain_list, full) -def domain_cert_install( - domain_list, force=False, no_checks=False, self_signed=False -): +def domain_cert_install(domain_list, force=False, no_checks=False, self_signed=False): from yunohost.certificate import certificate_install return certificate_install(domain_list, force, no_checks, self_signed) -def domain_cert_renew( - domain_list, force=False, no_checks=False, email=False -): +def domain_cert_renew(domain_list, force=False, no_checks=False, email=False): from yunohost.certificate import certificate_renew return certificate_renew(domain_list, force, no_checks, email) diff --git a/src/utils/config.py b/src/utils/config.py index f44fe5c22..ab18a19b0 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -1397,11 +1397,14 @@ def ask_questions_and_parse_answers( return out + def hydrate_questions_with_choices(raw_questions: List) -> List: out = [] for raw_question in raw_questions: - question = ARGUMENTS_TYPE_PARSERS[raw_question.get("type", "string")](raw_question) + question = ARGUMENTS_TYPE_PARSERS[raw_question.get("type", "string")]( + raw_question + ) if question.choices: raw_question["choices"] = question.choices raw_question["default"] = question.default From 0a59f863294ad6e57902387ea20cbf85933ebc55 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 19:10:28 +0100 Subject: [PATCH 30/36] configpanel: oopsies, super()._apply() was only called when changing the default app :P --- src/domain.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/domain.py b/src/domain.py index 338abc21b..361536011 100644 --- a/src/domain.py +++ b/src/domain.py @@ -469,7 +469,13 @@ class DomainConfigPanel(ConfigPanel): other_app=app_map(raw=True)[self.entity]["/"]["id"], ) - super()._apply() + super()._apply() + + # Reload ssowat if default app changed + if ( + "default_app" in self.future_values + and self.future_values["default_app"] != self.values["default_app"] + ): app_ssowatconf() def _get_toml(self): From f0a01ba25db5c57f3efc86286012662b90e5aaed Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 19:18:42 +0100 Subject: [PATCH 31/36] php73_to_php74: another search&replace for synapse --- src/migrations/0022_php73_to_php74_pools.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/migrations/0022_php73_to_php74_pools.py b/src/migrations/0022_php73_to_php74_pools.py index 3b6db919a..fd76adb77 100644 --- a/src/migrations/0022_php73_to_php74_pools.py +++ b/src/migrations/0022_php73_to_php74_pools.py @@ -17,6 +17,10 @@ NEWPHP_POOLS = "/etc/php/7.4/fpm/pool.d" OLDPHP_SOCKETS_PREFIX = "/run/php/php7.3-fpm" NEWPHP_SOCKETS_PREFIX = "/run/php/php7.4-fpm" +# Because of synapse é_è +OLDPHP_SOCKETS_PREFIX2 = "/run/php7.3-fpm" +NEWPHP_SOCKETS_PREFIX2 = "/run/php7.4-fpm" + MIGRATION_COMMENT = ( "; YunoHost note : this file was automatically moved from {}".format(OLDPHP_POOLS) ) @@ -50,6 +54,10 @@ class MyMigration(Migration): OLDPHP_SOCKETS_PREFIX, NEWPHP_SOCKETS_PREFIX, dest ) os.system(c) + c = "sed -i -e 's@{}@{}@g' {}".format( + OLDPHP_SOCKETS_PREFIX2, NEWPHP_SOCKETS_PREFIX2, dest + ) + os.system(c) # Also add a comment that it was automatically moved from php7.3 # (for human traceability and backward migration) @@ -69,6 +77,10 @@ class MyMigration(Migration): OLDPHP_SOCKETS_PREFIX, NEWPHP_SOCKETS_PREFIX, nf ) os.system(c) + c = "sed -i -e 's@{}@{}@g' {}".format( + OLDPHP_SOCKETS_PREFIX2, NEWPHP_SOCKETS_PREFIX2, nf + ) + os.system(c) os.system( "rm /etc/logrotate.d/php7.3-fpm" From 9ae7ec5930179f189d438b256347e456cb401caa Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 19:19:19 +0100 Subject: [PATCH 32/36] php73_to_php74: stopping php7.3 before starting 7.4 should be more robust in case confs are conflicting --- src/migrations/0022_php73_to_php74_pools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/migrations/0022_php73_to_php74_pools.py b/src/migrations/0022_php73_to_php74_pools.py index fd76adb77..a2e5eae54 100644 --- a/src/migrations/0022_php73_to_php74_pools.py +++ b/src/migrations/0022_php73_to_php74_pools.py @@ -87,10 +87,10 @@ class MyMigration(Migration): ) # We remove this otherwise the logrotate cron will be unhappy # Reload/restart the php pools - _run_service_command("restart", "php7.4-fpm") - _run_service_command("enable", "php7.4-fpm") os.system("systemctl stop php7.3-fpm") os.system("systemctl disable php7.3-fpm") + _run_service_command("restart", "php7.4-fpm") + _run_service_command("enable", "php7.4-fpm") # Reload nginx _run_service_command("reload", "nginx") From ab5580cb1197087292a7be8ad3a85b8d31ba292f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 29 Jan 2022 19:23:07 +0100 Subject: [PATCH 33/36] Update changelof for 11.0.4 --- debian/changelog | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/debian/changelog b/debian/changelog index b0229fe8d..7e35024c8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,20 @@ +yunohost (11.0.4) testing; urgency=low + + - [mod] certificate: drop unused 'staging' LE mode (4b78e8e3) + - [fix] cli: bash_completion was broken ([#1423](https://github.com/YunoHost/yunohost/pull/1423)) + - [enh] mdns: Wait for network to be fully up to start the service ([#1425](https://github.com/YunoHost/yunohost/pull/1425)) + - [fix] regenconf: make some systemctl enable/disable quiet (bccff1b4, 345e50ae) + - [fix] configpanels: Compute choices for the yunohost admin when installing an app ([#1427](https://github.com/YunoHost/yunohost/pull/1427)) + - [fix] configpanels: optimize _get_toml for domains to not load the whole DNS section stuff when just getting a simple info from another section (bf6252ac) + - [fix] configpanel: oopsies, could only change the default app for domain configs :P (0a59f863) + - [fix] php73_to_php74: another search&replace for synapse (f0a01ba2) + - [fix] php73_to_php74: stopping php7.3 before starting 7.4 should be more robust in case confs are conflicting (9ae7ec59) + - [i18n] Translations updated for French, Ukrainian + + Thanks to all contributors <3 ! (Éric Gaspar, Kay0u, Tagadda, tituspijean, Tymofii-Lytvynenko) + + -- Alexandre Aubin Sat, 29 Jan 2022 19:19:44 +0100 + yunohost (11.0.3) testing; urgency=low - [enh] mail: Add SNI support for postfix and dovecot ([#1413](https://github.com/YunoHost/yunohost/pull/1413)) From f2b95e5fbeabec1f4a99e81c6a93aac0b876223d Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Sun, 30 Jan 2022 20:45:06 +0000 Subject: [PATCH 34/36] configpanel: filter as a simple_js_expression --- share/config_domain.toml | 2 +- src/utils/config.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/share/config_domain.toml b/share/config_domain.toml index b0131f1c1..65e755365 100644 --- a/share/config_domain.toml +++ b/share/config_domain.toml @@ -14,7 +14,7 @@ i18n = "domain_config" [feature.app] [feature.app.default_app] type = "app" - filters = ["is_webapp"] + filter = "is_webapp" default = "_none" [feature.mail] diff --git a/src/utils/config.py b/src/utils/config.py index ab18a19b0..1e4f4cd1e 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -440,7 +440,7 @@ class ConfigPanel: "step", "accept", "redact", - "filters", + "filter", ], "defaults": {}, }, @@ -706,7 +706,7 @@ class Question: self.ask = question.get("ask", {"en": self.name}) self.help = question.get("help") self.redact = question.get("redact", False) - self.filters = question.get("filters", []) + self.filter = question.get("filter", []) # .current_value is the currently stored value self.current_value = question.get("current_value") # .value is the "proposed" value which we got from the user @@ -1142,12 +1142,12 @@ class AppQuestion(Question): super().__init__(question, context, hooks) apps = app_list(full=True)["apps"] - for _filter in self.filters: - apps = [app for app in apps if _filter in app and app[_filter]] + + apps = [app for app in apps if evaluate_simple_js_expression(self.filter, context=app)] def _app_display(app): - domain_path = f" ({app['domain_path']})" if "domain_path" in app else "" - return app["label"] + domain_path + domain_path_or_id = f" ({app.get('domain_path', app['id'])})" + return app["label"] + domain_path_or_id self.choices = {"_none": "---"} self.choices.update({app["id"]: _app_display(app) for app in apps}) From 3de3205648cdfaf530148defc51b58460e03ea10 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Sun, 30 Jan 2022 22:39:26 +0000 Subject: [PATCH 35/36] set default filter to always return true --- src/utils/config.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/utils/config.py b/src/utils/config.py index 1e4f4cd1e..0b2aca414 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -706,7 +706,7 @@ class Question: self.ask = question.get("ask", {"en": self.name}) self.help = question.get("help") self.redact = question.get("redact", False) - self.filter = question.get("filter", []) + self.filter = question.get("filter", "true") # .current_value is the currently stored value self.current_value = question.get("current_value") # .value is the "proposed" value which we got from the user @@ -1142,8 +1142,9 @@ class AppQuestion(Question): super().__init__(question, context, hooks) apps = app_list(full=True)["apps"] - - apps = [app for app in apps if evaluate_simple_js_expression(self.filter, context=app)] + + if self.filter: + apps = [app for app in apps if evaluate_simple_js_expression(self.filter, context=app)] def _app_display(app): domain_path_or_id = f" ({app.get('domain_path', app['id'])})" From d28f725762f8d60b1bf772a4d492ed9affde95ab Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Mon, 31 Jan 2022 02:32:46 +0000 Subject: [PATCH 36/36] [CI] Format code with Black --- src/diagnosers/50-systemresources.py | 2 +- src/migrations/0021_migrate_to_bullseye.py | 2 +- src/tools.py | 2 +- src/utils/config.py | 6 +++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/diagnosers/50-systemresources.py b/src/diagnosers/50-systemresources.py index 1096daebf..6ac7f0ec4 100644 --- a/src/diagnosers/50-systemresources.py +++ b/src/diagnosers/50-systemresources.py @@ -18,7 +18,7 @@ class MyDiagnoser(Diagnoser): def run(self): - MB = 1024 ** 2 + MB = 1024**2 GB = MB * 1024 # diff --git a/src/migrations/0021_migrate_to_bullseye.py b/src/migrations/0021_migrate_to_bullseye.py index f4361cb19..551a6f64b 100644 --- a/src/migrations/0021_migrate_to_bullseye.py +++ b/src/migrations/0021_migrate_to_bullseye.py @@ -293,7 +293,7 @@ class MyMigration(Migration): raise YunohostError("migration_0021_not_buster") # Have > 1 Go free space on /var/ ? - if free_space_in_directory("/var/") / (1024 ** 3) < 1.0: + if free_space_in_directory("/var/") / (1024**3) < 1.0: raise YunohostError("migration_0021_not_enough_free_space") # Check system is up to date diff --git a/src/tools.py b/src/tools.py index f85d0abdf..45163135f 100644 --- a/src/tools.py +++ b/src/tools.py @@ -226,7 +226,7 @@ def tools_postinstall( main_space = sum( psutil.disk_usage(d.mountpoint).total for d in main_disk_partitions ) - GB = 1024 ** 3 + GB = 1024**3 if not force_diskspace and main_space < 10 * GB: raise YunohostValidationError("postinstall_low_rootfsspace") diff --git a/src/utils/config.py b/src/utils/config.py index 0b2aca414..b8ea93589 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -1144,7 +1144,11 @@ class AppQuestion(Question): apps = app_list(full=True)["apps"] if self.filter: - apps = [app for app in apps if evaluate_simple_js_expression(self.filter, context=app)] + apps = [ + app + for app in apps + if evaluate_simple_js_expression(self.filter, context=app) + ] def _app_display(app): domain_path_or_id = f" ({app.get('domain_path', app['id'])})"