Skip to content

Commit

Permalink
feat: Added fields into UserFromSearch: active, created_at, cts_id, d…
Browse files Browse the repository at this point in the history
…escription, ip_phone, manager, office, other_ip_phone, other_phone, public_name, rts_id, update_at (#483)

Co-authored-by: Leonid Gorbunov <[email protected]>
  • Loading branch information
Melifarmo and Leonid Gorbunov authored Aug 2, 2024
1 parent 09a8cec commit e5237e5
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 119 deletions.
37 changes: 37 additions & 0 deletions pybotx/client/users_api/user_from_search.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from datetime import datetime
from typing import List, Literal, Optional
from uuid import UUID

Expand All @@ -19,6 +20,18 @@ class BotXAPISearchUserResult(VerifiedPayloadBaseModel):
emails: List[str] = Field(default_factory=list)
other_id: Optional[str] = None
user_kind: APIUserKinds
active: Optional[bool] = None
description: Optional[str] = None
ip_phone: Optional[int] = None
manager: Optional[str] = None
office: Optional[str] = None
other_ip_phone: Optional[int] = None
other_phone: Optional[int] = None
public_name: Optional[str] = None
cts_id: Optional[UUID] = None
rts_id: Optional[UUID] = None
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None


class BotXAPISearchUserResponsePayload(VerifiedPayloadBaseModel):
Expand All @@ -37,6 +50,18 @@ def to_domain(self) -> UserFromSearch:
emails=self.result.emails,
other_id=self.result.other_id,
user_kind=convert_user_kind_to_domain(self.result.user_kind),
active=None if self.result.active is None else bool(self.result.active),
description=self.result.description,
ip_phone=self.result.ip_phone,
manager=self.result.manager,
office=self.result.office,
other_ip_phone=self.result.other_ip_phone,
other_phone=self.result.other_phone,
public_name=self.result.public_name,
cts_id=self.result.cts_id,
rts_id=self.result.rts_id,
created_at=self.result.created_at,
updated_at=self.result.updated_at,
)


Expand All @@ -57,6 +82,18 @@ def to_domain(self) -> List[UserFromSearch]:
emails=user.emails,
other_id=user.other_id,
user_kind=convert_user_kind_to_domain(user.user_kind),
active=None if user.active is None else bool(user.active),
created_at=user.created_at,
cts_id=user.cts_id,
description=user.description,
ip_phone=user.ip_phone,
manager=user.manager,
office=user.office,
other_ip_phone=user.other_ip_phone,
other_phone=user.other_phone,
public_name=user.public_name,
rts_id=user.rts_id,
updated_at=user.updated_at,
)
for user in self.result
]
25 changes: 25 additions & 0 deletions pybotx/models/users.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from dataclasses import dataclass
from datetime import datetime
from typing import List, Optional
from uuid import UUID

Expand All @@ -20,6 +21,18 @@ class UserFromSearch:
emails: User emails.
other_id: User other identificator.
user_kind: User kind.
active: User active status.
description: User description.
ip_phone: User IP phone.
manager: User manager.
office: User office.
other_ip_phone: User other IP phone.
other_phone: User other phone.
public_name: User public name.
cts_id: User CTS id.
rts_id: User RTS id.
created_at: User creation timestamp.
updated_at: User update timestamp.
"""

huid: UUID
Expand All @@ -32,6 +45,18 @@ class UserFromSearch:
emails: List[str]
other_id: Optional[str]
user_kind: UserKinds
active: Optional[bool] = None
description: Optional[str] = None
ip_phone: Optional[int] = None
manager: Optional[str] = None
office: Optional[str] = None
other_ip_phone: Optional[int] = None
other_phone: Optional[int] = None
public_name: Optional[str] = None
cts_id: Optional[UUID] = None
rts_id: Optional[UUID] = None
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None


@dataclass
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pybotx"
version = "0.69.1"
version = "0.70.0"
description = "A python library for interacting with eXpress BotX API"
authors = [
"Sidnev Nikolay <[email protected]>",
Expand Down
117 changes: 117 additions & 0 deletions tests/client/users_api/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
from typing import Any, Dict
from uuid import UUID

import pytest

from pybotx import UserFromSearch, UserKinds
from tests.client.users_api.convert_to_datetime import convert_to_datetime


@pytest.fixture()
def user_from_search_with_data_json() -> Dict[str, Any]:
return {
"user_huid": "6fafda2c-6505-57a5-a088-25ea5d1d0364",
"ad_login": "ad_user_login",
"ad_domain": "cts.com",
"name": "Bob",
"company": "Bobs Co",
"company_position": "Director",
"department": "Owners",
"emails": ["[email protected]"],
"user_kind": "cts_user",
"active": True,
"created_at": "2023-03-26T14:36:08.740618Z",
"cts_id": "e0140f4c-4af2-5a2e-9ad1-5f37fceafbaf",
"description": "Director in Owners dep",
"ip_phone": 1271020,
"manager": "Alice",
"office": "SUN",
"other_ip_phone": 32593,
"other_phone": 1254218,
"public_name": "Bobby",
"rts_id": "f46440a4-d930-58d4-b3f5-8110ab846ee3",
"updated_at": "2023-03-26T14:36:08.740618Z",
}


@pytest.fixture
def user_from_search_with_data() -> UserFromSearch:
return UserFromSearch(
huid=UUID("6fafda2c-6505-57a5-a088-25ea5d1d0364"),
ad_login="ad_user_login",
ad_domain="cts.com",
username="Bob",
company="Bobs Co",
company_position="Director",
department="Owners",
emails=["[email protected]"],
other_id=None,
user_kind=UserKinds.CTS_USER,
active=True,
created_at=convert_to_datetime("2023-03-26T14:36:08.740618Z"),
cts_id=UUID("e0140f4c-4af2-5a2e-9ad1-5f37fceafbaf"),
description="Director in Owners dep",
ip_phone=1271020,
manager="Alice",
office="SUN",
other_ip_phone=32593,
other_phone=1254218,
public_name="Bobby",
rts_id=UUID("f46440a4-d930-58d4-b3f5-8110ab846ee3"),
updated_at=convert_to_datetime("2023-03-26T14:36:08.740618Z"),
)


@pytest.fixture
def user_from_search_without_data_json() -> Dict[str, Any]:
return {
"user_huid": "6fafda2c-6505-57a5-a088-25ea5d1d0364",
"ad_login": "ad_user_login",
"ad_domain": "cts.com",
"name": "Bob",
"company": "Bobs Co",
"company_position": "Director",
"department": "Owners",
"emails": ["[email protected]"],
"user_kind": "cts_user",
"active": None,
"created_at": None,
"cts_id": None,
"description": None,
"ip_phone": None,
"manager": None,
"office": None,
"other_ip_phone": None,
"other_phone": None,
"public_name": None,
"rts_id": None,
"updated_at": None,
}


@pytest.fixture
def user_from_search_without_data() -> UserFromSearch:
return UserFromSearch(
huid=UUID("6fafda2c-6505-57a5-a088-25ea5d1d0364"),
ad_login="ad_user_login",
ad_domain="cts.com",
username="Bob",
company="Bobs Co",
company_position="Director",
department="Owners",
emails=["[email protected]"],
other_id=None,
user_kind=UserKinds.CTS_USER,
active=None,
created_at=None,
cts_id=None,
description=None,
ip_phone=None,
manager=None,
office=None,
other_ip_phone=None,
other_phone=None,
public_name=None,
rts_id=None,
updated_at=None,
)
9 changes: 9 additions & 0 deletions tests/client/users_api/convert_to_datetime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from datetime import datetime, timezone


def convert_to_datetime(str_datetime: str) -> datetime:
datetime_instance = datetime.strptime(
str_datetime,
"%Y-%m-%dT%H:%M:%S.%fZ", # noqa: WPS325
)
return datetime_instance.replace(tzinfo=timezone.utc)
65 changes: 42 additions & 23 deletions tests/client/users_api/test_search_user_by_email.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from http import HTTPStatus
from typing import Any, Dict
from uuid import UUID

import httpx
Expand All @@ -13,7 +14,6 @@
UserNotFoundError,
lifespan_wrapper,
)
from pybotx.models.enums import UserKinds

pytestmark = [
pytest.mark.asyncio,
Expand Down Expand Up @@ -65,6 +65,8 @@ async def test__search_user_by_email__succeed(
host: str,
bot_id: UUID,
bot_account: BotAccountWithSecret,
user_from_search_with_data: UserFromSearch,
user_from_search_with_data_json: Dict[str, Any],
) -> None:
# - Arrange -
endpoint = respx_mock.get(
Expand All @@ -76,17 +78,7 @@ async def test__search_user_by_email__succeed(
HTTPStatus.OK,
json={
"status": "ok",
"result": {
"user_huid": "6fafda2c-6505-57a5-a088-25ea5d1d0364",
"ad_login": "ad_user_login",
"ad_domain": "cts.com",
"name": "Bob",
"company": "Bobs Co",
"company_position": "Director",
"department": "Owners",
"emails": ["[email protected]"],
"user_kind": "cts_user",
},
"result": user_from_search_with_data_json,
},
),
)
Expand All @@ -101,17 +93,44 @@ async def test__search_user_by_email__succeed(
)

# - Assert -
assert user == UserFromSearch(
huid=UUID("6fafda2c-6505-57a5-a088-25ea5d1d0364"),
ad_login="ad_user_login",
ad_domain="cts.com",
username="Bob",
company="Bobs Co",
company_position="Director",
department="Owners",
emails=["[email protected]"],
other_id=None,
user_kind=UserKinds.CTS_USER,
assert user == user_from_search_with_data

assert endpoint.called


async def test__search_user_by_email_without_extra_data__succeed(
respx_mock: MockRouter,
host: str,
bot_id: UUID,
bot_account: BotAccountWithSecret,
user_from_search_without_data: UserFromSearch,
user_from_search_without_data_json: Dict[str, Any],
) -> None:
# - Arrange -
endpoint = respx_mock.get(
f"https://{host}/api/v3/botx/users/by_email",
headers={"Authorization": "Bearer token"},
params={"email": "[email protected]"},
).mock(
return_value=httpx.Response(
HTTPStatus.OK,
json={
"status": "ok",
"result": user_from_search_without_data_json,
},
),
)

built_bot = Bot(collectors=[HandlerCollector()], bot_accounts=[bot_account])

# - Act -
async with lifespan_wrapper(built_bot) as bot:
user = await bot.search_user_by_email(
bot_id=bot_id,
email="[email protected]",
)

# - Assert -
assert user == user_from_search_without_data

assert endpoint.called
Loading

0 comments on commit e5237e5

Please sign in to comment.