diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 3d1d16f3c..613ca21df 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -54,7 +54,7 @@ from moulinette.utils.filesystem import ( from yunohost.service import service_status, _run_service_command from yunohost.utils import packages -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.log import is_unit_operation, OperationLogger logger = getActionLogger("yunohost.app") @@ -192,7 +192,7 @@ def app_info(app, full=False): from yunohost.permission import user_permission_list if not _is_installed(app): - raise YunohostError( + raise YunohostValidationError( "app_not_installed", app=app, all_apps=_get_all_installed_apps_id() ) @@ -321,7 +321,7 @@ def app_map(app=None, raw=False, user=None): if app is not None: if not _is_installed(app): - raise YunohostError( + raise YunohostValidationError( "app_not_installed", app=app, all_apps=_get_all_installed_apps_id() ) apps = [ @@ -421,14 +421,14 @@ def app_change_url(operation_logger, app, domain, path): installed = _is_installed(app) if not installed: - raise YunohostError( + raise YunohostValidationError( "app_not_installed", app=app, all_apps=_get_all_installed_apps_id() ) if not os.path.exists( os.path.join(APPS_SETTING_PATH, app, "scripts", "change_url") ): - raise YunohostError("app_change_url_no_script", app_name=app) + raise YunohostValidationError("app_change_url_no_script", app_name=app) old_domain = app_setting(app, "domain") old_path = app_setting(app, "path") @@ -438,7 +438,7 @@ def app_change_url(operation_logger, app, domain, path): domain, path = _normalize_domain_path(domain, path) if (domain, path) == (old_domain, old_path): - raise YunohostError( + raise YunohostValidationError( "app_change_url_identical_domains", domain=domain, path=path ) @@ -551,12 +551,12 @@ def app_upgrade(app=[], url=None, file=None, force=False): # Abort if any of those app is in fact not installed.. for app in [app_ for app_ in apps if not _is_installed(app_)]: - raise YunohostError( + raise YunohostValidationError( "app_not_installed", app=app, all_apps=_get_all_installed_apps_id() ) if len(apps) == 0: - raise YunohostError("apps_already_up_to_date") + raise YunohostValidationError("apps_already_up_to_date") if len(apps) > 1: logger.info(m18n.n("app_upgrade_several_apps", apps=", ".join(apps))) @@ -880,11 +880,11 @@ def app_install( confirm_install("thirdparty") manifest, extracted_app_folder = _extract_app_from_file(app) else: - raise YunohostError("app_unknown") + raise YunohostValidationError("app_unknown") # Check ID if "id" not in manifest or "__" in manifest["id"]: - raise YunohostError("app_id_invalid") + raise YunohostValidationError("app_id_invalid") app_id = manifest["id"] label = label if label else manifest["name"] @@ -897,7 +897,7 @@ def app_install( instance_number = _installed_instance_number(app_id, last=True) + 1 if instance_number > 1: if "multi_instance" not in manifest or not is_true(manifest["multi_instance"]): - raise YunohostError("app_already_installed", app=app_id) + raise YunohostValidationError("app_already_installed", app=app_id) # Change app_id to the forked app id app_instance_name = app_id + "__" + str(instance_number) @@ -1209,7 +1209,7 @@ def app_remove(operation_logger, app): ) if not _is_installed(app): - raise YunohostError( + raise YunohostValidationError( "app_not_installed", app=app, all_apps=_get_all_installed_apps_id() ) @@ -1372,10 +1372,10 @@ def app_makedefault(operation_logger, app, domain=None): domain = app_domain operation_logger.related_to.append(("domain", domain)) elif domain not in domain_list()["domains"]: - raise YunohostError("domain_name_unknown", domain=domain) + raise YunohostValidationError("domain_name_unknown", domain=domain) if "/" in app_map(raw=True)[domain]: - raise YunohostError( + raise YunohostValidationError( "app_make_default_location_already_used", app=app, domain=app_domain, @@ -1578,7 +1578,7 @@ def app_register_url(app, domain, path): if _is_installed(app): settings = _get_app_settings(app) if "path" in settings.keys() and "domain" in settings.keys(): - raise YunohostError("app_already_installed_cant_change_url") + raise YunohostValidationError("app_already_installed_cant_change_url") # Check the url is available _assert_no_conflicting_apps(domain, path) @@ -1694,7 +1694,7 @@ def app_change_label(app, new_label): installed = _is_installed(app) if not installed: - raise YunohostError( + raise YunohostValidationError( "app_not_installed", app=app, all_apps=_get_all_installed_apps_id() ) logger.warning(m18n.n("app_label_deprecated")) @@ -1730,7 +1730,7 @@ def app_action_run(operation_logger, app, action, args=None): actions = {x["id"]: x for x in actions} if action not in actions: - raise YunohostError( + raise YunohostValidationError( "action '%s' not available for app '%s', available actions are: %s" % (action, app, ", ".join(actions.keys())), raw_msg=True, @@ -1884,7 +1884,7 @@ def app_config_apply(operation_logger, app, args): installed = _is_installed(app) if not installed: - raise YunohostError( + raise YunohostValidationError( "app_not_installed", app=app, all_apps=_get_all_installed_apps_id() ) @@ -2199,7 +2199,7 @@ def _get_app_settings(app_id): """ if not _is_installed(app_id): - raise YunohostError( + raise YunohostValidationError( "app_not_installed", app=app_id, all_apps=_get_all_installed_apps_id() ) try: @@ -2546,9 +2546,9 @@ def _fetch_app_from_git(app): app_id, _ = _parse_app_instance_name(app) if app_id not in app_dict: - raise YunohostError("app_unknown") + raise YunohostValidationError("app_unknown") elif "git" not in app_dict[app_id]: - raise YunohostError("app_unsupported_remote_type") + raise YunohostValidationError("app_unsupported_remote_type") app_info = app_dict[app_id] url = app_info["git"]["url"] @@ -2684,7 +2684,7 @@ def _check_manifest_requirements(manifest, app_instance_name): packaging_format = int(manifest.get("packaging_format", 0)) if packaging_format not in [0, 1]: - raise YunohostError("app_packaging_format_not_supported") + raise YunohostValidationError("app_packaging_format_not_supported") requirements = manifest.get("requirements", dict()) @@ -2697,7 +2697,7 @@ def _check_manifest_requirements(manifest, app_instance_name): for pkgname, spec in requirements.items(): if not packages.meets_version_specifier(pkgname, spec): version = packages.ynh_packages_version()[pkgname]["version"] - raise YunohostError( + raise YunohostValidationError( "app_requirements_unmeet", pkgname=pkgname, version=version, @@ -2796,7 +2796,7 @@ class YunoHostArgumentFormatParser(object): # we don't have an answer, check optional and default_value if question.value is None or question.value == "": if not question.optional and question.default is None: - raise YunohostError("app_argument_required", name=question.name) + raise YunohostValidationError("app_argument_required", name=question.name) else: question.value = ( getattr(self, "default_value", None) @@ -2816,7 +2816,7 @@ class YunoHostArgumentFormatParser(object): return (question.value, self.argument_type) def _raise_invalid_answer(self, question): - raise YunohostError( + raise YunohostValidationError( "app_argument_choice_invalid", name=question.name, choices=", ".join(question.choices), @@ -2854,13 +2854,13 @@ class PasswordArgumentParser(YunoHostArgumentFormatParser): ) if question.default is not None: - raise YunohostError("app_argument_password_no_default", name=question.name) + raise YunohostValidationError("app_argument_password_no_default", name=question.name) return question def _post_parse_value(self, question): if any(char in question.value for char in self.forbidden_chars): - raise YunohostError( + raise YunohostValidationError( "pattern_password_app", forbidden_chars=self.forbidden_chars ) @@ -2913,7 +2913,7 @@ class BooleanArgumentParser(YunoHostArgumentFormatParser): if str(question.value).lower() in ["0", "no", "n", "false"]: return 0 - raise YunohostError( + raise YunohostValidationError( "app_argument_choice_invalid", name=question.name, choices="yes, no, y, n, 1, 0", @@ -2938,7 +2938,7 @@ class DomainArgumentParser(YunoHostArgumentFormatParser): return question def _raise_invalid_answer(self, question): - raise YunohostError( + raise YunohostValidationError( "app_argument_invalid", name=question.name, error=m18n.n("domain_unknown") ) @@ -2964,7 +2964,7 @@ class UserArgumentParser(YunoHostArgumentFormatParser): return question def _raise_invalid_answer(self, question): - raise YunohostError( + raise YunohostValidationError( "app_argument_invalid", name=question.name, error=m18n.n("user_unknown", user=question.value), @@ -2992,7 +2992,7 @@ class NumberArgumentParser(YunoHostArgumentFormatParser): if isinstance(question.value, str) and question.value.isdigit(): return int(question.value) - raise YunohostError( + raise YunohostValidationError( "app_argument_invalid", name=question.name, error=m18n.n("invalid_number") ) @@ -3123,7 +3123,7 @@ def _get_conflicting_apps(domain, path, ignore_app=None): # Abort if domain is unknown if domain not in domain_list()["domains"]: - raise YunohostError("domain_name_unknown", domain=domain) + raise YunohostValidationError("domain_name_unknown", domain=domain) # Fetch apps map apps_map = app_map(raw=True) @@ -3162,9 +3162,9 @@ def _assert_no_conflicting_apps(domain, path, ignore_app=None, full_domain=False ) if full_domain: - raise YunohostError("app_full_domain_unavailable", domain=domain) + raise YunohostValidationError("app_full_domain_unavailable", domain=domain) else: - raise YunohostError("app_location_unavailable", apps="\n".join(apps)) + raise YunohostValidationError("app_location_unavailable", apps="\n".join(apps)) def _make_environment_for_app_script(app, args={}, args_prefix="APP_ARG_"): @@ -3469,7 +3469,7 @@ def _assert_system_is_sane_for_app(manifest, when): faulty_services = [s for s in services if service_status(s)["status"] != "running"] if faulty_services: if when == "pre": - raise YunohostError( + raise YunohostValidationError( "app_action_cannot_be_ran_because_required_services_down", services=", ".join(faulty_services), ) @@ -3480,7 +3480,7 @@ def _assert_system_is_sane_for_app(manifest, when): if packages.dpkg_is_broken(): if when == "pre": - raise YunohostError("dpkg_is_broken") + raise YunohostValidationError("dpkg_is_broken") elif when == "post": raise YunohostError("this_action_broke_dpkg") @@ -3659,7 +3659,7 @@ def _patch_legacy_helpers(app_folder): # couldn't patch the deprecated helper in the previous lines. In # that case, abort the install or whichever step is performed if helper in content and infos["important"]: - raise YunohostError( + raise YunohostValidationError( "This app is likely pretty old and uses deprecated / outdated helpers that can't be migrated easily. It can't be installed anymore.", raw_msg=True, ) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 408cd6f15..b020c0f34 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -348,7 +348,7 @@ class BackupManager: # Try to recursively unmount stuff (from a previously failed backup ?) if not _recursive_umount(self.work_dir): - raise YunohostError("backup_output_directory_not_empty") + raise YunohostValidationError("backup_output_directory_not_empty") else: # If umount succeeded, remove the directory (we checked that # we're in /home/yunohost.backup/tmp so that should be okay... @@ -1027,7 +1027,7 @@ class RestoreManager: already_installed = [app for app in to_be_restored if _is_installed(app)] if already_installed != []: if already_installed == to_be_restored: - raise YunohostError( + raise YunohostValidationError( "restore_already_installed_apps", apps=", ".join(already_installed) ) else: @@ -1133,14 +1133,14 @@ class RestoreManager: return True elif free_space > needed_space: # TODO Add --force options to avoid the error raising - raise YunohostError( + raise YunohostValidationError( "restore_may_be_not_enough_disk_space", free_space=free_space, needed_space=needed_space, margin=margin, ) else: - raise YunohostError( + raise YunohostValidationError( "restore_not_enough_disk_space", free_space=free_space, needed_space=needed_space, @@ -1729,7 +1729,7 @@ class BackupMethod(object): free_space, backup_size, ) - raise YunohostError("not_enough_disk_space", path=self.repo) + raise YunohostValidationError("not_enough_disk_space", path=self.repo) def _organize_files(self): """ @@ -2186,7 +2186,7 @@ def backup_create( # Validate there is no archive with the same name if name and name in backup_list()["archives"]: - raise YunohostError("backup_archive_name_exists") + raise YunohostValidationError("backup_archive_name_exists") # By default we backup using the tar method if not methods: @@ -2201,14 +2201,14 @@ def backup_create( r"^/(|(bin|boot|dev|etc|lib|root|run|sbin|sys|usr|var)(|/.*))$", output_directory, ): - raise YunohostError("backup_output_directory_forbidden") + raise YunohostValidationError("backup_output_directory_forbidden") if "copy" in methods: if not output_directory: - raise YunohostError("backup_output_directory_required") + raise YunohostValidationError("backup_output_directory_required") # Check that output directory is empty elif os.path.isdir(output_directory) and os.listdir(output_directory): - raise YunohostError("backup_output_directory_not_empty") + raise YunohostValidationError("backup_output_directory_not_empty") # If no --system or --apps given, backup everything if system is None and apps is None: @@ -2381,7 +2381,7 @@ def backup_download(name): if not os.path.lexists(archive_file): archive_file += ".gz" if not os.path.lexists(archive_file): - raise YunohostError("backup_archive_name_unknown", name=name) + raise YunohostValidationError("backup_archive_name_unknown", name=name) # If symlink, retrieve the real path if os.path.islink(archive_file): @@ -2389,7 +2389,7 @@ def backup_download(name): # Raise exception if link is broken (e.g. on unmounted external storage) if not os.path.exists(archive_file): - raise YunohostError("backup_archive_broken_link", path=archive_file) + raise YunohostValidationError("backup_archive_broken_link", path=archive_file) # We return a raw bottle HTTPresponse (instead of serializable data like # list/dict, ...), which is gonna be picked and used directly by moulinette @@ -2415,7 +2415,7 @@ def backup_info(name, with_details=False, human_readable=False): if not os.path.lexists(archive_file): archive_file += ".gz" if not os.path.lexists(archive_file): - raise YunohostError("backup_archive_name_unknown", name=name) + raise YunohostValidationError("backup_archive_name_unknown", name=name) # If symlink, retrieve the real path if os.path.islink(archive_file): @@ -2423,7 +2423,7 @@ def backup_info(name, with_details=False, human_readable=False): # Raise exception if link is broken (e.g. on unmounted external storage) if not os.path.exists(archive_file): - raise YunohostError("backup_archive_broken_link", path=archive_file) + raise YunohostValidationError("backup_archive_broken_link", path=archive_file) info_file = "%s/%s.info.json" % (ARCHIVES_PATH, name) @@ -2531,7 +2531,7 @@ def backup_delete(name): """ if name not in backup_list()["archives"]: - raise YunohostError("backup_archive_name_unknown", name=name) + raise YunohostValidationError("backup_archive_name_unknown", name=name) hook_callback("pre_backup_delete", args=[name]) diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py index c48af2c07..56ea70a04 100644 --- a/src/yunohost/certificate.py +++ b/src/yunohost/certificate.py @@ -37,7 +37,7 @@ from moulinette.utils.log import getActionLogger from moulinette.utils.filesystem import read_file from yunohost.vendor.acme_tiny.acme_tiny import get_crt as sign_certificate -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.utils.network import get_public_ip from yunohost.diagnosis import Diagnoser @@ -90,7 +90,7 @@ def certificate_status(domain_list, full=False): for domain in domain_list: # Is it in Yunohost domain list? if domain not in yunohost_domains_list: - raise YunohostError("domain_name_unknown", domain=domain) + raise YunohostValidationError("domain_name_unknown", domain=domain) certificates = {} @@ -166,7 +166,7 @@ def _certificate_install_selfsigned(domain_list, force=False): status = _get_status(domain) if status["summary"]["code"] in ("good", "great"): - raise YunohostError( + raise YunohostValidationError( "certmanager_attempt_to_replace_valid_cert", domain=domain ) @@ -267,12 +267,12 @@ def _certificate_install_letsencrypt( for domain in domain_list: yunohost_domains_list = yunohost.domain.domain_list()["domains"] if domain not in yunohost_domains_list: - raise YunohostError("domain_name_unknown", domain=domain) + raise YunohostValidationError("domain_name_unknown", domain=domain) # Is it self-signed? status = _get_status(domain) if not force and status["CA_type"]["code"] != "self-signed": - raise YunohostError( + raise YunohostValidationError( "certmanager_domain_cert_not_selfsigned", domain=domain ) @@ -370,25 +370,25 @@ def certificate_renew( # Is it in Yunohost dmomain list? if domain not in yunohost.domain.domain_list()["domains"]: - raise YunohostError("domain_name_unknown", domain=domain) + raise YunohostValidationError("domain_name_unknown", domain=domain) status = _get_status(domain) # Does it expire soon? if status["validity"] > VALIDITY_LIMIT and not force: - raise YunohostError( + raise YunohostValidationError( "certmanager_attempt_to_renew_valid_cert", domain=domain ) # Does it have a Let's Encrypt cert? if status["CA_type"]["code"] != "lets-encrypt": - raise YunohostError( + raise YunohostValidationError( "certmanager_attempt_to_renew_nonLE_cert", domain=domain ) # Check ACME challenge configured for given domain if not _check_acme_challenge_configuration(domain): - raise YunohostError( + raise YunohostValidationError( "certmanager_acme_not_configured_for_domain", domain=domain ) @@ -898,20 +898,20 @@ def _check_domain_is_ready_for_ACME(domain): ) if not dnsrecords or not httpreachable: - raise YunohostError("certmanager_domain_not_diagnosed_yet", domain=domain) + raise YunohostValidationError("certmanager_domain_not_diagnosed_yet", domain=domain) # Check if IP from DNS matches public IP if not dnsrecords.get("status") in [ "SUCCESS", "WARNING", ]: # Warning is for missing IPv6 record which ain't critical for ACME - raise YunohostError( + raise YunohostValidationError( "certmanager_domain_dns_ip_differs_from_public_ip", domain=domain ) # Check if domain seems to be accessible through HTTP? if not httpreachable.get("status") == "SUCCESS": - raise YunohostError("certmanager_domain_http_not_working", domain=domain) + raise YunohostValidationError("certmanager_domain_http_not_working", domain=domain) # FIXME / TODO : ideally this should not be needed. There should be a proper diff --git a/src/yunohost/data_migrations/0017_postgresql_9p6_to_11.py b/src/yunohost/data_migrations/0017_postgresql_9p6_to_11.py index 728ae443f..0526c025d 100644 --- a/src/yunohost/data_migrations/0017_postgresql_9p6_to_11.py +++ b/src/yunohost/data_migrations/0017_postgresql_9p6_to_11.py @@ -23,7 +23,7 @@ class MyMigration(Migration): return if not self.package_is_installed("postgresql-11"): - raise YunohostError("migration_0017_postgresql_11_not_installed") + raise YunohostValidationError("migration_0017_postgresql_11_not_installed") # Make sure there's a 9.6 cluster try: @@ -37,7 +37,7 @@ class MyMigration(Migration): if not space_used_by_directory( "/var/lib/postgresql/9.6" ) > free_space_in_directory("/var/lib/postgresql"): - raise YunohostError( + raise YunohostValidationError( "migration_0017_not_enough_space", path="/var/lib/postgresql/" ) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index d01d56613..cc0035755 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -37,7 +37,7 @@ from moulinette.utils.filesystem import ( write_to_yaml, ) -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.hook import hook_list, hook_exec logger = log.getActionLogger("yunohost.diagnosis") @@ -59,11 +59,11 @@ def diagnosis_get(category, item): all_categories_names = [c for c, _ in all_categories] if category not in all_categories_names: - raise YunohostError("diagnosis_unknown_categories", categories=category) + raise YunohostValidationError("diagnosis_unknown_categories", categories=category) if isinstance(item, list): if any("=" not in criteria for criteria in item): - raise YunohostError( + raise YunohostValidationError( "Criterias should be of the form key=value (e.g. domain=yolo.test)" ) @@ -91,7 +91,7 @@ def diagnosis_show( else: unknown_categories = [c for c in categories if c not in all_categories_names] if unknown_categories: - raise YunohostError( + raise YunohostValidationError( "diagnosis_unknown_categories", categories=", ".join(unknown_categories) ) @@ -181,7 +181,7 @@ def diagnosis_run( else: unknown_categories = [c for c in categories if c not in all_categories_names] if unknown_categories: - raise YunohostError( + raise YunohostValidationError( "diagnosis_unknown_categories", categories=", ".join(unknown_categories) ) @@ -270,14 +270,14 @@ def diagnosis_ignore(add_filter=None, remove_filter=None, list=False): # Sanity checks for the provided arguments if len(filter_) == 0: - raise YunohostError( + raise YunohostValidationError( "You should provide at least one criteria being the diagnosis category to ignore" ) category = filter_[0] if category not in all_categories_names: - raise YunohostError("%s is not a diagnosis category" % category) + raise YunohostValidationError("%s is not a diagnosis category" % category) if any("=" not in criteria for criteria in filter_[1:]): - raise YunohostError( + raise YunohostValidationError( "Criterias should be of the form key=value (e.g. domain=yolo.test)" ) @@ -331,7 +331,7 @@ def diagnosis_ignore(add_filter=None, remove_filter=None, list=False): configuration["ignore_filters"][category] = [] if criterias not in configuration["ignore_filters"][category]: - raise YunohostError("This filter does not exists.") + raise YunohostValidationError("This filter does not exists.") configuration["ignore_filters"][category].remove(criterias) _diagnosis_write_configuration(configuration) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 1198ef473..fdf247f89 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -101,16 +101,14 @@ def domain_add(operation_logger, domain, dyndns=False): from yunohost.utils.ldap import _get_ldap_interface if domain.startswith("xmpp-upload."): - raise YunohostError("domain_cannot_add_xmpp_upload") + raise YunohostValidationError("domain_cannot_add_xmpp_upload") ldap = _get_ldap_interface() try: ldap.validate_uniqueness({"virtualdomain": domain}) except MoulinetteError: - raise YunohostError("domain_exists") - - operation_logger.start() + raise YunohostValidationError("domain_exists") # Lower domain to avoid some edge cases issues # See: https://forum.yunohost.org/t/invalid-domain-causes-diagnosis-web-to-fail-fr-on-demand/11765 @@ -119,17 +117,21 @@ def domain_add(operation_logger, domain, dyndns=False): # DynDNS domain if dyndns: - from yunohost.dyndns import dyndns_subscribe, _dyndns_provides, _guess_current_dyndns_domain + from yunohost.dyndns import _dyndns_provides, _guess_current_dyndns_domain # Do not allow to subscribe to multiple dyndns domains... if _guess_current_dyndns_domain("dyndns.yunohost.org") != (None, None): - raise YunohostError('domain_dyndns_already_subscribed') + raise YunohostValidationError('domain_dyndns_already_subscribed') # Check that this domain can effectively be provided by # dyndns.yunohost.org. (i.e. is it a nohost.me / noho.st) if not _dyndns_provides("dyndns.yunohost.org", domain): - raise YunohostError("domain_dyndns_root_unknown") + raise YunohostValidationError("domain_dyndns_root_unknown") + operation_logger.start() + + if dyndns: + from yunohost.dyndns import dndns_subscribe # Actually subscribe dyndns_subscribe(domain=domain) @@ -197,7 +199,7 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False): # we don't want to check the domain exists because the ldap add may have # failed if not force and domain not in domain_list()['domains']: - raise YunohostError('domain_name_unknown', domain=domain) + raise YunohostValidationError('domain_name_unknown', domain=domain) # Check domain is not the main domain if domain == _get_maindomain(): @@ -205,13 +207,13 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False): other_domains.remove(domain) if other_domains: - raise YunohostError( + raise YunohostValidationError( "domain_cannot_remove_main", domain=domain, other_domains="\n * " + ("\n * ".join(other_domains)), ) else: - raise YunohostError("domain_cannot_remove_main_add_new_one", domain=domain) + raise YunohostValidationError("domain_cannot_remove_main_add_new_one", domain=domain) # Check if apps are installed on the domain apps_on_that_domain = [] @@ -234,9 +236,10 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False): for app, _ in apps_on_that_domain: app_remove(app) else: - raise YunohostError('domain_uninstall_app_first', apps="\n".join([x[1] for x in apps_on_that_domain])) + raise YunohostValidationError('domain_uninstall_app_first', apps="\n".join([x[1] for x in apps_on_that_domain])) operation_logger.start() + ldap = _get_ldap_interface() try: ldap.remove("virtualdomain=" + domain + ",ou=domains") @@ -288,7 +291,7 @@ def domain_dns_conf(domain, ttl=None): """ if domain not in domain_list()["domains"]: - raise YunohostError("domain_name_unknown", domain=domain) + raise YunohostValidationError("domain_name_unknown", domain=domain) ttl = 3600 if ttl is None else ttl @@ -345,7 +348,7 @@ def domain_main_domain(operation_logger, new_main_domain=None): # Check domain exists if new_main_domain not in domain_list()["domains"]: - raise YunohostError("domain_name_unknown", domain=new_main_domain) + raise YunohostValidationError("domain_name_unknown", domain=new_main_domain) operation_logger.related_to.append(("domain", new_main_domain)) operation_logger.start() diff --git a/src/yunohost/dyndns.py b/src/yunohost/dyndns.py index a921cfb5c..b2ac3de6d 100644 --- a/src/yunohost/dyndns.py +++ b/src/yunohost/dyndns.py @@ -36,7 +36,7 @@ from moulinette.utils.log import getActionLogger from moulinette.utils.filesystem import write_to_file, read_file from moulinette.utils.network import download_json -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.domain import _get_maindomain, _build_dns_conf from yunohost.utils.network import get_public_ip, dig from yunohost.log import is_unit_operation @@ -124,7 +124,7 @@ def dyndns_subscribe( """ if _guess_current_dyndns_domain(subscribe_host) != (None, None): - raise YunohostError('domain_dyndns_already_subscribed') + raise YunohostValidationError('domain_dyndns_already_subscribed') if domain is None: domain = _get_maindomain() @@ -132,13 +132,13 @@ def dyndns_subscribe( # Verify if domain is provided by subscribe_host if not _dyndns_provides(subscribe_host, domain): - raise YunohostError( + raise YunohostValidationError( "dyndns_domain_not_provided", domain=domain, provider=subscribe_host ) # Verify if domain is available if not _dyndns_available(subscribe_host, domain): - raise YunohostError("dyndns_unavailable", domain=domain) + raise YunohostValidationError("dyndns_unavailable", domain=domain) operation_logger.start() @@ -231,7 +231,7 @@ def dyndns_update( (domain, key) = _guess_current_dyndns_domain(dyn_host) if domain is None: - raise YunohostError('dyndns_no_domain_registered') + raise YunohostValidationError('dyndns_no_domain_registered') # If key is not given, pick the first file we find with the domain given else: @@ -239,7 +239,7 @@ def dyndns_update( keys = glob.glob("/etc/yunohost/dyndns/K{0}.+*.private".format(domain)) if not keys: - raise YunohostError("dyndns_key_not_found") + raise YunohostValidationError("dyndns_key_not_found") key = keys[0] diff --git a/src/yunohost/firewall.py b/src/yunohost/firewall.py index 1b708a626..bc21f1948 100644 --- a/src/yunohost/firewall.py +++ b/src/yunohost/firewall.py @@ -28,7 +28,7 @@ import yaml import miniupnpc from moulinette import m18n -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from moulinette.utils import process from moulinette.utils.log import getActionLogger from moulinette.utils.text import prependlines @@ -366,7 +366,7 @@ def firewall_upnp(action="status", no_refresh=False): if action == "status": no_refresh = True else: - raise YunohostError("action_invalid", action=action) + raise YunohostValidationError("action_invalid", action=action) # Refresh port mapping using UPnP if not no_refresh: diff --git a/src/yunohost/hook.py b/src/yunohost/hook.py index e9857e4f9..493ad2c35 100644 --- a/src/yunohost/hook.py +++ b/src/yunohost/hook.py @@ -32,7 +32,7 @@ from glob import iglob from importlib import import_module from moulinette import m18n, msettings -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from moulinette.utils import log from moulinette.utils.filesystem import read_json @@ -117,7 +117,7 @@ def hook_info(action, name): ) if not hooks: - raise YunohostError("hook_name_unknown", name=name) + raise YunohostValidationError("hook_name_unknown", name=name) return { "action": action, "name": name, @@ -186,7 +186,7 @@ def hook_list(action, list_by="name", show_info=False): d.add(name) else: - raise YunohostError("hook_list_by_invalid") + raise YunohostValidationError("hook_list_by_invalid") def _append_folder(d, folder): # Iterate over and add hook from a folder @@ -273,7 +273,7 @@ def hook_callback( try: hl = hooks_names[n] except KeyError: - raise YunohostError("hook_name_unknown", n) + raise YunohostValidationError("hook_name_unknown", n) # Iterate over hooks with this name for h in hl: # Update hooks dict diff --git a/src/yunohost/log.py b/src/yunohost/log.py index e5a53d466..1260cd98d 100644 --- a/src/yunohost/log.py +++ b/src/yunohost/log.py @@ -191,7 +191,7 @@ def log_show( log_path = base_path + LOG_FILE_EXT if not os.path.exists(md_path) and not os.path.exists(log_path): - raise YunohostError("log_does_exists", log=path) + raise YunohostValidationError("log_does_exists", log=path) infos = {} diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 3cd67b148..e0a3c6be8 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -31,7 +31,7 @@ import random from moulinette import m18n from moulinette.utils.log import getActionLogger -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.log import is_unit_operation logger = getActionLogger("yunohost.user") @@ -175,14 +175,14 @@ def user_permission_update( # Refuse to add "visitors" to mail, xmpp ... they require an account to make sense. if add and "visitors" in add and permission.split(".")[0] in SYSTEM_PERMS: - raise YunohostError("permission_require_account", permission=permission) + raise YunohostValidationError("permission_require_account", permission=permission) # Refuse to add "visitors" to protected permission if ( (add and "visitors" in add and existing_permission["protected"]) or (remove and "visitors" in remove and existing_permission["protected"]) ) and not force: - raise YunohostError("permission_protected", permission=permission) + raise YunohostValidationError("permission_protected", permission=permission) # Fetch currently allowed groups for this permission @@ -198,7 +198,7 @@ def user_permission_update( groups_to_add = [add] if not isinstance(add, list) else add for group in groups_to_add: if group not in all_existing_groups: - raise YunohostError("group_unknown", group=group) + raise YunohostValidationError("group_unknown", group=group) if group in current_allowed_groups: logger.warning( m18n.n( @@ -326,7 +326,7 @@ def user_permission_info(permission): permission, None ) if existing_permission is None: - raise YunohostError("permission_not_found", permission=permission) + raise YunohostValidationError("permission_not_found", permission=permission) return existing_permission @@ -391,7 +391,7 @@ def permission_create( if ldap.get_conflict( {"cn": permission}, base_dn="ou=permission,dc=yunohost,dc=org" ): - raise YunohostError("permission_already_exist", permission=permission) + raise YunohostValidationError("permission_already_exist", permission=permission) # Get random GID all_gid = {x.gr_gid for x in grp.getgrall()} @@ -427,7 +427,7 @@ def permission_create( all_existing_groups = user_group_list()["groups"].keys() for group in allowed or []: if group not in all_existing_groups: - raise YunohostError("group_unknown", group=group) + raise YunohostValidationError("group_unknown", group=group) operation_logger.related_to.append(("app", permission.split(".")[0])) operation_logger.start() @@ -594,7 +594,7 @@ def permission_delete(operation_logger, permission, force=False, sync_perm=True) permission = permission + ".main" if permission.endswith(".main") and not force: - raise YunohostError("permission_cannot_remove_main") + raise YunohostValidationError("permission_cannot_remove_main") from yunohost.utils.ldap import _get_ldap_interface @@ -861,7 +861,7 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app): try: re.compile(regex) except Exception: - raise YunohostError("invalid_regex", regex=regex) + raise YunohostValidationError("invalid_regex", regex=regex) if url.startswith("re:"): @@ -874,12 +874,12 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app): # regex with domain if "/" not in url: - raise YunohostError("regex_with_only_domain") + raise YunohostValidationError("regex_with_only_domain") domain, path = url[3:].split("/", 1) path = "/" + path if domain.replace("%", "").replace("\\", "") not in domains: - raise YunohostError("domain_name_unknown", domain=domain) + raise YunohostValidationError("domain_name_unknown", domain=domain) validate_regex(path) @@ -914,7 +914,7 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app): sanitized_url = domain + path if domain not in domains: - raise YunohostError("domain_name_unknown", domain=domain) + raise YunohostValidationError("domain_name_unknown", domain=domain) _assert_no_conflicting_apps(domain, path, ignore_app=app) diff --git a/src/yunohost/service.py b/src/yunohost/service.py index 2de395131..3a0450bce 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -34,7 +34,7 @@ from glob import glob from datetime import datetime from moulinette import m18n -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from moulinette.utils.process import check_output from moulinette.utils.log import getActionLogger from moulinette.utils.filesystem import read_file, append_to_file, write_to_file @@ -145,7 +145,7 @@ def service_remove(name): services = _get_services() if name not in services: - raise YunohostError("service_unknown", service=name) + raise YunohostValidationError("service_unknown", service=name) del services[name] try: @@ -325,7 +325,7 @@ def service_status(names=[]): # Validate service names requested for name in names: if name not in services.keys(): - raise YunohostError("service_unknown", service=name) + raise YunohostValidationError("service_unknown", service=name) # Filter only requested servivces services = {k: v for k, v in services.items() if k in names} @@ -484,7 +484,7 @@ def service_log(name, number=50): number = int(number) if name not in services.keys(): - raise YunohostError("service_unknown", service=name) + raise YunohostValidationError("service_unknown", service=name) log_list = services[name].get("log", []) @@ -545,7 +545,7 @@ def service_regen_conf( for name in names: if name not in services.keys(): - raise YunohostError("service_unknown", service=name) + raise YunohostValidationError("service_unknown", service=name) if names is []: names = list(services.keys()) @@ -568,7 +568,7 @@ def _run_service_command(action, service): """ services = _get_services() if service not in services.keys(): - raise YunohostError("service_unknown", service=service) + raise YunohostValidationError("service_unknown", service=service) possible_actions = [ "start", diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index 9bf75ff1d..9d1a6d11f 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -6,7 +6,7 @@ from datetime import datetime from collections import OrderedDict from moulinette import m18n -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from moulinette.utils.log import getActionLogger from yunohost.regenconf import regen_conf @@ -109,7 +109,7 @@ def settings_get(key, full=False): settings = _get_settings() if key not in settings: - raise YunohostError("global_settings_key_doesnt_exists", settings_key=key) + raise YunohostValidationError("global_settings_key_doesnt_exists", settings_key=key) if full: return settings[key] @@ -137,7 +137,7 @@ def settings_set(key, value): settings = _get_settings() if key not in settings: - raise YunohostError("global_settings_key_doesnt_exists", settings_key=key) + raise YunohostValidationError("global_settings_key_doesnt_exists", settings_key=key) key_type = settings[key]["type"] @@ -146,7 +146,7 @@ def settings_set(key, value): if boolean_value[0]: value = boolean_value[1] else: - raise YunohostError( + raise YunohostValidationError( "global_settings_bad_type_for_setting", setting=key, received_type=type(value).__name__, @@ -158,14 +158,14 @@ def settings_set(key, value): try: value = int(value) except Exception: - raise YunohostError( + raise YunohostValidationError( "global_settings_bad_type_for_setting", setting=key, received_type=type(value).__name__, expected_type=key_type, ) else: - raise YunohostError( + raise YunohostValidationError( "global_settings_bad_type_for_setting", setting=key, received_type=type(value).__name__, @@ -173,7 +173,7 @@ def settings_set(key, value): ) elif key_type == "string": if not isinstance(value, str): - raise YunohostError( + raise YunohostValidationError( "global_settings_bad_type_for_setting", setting=key, received_type=type(value).__name__, @@ -181,14 +181,14 @@ def settings_set(key, value): ) elif key_type == "enum": if value not in settings[key]["choices"]: - raise YunohostError( + raise YunohostValidationError( "global_settings_bad_choice_for_enum", setting=key, choice=str(value), available_choices=", ".join(settings[key]["choices"]), ) else: - raise YunohostError( + raise YunohostValidationError( "global_settings_unknown_type", setting=key, unknown_type=key_type ) @@ -214,7 +214,7 @@ def settings_reset(key): settings = _get_settings() if key not in settings: - raise YunohostError("global_settings_key_doesnt_exists", settings_key=key) + raise YunohostValidationError("global_settings_key_doesnt_exists", settings_key=key) settings[key]["value"] = settings[key]["default"] _save_settings(settings) @@ -304,7 +304,7 @@ def _get_settings(): ) unknown_settings[key] = value except Exception as e: - raise YunohostError("global_settings_cant_open_settings", reason=e) + raise YunohostValidationError("global_settings_cant_open_settings", reason=e) if unknown_settings: try: diff --git a/src/yunohost/ssh.py b/src/yunohost/ssh.py index f7c6fcbb1..e9e7e1831 100644 --- a/src/yunohost/ssh.py +++ b/src/yunohost/ssh.py @@ -5,7 +5,7 @@ import os import pwd import subprocess -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from moulinette.utils.filesystem import read_file, write_to_file, chown, chmod, mkdir SSHD_CONFIG_PATH = "/etc/ssh/sshd_config" @@ -21,7 +21,7 @@ def user_ssh_allow(username): # TODO it would be good to support different kind of shells if not _get_user_for_ssh(username): - raise YunohostError("user_unknown", user=username) + raise YunohostValidationError("user_unknown", user=username) from yunohost.utils.ldap import _get_ldap_interface @@ -43,7 +43,7 @@ def user_ssh_disallow(username): # TODO it would be good to support different kind of shells if not _get_user_for_ssh(username): - raise YunohostError("user_unknown", user=username) + raise YunohostValidationError("user_unknown", user=username) from yunohost.utils.ldap import _get_ldap_interface diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index e1ebe1307..e5699dede 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -51,7 +51,7 @@ from yunohost.utils.packages import ( _list_upgradable_apt_packages, ynh_packages_version, ) -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.log import is_unit_operation, OperationLogger # FIXME this is a duplicate from apps.py @@ -156,7 +156,7 @@ def tools_adminpw(new_password, check_strength=True): # UNIX seems to not like password longer than 127 chars ... # e.g. SSH login gets broken (or even 'su admin' when entering the password) if len(new_password) >= 127: - raise YunohostError("admin_password_too_long") + raise YunohostValidationError("admin_password_too_long") new_hash = _hash_user_password(new_password) @@ -285,10 +285,10 @@ def tools_postinstall( # Do some checks at first if os.path.isfile("/etc/yunohost/installed"): - raise YunohostError("yunohost_already_installed") + raise YunohostValidationError("yunohost_already_installed") if os.path.isdir("/etc/yunohost/apps") and os.listdir("/etc/yunohost/apps") != []: - raise YunohostError( + raise YunohostValidationError( "It looks like you're trying to re-postinstall a system that was already working previously ... If you recently had some bug or issues with your installation, please first discuss with the team on how to fix the situation instead of savagely re-running the postinstall ...", raw_msg=True, ) @@ -301,7 +301,7 @@ def tools_postinstall( ) GB = 1024 ** 3 if not force_diskspace and main_space < 10 * GB: - raise YunohostError("postinstall_low_rootfsspace") + raise YunohostValidationError("postinstall_low_rootfsspace") # Check password if not force_password: @@ -331,14 +331,14 @@ def tools_postinstall( dyndns = True # If not, abort the postinstall else: - raise YunohostError("dyndns_unavailable", domain=domain) + raise YunohostValidationError("dyndns_unavailable", domain=domain) else: dyndns = False else: dyndns = False if os.system("iptables -V >/dev/null 2>/dev/null") != 0: - raise YunohostError( + raise YunohostValidationError( "iptables/nftables does not seems to be working on your setup. You may be in a container or your kernel does have the proper modules loaded. Sometimes, rebooting the machine may solve the issue.", raw_msg=True, ) @@ -530,17 +530,17 @@ def tools_upgrade( from yunohost.utils import packages if packages.dpkg_is_broken(): - raise YunohostError("dpkg_is_broken") + raise YunohostValidationError("dpkg_is_broken") # Check for obvious conflict with other dpkg/apt commands already running in parallel if not packages.dpkg_lock_available(): - raise YunohostError("dpkg_lock_not_available") + raise YunohostValidationError("dpkg_lock_not_available") if system is not False and apps is not None: - raise YunohostError("tools_upgrade_cant_both") + raise YunohostValidationError("tools_upgrade_cant_both") if system is False and apps is None: - raise YunohostError("tools_upgrade_at_least_one") + raise YunohostValidationError("tools_upgrade_at_least_one") # # Apps @@ -825,7 +825,7 @@ def tools_migrations_list(pending=False, done=False): # Check for option conflict if pending and done: - raise YunohostError("migrations_list_conflict_pending_done") + raise YunohostValidationError("migrations_list_conflict_pending_done") # Get all migrations migrations = _get_migrations_list() @@ -875,17 +875,17 @@ def tools_migrations_run( if m.id == target or m.name == target or m.id.split("_")[0] == target: return m - raise YunohostError("migrations_no_such_migration", id=target) + raise YunohostValidationError("migrations_no_such_migration", id=target) # auto, skip and force are exclusive options if auto + skip + force_rerun > 1: - raise YunohostError("migrations_exclusive_options") + raise YunohostValidationError("migrations_exclusive_options") # If no target specified if not targets: # skip, revert or force require explicit targets if skip or force_rerun: - raise YunohostError("migrations_must_provide_explicit_targets") + raise YunohostValidationError("migrations_must_provide_explicit_targets") # Otherwise, targets are all pending migrations targets = [m for m in all_migrations if m.state == "pending"] @@ -897,11 +897,11 @@ def tools_migrations_run( pending = [t.id for t in targets if t.state == "pending"] if skip and done: - raise YunohostError("migrations_not_pending_cant_skip", ids=", ".join(done)) + raise YunohostValidationError("migrations_not_pending_cant_skip", ids=", ".join(done)) if force_rerun and pending: - raise YunohostError("migrations_pending_cant_rerun", ids=", ".join(pending)) + raise YunohostValidationError("migrations_pending_cant_rerun", ids=", ".join(pending)) if not (skip or force_rerun) and done: - raise YunohostError("migrations_already_ran", ids=", ".join(done)) + raise YunohostValidationError("migrations_already_ran", ids=", ".join(done)) # So, is there actually something to do ? if not targets: diff --git a/src/yunohost/user.py b/src/yunohost/user.py index f1fab786a..089f2ba0e 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -37,7 +37,7 @@ from moulinette import msignals, msettings, m18n from moulinette.utils.log import getActionLogger from moulinette.utils.process import check_output -from yunohost.utils.error import YunohostError +from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.service import service_status from yunohost.log import is_unit_operation @@ -125,7 +125,7 @@ def user_create( # Validate domain used for email address/xmpp account if domain is None: if msettings.get("interface") == "api": - raise YunohostError("Invalide usage, specify domain argument") + raise YunohostValidationError("Invalid usage, you should specify a domain argument") else: # On affiche les differents domaines possibles msignals.display(m18n.n("domains_available")) @@ -141,24 +141,24 @@ def user_create( # Check that the domain exists if domain not in domain_list()["domains"]: - raise YunohostError("domain_name_unknown", domain=domain) + raise YunohostValidationError("domain_name_unknown", domain=domain) mail = username + "@" + domain ldap = _get_ldap_interface() if username in user_list()["users"]: - raise YunohostError("user_already_exists", user=username) + raise YunohostValidationError("user_already_exists", user=username) # Validate uniqueness of username and mail in LDAP try: ldap.validate_uniqueness({"uid": username, "mail": mail, "cn": username}) except Exception as e: - raise YunohostError("user_creation_failed", user=username, error=e) + raise YunohostValidationError("user_creation_failed", user=username, error=e) # Validate uniqueness of username in system users all_existing_usernames = {x.pw_name for x in pwd.getpwall()} if username in all_existing_usernames: - raise YunohostError("system_username_exists") + raise YunohostValidationError("system_username_exists") main_domain = _get_maindomain() aliases = [ @@ -170,7 +170,7 @@ def user_create( ] if mail in aliases: - raise YunohostError("mail_unavailable") + raise YunohostValidationError("mail_unavailable") operation_logger.start() @@ -264,7 +264,7 @@ def user_delete(operation_logger, username, purge=False): from yunohost.utils.ldap import _get_ldap_interface if username not in user_list()["users"]: - raise YunohostError("user_unknown", user=username) + raise YunohostValidationError("user_unknown", user=username) operation_logger.start() @@ -347,7 +347,7 @@ def user_update( attrs=attrs_to_fetch, ) if not result: - raise YunohostError("user_unknown", user=username) + raise YunohostValidationError("user_unknown", user=username) user = result[0] env_dict = {"YNH_USER_USERNAME": username} @@ -396,13 +396,13 @@ def user_update( try: ldap.validate_uniqueness({"mail": mail}) except Exception as e: - raise YunohostError("user_update_failed", user=username, error=e) + raise YunohostValidationError("user_update_failed", user=username, error=e) if mail[mail.find("@") + 1 :] not in domains: - raise YunohostError( + raise YunohostValidationError( "mail_domain_unknown", domain=mail[mail.find("@") + 1 :] ) if mail in aliases: - raise YunohostError("mail_unavailable") + raise YunohostValidationError("mail_unavailable") del user["mail"][0] new_attr_dict["mail"] = [mail] + user["mail"] @@ -414,9 +414,9 @@ def user_update( try: ldap.validate_uniqueness({"mail": mail}) except Exception as e: - raise YunohostError("user_update_failed", user=username, error=e) + raise YunohostValidationError("user_update_failed", user=username, error=e) if mail[mail.find("@") + 1 :] not in domains: - raise YunohostError( + raise YunohostValidationError( "mail_domain_unknown", domain=mail[mail.find("@") + 1 :] ) user["mail"].append(mail) @@ -429,7 +429,7 @@ def user_update( if len(user["mail"]) > 1 and mail in user["mail"][1:]: user["mail"].remove(mail) else: - raise YunohostError("mail_alias_remove_failed", mail=mail) + raise YunohostValidationError("mail_alias_remove_failed", mail=mail) new_attr_dict["mail"] = user["mail"] if "mail" in new_attr_dict: @@ -451,7 +451,7 @@ def user_update( if len(user["maildrop"]) > 1 and mail in user["maildrop"][1:]: user["maildrop"].remove(mail) else: - raise YunohostError("mail_forward_remove_failed", mail=mail) + raise YunohostValidationError("mail_forward_remove_failed", mail=mail) new_attr_dict["maildrop"] = user["maildrop"] if "maildrop" in new_attr_dict: @@ -500,7 +500,7 @@ def user_info(username): if result: user = result[0] else: - raise YunohostError("user_unknown", user=username) + raise YunohostValidationError("user_unknown", user=username) result_dict = { "username": user["uid"][0], @@ -638,7 +638,7 @@ def user_group_create( {"cn": groupname}, base_dn="ou=groups,dc=yunohost,dc=org" ) if conflict: - raise YunohostError("group_already_exist", group=groupname) + raise YunohostValidationError("group_already_exist", group=groupname) # Validate uniqueness of groupname in system group all_existing_groupnames = {x.gr_name for x in grp.getgrall()} @@ -651,7 +651,7 @@ def user_group_create( "sed --in-place '/^%s:/d' /etc/group" % groupname, shell=True ) else: - raise YunohostError("group_already_exist_on_system", group=groupname) + raise YunohostValidationError("group_already_exist_on_system", group=groupname) if not gid: # Get random GID @@ -705,7 +705,7 @@ def user_group_delete(operation_logger, groupname, force=False, sync_perm=True): existing_groups = list(user_group_list()["groups"].keys()) if groupname not in existing_groups: - raise YunohostError("group_unknown", group=groupname) + raise YunohostValidationError("group_unknown", group=groupname) # Refuse to delete primary groups of a user (e.g. group 'sam' related to user 'sam') # without the force option... @@ -714,7 +714,7 @@ def user_group_delete(operation_logger, groupname, force=False, sync_perm=True): existing_users = list(user_list()["users"].keys()) undeletable_groups = existing_users + ["all_users", "visitors"] if groupname in undeletable_groups and not force: - raise YunohostError("group_cannot_be_deleted", group=groupname) + raise YunohostValidationError("group_cannot_be_deleted", group=groupname) operation_logger.start() ldap = _get_ldap_interface() @@ -756,11 +756,11 @@ def user_group_update( # We also can't edit "all_users" without the force option because that's a special group... if not force: if groupname == "all_users": - raise YunohostError("group_cannot_edit_all_users") + raise YunohostValidationError("group_cannot_edit_all_users") elif groupname == "visitors": - raise YunohostError("group_cannot_edit_visitors") + raise YunohostValidationError("group_cannot_edit_visitors") elif groupname in existing_users: - raise YunohostError("group_cannot_edit_primary_group", group=groupname) + raise YunohostValidationError("group_cannot_edit_primary_group", group=groupname) # We extract the uid for each member of the group to keep a simple flat list of members current_group = user_group_info(groupname)["members"] @@ -771,7 +771,7 @@ def user_group_update( for user in users_to_add: if user not in existing_users: - raise YunohostError("user_unknown", user=user) + raise YunohostValidationError("user_unknown", user=user) if user in current_group: logger.warning( @@ -843,7 +843,7 @@ def user_group_info(groupname): ) if not result: - raise YunohostError("group_unknown", group=groupname) + raise YunohostValidationError("group_unknown", group=groupname) infos = result[0] diff --git a/src/yunohost/utils/error.py b/src/yunohost/utils/error.py index 3000a52f8..e78beb2c9 100644 --- a/src/yunohost/utils/error.py +++ b/src/yunohost/utils/error.py @@ -49,3 +49,7 @@ class YunohostError(MoulinetteError): return super(YunohostError, self).content() else: return {"error": self.strerror, "log_ref": self.log_ref} + + +class YunohostValidationError(YunohostError): + pass diff --git a/src/yunohost/utils/password.py b/src/yunohost/utils/password.py index dce337f84..9e693d8cd 100644 --- a/src/yunohost/utils/password.py +++ b/src/yunohost/utils/password.py @@ -90,11 +90,11 @@ class PasswordValidator(object): # on top (at least not the moulinette ones) # because the moulinette needs to be correctly initialized # as well as modules available in python's path. - from yunohost.utils.error import YunohostError + from yunohost.utils.error import YunohostValidationError status, msg = self.validation_summary(password) if status == "error": - raise YunohostError(msg) + raise YunohostValidationError(msg) def validation_summary(self, password): """ diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index 6876cbcd8..799dc0d0c 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -25,9 +25,11 @@ def find_expected_string_keys(): # Try to find : # m18n.n( "foo" # YunohostError("foo" + # YunohostValidationError("foo" # # i18n: foo p1 = re.compile(r"m18n\.n\(\n*\s*[\"\'](\w+)[\"\']") p2 = re.compile(r"YunohostError\(\n*\s*[\'\"](\w+)[\'\"]") + p2 = re.compile(r"YunohostValidationError\(\n*\s*[\'\"](\w+)[\'\"]") p3 = re.compile(r"# i18n: [\'\"]?(\w+)[\'\"]?") python_files = glob.glob("src/yunohost/*.py")