diff --git a/huntflow_api_client/entities/user_settings.py b/huntflow_api_client/entities/user_settings.py index b020190..9943127 100644 --- a/huntflow_api_client/entities/user_settings.py +++ b/huntflow_api_client/entities/user_settings.py @@ -1,6 +1,12 @@ from huntflow_api_client.entities.base import BaseEntity +from huntflow_api_client.models.common import StatusResponse +from huntflow_api_client.models.request.user_settings import ( + ExchangeEmailAccountRequest, + OtherEmailAccountRequest, +) from huntflow_api_client.models.response.user_settings import ( CalendarAccountsListResponse, + EmailAccount, EmailAccountsListResponse, ) @@ -23,3 +29,87 @@ async def get_calendar_accounts(self) -> CalendarAccountsListResponse: """ response = await self._api.request("GET", "/calendar_accounts") return CalendarAccountsListResponse.model_validate(response.json()) + + async def create_exchange_email_account( + self, + data: ExchangeEmailAccountRequest, + ) -> EmailAccount: + """ + API method reference https://api.huntflow.ai/v2/docs#post-/email_accounts/exchange + + :param data: Exchange user email account data + :return: Created Exchange user email account for API robot. + """ + response = await self._api.request( + "POST", + "/email_accounts/exchange", + json=data.jsonable_dict(exclude_none=True), + ) + return EmailAccount.model_validate(response.json()) + + async def update_exchange_email_account( + self, + data: ExchangeEmailAccountRequest, + account_email_id: int, + ) -> EmailAccount: + """ + API method reference + https://api.huntflow.ai/v2/docs#put-/email_accounts/exchange/-account_email_id- + + :param account_email_id: Email account ID + :param data: Exchange user email account data + :return: Updated Exchange user email account for API robot. + """ + response = await self._api.request( + "PUT", + f"/email_accounts/exchange/{account_email_id}", + json=data.jsonable_dict(exclude_none=True), + ) + return EmailAccount.model_validate(response.json()) + + async def create_other_email_account( + self, + data: OtherEmailAccountRequest, + ) -> EmailAccount: + """ + API method reference https://api.huntflow.ai/v2/docs#post-/email_accounts/other + + :param data: SMTP/POP3/IMAP user email account data + :return: Created SMTP/POP3/IMAP user email account for API robot. + """ + response = await self._api.request( + "POST", + "/email_accounts/other", + json=data.jsonable_dict(exclude_none=True), + ) + return EmailAccount.model_validate(response.json()) + + async def update_other_email_account( + self, + data: OtherEmailAccountRequest, + account_email_id: int, + ) -> EmailAccount: + """ + API method reference + https://api.huntflow.ai/v2/docs#put-/email_accounts/other/-account_email_id- + + :param account_email_id: Email account ID + :param data: SMTP/POP3/IMAP user email account data + :return: Updated SMTP/POP3/IMAP user email account for API robot. + """ + response = await self._api.request( + "PUT", + f"/email_accounts/other/{account_email_id}", + json=data.jsonable_dict(exclude_none=True), + ) + return EmailAccount.model_validate(response.json()) + + async def delete_email_account(self, account_email_id: int) -> StatusResponse: + """ + API method reference + https://api.huntflow.ai/v2/docs#delete-/email_accounts/-account_email_id- + + :param account_email_id: Email account ID + """ + response = await self._api.request("DELETE", f"/email_accounts/{account_email_id}") + return StatusResponse.model_validate(response.json()) diff --git a/huntflow_api_client/models/consts.py b/huntflow_api_client/models/consts.py index 37bbb36..6e4d28e 100644 --- a/huntflow_api_client/models/consts.py +++ b/huntflow_api_client/models/consts.py @@ -196,3 +196,13 @@ class RecommendationStatus(str, Enum): class InterviewType(str, Enum): USER = "user" INTERVIEW = "interview" + + +class ExchangeAccessType(str, Enum): + DEFAULT = "DEFAULT" + IMPERSONATION = "IMPERSONATION" + + +class EmailInboundType(str, Enum): + DEFAULT = "IMAP" + IMPERSONATION = "POP3" diff --git a/huntflow_api_client/models/request/user_settings.py b/huntflow_api_client/models/request/user_settings.py new file mode 100644 index 0000000..d3c021a --- /dev/null +++ b/huntflow_api_client/models/request/user_settings.py @@ -0,0 +1,35 @@ +from typing import Optional + +from pydantic import AnyHttpUrl, EmailStr, Field, PositiveInt + +from huntflow_api_client.models.common import JsonRequestModel +from huntflow_api_client.models.consts import EmailInboundType, ExchangeAccessType + + +class ExchangeEmailAccountRequest(JsonRequestModel): + """ + Model for EXCHANGE email connection + """ + + access_type: ExchangeAccessType = Field(..., description="Exchange access type") + email: EmailStr = Field(..., description="Email address") + ews_url: AnyHttpUrl = Field(..., description="Exchange server URL") + password: str = Field(..., description="Exchange password") + user: Optional[str] = Field(None, description="Exchange user name") + + +class OtherEmailAccountRequest(JsonRequestModel): + """ + Model for IMAP/POP3 & SMTP email connection + """ + + email: EmailStr = Field(..., description="Email address") + password: str = Field(..., description="Mailbox password") + + inbound_host: str = Field(..., description="Inbound mail server URL without protocol") + inbound_port: Optional[PositiveInt] = Field(None, description="Inbound mail port") + inbound_ssl: bool = Field(False, description="Inbound mail server uses SSL") + outbound_host: str = Field(..., description="Outbound mail server URL without protocol") + outbound_port: Optional[PositiveInt] = Field(None, description="Outbound mail port") + outbound_ssl: bool = Field(False, description="Outbound mail server uses SSL") + type: EmailInboundType = Field(..., description="Type of inbound mail server") diff --git a/pyproject.toml b/pyproject.toml index 0b4e13d..371e3b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "huntflow-api-client" -version = "2.7.0" +version = "2.8.0" description = "Huntflow API Client for Python" authors = [ {name = "Developers huntflow", email = "developer@huntflow.ru"}, diff --git a/tests/test_entities/test_user_settings.py b/tests/test_entities/test_user_settings.py index 8fe693c..cdc5943 100644 --- a/tests/test_entities/test_user_settings.py +++ b/tests/test_entities/test_user_settings.py @@ -4,26 +4,30 @@ from huntflow_api_client import HuntflowAPI from huntflow_api_client.entities.user_settings import UserSettings +from huntflow_api_client.models.common import StatusResponse +from huntflow_api_client.models.request.user_settings import ( + ExchangeEmailAccountRequest, + OtherEmailAccountRequest, +) from huntflow_api_client.models.response.user_settings import ( CalendarAccountsListResponse, + EmailAccount, EmailAccountsListResponse, ) from huntflow_api_client.tokens.proxy import HuntflowTokenProxy from tests.api import BASE_URL, VERSIONED_BASE_URL -GET_USER_EMAIL_ACCOUNTS_RESPONSE: Dict[str, Any] = { - "items": [ - { - "id": 10, - "name": "test@example.com", - "email": "test@example.com", - "receive": False, - "send": False, - "last_sync": "2020-01-01T00:00:00+03:00", - }, - ], +EMAIL_ACCOUNT: Dict[str, Any] = { + "id": 10, + "name": "test@example.com", + "email": "test@example.com", + "receive": False, + "send": False, + "last_sync": "2020-01-01T00:00:00+03:00", } +GET_USER_EMAIL_ACCOUNTS_RESPONSE: Dict[str, Any] = {"items": [EMAIL_ACCOUNT]} + GET_USER_CALENDAR_ACCOUNTS_RESPONSE: Dict[str, Any] = { "items": [ { @@ -43,6 +47,30 @@ ], } +EXCHANGE_EMAIL_ACCOUNT_CREATE_REQUEST: Dict[str, Any] = { + "access_type": "DEFAULT", + "email": "mail@mail.ru", + "ews_url": "https://your-company.org/ews/exchange.asmx", + "password": "string", + "user": "string", +} + +ACCOUNT_EMAIL_ID = 1 + +IMAP_EMAIL_ACCOUNT_CREATE_REQUEST: Dict[str, Any] = { + "email": "mail@mail.ru", + "password": "string", + "inbound_host": "imap.your-company.org", + "inbound_port": 1, + "inbound_ssl": False, + "outbound_host": "smtp.your-company.org", + "outbound_port": 1, + "outbound_ssl": False, + "type": "IMAP", +} + +DELETE_ACCOUNT_EMAIL_RESPONSE: Dict[str, Any] = {"status": True} + async def test_get_email_accounts( httpx_mock: HTTPXMock, @@ -72,3 +100,86 @@ async def test_get_calendar_accounts( response = await settings.get_calendar_accounts() assert response == CalendarAccountsListResponse(**GET_USER_CALENDAR_ACCOUNTS_RESPONSE) + + +async def test_create_exchange_email_account( + httpx_mock: HTTPXMock, + token_proxy: HuntflowTokenProxy, +) -> None: + httpx_mock.add_response( + url=f"{VERSIONED_BASE_URL}/email_accounts/exchange", + json=EMAIL_ACCOUNT, + ) + api_client = HuntflowAPI(BASE_URL, token_proxy=token_proxy) + + api_request = ExchangeEmailAccountRequest(**EXCHANGE_EMAIL_ACCOUNT_CREATE_REQUEST) + settings = UserSettings(api_client) + + response = await settings.create_exchange_email_account(api_request) + assert response == EmailAccount(**EMAIL_ACCOUNT) + + +async def test_update_exchange_email_account( + httpx_mock: HTTPXMock, + token_proxy: HuntflowTokenProxy, +) -> None: + httpx_mock.add_response( + url=f"{VERSIONED_BASE_URL}/email_accounts/exchange/{ACCOUNT_EMAIL_ID}", + json=EMAIL_ACCOUNT, + ) + api_client = HuntflowAPI(BASE_URL, token_proxy=token_proxy) + + api_request = ExchangeEmailAccountRequest(**EXCHANGE_EMAIL_ACCOUNT_CREATE_REQUEST) + settings = UserSettings(api_client) + + response = await settings.update_exchange_email_account(api_request, ACCOUNT_EMAIL_ID) + assert response == EmailAccount(**EMAIL_ACCOUNT) + + +async def test_create_other_email_account( + httpx_mock: HTTPXMock, + token_proxy: HuntflowTokenProxy, +) -> None: + httpx_mock.add_response( + url=f"{VERSIONED_BASE_URL}/email_accounts/other", + json=EMAIL_ACCOUNT, + ) + api_client = HuntflowAPI(BASE_URL, token_proxy=token_proxy) + + api_request = OtherEmailAccountRequest(**IMAP_EMAIL_ACCOUNT_CREATE_REQUEST) + settings = UserSettings(api_client) + + response = await settings.create_other_email_account(api_request) + assert response == EmailAccount(**EMAIL_ACCOUNT) + + +async def test_update_other_email_account( + httpx_mock: HTTPXMock, + token_proxy: HuntflowTokenProxy, +) -> None: + httpx_mock.add_response( + url=f"{VERSIONED_BASE_URL}/email_accounts/other/{ACCOUNT_EMAIL_ID}", + json=EMAIL_ACCOUNT, + ) + api_client = HuntflowAPI(BASE_URL, token_proxy=token_proxy) + + api_request = OtherEmailAccountRequest(**IMAP_EMAIL_ACCOUNT_CREATE_REQUEST) + settings = UserSettings(api_client) + + response = await settings.update_other_email_account(api_request, ACCOUNT_EMAIL_ID) + assert response == EmailAccount(**EMAIL_ACCOUNT) + + +async def test_delete_email_account( + httpx_mock: HTTPXMock, + token_proxy: HuntflowTokenProxy, +) -> None: + httpx_mock.add_response( + url=f"{VERSIONED_BASE_URL}/email_accounts/{ACCOUNT_EMAIL_ID}", + json=DELETE_ACCOUNT_EMAIL_RESPONSE, + ) + api_client = HuntflowAPI(BASE_URL, token_proxy=token_proxy) + settings = UserSettings(api_client) + + response = await settings.delete_email_account(ACCOUNT_EMAIL_ID) + assert response == StatusResponse(**DELETE_ACCOUNT_EMAIL_RESPONSE)