Skip to content

Commit

Permalink
feat: Method for getting a list of SmartApps
Browse files Browse the repository at this point in the history
  • Loading branch information
nidemidovich committed Jul 21, 2022
1 parent 6d7bdbf commit eb5b3ee
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 2 deletions.
42 changes: 41 additions & 1 deletion pybotx/bot/bot.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
from asyncio import Task
from types import SimpleNamespace
from typing import Any, AsyncIterable, Dict, Iterator, List, Optional, Sequence, Union
from typing import (
Any,
AsyncIterable,
Dict,
Iterator,
List,
Optional,
Sequence,
Tuple,
Union,
)
from uuid import UUID

import httpx
Expand Down Expand Up @@ -96,6 +106,10 @@
BotXAPISmartAppNotificationRequestPayload,
SmartAppNotificationMethod,
)
from pybotx.client.smartapps_api.smartapps_list import (
BotXAPISmartAppsListRequestPayload,
SmartAppsListMethod,
)
from pybotx.client.stickers_api.add_sticker import (
AddStickerMethod,
BotXAPIAddStickerRequestPayload,
Expand Down Expand Up @@ -168,6 +182,7 @@
from pybotx.models.message.outgoing_message import OutgoingMessage
from pybotx.models.message.reply_message import ReplyMessage
from pybotx.models.method_callbacks import BotXMethodCallback
from pybotx.models.smartapps import SmartApp
from pybotx.models.status import (
BotAPIStatusRecipient,
BotMenu,
Expand Down Expand Up @@ -1262,6 +1277,31 @@ async def send_smartapp_notification(

await method.execute(payload)

async def get_smartapps_list(
self,
*,
bot_id: UUID,
version: Missing[int] = Undefined,
) -> Tuple[List[SmartApp], int]:
"""Get list of SmartApps on the current CTS.
:param bot_id: Bot which should perform the request.
:param version: Specific list version.
:return: List of SmartApps, list version.
"""

method = SmartAppsListMethod(
bot_id,
self._httpx_client,
self._bot_accounts_storage,
)
payload = BotXAPISmartAppsListRequestPayload.from_domain(version=version)

botx_api_smartapps_list = await method.execute(payload)

return botx_api_smartapps_list.to_domain()

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

from pybotx.client.authorized_botx_method import AuthorizedBotXMethod
from pybotx.missing import Missing, Undefined
from pybotx.models.api_base import UnverifiedPayloadBaseModel, VerifiedPayloadBaseModel
from pybotx.models.smartapps import SmartApp


class BotXAPISmartAppsListRequestPayload(UnverifiedPayloadBaseModel):
version: Missing[int] = Undefined

@classmethod
def from_domain(
cls,
version: Missing[int] = Undefined,
) -> "BotXAPISmartAppsListRequestPayload":
return cls(version=version)


class BotXAPISmartAppEntity(VerifiedPayloadBaseModel):
app_id: str
enabled: bool
id: UUID
name: str
avatar: Optional[str] = None
avatar_preview: Optional[str] = None


class BotXAPISmartAppsListResult(VerifiedPayloadBaseModel):
phonebook_version: int
smartapps: List[BotXAPISmartAppEntity]


class BotXAPISmartAppsListResponsePayload(VerifiedPayloadBaseModel):
result: BotXAPISmartAppsListResult
status: Literal["ok"]

def to_domain(self) -> Tuple[List[SmartApp], int]:
smartapps_list = [
SmartApp(
app_id=smartapp.app_id,
enabled=smartapp.enabled,
id=smartapp.id,
name=smartapp.name,
avatar=smartapp.avatar,
avatar_preview=smartapp.avatar_preview,
)
for smartapp in self.result.smartapps
]
return (
smartapps_list,
self.result.phonebook_version,
)


class SmartAppsListMethod(AuthorizedBotXMethod):
status_handlers = {
**AuthorizedBotXMethod.status_handlers,
}

async def execute(
self,
payload: BotXAPISmartAppsListRequestPayload,
) -> BotXAPISmartAppsListResponsePayload:
path = "/api/v3/botx/smartapps/list"

response = await self._botx_method_call(
"GET",
self._build_url(path),
params=payload.jsonable_dict(),
)

return self._verify_and_extract_api_model(
BotXAPISmartAppsListResponsePayload,
response,
)
24 changes: 24 additions & 0 deletions pybotx/models/smartapps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from dataclasses import dataclass
from typing import Optional
from uuid import UUID


@dataclass
class SmartApp:
"""SmartApp from list of SmartApps.
Attributes:
app_id: Readable SmartApp id.
enabled: Is the SmartApp enabled or not.
id: SmartApp uuid.
name: SmartApp name.
avatar: SmartApp avatar url.
avatar_preview: SmartApp avatar preview url.
"""

app_id: str
enabled: bool
id: UUID
name: str
avatar: Optional[str] = None
avatar_preview: Optional[str] = None
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.46.0"
version = "0.47.0"
description = "A python library for interacting with eXpress BotX API"
authors = [
"Sidnev Nikolay <[email protected]>",
Expand Down
71 changes: 71 additions & 0 deletions tests/client/smartapps_api/test_smartapps_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from http import HTTPStatus
from uuid import UUID

import httpx
import pytest
from respx.router import MockRouter

from pybotx import Bot, HandlerCollector, lifespan_wrapper
from pybotx.models.bot_account import BotAccountWithSecret
from pybotx.models.smartapps import SmartApp

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


async def test__smartapps_list__succeed(
respx_mock: MockRouter,
host: str,
bot_id: UUID,
bot_account: BotAccountWithSecret,
) -> None:
# - Arrange -
endpoint = respx_mock.get(
f"https://{host}/api/v3/botx/smartapps/list",
headers={"Authorization": "Bearer token"},
).mock(
return_value=httpx.Response(
HTTPStatus.OK,
json={
"result": {
"phonebook_version": 1,
"smartapps": [
{
"app_id": "amazing_smartapp",
"avatar": "https://cts.example.com/uploads/profile_avatar/foo",
"avatar_preview": "https://cts.example.com/uploads/profile_avatar/bar",
"enabled": True,
"id": "dc4acaf2-310f-4b0f-aec7-253b9def42ac",
"name": "Amazing SmartApp",
},
],
},
"status": "ok",
},
),
)

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

# - Act -
async with lifespan_wrapper(built_bot) as bot:
smartapps_list, version = await bot.get_smartapps_list(
bot_id=bot_id,
)

# - Assert -
assert endpoint.called
assert smartapps_list == [
SmartApp(
app_id="amazing_smartapp",
avatar="https://cts.example.com/uploads/profile_avatar/foo",
avatar_preview="https://cts.example.com/uploads/profile_avatar/bar",
enabled=True,
id=UUID("dc4acaf2-310f-4b0f-aec7-253b9def42ac"),
name="Amazing SmartApp",
),
]
assert version == 1

0 comments on commit eb5b3ee

Please sign in to comment.