mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
form:UserOption: merge choices and default into root validator with first admin user as default
This commit is contained in:
parent
4a270b88b6
commit
650c0136f2
2 changed files with 25 additions and 56 deletions
|
@ -1449,6 +1449,7 @@ class TestSelect(BaseTest):
|
||||||
# │ TAGS │
|
# │ TAGS │
|
||||||
# ╰───────────────────────────────────────────────────────╯
|
# ╰───────────────────────────────────────────────────────╯
|
||||||
|
|
||||||
|
|
||||||
# [], ["one"], {}
|
# [], ["one"], {}
|
||||||
class TestTags(BaseTest):
|
class TestTags(BaseTest):
|
||||||
raw_option = {"type": "tags", "id": "tags_id"}
|
raw_option = {"type": "tags", "id": "tags_id"}
|
||||||
|
@ -1678,47 +1679,29 @@ class TestApp(BaseTest):
|
||||||
|
|
||||||
admin_username = "admin_user"
|
admin_username = "admin_user"
|
||||||
admin_user = {
|
admin_user = {
|
||||||
"ssh_allowed": False,
|
|
||||||
"username": admin_username,
|
"username": admin_username,
|
||||||
"mailbox-quota": "0",
|
|
||||||
"mail": "a@ynh.local",
|
"mail": "a@ynh.local",
|
||||||
"mail-aliases": [f"root@{main_domain}"], # Faking "admin"
|
|
||||||
"fullname": "john doe",
|
"fullname": "john doe",
|
||||||
"group": [],
|
"groups": ["admins"],
|
||||||
}
|
}
|
||||||
regular_username = "normal_user"
|
regular_username = "normal_user"
|
||||||
regular_user = {
|
regular_user = {
|
||||||
"ssh_allowed": False,
|
|
||||||
"username": regular_username,
|
"username": regular_username,
|
||||||
"mailbox-quota": "0",
|
|
||||||
"mail": "z@ynh.local",
|
"mail": "z@ynh.local",
|
||||||
"fullname": "john doe",
|
"fullname": "john doe",
|
||||||
"group": [],
|
"groups": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def patch_users(
|
def patch_users(*, users):
|
||||||
*,
|
|
||||||
users,
|
|
||||||
admin_username,
|
|
||||||
main_domain,
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Data mocking for UserOption:
|
Data mocking for UserOption:
|
||||||
- yunohost.user.user_list
|
- yunohost.user.user_list
|
||||||
- yunohost.user.user_info
|
- yunohost.user.user_info
|
||||||
- yunohost.domain._get_maindomain
|
- yunohost.domain._get_maindomain
|
||||||
"""
|
"""
|
||||||
admin_info = next(
|
with patch.object(user, "user_list", return_value={"users": users}):
|
||||||
(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):
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@ -1729,8 +1712,8 @@ class TestUser(BaseTest):
|
||||||
# No tests for empty users since it should not happens
|
# No tests for empty users since it should not happens
|
||||||
{
|
{
|
||||||
"data": [
|
"data": [
|
||||||
{"users": {admin_username: admin_user}, "admin_username": admin_username, "main_domain": main_domain},
|
{"users": {admin_username: admin_user}},
|
||||||
{"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": [
|
"scenarios": [
|
||||||
# FIXME User option is not really nullable, even if optional
|
# FIXME User option is not really nullable, even if optional
|
||||||
|
@ -1741,7 +1724,7 @@ class TestUser(BaseTest):
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"data": [
|
"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": [
|
"scenarios": [
|
||||||
*xpass(scenarios=[
|
*xpass(scenarios=[
|
||||||
|
@ -1756,18 +1739,12 @@ class TestUser(BaseTest):
|
||||||
|
|
||||||
@pytest.mark.usefixtures("patch_no_tty")
|
@pytest.mark.usefixtures("patch_no_tty")
|
||||||
def test_basic_attrs(self):
|
def test_basic_attrs(self):
|
||||||
with patch_users(
|
with patch_users(users={admin_username: admin_user}):
|
||||||
users={admin_username: admin_user},
|
|
||||||
admin_username=admin_username,
|
|
||||||
main_domain=main_domain,
|
|
||||||
):
|
|
||||||
self._test_basic_attrs()
|
self._test_basic_attrs()
|
||||||
|
|
||||||
def test_options_prompted_with_ask_help(self, prefill_data=None):
|
def test_options_prompted_with_ask_help(self, prefill_data=None):
|
||||||
with patch_users(
|
with patch_users(
|
||||||
users={admin_username: admin_user, regular_username: regular_user},
|
users={admin_username: admin_user, regular_username: regular_user}
|
||||||
admin_username=admin_username,
|
|
||||||
main_domain=main_domain,
|
|
||||||
):
|
):
|
||||||
super().test_options_prompted_with_ask_help(
|
super().test_options_prompted_with_ask_help(
|
||||||
prefill_data={"raw_option": {}, "prefill": admin_username}
|
prefill_data={"raw_option": {}, "prefill": admin_username}
|
||||||
|
|
|
@ -46,6 +46,7 @@ from pydantic import (
|
||||||
ValidationError,
|
ValidationError,
|
||||||
create_model,
|
create_model,
|
||||||
validator,
|
validator,
|
||||||
|
root_validator,
|
||||||
)
|
)
|
||||||
from pydantic.color import Color
|
from pydantic.color import Color
|
||||||
from pydantic.fields import Field
|
from pydantic.fields import Field
|
||||||
|
@ -1705,43 +1706,34 @@ class UserOption(BaseChoicesOption):
|
||||||
filter: Literal[None] = None
|
filter: Literal[None] = None
|
||||||
choices: Union[dict[str, str], None]
|
choices: Union[dict[str, str], None]
|
||||||
|
|
||||||
@validator("choices", pre=True, always=True)
|
@root_validator(pre=True)
|
||||||
def inject_users_choices(
|
def inject_users_choices_and_default(cls, values: Values) -> Values:
|
||||||
cls, value: Union[dict[str, str], None], values: Values
|
|
||||||
) -> dict[str, str]:
|
|
||||||
# TODO remove calls to resources in validators (pydantic V2 should adress this)
|
# TODO remove calls to resources in validators (pydantic V2 should adress this)
|
||||||
from yunohost.user import user_list
|
from yunohost.user import user_list
|
||||||
|
|
||||||
value = {
|
users = user_list(fields=["username", "fullname", "mail", "groups"])["users"]
|
||||||
|
|
||||||
|
values["choices"] = {
|
||||||
username: f"{infos['fullname']} ({infos['mail']})"
|
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?
|
# FIXME keep this to test if any user, do not raise error if no admin?
|
||||||
if not value:
|
if not values["choices"]:
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"app_argument_invalid",
|
"app_argument_invalid",
|
||||||
name=values["id"],
|
name=values["id"],
|
||||||
error="You should create a YunoHost user first.",
|
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)
|
return values
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class GroupOption(BaseChoicesOption):
|
class GroupOption(BaseChoicesOption):
|
||||||
|
|
Loading…
Add table
Reference in a new issue