diff --git a/pybotx/__init__.py b/pybotx/__init__.py index cb0539cb..fb8f60d5 100644 --- a/pybotx/__init__.py +++ b/pybotx/__init__.py @@ -62,6 +62,9 @@ from pybotx.client.smartapps_api.exceptions import SyncSmartAppEventHandlerNotFoundError from pybotx.client.smartapps_api.smartapp_manifest import ( SmartappManifest, + SmartappManifestAndroidParams, + SmartappManifestIosParams, + SmartappManifestUnreadCounterParams, SmartappManifestWebParams, ) from pybotx.client.stickers_api.exceptions import ( @@ -234,6 +237,9 @@ "SmartApp", "SmartAppEvent", "SmartappManifest", + "SmartappManifestAndroidParams", + "SmartappManifestIosParams", + "SmartappManifestUnreadCounterParams", "SmartappManifestWebLayoutChoices", "SmartappManifestWebParams", "StatusRecipient", diff --git a/pybotx/bot/bot.py b/pybotx/bot/bot.py index f26a7e53..670a6cf3 100644 --- a/pybotx/bot/bot.py +++ b/pybotx/bot/bot.py @@ -138,7 +138,11 @@ from pybotx.client.smartapps_api.smartapp_manifest import ( BotXAPISmartAppManifestRequestPayload, SmartappManifest, + SmartappManifestAndroidParams, + SmartappManifestIosParams, SmartAppManifestMethod, + SmartappManifestUnreadCounterParams, + SmartappManifestWebParams, ) from pybotx.client.smartapps_api.smartapp_notification import ( BotXAPISmartAppNotificationRequestPayload, @@ -231,7 +235,6 @@ from pybotx.models.chats import ChatInfo, ChatListItem from pybotx.models.commands import BotAPICommand, BotCommand from pybotx.models.enums import ChatTypes -from pybotx.models.enums import SmartappManifestWebLayoutChoices as WebLayoutChoices from pybotx.models.message.edit_message import EditMessage from pybotx.models.message.markup import BubbleMarkup, KeyboardMarkup from pybotx.models.message.message_status import MessageStatus @@ -1551,17 +1554,18 @@ async def send_smartapp_manifest( self, *, bot_id: UUID, - web_default_layout: WebLayoutChoices = WebLayoutChoices.minimal, - web_expanded_layout: WebLayoutChoices = WebLayoutChoices.half, - web_always_pinned: bool = False, + ios: Missing[SmartappManifestIosParams] = Undefined, + android: Missing[SmartappManifestAndroidParams] = Undefined, + web_layout: Missing[SmartappManifestWebParams] = Undefined, + unread_counter: Missing[SmartappManifestUnreadCounterParams] = Undefined, ) -> SmartappManifest: """Send smartapp manifest with given parameters. :param bot_id: Bot which should perform the request. - :param web_default_layout: default smartapp layout for web clients. - :param web_expanded_layout: expanded smartapp layout for web clients. - :param web_always_pinned: True if smartapp icon should be always pinned - in the web clients sidebar. + :param ios: Smartapp layout for ios clients. + :param android: Smartapp layout for android clients. + :param web_layout: Smartapp layout for web clients. + :param unread_counter: Entities that can be subscribed to in the unread counter. :return: Smartapp manifest with the set parameters received from BotX. """ @@ -1572,9 +1576,10 @@ async def send_smartapp_manifest( self._bot_accounts_storage, ) payload = BotXAPISmartAppManifestRequestPayload.from_domain( - web_default_layout=web_default_layout, - web_expanded_layout=web_expanded_layout, - web_always_pinned=web_always_pinned, + ios=ios, + android=android, + web_layout=web_layout, + unread_counter=unread_counter, ) smartapp_manifest_response = await method.execute(payload) return smartapp_manifest_response.to_domain() diff --git a/pybotx/client/smartapps_api/smartapp_manifest.py b/pybotx/client/smartapps_api/smartapp_manifest.py index cde503d5..53e0a4ec 100644 --- a/pybotx/client/smartapps_api/smartapp_manifest.py +++ b/pybotx/client/smartapps_api/smartapp_manifest.py @@ -1,37 +1,68 @@ -from typing import Literal +from typing import List, Literal +from uuid import UUID + +from pydantic import Field from pybotx.client.authorized_botx_method import AuthorizedBotXMethod -from pybotx.models.api_base import VerifiedPayloadBaseModel +from pybotx.missing import Missing, Undefined +from pybotx.models.api_base import UnverifiedPayloadBaseModel, VerifiedPayloadBaseModel from pybotx.models.enums import SmartappManifestWebLayoutChoices as WebLayoutChoices +class SmartappManifestIosParams(VerifiedPayloadBaseModel): + fullscreen_layout: bool = False + + +class SmartappManifestAndroidParams(VerifiedPayloadBaseModel): + fullscreen_layout: bool = False + + class SmartappManifestWebParams(VerifiedPayloadBaseModel): default_layout: WebLayoutChoices = WebLayoutChoices.minimal expanded_layout: WebLayoutChoices = WebLayoutChoices.half always_pinned: bool = False +class SmartappManifestUnreadCounterParams(VerifiedPayloadBaseModel): + user_huid: List[UUID] = Field(default_factory=list) + group_chat_id: List[UUID] = Field(default_factory=list) + app_id: List[str] = Field(default_factory=list) + + class SmartappManifest(VerifiedPayloadBaseModel): + ios: SmartappManifestIosParams + android: SmartappManifestAndroidParams web: SmartappManifestWebParams + unread_counter_link: SmartappManifestUnreadCounterParams + +class SmartappManifestPayload(UnverifiedPayloadBaseModel): + ios: Missing[SmartappManifestIosParams] = Undefined + android: Missing[SmartappManifestAndroidParams] = Undefined + web: Missing[SmartappManifestWebParams] = Undefined + unread_counter_link: Missing[SmartappManifestUnreadCounterParams] = Undefined -class BotXAPISmartAppManifestRequestPayload(VerifiedPayloadBaseModel): - manifest: SmartappManifest + +class BotXAPISmartAppManifestRequestPayload(UnverifiedPayloadBaseModel): + manifest: SmartappManifestPayload @classmethod def from_domain( cls, - web_default_layout: WebLayoutChoices = WebLayoutChoices.minimal, - web_expanded_layout: WebLayoutChoices = WebLayoutChoices.half, - web_always_pinned: bool = False, + ios: Missing[SmartappManifestIosParams] = Undefined, + android: Missing[SmartappManifestAndroidParams] = Undefined, + web_layout: Missing[SmartappManifestWebParams] = Undefined, + unread_counter: Missing[SmartappManifestUnreadCounterParams] = Undefined, ) -> "BotXAPISmartAppManifestRequestPayload": + if web_layout is Undefined and unread_counter is Undefined: + return cls(manifest={}) + return cls( - manifest=SmartappManifest( - web=SmartappManifestWebParams( - default_layout=web_default_layout, - expanded_layout=web_expanded_layout, - always_pinned=web_always_pinned, - ), + manifest=SmartappManifestPayload( + ios=ios, + android=android, + web=web_layout, + unread_counter_link=unread_counter, ), ) diff --git a/pyproject.toml b/pyproject.toml index 02ccfb1b..c769b559 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pybotx" -version = "0.71.0" +version = "0.72.0" description = "A python library for interacting with eXpress BotX API" authors = [ "Sidnev Nikolay ", diff --git a/tests/client/smartapps_api/test_smartapp_manifest.py b/tests/client/smartapps_api/test_smartapp_manifest.py index 714066ca..6916882c 100644 --- a/tests/client/smartapps_api/test_smartapp_manifest.py +++ b/tests/client/smartapps_api/test_smartapp_manifest.py @@ -14,6 +14,11 @@ SmartappManifestWebParams, lifespan_wrapper, ) +from pybotx.client.smartapps_api.smartapp_manifest import ( + SmartappManifestAndroidParams, + SmartappManifestIosParams, + SmartappManifestUnreadCounterParams, +) pytestmark = [ pytest.mark.asyncio, @@ -34,11 +39,22 @@ async def test__send_smartapp_manifest__all_params_provided__succeed( headers={"Authorization": "Bearer token", "Content-Type": "application/json"}, json={ "manifest": { + "ios": { + "fullscreen_layout": False, + }, + "android": { + "fullscreen_layout": False, + }, "web": { "always_pinned": True, "default_layout": "full", "expanded_layout": "full", }, + "unread_counter_link": { + "user_huid": ["e3568b81-0446-4030-9210-1725841bf8f0"], + "group_chat_id": ["adc03af8-9193-4d3b-b913-7a023cdb4029"], + "app_id": ["test_app"], + }, }, }, ).mock( @@ -46,11 +62,22 @@ async def test__send_smartapp_manifest__all_params_provided__succeed( HTTPStatus.ACCEPTED, json={ "result": { + "ios": { + "fullscreen_layout": False, + }, + "android": { + "fullscreen_layout": False, + }, "web": { "always_pinned": True, "default_layout": "full", "expanded_layout": "full", }, + "unread_counter_link": { + "user_huid": ["e3568b81-0446-4030-9210-1725841bf8f0"], + "group_chat_id": ["adc03af8-9193-4d3b-b913-7a023cdb4029"], + "app_id": ["test_app"], + }, }, "status": "ok", }, @@ -63,19 +90,43 @@ async def test__send_smartapp_manifest__all_params_provided__succeed( async with lifespan_wrapper(built_bot) as bot: smartapp_manifest = await bot.send_smartapp_manifest( bot_id=bot_id, - web_default_layout=SmartappManifestWebLayoutChoices.full, - web_expanded_layout=SmartappManifestWebLayoutChoices.full, - web_always_pinned=True, + ios=SmartappManifestIosParams( + fullscreen_layout=False, + ), + android=SmartappManifestAndroidParams( + fullscreen_layout=False, + ), + web_layout=SmartappManifestWebParams( + default_layout=SmartappManifestWebLayoutChoices.full, + expanded_layout=SmartappManifestWebLayoutChoices.full, + always_pinned=True, + ), + unread_counter=SmartappManifestUnreadCounterParams( + user_huid=[UUID("e3568b81-0446-4030-9210-1725841bf8f0")], + group_chat_id=[UUID("adc03af8-9193-4d3b-b913-7a023cdb4029")], + app_id=["test_app"], + ), ) # - Assert - assert endpoint.called assert smartapp_manifest == SmartappManifest( + ios=SmartappManifestIosParams( + fullscreen_layout=False, + ), + android=SmartappManifestAndroidParams( + fullscreen_layout=False, + ), web=SmartappManifestWebParams( default_layout=SmartappManifestWebLayoutChoices.full, expanded_layout=SmartappManifestWebLayoutChoices.full, always_pinned=True, ), + unread_counter_link=SmartappManifestUnreadCounterParams( + user_huid=[UUID("e3568b81-0446-4030-9210-1725841bf8f0")], + group_chat_id=[UUID("adc03af8-9193-4d3b-b913-7a023cdb4029")], + app_id=["test_app"], + ), ) @@ -90,24 +141,29 @@ async def test__send_smartapp_manifest__only_default_params_provided__succeed( f"https://{host}/api/v1/botx/smartapps/manifest", headers={"Authorization": "Bearer token", "Content-Type": "application/json"}, json={ - "manifest": { - "web": { - "always_pinned": False, - "default_layout": "minimal", - "expanded_layout": "half", - }, - }, + "manifest": {}, }, ).mock( return_value=httpx.Response( HTTPStatus.ACCEPTED, json={ "result": { + "ios": { + "fullscreen_layout": False, + }, + "android": { + "fullscreen_layout": False, + }, "web": { "always_pinned": False, "default_layout": "minimal", "expanded_layout": "half", }, + "unread_counter_link": { + "app_id": [], + "group_chat_id": [], + "user_huid": [], + }, }, "status": "ok", }, @@ -123,9 +179,20 @@ async def test__send_smartapp_manifest__only_default_params_provided__succeed( # - Assert - assert endpoint.called assert smartapp_manifest == SmartappManifest( + ios=SmartappManifestIosParams( + fullscreen_layout=False, + ), + android=SmartappManifestAndroidParams( + fullscreen_layout=False, + ), web=SmartappManifestWebParams( default_layout=SmartappManifestWebLayoutChoices.minimal, expanded_layout=SmartappManifestWebLayoutChoices.half, always_pinned=False, ), + unread_counter_link=SmartappManifestUnreadCounterParams( + user_huid=[], + group_chat_id=[], + app_id=[], + ), )