diff --git a/pybotx/client/users_api/user_from_search.py b/pybotx/client/users_api/user_from_search.py index 2c1c8ffb..9d487298 100644 --- a/pybotx/client/users_api/user_from_search.py +++ b/pybotx/client/users_api/user_from_search.py @@ -13,6 +13,8 @@ class BotXAPISearchUserResult(VerifiedPayloadBaseModel): user_huid: UUID ad_login: str | None = None ad_domain: str | None = None + ad_groups: list[str] = Field(default_factory=list) + openid_roles: list[str] = Field(default_factory=list) avatar: str | None = None avatar_preview: str | None = None name: str @@ -53,6 +55,8 @@ def to_domain(self) -> UserFromSearch: huid=self.result.user_huid, ad_login=self.result.ad_login, ad_domain=self.result.ad_domain, + ad_groups=self.result.ad_groups, + openid_roles=self.result.openid_roles, avatar=self.result.avatar, avatar_preview=self.result.avatar_preview, username=self.result.name, @@ -87,6 +91,8 @@ def to_domain(self) -> list[UserFromSearch]: huid=user.user_huid, ad_login=user.ad_login, ad_domain=user.ad_domain, + ad_groups=user.ad_groups, + openid_roles=user.openid_roles, avatar=user.avatar, avatar_preview=user.avatar_preview, username=user.name, diff --git a/pybotx/models/users.py b/pybotx/models/users.py index b0ca61ca..6116a1e2 100644 --- a/pybotx/models/users.py +++ b/pybotx/models/users.py @@ -1,4 +1,4 @@ -from dataclasses import dataclass +from dataclasses import dataclass, field from datetime import datetime from uuid import UUID @@ -34,6 +34,12 @@ class UserFromSearch: rts_id: User RTS id. created_at: User creation timestamp. updated_at: User update timestamp. + ad_groups: User AD group names. BotX returns them only when the bot has + allow_read_ad_groups enabled. An empty list does not distinguish + no group membership from unavailable data. + openid_roles: User OpenID role names. BotX returns them only when the bot + has allow_read_openid_roles enabled. An empty list does not + distinguish no roles from unavailable data. """ huid: UUID @@ -60,6 +66,8 @@ class UserFromSearch: rts_id: UUID | None = None created_at: datetime | None = None updated_at: datetime | None = None + ad_groups: list[str] = field(default_factory=list) + openid_roles: list[str] = field(default_factory=list) @dataclass(slots=True) diff --git a/tests/fixtures/users_api.py b/tests/fixtures/users_api.py index d26b3368..4996633d 100644 --- a/tests/fixtures/users_api.py +++ b/tests/fixtures/users_api.py @@ -13,6 +13,8 @@ def user_from_search_with_data_json() -> dict[str, Any]: "user_huid": "6fafda2c-6505-57a5-a088-25ea5d1d0364", "ad_login": "ad_user_login", "ad_domain": "cts.com", + "ad_groups": ["employees", "developers", "vpn-users"], + "openid_roles": ["openid_user", "openid_profile"], "avatar": ( "https://test-cts.ru/uploads/profile_avatar/fa13e946-121b-52ce-aa92-677b51d19d83/" "3ebb64d5e2f54e1ab9a3f2ff8096f55a.jpg" @@ -50,6 +52,8 @@ def user_from_search_with_data() -> UserFromSearch: huid=UUID("6fafda2c-6505-57a5-a088-25ea5d1d0364"), ad_login="ad_user_login", ad_domain="cts.com", + ad_groups=["employees", "developers", "vpn-users"], + openid_roles=["openid_user", "openid_profile"], avatar=( "https://test-cts.ru/uploads/profile_avatar/fa13e946-121b-52ce-aa92-677b51d19d83/" "3ebb64d5e2f54e1ab9a3f2ff8096f55a.jpg" @@ -115,6 +119,8 @@ def user_from_search_without_data() -> UserFromSearch: huid=UUID("6fafda2c-6505-57a5-a088-25ea5d1d0364"), ad_login="ad_user_login", ad_domain="cts.com", + ad_groups=[], + openid_roles=[], avatar=None, avatar_preview=None, username="Bob", diff --git a/tests/models/test_users.py b/tests/models/test_users.py new file mode 100644 index 00000000..8ade91d1 --- /dev/null +++ b/tests/models/test_users.py @@ -0,0 +1,58 @@ +from uuid import UUID + +from pybotx import UserFromSearch, UserKinds + + +def test__user_from_search__preserves_existing_positional_arguments() -> None: + user = UserFromSearch( + UUID("6fafda2c-6505-57a5-a088-25ea5d1d0364"), + "alice", + "example.com", + "Alice", + None, + None, + None, + ["alice@example.com"], + None, + UserKinds.CTS_USER, + "https://example.com/avatar.png", + "https://example.com/avatar-preview.png", + ) + + assert user.avatar == "https://example.com/avatar.png" + assert user.avatar_preview == "https://example.com/avatar-preview.png" + assert user.ad_groups == [] + assert user.openid_roles == [] + + +def test__user_from_search__group_and_role_defaults_are_independent() -> None: + first = UserFromSearch( + huid=UUID("6fafda2c-6505-57a5-a088-25ea5d1d0364"), + ad_login=None, + ad_domain=None, + username="Alice", + company=None, + company_position=None, + department=None, + emails=[], + other_id=None, + user_kind=UserKinds.CTS_USER, + ) + second = UserFromSearch( + huid=UUID("6fafda2c-6505-57a5-a088-25ea5d1d0364"), + ad_login=None, + ad_domain=None, + username="Alice", + company=None, + company_position=None, + department=None, + emails=[], + other_id=None, + user_kind=UserKinds.CTS_USER, + ) + + first.ad_groups.append("employees") + first.openid_roles.append("reader") + + assert second.ad_groups == [] + assert second.openid_roles == []