Skip to content

Commit

Permalink
feat: /api/v4/botx/smartapps/unread_counter support
Browse files Browse the repository at this point in the history
  • Loading branch information
vavilovnv committed Sep 4, 2024
1 parent e5237e5 commit 4c3be1d
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 1 deletion.
45 changes: 45 additions & 0 deletions pybotx/bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@
BotXAPISmartAppNotificationRequestPayload,
SmartAppNotificationMethod,
)
from pybotx.client.smartapps_api.smartapp_unread_counter import (
BotXAPISmartAppUnreadCounterRequestPayload,
SmartAppUnreadCounterMethod,
)
from pybotx.client.smartapps_api.smartapps_list import (
BotXAPISmartAppsListRequestPayload,
SmartAppsListMethod,
Expand Down Expand Up @@ -1648,6 +1652,47 @@ async def send_smartapp_custom_notification(

return botx_api_sync_id.to_domain()

async def send_smartapp_unread_counter(
self,
*,
bot_id: UUID,
group_chat_id: UUID,
counter: int,
wait_callback: bool = True,
callback_timeout: Optional[float] = None,
) -> UUID:
"""Send SmartApp unread counter.
:param bot_id: Bot which should perform the request.
:param group_chat_id: Target chat id.
:param counter: Counter value.
:param wait_callback: Block method call until callback received.
:param callback_timeout: Callback timeout in seconds (or `None` for
endless waiting).
:return: Sent message's sync_id.
"""

method = SmartAppUnreadCounterMethod(
bot_id,
self._httpx_client,
self._bot_accounts_storage,
self._callbacks_manager,
)
payload = BotXAPISmartAppUnreadCounterRequestPayload.from_domain(
group_chat_id=group_chat_id,
counter=counter,
)

botx_api_sync_id = await method.execute(
payload,
wait_callback,
callback_timeout,
self._default_callback_timeout,
)

return botx_api_sync_id.to_domain()

# - Stickers API -
async def create_sticker_pack(
self,
Expand Down
68 changes: 68 additions & 0 deletions pybotx/client/smartapps_api/smartapp_unread_counter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from typing import Literal, Optional
from uuid import UUID

from pybotx.client.authorized_botx_method import AuthorizedBotXMethod
from pybotx.models.api_base import UnverifiedPayloadBaseModel, VerifiedPayloadBaseModel


class BotXAPISmartAppUnreadCounterRequestPayload(UnverifiedPayloadBaseModel):
group_chat_id: UUID
counter: int

@classmethod
def from_domain(
cls,
group_chat_id: UUID,
counter: int,
) -> "BotXAPISmartAppUnreadCounterRequestPayload":
return cls(
group_chat_id=group_chat_id,
counter=counter,
)


class BotXAPISyncIdResult(VerifiedPayloadBaseModel):
sync_id: UUID


class BotXAPISmartAppUnreadCounterResponsePayload(VerifiedPayloadBaseModel):
status: Literal["ok"]
result: BotXAPISyncIdResult

def to_domain(self) -> UUID:
return self.result.sync_id


class SmartAppUnreadCounterMethod(AuthorizedBotXMethod):
error_callback_handlers = {
**AuthorizedBotXMethod.error_callback_handlers,
}

async def execute(
self,
payload: BotXAPISmartAppUnreadCounterRequestPayload,
wait_callback: bool,
callback_timeout: Optional[float],
default_callback_timeout: float,
) -> BotXAPISmartAppUnreadCounterResponsePayload:
path = "/api/v4/botx/smartapps/unread_counter"

response = await self._botx_method_call(
"POST",
self._build_url(path),
json=payload.jsonable_dict(),
)

api_model = self._verify_and_extract_api_model(
BotXAPISmartAppUnreadCounterResponsePayload,
response,
)

await self._process_callback(
api_model.result.sync_id,
wait_callback,
callback_timeout,
default_callback_timeout,
)

return api_model
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.70.0"
version = "0.71.0"
description = "A python library for interacting with eXpress BotX API"
authors = [
"Sidnev Nikolay <[email protected]>",
Expand Down
66 changes: 66 additions & 0 deletions tests/client/smartapps_api/test_smartapp_unread_counter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import asyncio
from http import HTTPStatus
from uuid import UUID

import httpx
import pytest
from respx.router import MockRouter

from pybotx import Bot, BotAccountWithSecret, HandlerCollector, lifespan_wrapper

pytestmark = [
pytest.mark.asyncio,
pytest.mark.mock_authorization,
pytest.mark.usefixtures("respx_mock"),
]


async def test__send_smartapp_unread_counter__succeed(
respx_mock: MockRouter,
host: str,
bot_id: UUID,
bot_account: BotAccountWithSecret,
) -> None:
# - Arrange -
endpoint = respx_mock.post(
f"https://{host}/api/v4/botx/smartapps/unread_counter",
headers={"Authorization": "Bearer token", "Content-Type": "application/json"},
json={
"group_chat_id": "705df263-6bfd-536a-9d51-13524afaab5c",
"counter": 45,
},
).mock(
return_value=httpx.Response(
HTTPStatus.ACCEPTED,
json={
"status": "ok",
"result": {"sync_id": "21a9ec9e-f21f-4406-ac44-1a78d2ccf9e3"},
},
),
)

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

# - Act -
async with lifespan_wrapper(built_bot) as bot:
task = asyncio.create_task(
bot.send_smartapp_unread_counter(
bot_id=bot_id,
group_chat_id=UUID("705df263-6bfd-536a-9d51-13524afaab5c"),
counter=45,
),
)
await asyncio.sleep(0) # Return control to event loop

await bot.set_raw_botx_method_result(
{
"status": "ok",
"sync_id": "21a9ec9e-f21f-4406-ac44-1a78d2ccf9e3",
"result": {},
},
verify_request=False,
)

# - Assert -
assert await task == UUID("21a9ec9e-f21f-4406-ac44-1a78d2ccf9e3")
assert endpoint.called

0 comments on commit 4c3be1d

Please sign in to comment.