mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Merge pull request #1406 from Tagadda/enh-domain-default-app
Manage default application with DomainConfigPanel
This commit is contained in:
commit
981c7b5649
7 changed files with 127 additions and 31 deletions
|
@ -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",
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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']
|
||||
|
|
61
src/app.py
61
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():
|
||||
|
||||
|
|
|
@ -454,6 +454,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
|
||||
|
||||
|
|
|
@ -440,6 +440,7 @@ class ConfigPanel:
|
|||
"step",
|
||||
"accept",
|
||||
"redact",
|
||||
"filters",
|
||||
],
|
||||
"defaults": {},
|
||||
},
|
||||
|
@ -705,6 +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", [])
|
||||
# .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
|
||||
|
@ -1126,6 +1128,28 @@ 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:
|
||||
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})
|
||||
|
||||
|
||||
class UserQuestion(Question):
|
||||
argument_type = "user"
|
||||
|
||||
|
@ -1319,6 +1343,7 @@ ARGUMENTS_TYPE_PARSERS = {
|
|||
"alert": DisplayTextQuestion,
|
||||
"markdown": DisplayTextQuestion,
|
||||
"file": FileQuestion,
|
||||
"app": AppQuestion,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ from moulinette.utils.filesystem import (
|
|||
read_file,
|
||||
write_to_file,
|
||||
write_to_yaml,
|
||||
write_to_json,
|
||||
read_yaml,
|
||||
)
|
||||
|
||||
|
@ -68,6 +69,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(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('/'):
|
||||
continue
|
||||
for app in apps:
|
||||
if app.get('domain_path') != dest_url:
|
||||
continue
|
||||
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)
|
||||
|
||||
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"),
|
||||
|
|
Loading…
Add table
Reference in a new issue