From f1038de56d0289d770317109d770bf5144129703 Mon Sep 17 00:00:00 2001 From: axolotle Date: Tue, 18 Apr 2023 17:51:21 +0200 Subject: [PATCH] form: fix entities validators order for filter and apply the right default --- src/tests/test_questions.py | 11 +---------- src/utils/form.py | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/tests/test_questions.py b/src/tests/test_questions.py index 959f2c8b7..387d5c0f9 100644 --- a/src/tests/test_questions.py +++ b/src/tests/test_questions.py @@ -1816,9 +1816,7 @@ class TestGroup(BaseTest): "scenarios": [ ("custom_group", "custom_group"), *all_as("", None, output="visitors", raw_option={"default": "visitors"}), - *xpass(scenarios=[ - ("", "custom_group", {"default": "custom_group"}), - ], reason="Should throw 'default must be in (None, 'all_users', 'visitors', 'admins')"), + ("", FAIL, {"default": "custom_group"}), # Not allowed to set a default which is not a default group # readonly ("admins", FAIL, {"readonly": True}), # readonly is forbidden ] @@ -1837,13 +1835,6 @@ class TestGroup(BaseTest): "prefill": "admins", } ) - # FIXME This should fail, not allowed to set a default which is not a default group - super().test_options_prompted_with_ask_help( - prefill_data={ - "raw_option": {"default": "custom_group"}, - "prefill": "custom_group", - } - ) def test_scenarios(self, intake, expected_output, raw_option, data): with patch_groups(**data): diff --git a/src/utils/form.py b/src/utils/form.py index 7a97259b9..7098692a4 100644 --- a/src/utils/form.py +++ b/src/utils/form.py @@ -951,6 +951,7 @@ ChoosableOptions = Literal[ class BaseChoicesOption(BaseInputOption): # FIXME probably forbid choices to be None? + filter: Union[JSExpression, None] = None # filter before choices choices: Union[dict[str, Any], list[Any], None] @validator("choices", pre=True) @@ -1093,6 +1094,7 @@ class TagsOption(BaseChoicesOption): class DomainOption(BaseChoicesOption): type: Literal[OptionType.domain] = OptionType.domain + filter: Literal[None] = None choices: Union[dict[str, str], None] @validator("choices", pre=True, always=True) @@ -1108,17 +1110,14 @@ class DomainOption(BaseChoicesOption): for domain in data["domains"] } - @validator("default") + @validator("default", pre=True, always=True) def inject_default( cls, value: Union[str, None], values: Values ) -> Union[str, None]: # TODO remove calls to resources in validators (pydantic V2 should adress this) from yunohost.domain import _get_maindomain - if value is None: - return _get_maindomain() - - return value + return _get_maindomain() @staticmethod def normalize(value, option={}): @@ -1135,9 +1134,9 @@ class DomainOption(BaseChoicesOption): class AppOption(BaseChoicesOption): type: Literal[OptionType.app] = OptionType.app - choices: Union[dict[str, str], None] + filter: Union[JSExpression, None] = None add_yunohost_portal_to_choices: bool = False - filter: Union[str, None] = None + choices: Union[dict[str, str], None] @validator("choices", pre=True, always=True) def inject_apps_choices( @@ -1172,6 +1171,7 @@ class AppOption(BaseChoicesOption): class UserOption(BaseChoicesOption): type: Literal[OptionType.user] = OptionType.user + filter: Literal[None] = None choices: Union[dict[str, str], None] @validator("choices", pre=True, always=True) @@ -1196,19 +1196,19 @@ class UserOption(BaseChoicesOption): return value - @validator("default") + @validator("default", pre=True, always=True) def inject_default( cls, value: Union[str, None], values: Values ) -> Union[str, None]: # TODO remove calls to resources in validators (pydantic V2 should adress this) from yunohost.domain import _get_maindomain - from yunohost.user import user_info + from yunohost.user import user_list, user_info if value is None: # FIXME: this code is obsolete with the new admins group # Should be replaced by something like "any first user we find in the admin group" root_mail = "root@%s" % _get_maindomain() - for user in values["choices"].keys(): + for user in user_list()["users"].keys(): if root_mail in user_info(user).get("mail-aliases", []): return user @@ -1217,6 +1217,7 @@ class UserOption(BaseChoicesOption): class GroupOption(BaseChoicesOption): type: Literal[OptionType.group] = OptionType.group + filter: Literal[None] = None choices: Union[dict[str, str], None] default: Union[Literal["visitors", "all_users", "admins"], None] = "all_users" @@ -1241,6 +1242,13 @@ class GroupOption(BaseChoicesOption): return {groupname: _human_readable_group(groupname) for groupname in groups} + @validator("default", pre=True, always=True) + def inject_default(cls, value: Union[str, None], values: Values) -> str: + # FIXME do we really want to default to something all the time? + if value is None: + return "all_users" + return value + OPTIONS = { OptionType.display_text: DisplayTextOption,