mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Merge branch 'dev' into enh-dns-autoconf
This commit is contained in:
commit
f9b3265f71
11 changed files with 90 additions and 102 deletions
|
@ -123,7 +123,10 @@ _ynh_app_config_apply() {
|
||||||
ynh_print_info --message="File '$bind_file' removed"
|
ynh_print_info --message="File '$bind_file' removed"
|
||||||
else
|
else
|
||||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||||
|
if [[ "${!short_setting}" != "$bind_file" ]]
|
||||||
|
then
|
||||||
cp "${!short_setting}" "$bind_file"
|
cp "${!short_setting}" "$bind_file"
|
||||||
|
fi
|
||||||
ynh_store_file_checksum --file="$bind_file" --update_only
|
ynh_store_file_checksum --file="$bind_file" --update_only
|
||||||
ynh_print_info --message="File '$bind_file' overwrited with ${!short_setting}"
|
ynh_print_info --message="File '$bind_file' overwrited with ${!short_setting}"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
YNH_APP_BASEDIR=$(realpath $([[ "$(basename $0)" =~ ^backup|restore$ ]] && echo '../settings' || [[ -n "${YNH_ACTION:-}" ]] && echo '.' || echo '..' ))
|
YNH_APP_BASEDIR=${YNH_APP_BASEDIR:-$(realpath ..)}
|
||||||
|
|
||||||
# Handle script crashes / failures
|
# Handle script crashes / failures
|
||||||
#
|
#
|
||||||
|
|
|
@ -12,7 +12,7 @@ ynh_backup --src_path="./manually_modified_files_list"
|
||||||
|
|
||||||
for file in $(cat ./manually_modified_files_list)
|
for file in $(cat ./manually_modified_files_list)
|
||||||
do
|
do
|
||||||
ynh_backup --src_path="$file"
|
[[ -e $file ]] && ynh_backup --src_path="$file"
|
||||||
done
|
done
|
||||||
|
|
||||||
ynh_backup --src_path="/etc/ssowat/conf.json.persistent"
|
ynh_backup --src_path="/etc/ssowat/conf.json.persistent"
|
||||||
|
|
|
@ -10,11 +10,10 @@ routes:
|
||||||
Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{{ current_commit }}/doc/generate_helper_doc.py) on {{data.date}} (YunoHost version {{data.version}})
|
Doc auto-generated by [this script](https://github.com/YunoHost/yunohost/blob/{{ current_commit }}/doc/generate_helper_doc.py) on {{data.date}} (YunoHost version {{data.version}})
|
||||||
|
|
||||||
{% for category, helpers in data.helpers %}
|
{% for category, helpers in data.helpers %}
|
||||||
### {{ category.upper() }}
|
## {{ category.upper() }}
|
||||||
{% for h in helpers %}
|
{% for h in helpers %}
|
||||||
**{{ h.name }}**<br/>
|
#### {{ h.name }}
|
||||||
[details summary="<i>{{ h.brief }}</i>" class="helper-card-subtitle text-muted"]
|
[details summary="<i>{{ h.brief }}</i>" class="helper-card-subtitle text-muted"]
|
||||||
<p></p>
|
|
||||||
|
|
||||||
**Usage**: `{{ h.usage }}`
|
**Usage**: `{{ h.usage }}`
|
||||||
{%- if h.args %}
|
{%- if h.args %}
|
||||||
|
|
|
@ -150,7 +150,7 @@
|
||||||
"config_validate_color": "Should be a valid RGB hexadecimal color",
|
"config_validate_color": "Should be a valid RGB hexadecimal color",
|
||||||
"config_validate_date": "Should be a valid date like in the format YYYY-MM-DD",
|
"config_validate_date": "Should be a valid date like in the format YYYY-MM-DD",
|
||||||
"config_validate_email": "Should be a valid email",
|
"config_validate_email": "Should be a valid email",
|
||||||
"config_validate_time": "Should be a valid time like XX:YY",
|
"config_validate_time": "Should be a valid time like HH:MM",
|
||||||
"config_validate_url": "Should be a valid web URL",
|
"config_validate_url": "Should be a valid web URL",
|
||||||
"config_version_not_supported": "Config panel versions '{version}' are not supported.",
|
"config_version_not_supported": "Config panel versions '{version}' are not supported.",
|
||||||
"confirm_app_install_danger": "DANGER! This app is known to be still experimental (if not explicitly not working)! You should probably NOT install it unless you know what you are doing. NO SUPPORT will be provided if this app doesn't work or breaks your system... If you are willing to take that risk anyway, type '{answers}'",
|
"confirm_app_install_danger": "DANGER! This app is known to be still experimental (if not explicitly not working)! You should probably NOT install it unless you know what you are doing. NO SUPPORT will be provided if this app doesn't work or breaks your system... If you are willing to take that risk anyway, type '{answers}'",
|
||||||
|
|
|
@ -56,7 +56,6 @@ from yunohost.utils import packages
|
||||||
from yunohost.utils.config import (
|
from yunohost.utils.config import (
|
||||||
ConfigPanel,
|
ConfigPanel,
|
||||||
parse_args_in_yunohost_format,
|
parse_args_in_yunohost_format,
|
||||||
Question,
|
|
||||||
)
|
)
|
||||||
from yunohost.utils.i18n import _value_for_locale
|
from yunohost.utils.i18n import _value_for_locale
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
|
@ -460,19 +459,21 @@ def app_change_url(operation_logger, app, domain, path):
|
||||||
# TODO: Allow to specify arguments
|
# TODO: Allow to specify arguments
|
||||||
args_odict = _parse_args_from_manifest(manifest, "change_url")
|
args_odict = _parse_args_from_manifest(manifest, "change_url")
|
||||||
|
|
||||||
|
tmp_workdir_for_app = _make_tmp_workdir_for_app(app=app)
|
||||||
|
|
||||||
# Prepare env. var. to pass to script
|
# Prepare env. var. to pass to script
|
||||||
env_dict = _make_environment_for_app_script(app, args=args_odict)
|
env_dict = _make_environment_for_app_script(app, args=args_odict)
|
||||||
env_dict["YNH_APP_OLD_DOMAIN"] = old_domain
|
env_dict["YNH_APP_OLD_DOMAIN"] = old_domain
|
||||||
env_dict["YNH_APP_OLD_PATH"] = old_path
|
env_dict["YNH_APP_OLD_PATH"] = old_path
|
||||||
env_dict["YNH_APP_NEW_DOMAIN"] = domain
|
env_dict["YNH_APP_NEW_DOMAIN"] = domain
|
||||||
env_dict["YNH_APP_NEW_PATH"] = path
|
env_dict["YNH_APP_NEW_PATH"] = path
|
||||||
|
env_dict["YNH_APP_BASEDIR"] = tmp_workdir_for_app
|
||||||
|
|
||||||
if domain != old_domain:
|
if domain != old_domain:
|
||||||
operation_logger.related_to.append(("domain", old_domain))
|
operation_logger.related_to.append(("domain", old_domain))
|
||||||
operation_logger.extra.update({"env": env_dict})
|
operation_logger.extra.update({"env": env_dict})
|
||||||
operation_logger.start()
|
operation_logger.start()
|
||||||
|
|
||||||
tmp_workdir_for_app = _make_tmp_workdir_for_app(app=app)
|
|
||||||
change_url_script = os.path.join(tmp_workdir_for_app, "scripts/change_url")
|
change_url_script = os.path.join(tmp_workdir_for_app, "scripts/change_url")
|
||||||
|
|
||||||
# Execute App change_url script
|
# Execute App change_url script
|
||||||
|
@ -623,6 +624,7 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
|
||||||
env_dict["YNH_APP_MANIFEST_VERSION"] = str(app_new_version)
|
env_dict["YNH_APP_MANIFEST_VERSION"] = str(app_new_version)
|
||||||
env_dict["YNH_APP_CURRENT_VERSION"] = str(app_current_version)
|
env_dict["YNH_APP_CURRENT_VERSION"] = str(app_current_version)
|
||||||
env_dict["NO_BACKUP_UPGRADE"] = "1" if no_safety_backup else "0"
|
env_dict["NO_BACKUP_UPGRADE"] = "1" if no_safety_backup else "0"
|
||||||
|
env_dict["YNH_APP_BASEDIR"] = extracted_app_folder
|
||||||
|
|
||||||
# We'll check that the app didn't brutally edit some system configuration
|
# We'll check that the app didn't brutally edit some system configuration
|
||||||
manually_modified_files_before_install = manually_modified_files()
|
manually_modified_files_before_install = manually_modified_files()
|
||||||
|
@ -920,19 +922,6 @@ def app_install(
|
||||||
# We'll check that the app didn't brutally edit some system configuration
|
# We'll check that the app didn't brutally edit some system configuration
|
||||||
manually_modified_files_before_install = manually_modified_files()
|
manually_modified_files_before_install = manually_modified_files()
|
||||||
|
|
||||||
# Tell the operation_logger to redact all password-type args
|
|
||||||
# Also redact the % escaped version of the password that might appear in
|
|
||||||
# the 'args' section of metadata (relevant for password with non-alphanumeric char)
|
|
||||||
data_to_redact = [
|
|
||||||
value[0] for value in args_odict.values() if value[1] == "password"
|
|
||||||
]
|
|
||||||
data_to_redact += [
|
|
||||||
urllib.parse.quote(data)
|
|
||||||
for data in data_to_redact
|
|
||||||
if urllib.parse.quote(data) != data
|
|
||||||
]
|
|
||||||
operation_logger.data_to_redact.extend(data_to_redact)
|
|
||||||
|
|
||||||
operation_logger.related_to = [
|
operation_logger.related_to = [
|
||||||
s for s in operation_logger.related_to if s[0] != "app"
|
s for s in operation_logger.related_to if s[0] != "app"
|
||||||
]
|
]
|
||||||
|
@ -988,6 +977,7 @@ def app_install(
|
||||||
|
|
||||||
# Prepare env. var. to pass to script
|
# Prepare env. var. to pass to script
|
||||||
env_dict = _make_environment_for_app_script(app_instance_name, args=args_odict)
|
env_dict = _make_environment_for_app_script(app_instance_name, args=args_odict)
|
||||||
|
env_dict["YNH_APP_BASEDIR"] = extracted_app_folder
|
||||||
|
|
||||||
env_dict_for_logging = env_dict.copy()
|
env_dict_for_logging = env_dict.copy()
|
||||||
for arg_name, arg_value_and_type in args_odict.items():
|
for arg_name, arg_value_and_type in args_odict.items():
|
||||||
|
@ -1052,6 +1042,7 @@ def app_install(
|
||||||
env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name
|
env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name
|
||||||
env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number)
|
env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number)
|
||||||
env_dict_remove["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?")
|
env_dict_remove["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?")
|
||||||
|
env_dict_remove["YNH_APP_BASEDIR"] = extracted_app_folder
|
||||||
|
|
||||||
# Execute remove script
|
# Execute remove script
|
||||||
operation_logger_remove = OperationLogger(
|
operation_logger_remove = OperationLogger(
|
||||||
|
@ -1169,6 +1160,8 @@ def app_remove(operation_logger, app, purge=False):
|
||||||
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
|
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
|
||||||
env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?")
|
env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?")
|
||||||
env_dict["YNH_APP_PURGE"] = str(purge)
|
env_dict["YNH_APP_PURGE"] = str(purge)
|
||||||
|
env_dict["YNH_APP_BASEDIR"] = tmp_workdir_for_app
|
||||||
|
|
||||||
operation_logger.extra.update({"env": env_dict})
|
operation_logger.extra.update({"env": env_dict})
|
||||||
operation_logger.flush()
|
operation_logger.flush()
|
||||||
|
|
||||||
|
@ -1654,12 +1647,14 @@ def app_action_run(operation_logger, app, action, args=None):
|
||||||
)
|
)
|
||||||
args_odict = _parse_args_for_action(actions[action], args=args_dict)
|
args_odict = _parse_args_for_action(actions[action], args=args_dict)
|
||||||
|
|
||||||
|
tmp_workdir_for_app = _make_tmp_workdir_for_app(app=app)
|
||||||
|
|
||||||
env_dict = _make_environment_for_app_script(
|
env_dict = _make_environment_for_app_script(
|
||||||
app, args=args_odict, args_prefix="ACTION_"
|
app, args=args_odict, args_prefix="ACTION_"
|
||||||
)
|
)
|
||||||
env_dict["YNH_ACTION"] = action
|
env_dict["YNH_ACTION"] = action
|
||||||
|
env_dict["YNH_APP_BASEDIR"] = tmp_workdir_for_app
|
||||||
|
|
||||||
tmp_workdir_for_app = _make_tmp_workdir_for_app(app=app)
|
|
||||||
_, action_script = tempfile.mkstemp(dir=tmp_workdir_for_app)
|
_, action_script = tempfile.mkstemp(dir=tmp_workdir_for_app)
|
||||||
|
|
||||||
with open(action_script, "w") as script:
|
with open(action_script, "w") as script:
|
||||||
|
@ -1731,8 +1726,6 @@ def app_config_set(
|
||||||
|
|
||||||
config_ = AppConfigPanel(app)
|
config_ = AppConfigPanel(app)
|
||||||
|
|
||||||
Question.operation_logger = operation_logger
|
|
||||||
|
|
||||||
return config_.set(key, value, args, args_file, operation_logger=operation_logger)
|
return config_.set(key, value, args, args_file, operation_logger=operation_logger)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1787,7 +1780,8 @@ ynh_app_config_run $1
|
||||||
"app_id": app_id,
|
"app_id": app_id,
|
||||||
"app": self.app,
|
"app": self.app,
|
||||||
"app_instance_nb": str(app_instance_nb),
|
"app_instance_nb": str(app_instance_nb),
|
||||||
"final_path": settings.get("final_path", "")
|
"final_path": settings.get("final_path", ""),
|
||||||
|
"YNH_APP_BASEDIR": os.path.join(APPS_SETTING_PATH, self.app),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -707,6 +707,7 @@ class BackupManager:
|
||||||
|
|
||||||
# Prepare environment
|
# Prepare environment
|
||||||
env_dict = self._get_env_var(app)
|
env_dict = self._get_env_var(app)
|
||||||
|
env_dict["YNH_APP_BASEDIR"] = os.path.join(self.work_dir, "apps", app, "settings")
|
||||||
tmp_app_bkp_dir = env_dict["YNH_APP_BACKUP_DIR"]
|
tmp_app_bkp_dir = env_dict["YNH_APP_BACKUP_DIR"]
|
||||||
settings_dir = os.path.join(self.work_dir, "apps", app, "settings")
|
settings_dir = os.path.join(self.work_dir, "apps", app, "settings")
|
||||||
|
|
||||||
|
@ -1487,6 +1488,7 @@ class RestoreManager:
|
||||||
"YNH_APP_BACKUP_DIR": os.path.join(
|
"YNH_APP_BACKUP_DIR": os.path.join(
|
||||||
self.work_dir, "apps", app_instance_name, "backup"
|
self.work_dir, "apps", app_instance_name, "backup"
|
||||||
),
|
),
|
||||||
|
"YNH_APP_BASEDIR": os.path.join(self.work_dir, "apps", app_instance_name, "settings"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1524,6 +1526,7 @@ class RestoreManager:
|
||||||
|
|
||||||
# Setup environment for remove script
|
# Setup environment for remove script
|
||||||
env_dict_remove = _make_environment_for_app_script(app_instance_name)
|
env_dict_remove = _make_environment_for_app_script(app_instance_name)
|
||||||
|
env_dict_remove["YNH_APP_BASEDIR"] = os.path.join(self.work_dir, "apps", app_instance_name, "settings")
|
||||||
|
|
||||||
remove_operation_logger = OperationLogger(
|
remove_operation_logger = OperationLogger(
|
||||||
"remove_on_failed_restore",
|
"remove_on_failed_restore",
|
||||||
|
|
|
@ -186,12 +186,17 @@ def log_show(
|
||||||
r"DEBUG - \+ exit (1|0)$",
|
r"DEBUG - \+ exit (1|0)$",
|
||||||
]
|
]
|
||||||
filters = [re.compile(f) for f in filters]
|
filters = [re.compile(f) for f in filters]
|
||||||
return [line for line in lines if not any(f.search(line.strip()) for f in filters)]
|
return [
|
||||||
|
line
|
||||||
|
for line in lines
|
||||||
|
if not any(f.search(line.strip()) for f in filters)
|
||||||
|
]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
def _filter(lines):
|
def _filter(lines):
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
# Normalize log/metadata paths and filenames
|
# Normalize log/metadata paths and filenames
|
||||||
abs_path = path
|
abs_path = path
|
||||||
log_path = None
|
log_path = None
|
||||||
|
|
|
@ -457,6 +457,7 @@ def permission_create(
|
||||||
"permission_creation_failed", permission=permission, error=e
|
"permission_creation_failed", permission=permission, error=e
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
permission_url(
|
permission_url(
|
||||||
permission,
|
permission,
|
||||||
url=url,
|
url=url,
|
||||||
|
@ -473,6 +474,9 @@ def permission_create(
|
||||||
protected=protected,
|
protected=protected,
|
||||||
sync_perm=sync_perm,
|
sync_perm=sync_perm,
|
||||||
)
|
)
|
||||||
|
except:
|
||||||
|
permission_delete(permission, force=True)
|
||||||
|
raise
|
||||||
|
|
||||||
logger.debug(m18n.n("permission_created", permission=permission))
|
logger.debug(m18n.n("permission_created", permission=permission))
|
||||||
return new_permission
|
return new_permission
|
||||||
|
|
|
@ -348,8 +348,6 @@ def test_question_password():
|
||||||
]
|
]
|
||||||
answers = {"some_password": "some_value"}
|
answers = {"some_password": "some_value"}
|
||||||
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
||||||
Question.operation_logger = MagicMock()
|
|
||||||
with patch.object(Question.operation_logger, "data_to_redact", create=True):
|
|
||||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||||
|
|
||||||
|
|
||||||
|
@ -375,13 +373,9 @@ def test_question_password_input():
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
answers = {}
|
answers = {}
|
||||||
Question.operation_logger = {"data_to_redact": []}
|
|
||||||
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||||
with patch.object(
|
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
|
||||||
os, "isatty", return_value=True
|
os, "isatty", return_value=True
|
||||||
):
|
):
|
||||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||||
|
@ -397,10 +391,7 @@ def test_question_password_input_no_ask():
|
||||||
answers = {}
|
answers = {}
|
||||||
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||||
with patch.object(
|
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
|
||||||
os, "isatty", return_value=True
|
os, "isatty", return_value=True
|
||||||
):
|
):
|
||||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||||
|
@ -417,20 +408,14 @@ def test_question_password_no_input_optional():
|
||||||
answers = {}
|
answers = {}
|
||||||
expected_result = OrderedDict({"some_password": ("", "password")})
|
expected_result = OrderedDict({"some_password": ("", "password")})
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
with patch.object(os, "isatty", return_value=False):
|
||||||
with patch.object(
|
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(os, "isatty", return_value=False):
|
|
||||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||||
|
|
||||||
questions = [
|
questions = [
|
||||||
{"name": "some_password", "type": "password", "optional": True, "default": ""}
|
{"name": "some_password", "type": "password", "optional": True, "default": ""}
|
||||||
]
|
]
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
with patch.object(os, "isatty", return_value=False):
|
||||||
with patch.object(
|
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(os, "isatty", return_value=False):
|
|
||||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||||
|
|
||||||
|
|
||||||
|
@ -446,10 +431,7 @@ def test_question_password_optional_with_input():
|
||||||
answers = {}
|
answers = {}
|
||||||
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||||
with patch.object(
|
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
|
||||||
os, "isatty", return_value=True
|
os, "isatty", return_value=True
|
||||||
):
|
):
|
||||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||||
|
@ -467,10 +449,7 @@ def test_question_password_optional_with_empty_input():
|
||||||
answers = {}
|
answers = {}
|
||||||
expected_result = OrderedDict({"some_password": ("", "password")})
|
expected_result = OrderedDict({"some_password": ("", "password")})
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
with patch.object(Moulinette, "prompt", return_value=""), patch.object(
|
||||||
with patch.object(
|
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(Moulinette, "prompt", return_value=""), patch.object(
|
|
||||||
os, "isatty", return_value=True
|
os, "isatty", return_value=True
|
||||||
):
|
):
|
||||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||||
|
@ -487,10 +466,7 @@ def test_question_password_optional_with_input_without_ask():
|
||||||
answers = {}
|
answers = {}
|
||||||
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||||
with patch.object(
|
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
|
||||||
os, "isatty", return_value=True
|
os, "isatty", return_value=True
|
||||||
):
|
):
|
||||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||||
|
@ -540,10 +516,7 @@ def test_question_password_input_test_ask():
|
||||||
]
|
]
|
||||||
answers = {}
|
answers = {}
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
|
||||||
with patch.object(
|
with patch.object(
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(
|
|
||||||
Moulinette, "prompt", return_value="some_value"
|
Moulinette, "prompt", return_value="some_value"
|
||||||
) as prompt, patch.object(
|
) as prompt, patch.object(
|
||||||
os, "isatty", return_value=True
|
os, "isatty", return_value=True
|
||||||
|
@ -572,10 +545,7 @@ def test_question_password_input_test_ask_with_example():
|
||||||
]
|
]
|
||||||
answers = {}
|
answers = {}
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
|
||||||
with patch.object(
|
with patch.object(
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(
|
|
||||||
Moulinette, "prompt", return_value="some_value"
|
Moulinette, "prompt", return_value="some_value"
|
||||||
) as prompt, patch.object(
|
) as prompt, patch.object(
|
||||||
os, "isatty", return_value=True
|
os, "isatty", return_value=True
|
||||||
|
@ -599,10 +569,7 @@ def test_question_password_input_test_ask_with_help():
|
||||||
]
|
]
|
||||||
answers = {}
|
answers = {}
|
||||||
|
|
||||||
Question.operation_logger = MagicMock()
|
|
||||||
with patch.object(
|
with patch.object(
|
||||||
Question.operation_logger, "data_to_redact", create=True
|
|
||||||
), patch.object(
|
|
||||||
Moulinette, "prompt", return_value="some_value"
|
Moulinette, "prompt", return_value="some_value"
|
||||||
) as prompt, patch.object(
|
) as prompt, patch.object(
|
||||||
os, "isatty", return_value=True
|
os, "isatty", return_value=True
|
||||||
|
|
|
@ -39,6 +39,7 @@ from moulinette.utils.filesystem import (
|
||||||
|
|
||||||
from yunohost.utils.i18n import _value_for_locale
|
from yunohost.utils.i18n import _value_for_locale
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
|
from yunohost.log import OperationLogger
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.config")
|
logger = getActionLogger("yunohost.config")
|
||||||
CONFIG_PANEL_VERSION_SUPPORTED = 1.0
|
CONFIG_PANEL_VERSION_SUPPORTED = 1.0
|
||||||
|
@ -453,7 +454,6 @@ class ConfigPanel:
|
||||||
|
|
||||||
class Question(object):
|
class Question(object):
|
||||||
hide_user_input_in_prompt = False
|
hide_user_input_in_prompt = False
|
||||||
operation_logger = None
|
|
||||||
pattern = None
|
pattern = None
|
||||||
|
|
||||||
def __init__(self, question, user_answers):
|
def __init__(self, question, user_answers):
|
||||||
|
@ -587,13 +587,9 @@ class Question(object):
|
||||||
for data in data_to_redact
|
for data in data_to_redact
|
||||||
if urllib.parse.quote(data) != data
|
if urllib.parse.quote(data) != data
|
||||||
]
|
]
|
||||||
if self.operation_logger:
|
|
||||||
self.operation_logger.data_to_redact.extend(data_to_redact)
|
for operation_logger in OperationLogger._instances:
|
||||||
elif data_to_redact:
|
operation_logger.data_to_redact.extend(data_to_redact)
|
||||||
raise YunohostError(
|
|
||||||
f"Can't redact {self.name} because no operation logger available in the context",
|
|
||||||
raw_msg=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
@ -658,6 +654,12 @@ class TagsQuestion(Question):
|
||||||
return ",".join(value)
|
return ",".join(value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def normalize(value, option={}):
|
||||||
|
if isinstance(value, list):
|
||||||
|
return ",".join(value)
|
||||||
|
return value
|
||||||
|
|
||||||
def _prevalidate(self):
|
def _prevalidate(self):
|
||||||
values = self.value
|
values = self.value
|
||||||
if isinstance(values, str):
|
if isinstance(values, str):
|
||||||
|
@ -669,6 +671,11 @@ class TagsQuestion(Question):
|
||||||
super()._prevalidate()
|
super()._prevalidate()
|
||||||
self.value = values
|
self.value = values
|
||||||
|
|
||||||
|
def _post_parse_value(self):
|
||||||
|
if isinstance(self.value, list):
|
||||||
|
self.value = ",".join(self.value)
|
||||||
|
return super()._post_parse_value()
|
||||||
|
|
||||||
|
|
||||||
class PasswordQuestion(Question):
|
class PasswordQuestion(Question):
|
||||||
hide_user_input_in_prompt = True
|
hide_user_input_in_prompt = True
|
||||||
|
@ -706,11 +713,17 @@ class PasswordQuestion(Question):
|
||||||
|
|
||||||
def _format_text_for_user_input_in_cli(self):
|
def _format_text_for_user_input_in_cli(self):
|
||||||
need_column = self.current_value or self.optional
|
need_column = self.current_value or self.optional
|
||||||
text_for_user_input_in_cli = super()._format_text_for_user_input_in_cli(need_column)
|
text_for_user_input_in_cli = super()._format_text_for_user_input_in_cli(
|
||||||
|
need_column
|
||||||
|
)
|
||||||
if self.current_value:
|
if self.current_value:
|
||||||
text_for_user_input_in_cli += "\n - " + m18n.n("app_argument_password_help_keep")
|
text_for_user_input_in_cli += "\n - " + m18n.n(
|
||||||
|
"app_argument_password_help_keep"
|
||||||
|
)
|
||||||
if self.optional:
|
if self.optional:
|
||||||
text_for_user_input_in_cli += "\n - " + m18n.n("app_argument_password_help_optional")
|
text_for_user_input_in_cli += "\n - " + m18n.n(
|
||||||
|
"app_argument_password_help_optional"
|
||||||
|
)
|
||||||
|
|
||||||
return text_for_user_input_in_cli
|
return text_for_user_input_in_cli
|
||||||
|
|
||||||
|
@ -834,7 +847,7 @@ class UserQuestion(Question):
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"app_argument_invalid",
|
"app_argument_invalid",
|
||||||
name=self.name,
|
name=self.name,
|
||||||
error="You should create a YunoHost user first."
|
error="You should create a YunoHost user first.",
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.default is None:
|
if self.default is None:
|
||||||
|
@ -949,11 +962,11 @@ class FileQuestion(Question):
|
||||||
"content": self.value,
|
"content": self.value,
|
||||||
"filename": user_answers.get(f"{self.name}[name]", self.name),
|
"filename": user_answers.get(f"{self.name}[name]", self.name),
|
||||||
}
|
}
|
||||||
# If path file are the same
|
|
||||||
if self.value and str(self.value) == self.current_value:
|
|
||||||
self.value = None
|
|
||||||
|
|
||||||
def _prevalidate(self):
|
def _prevalidate(self):
|
||||||
|
if self.value is None:
|
||||||
|
self.value = self.current_value
|
||||||
|
|
||||||
super()._prevalidate()
|
super()._prevalidate()
|
||||||
if (
|
if (
|
||||||
isinstance(self.value, str)
|
isinstance(self.value, str)
|
||||||
|
@ -988,7 +1001,7 @@ class FileQuestion(Question):
|
||||||
if not self.value:
|
if not self.value:
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
if Moulinette.interface.type == "api":
|
if Moulinette.interface.type == "api" and isinstance(self.value, dict):
|
||||||
|
|
||||||
upload_dir = tempfile.mkdtemp(prefix="tmp_configpanel_")
|
upload_dir = tempfile.mkdtemp(prefix="tmp_configpanel_")
|
||||||
FileQuestion.upload_dirs += [upload_dir]
|
FileQuestion.upload_dirs += [upload_dir]
|
||||||
|
|
Loading…
Add table
Reference in a new issue