From 07cec39af50a203151a5845054ec2e44b9531e4c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 30 Sep 2020 17:38:42 +0200 Subject: [PATCH] Move a bunch of function from domain.py to app.py because it's much simpler to have them here --- src/yunohost/app.py | 83 ++++++++++++++++++++++++++++--- src/yunohost/domain.py | 80 +---------------------------- src/yunohost/permission.py | 4 +- src/yunohost/tests/test_appurl.py | 4 +- 4 files changed, 81 insertions(+), 90 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 282f37c72..3e4e6b84d 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -317,7 +317,6 @@ def app_change_url(operation_logger, app, domain, path): """ from yunohost.hook import hook_exec, hook_callback - from yunohost.domain import _normalize_domain_path, _assert_no_conflicting_apps installed = _is_installed(app) if not installed: @@ -1309,10 +1308,6 @@ def app_register_url(app, domain, path): path -- The path to be registered (e.g. /coffee) """ - # This line can't be moved on top of file, otherwise it creates an infinite - # loop of import with tools.py... - from .domain import _assert_no_conflicting_apps, _normalize_domain_path - domain, path = _normalize_domain_path(domain, path) # We cannot change the url of an app already installed simply by changing @@ -2586,8 +2581,6 @@ def _parse_args_in_yunohost_format(user_answers, argument_questions): def _validate_and_normalize_webpath(manifest, args_dict, app_folder): - from yunohost.domain import _assert_no_conflicting_apps, _normalize_domain_path - # If there's only one "domain" and "path", validate that domain/path # is an available url and normalize the path. @@ -2627,6 +2620,82 @@ def _validate_and_normalize_webpath(manifest, args_dict, app_folder): _assert_no_conflicting_apps(domain, "/", full_domain=True) +def _normalize_domain_path(domain, path): + + # We want url to be of the format : + # some.domain.tld/foo + + # Remove http/https prefix if it's there + if domain.startswith("https://"): + domain = domain[len("https://"):] + elif domain.startswith("http://"): + domain = domain[len("http://"):] + + # Remove trailing slashes + domain = domain.rstrip("/").lower() + path = "/" + path.strip("/") + + return domain, path + + +def _get_conflicting_apps(domain, path, ignore_app=None): + """ + Return a list of all conflicting apps with a domain/path (it can be empty) + + Keyword argument: + domain -- The domain for the web path (e.g. your.domain.tld) + path -- The path to check (e.g. /coffee) + ignore_app -- An optional app id to ignore (c.f. the change_url usecase) + """ + + from yunohost.domain import domain_list + + domain, path = _normalize_domain_path(domain, path) + + # Abort if domain is unknown + if domain not in domain_list()['domains']: + raise YunohostError('domain_name_unknown', domain=domain) + + # Fetch apps map + apps_map = app_map(raw=True) + + # Loop through all apps to check if path is taken by one of them + conflicts = [] + if domain in apps_map: + # Loop through apps + for p, a in apps_map[domain].items(): + if a["id"] == ignore_app: + continue + if path == p: + conflicts.append((p, a["id"], a["label"])) + # We also don't want conflicts with other apps starting with + # same name + elif path.startswith(p) or p.startswith(path): + conflicts.append((p, a["id"], a["label"])) + + return conflicts + + +def _assert_no_conflicting_apps(domain, path, ignore_app=None, full_domain=False): + + conflicts = _get_conflicting_apps(domain, path, ignore_app) + + if conflicts: + apps = [] + for path, app_id, app_label in conflicts: + apps.append(" * {domain:s}{path:s} → {app_label:s} ({app_id:s})".format( + domain=domain, + path=path, + app_id=app_id, + app_label=app_label, + )) + + if full_domain: + raise YunohostError('app_full_domain_unavailable', domain=domain) + else: + raise YunohostError('app_location_unavailable', apps="\n".join(apps)) + + def _make_environment_dict(args_dict, prefix="APP_ARG_"): """ Convert a dictionnary containing manifest arguments diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 8a9917864..050cbbfda 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -31,7 +31,7 @@ from moulinette.core import MoulinetteError from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger -from yunohost.app import app_ssowatconf, _installed_apps, _get_app_settings +from yunohost.app import app_ssowatconf, _installed_apps, _get_app_settings, _get_conflicting_apps from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf from yunohost.utils.network import get_public_ip from yunohost.log import is_unit_operation @@ -349,66 +349,6 @@ def domain_cert_renew(domain_list, force=False, no_checks=False, email=False, st return yunohost.certificate.certificate_renew(domain_list, force, no_checks, email, staging) -def _get_conflicting_apps(domain, path, ignore_app=None): - """ - Return a list of all conflicting apps with a domain/path (it can be empty) - - Keyword argument: - domain -- The domain for the web path (e.g. your.domain.tld) - path -- The path to check (e.g. /coffee) - ignore_app -- An optional app id to ignore (c.f. the change_url usecase) - """ - - domain, path = _normalize_domain_path(domain, path) - - # Abort if domain is unknown - if domain not in domain_list()['domains']: - raise YunohostError('domain_name_unknown', domain=domain) - - # This import cannot be put on top of file because it would create a - # recursive import... - from yunohost.app import app_map - - # Fetch apps map - apps_map = app_map(raw=True) - - # Loop through all apps to check if path is taken by one of them - conflicts = [] - if domain in apps_map: - # Loop through apps - for p, a in apps_map[domain].items(): - if a["id"] == ignore_app: - continue - if path == p: - conflicts.append((p, a["id"], a["label"])) - # We also don't want conflicts with other apps starting with - # same name - elif path.startswith(p) or p.startswith(path): - conflicts.append((p, a["id"], a["label"])) - - return conflicts - - -def _assert_no_conflicting_apps(domain, path, ignore_app=None, full_domain=False): - - conflicts = _get_conflicting_apps(domain, path, ignore_app) - - if conflicts: - apps = [] - for path, app_id, app_label in conflicts: - apps.append(" * {domain:s}{path:s} → {app_label:s} ({app_id:s})".format( - domain=domain, - path=path, - app_id=app_id, - app_label=app_label, - )) - - if full_domain: - raise YunohostError('app_full_domain_unavailable', domain=domain) - else: - raise YunohostError('app_location_unavailable', apps="\n".join(apps)) - - def domain_url_available(domain, path): """ Check availability of a web path @@ -432,24 +372,6 @@ def _set_maindomain(domain): f.write(domain) -def _normalize_domain_path(domain, path): - - # We want url to be of the format : - # some.domain.tld/foo - - # Remove http/https prefix if it's there - if domain.startswith("https://"): - domain = domain[len("https://"):] - elif domain.startswith("http://"): - domain = domain[len("http://"):] - - # Remove trailing slashes - domain = domain.rstrip("/").lower() - path = "/" + path.strip("/") - - return domain, path - - def _build_dns_conf(domain, ttl=3600, include_empty_AAAA_if_no_ipv6=False): """ Internal function that will returns a data structure containing the needed diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 84b9614f6..ccb05ef89 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -676,8 +676,8 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app): re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ """ - from yunohost.domain import domain_list, _assert_no_conflicting_apps - + from yunohost.domain import domain_list + from yunohost.app import _assert_no_conflicting_apps domains = domain_list()['domains'] diff --git a/src/yunohost/tests/test_appurl.py b/src/yunohost/tests/test_appurl.py index bbac69f82..21939c411 100644 --- a/src/yunohost/tests/test_appurl.py +++ b/src/yunohost/tests/test_appurl.py @@ -4,8 +4,8 @@ import os from conftest import get_test_apps_dir from yunohost.utils.error import YunohostError -from yunohost.app import app_install, app_remove -from yunohost.domain import _get_maindomain, domain_url_available, _normalize_domain_path +from yunohost.app import app_install, app_remove, _normalize_domain_path +from yunohost.domain import _get_maindomain, domain_url_available from yunohost.permission import _validate_and_sanitize_permission_url # Get main domain