From dbaea019fe1945fe8e126d51c00fcc019eeca1c2 Mon Sep 17 00:00:00 2001 From: axolotle Date: Tue, 18 Apr 2023 16:54:54 +0200 Subject: [PATCH] form+config: replace _parse_pre_answered method with generic function --- src/utils/configpanel.py | 19 ++++++------------- src/utils/form.py | 31 +++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/utils/configpanel.py b/src/utils/configpanel.py index e39d5c91c..1f240a105 100644 --- a/src/utils/configpanel.py +++ b/src/utils/configpanel.py @@ -43,6 +43,7 @@ from yunohost.utils.form import ( ask_questions_and_parse_answers, build_form, evaluate_simple_js_expression, + parse_prefilled_values, ) from yunohost.utils.i18n import _value_for_locale @@ -397,7 +398,10 @@ class ConfigPanel: # Import and parse pre-answered options logger.debug("Import and parse pre-answered options") - self._parse_pre_answered(args, value, args_file) + if option_id and value is not None: + self.args = {option_id: value} + else: + self.args = parse_prefilled_values(args, value, args_file) # Read or get values and hydrate the config self._get_raw_settings() @@ -468,7 +472,7 @@ class ConfigPanel: # Import and parse pre-answered options logger.debug("Import and parse pre-answered options") - self._parse_pre_answered(args, None, args_file) + self.args = parse_prefilled_values(args, args_file) # Read or get values and hydrate the config self._get_raw_settings() @@ -678,17 +682,6 @@ class ConfigPanel: } ) - def _parse_pre_answered(self, args, value, args_file): - args = urllib.parse.parse_qs(args or "", keep_blank_values=True) - self.args = {key: ",".join(value_) for key, value_ in args.items()} - - if args_file: - # Import YAML / JSON file but keep --args values - self.args = {**read_yaml(args_file), **self.args} - - if value is not None: - self.args = {self.filter_key.split(".")[-1]: value} - def _apply(self): logger.info("Saving the new configuration...") dir_path = os.path.dirname(os.path.realpath(self.save_path)) diff --git a/src/utils/form.py b/src/utils/form.py index 8ed83393e..7a97259b9 100644 --- a/src/utils/form.py +++ b/src/utils/form.py @@ -53,7 +53,7 @@ from pydantic.types import constr from moulinette import Moulinette, m18n from moulinette.interfaces.cli import colorize -from moulinette.utils.filesystem import read_file, write_to_file +from moulinette.utils.filesystem import read_file, read_yaml, write_to_file from yunohost.log import OperationLogger from yunohost.utils.error import YunohostError, YunohostValidationError from yunohost.utils.i18n import _value_for_locale @@ -1431,6 +1431,31 @@ def hydrate_option_type(raw_option: dict[str, Any]) -> dict[str, Any]: Hooks = dict[str, Callable[[BaseInputOption], Any]] +def parse_prefilled_values( + args: Union[str, None] = None, + args_file: Union[str, None] = None, + method: Literal["parse_qs", "parse_qsl"] = "parse_qs", +) -> dict[str, Any]: + """ + Retrieve form values from yaml file or query string. + """ + values: Values = {} + if args_file: + # Import YAML / JSON file + values |= read_yaml(args_file) + if args: + # FIXME See `ask_questions_and_parse_answers` + parsed = getattr(urllib.parse, method)(args, keep_blank_values=True) + if isinstance(parsed, dict): # parse_qs + # FIXME could do the following to get a list directly? + # k: None if not len(v) else (v if len(v) > 1 else v[0]) + values |= {k: ",".join(v) for k, v in parsed.items()} + else: + values |= dict(parsed) + + return values + + def prompt_or_validate_form( options: list[AnyOption], form: FormModel, @@ -1561,9 +1586,7 @@ def ask_questions_and_parse_answers( # whereas parse.qs return list of values (which is useful for tags, etc) # For now, let's not migrate this piece of code to parse_qs # Because Aleks believes some bits of the app CI rely on overriding values (e.g. foo=foo&...&foo=bar) - answers = dict( - urllib.parse.parse_qsl(prefilled_answers or "", keep_blank_values=True) - ) + answers = parse_prefilled_values(prefilled_answers, method="parse_qsl") elif isinstance(prefilled_answers, Mapping): answers = {**prefilled_answers} else: