form:UserOption: merge choices and default into root validator with first admin user as default

This commit is contained in:
axolotle 2023-11-26 18:29:43 +01:00
parent 4a270b88b6
commit 650c0136f2
2 changed files with 25 additions and 56 deletions

View file

@ -1449,6 +1449,7 @@ class TestSelect(BaseTest):
# │ TAGS │
# ╰───────────────────────────────────────────────────────╯
# [], ["one"], {}
class TestTags(BaseTest):
raw_option = {"type": "tags", "id": "tags_id"}
@ -1678,47 +1679,29 @@ class TestApp(BaseTest):
admin_username = "admin_user"
admin_user = {
"ssh_allowed": False,
"username": admin_username,
"mailbox-quota": "0",
"mail": "a@ynh.local",
"mail-aliases": [f"root@{main_domain}"], # Faking "admin"
"fullname": "john doe",
"group": [],
"groups": ["admins"],
}
regular_username = "normal_user"
regular_user = {
"ssh_allowed": False,
"username": regular_username,
"mailbox-quota": "0",
"mail": "z@ynh.local",
"fullname": "john doe",
"group": [],
"groups": [],
}
@contextmanager
def patch_users(
*,
users,
admin_username,
main_domain,
):
def patch_users(*, users):
"""
Data mocking for UserOption:
- yunohost.user.user_list
- yunohost.user.user_info
- yunohost.domain._get_maindomain
"""
admin_info = next(
(user for user in users.values() if user["username"] == admin_username),
{"mail-aliases": []},
)
with patch.object(user, "user_list", return_value={"users": users}), patch.object(
user,
"user_info",
return_value=admin_info, # Faking admin user
), patch.object(domain, "_get_maindomain", return_value=main_domain):
with patch.object(user, "user_list", return_value={"users": users}):
yield
@ -1729,8 +1712,8 @@ class TestUser(BaseTest):
# No tests for empty users since it should not happens
{
"data": [
{"users": {admin_username: admin_user}, "admin_username": admin_username, "main_domain": main_domain},
{"users": {admin_username: admin_user, regular_username: regular_user}, "admin_username": admin_username, "main_domain": main_domain},
{"users": {admin_username: admin_user}},
{"users": {admin_username: admin_user, regular_username: regular_user}},
],
"scenarios": [
# FIXME User option is not really nullable, even if optional
@ -1741,7 +1724,7 @@ class TestUser(BaseTest):
},
{
"data": [
{"users": {admin_username: admin_user, regular_username: regular_user}, "admin_username": admin_username, "main_domain": main_domain},
{"users": {admin_username: admin_user, regular_username: regular_user}},
],
"scenarios": [
*xpass(scenarios=[
@ -1756,18 +1739,12 @@ class TestUser(BaseTest):
@pytest.mark.usefixtures("patch_no_tty")
def test_basic_attrs(self):
with patch_users(
users={admin_username: admin_user},
admin_username=admin_username,
main_domain=main_domain,
):
with patch_users(users={admin_username: admin_user}):
self._test_basic_attrs()
def test_options_prompted_with_ask_help(self, prefill_data=None):
with patch_users(
users={admin_username: admin_user, regular_username: regular_user},
admin_username=admin_username,
main_domain=main_domain,
users={admin_username: admin_user, regular_username: regular_user}
):
super().test_options_prompted_with_ask_help(
prefill_data={"raw_option": {}, "prefill": admin_username}

View file

@ -46,6 +46,7 @@ from pydantic import (
ValidationError,
create_model,
validator,
root_validator,
)
from pydantic.color import Color
from pydantic.fields import Field
@ -1705,43 +1706,34 @@ class UserOption(BaseChoicesOption):
filter: Literal[None] = None
choices: Union[dict[str, str], None]
@validator("choices", pre=True, always=True)
def inject_users_choices(
cls, value: Union[dict[str, str], None], values: Values
) -> dict[str, str]:
@root_validator(pre=True)
def inject_users_choices_and_default(cls, values: Values) -> Values:
# TODO remove calls to resources in validators (pydantic V2 should adress this)
from yunohost.user import user_list
value = {
users = user_list(fields=["username", "fullname", "mail", "groups"])["users"]
values["choices"] = {
username: f"{infos['fullname']} ({infos['mail']})"
for username, infos in user_list()["users"].items()
for username, infos in users.items()
}
# FIXME keep this to test if any user, do not raise error if no admin?
if not value:
if not values["choices"]:
raise YunohostValidationError(
"app_argument_invalid",
name=values["id"],
error="You should create a YunoHost user first.",
)
return value
if not values.get("default"):
values["default"] = next(
username
for username, infos in users.items()
if "admins" in infos["groups"]
)
@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_list, user_info
if value is None:
# FIXME : in the past we looked for the user holding the "root@" alias
# but it's now obsolete...
# Should be replaced by something like "any first user we find in the admin group"
pass
return value
return values
class GroupOption(BaseChoicesOption):