diff --git a/pybotx/__init__.py b/pybotx/__init__.py index b3952366..e6e83bb2 100644 --- a/pybotx/__init__.py +++ b/pybotx/__init__.py @@ -71,7 +71,7 @@ UserSender, ) from pybotx.models.message.markup import BubbleMarkup, Button, KeyboardMarkup -from pybotx.models.message.mentions import Mention, MentionList +from pybotx.models.message.mentions import Mention, MentionBuilder, MentionList from pybotx.models.message.message_status import MessageStatus from pybotx.models.message.outgoing_message import OutgoingMessage from pybotx.models.message.reply import Reply @@ -147,6 +147,7 @@ "KeyboardMarkup", "LeftFromChatEvent", "Mention", + "MentionBuilder", "MentionList", "MentionTypes", "Middleware", diff --git a/pybotx/models/enums.py b/pybotx/models/enums.py index 89f8026b..3d67002e 100644 --- a/pybotx/models/enums.py +++ b/pybotx/models/enums.py @@ -134,22 +134,6 @@ def convert_client_platform_to_domain( return converted_type -def convert_mention_type_to_domain(mention_type: BotAPIMentionTypes) -> MentionTypes: - mention_types_mapping = { - BotAPIMentionTypes.CONTACT: MentionTypes.CONTACT, - BotAPIMentionTypes.CHAT: MentionTypes.CHAT, - BotAPIMentionTypes.CHANNEL: MentionTypes.CHANNEL, - BotAPIMentionTypes.USER: MentionTypes.USER, - BotAPIMentionTypes.ALL: MentionTypes.ALL, - } - - converted_type = mention_types_mapping.get(mention_type) - if converted_type is None: - raise NotImplementedError(f"Unsupported mention type: {mention_type}") - - return converted_type - - def convert_mention_type_from_domain( mention_type: MentionTypes, ) -> BotAPIMentionTypes: diff --git a/pybotx/models/message/incoming_message.py b/pybotx/models/message/incoming_message.py index ac65518d..2687a689 100644 --- a/pybotx/models/message/incoming_message.py +++ b/pybotx/models/message/incoming_message.py @@ -33,7 +33,6 @@ ClientPlatforms, convert_chat_type_to_domain, convert_client_platform_to_domain, - convert_mention_type_to_domain, ) from pybotx.models.message.forward import BotAPIForward, Forward from pybotx.models.message.mentions import ( @@ -41,6 +40,7 @@ BotAPIMentionData, BotAPINestedMentionData, Mention, + MentionBuilder, MentionList, ) from pybotx.models.message.reply import BotAPIReply, Reply @@ -117,18 +117,37 @@ def arguments(self) -> Tuple[str, ...]: def _convert_bot_api_mention_to_domain(api_mention_data: BotAPIMentionData) -> Mention: - entity_id: Optional[UUID] = None - name: Optional[str] = None - - if api_mention_data.mention_type != BotAPIMentionTypes.ALL: - mention_data = cast(BotAPINestedMentionData, api_mention_data.mention_data) - entity_id = mention_data.entity_id - name = mention_data.name - - return Mention( - type=convert_mention_type_to_domain(api_mention_data.mention_type), - entity_id=entity_id, - name=name, + mention_data = cast(BotAPINestedMentionData, api_mention_data.mention_data) + + if api_mention_data.mention_type == BotAPIMentionTypes.USER: + return MentionBuilder.user( + entity_id=mention_data.entity_id, + name=mention_data.name, + ) + + if api_mention_data.mention_type == BotAPIMentionTypes.CHAT: + return MentionBuilder.chat( + entity_id=mention_data.entity_id, + name=mention_data.name, + ) + + if api_mention_data.mention_type == BotAPIMentionTypes.CONTACT: + return MentionBuilder.contact( + entity_id=mention_data.entity_id, + name=mention_data.name, + ) + + if api_mention_data.mention_type == BotAPIMentionTypes.CHANNEL: + return MentionBuilder.channel( + entity_id=mention_data.entity_id, + name=mention_data.name, + ) + + if api_mention_data.mention_type == BotAPIMentionTypes.ALL: + return MentionBuilder.all() + + raise NotImplementedError( + f"Unsupported mention type: {api_mention_data.mention_type}", ) @@ -255,7 +274,10 @@ def to_domain(self, raw_command: Dict[str, Any]) -> IncomingMessage: # noqa: WP logger.warning("Received unknown entity type") else: entity_domain = convert_bot_api_entity_to_domain(entity) - if isinstance(entity_domain, Mention): + if isinstance( + entity_domain, + Mention.__args__, # type: ignore [attr-defined] # noqa: WPS609 + ): mentions.append(entity_domain) elif isinstance(entity_domain, Forward): # Max one forward per message diff --git a/pybotx/models/message/mentions.py b/pybotx/models/message/mentions.py index 91c0dccd..ec6a3850 100644 --- a/pybotx/models/message/mentions.py +++ b/pybotx/models/message/mentions.py @@ -15,53 +15,117 @@ ) +def build_embed_mention( + mention_type: MentionTypes, + entity_id: Optional[UUID] = None, + name: Optional[str] = None, +) -> str: + name = name or "" + entity_id_str = "" if entity_id is None else str(entity_id) + return f"{mention_type.value}:{entity_id_str}:{name}" + + +@dataclass +class BaseTargetMention: + entity_id: Optional[UUID] + name: Optional[str] + + +@dataclass +class MentionUser(BaseTargetMention): + type: Literal[MentionTypes.USER] + + def __str__(self) -> str: + return build_embed_mention(self.type, self.entity_id, self.name) + + +@dataclass +class MentionContact(BaseTargetMention): + type: Literal[MentionTypes.CONTACT] + + def __str__(self) -> str: + return build_embed_mention(self.type, self.entity_id, self.name) + + +@dataclass +class MentionChat(BaseTargetMention): + type: Literal[MentionTypes.CHAT] + + def __str__(self) -> str: + return build_embed_mention(self.type, self.entity_id, self.name) + + +@dataclass +class MentionChannel(BaseTargetMention): + type: Literal[MentionTypes.CHANNEL] + + def __str__(self) -> str: + return build_embed_mention(self.type, self.entity_id, self.name) + + @dataclass -class Mention: - type: MentionTypes - entity_id: Optional[UUID] = None - name: Optional[str] = None +class MentionAll: + type: Literal[MentionTypes.ALL] def __str__(self) -> str: - name = self.name or "" - entity_id = self.entity_id or "" - mention_type = self.type.value - return f"{mention_type}:{entity_id}:{name}" + return build_embed_mention(self.type) + + +Mention = Union[ + MentionUser, + MentionContact, + MentionChat, + MentionChannel, + MentionAll, +] + +class MentionBuilder: @classmethod - def user(cls, huid: UUID, name: Optional[str] = None) -> "Mention": - return cls( + def user(cls, entity_id: Optional[UUID], name: Optional[str] = None) -> MentionUser: + return MentionUser( type=MentionTypes.USER, - entity_id=huid, + entity_id=entity_id, name=name, ) @classmethod - def contact(cls, huid: UUID, name: Optional[str] = None) -> "Mention": - return cls( + def contact( + cls, + entity_id: Optional[UUID], + name: Optional[str] = None, + ) -> MentionContact: + return MentionContact( type=MentionTypes.CONTACT, - entity_id=huid, + entity_id=entity_id, name=name, ) @classmethod - def chat(cls, chat_id: UUID, name: Optional[str] = None) -> "Mention": - return cls( + def chat(cls, entity_id: Optional[UUID], name: Optional[str] = None) -> MentionChat: + return MentionChat( type=MentionTypes.CHAT, - entity_id=chat_id, + entity_id=entity_id, name=name, ) @classmethod - def channel(cls, chat_id: UUID, name: Optional[str] = None) -> "Mention": - return cls( + def channel( + cls, + entity_id: Optional[UUID], + name: Optional[str] = None, + ) -> MentionChannel: + return MentionChannel( type=MentionTypes.CHANNEL, - entity_id=chat_id, + entity_id=entity_id, name=name, ) @classmethod - def all(cls) -> "Mention": - return cls(type=MentionTypes.ALL) + def all(cls) -> MentionAll: + return MentionAll( + type=MentionTypes.ALL, + ) class MentionList(List[Mention]): diff --git a/pyproject.toml b/pyproject.toml index 1553d553..5a689d36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pybotx" -version = "0.33.0" +version = "0.34.0" description = "A python library for interacting with eXpress BotX API" authors = [ "Sidnev Nikolay ", diff --git a/tests/client/events_api/test_edit_event.py b/tests/client/events_api/test_edit_event.py index b536a603..07fcc223 100644 --- a/tests/client/events_api/test_edit_event.py +++ b/tests/client/events_api/test_edit_event.py @@ -13,7 +13,7 @@ EditMessage, HandlerCollector, KeyboardMarkup, - Mention, + MentionBuilder, OutgoingAttachment, lifespan_wrapper, ) @@ -146,7 +146,7 @@ async def test__edit_message__maximum_edit_succeed( await bot.edit_message( bot_id=bot_id, sync_id=UUID("8ba66c5b-40bf-5c77-911d-519cb4e382e9"), - body=f"{Mention.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!", + body=f"{MentionBuilder.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!", metadata={"message": "metadata"}, bubbles=bubbles, keyboard=keyboard, @@ -289,7 +289,7 @@ async def test__edit__succeed( message = EditMessage( bot_id=bot_id, sync_id=UUID("8ba66c5b-40bf-5c77-911d-519cb4e382e9"), - body=f"{Mention.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!", + body=f"{MentionBuilder.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!", metadata={"message": "metadata"}, bubbles=bubbles, keyboard=keyboard, diff --git a/tests/client/events_api/test_reply_event.py b/tests/client/events_api/test_reply_event.py index da80ab76..b60e0f18 100644 --- a/tests/client/events_api/test_reply_event.py +++ b/tests/client/events_api/test_reply_event.py @@ -12,7 +12,7 @@ BubbleMarkup, HandlerCollector, KeyboardMarkup, - Mention, + MentionBuilder, OutgoingAttachment, ReplyMessage, lifespan_wrapper, @@ -162,7 +162,7 @@ async def test__reply_message__maximum_filled_reply_succeed( await bot.reply_message( bot_id=bot_id, sync_id=UUID("8ba66c5b-40bf-5c77-911d-519cb4e382e9"), - body=f"{Mention.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!", + body=f"{MentionBuilder.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!", metadata={"message": "metadata"}, bubbles=bubbles, keyboard=keyboard, @@ -270,7 +270,7 @@ async def test__reply__succeed( message = ReplyMessage( bot_id=bot_id, sync_id=UUID("8ba66c5b-40bf-5c77-911d-519cb4e382e9"), - body=f"{Mention.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!", + body=f"{MentionBuilder.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!", metadata={"message": "metadata"}, bubbles=bubbles, keyboard=keyboard, diff --git a/tests/client/notifications_api/test_direct_notification.py b/tests/client/notifications_api/test_direct_notification.py index ed51ed12..3cba3401 100644 --- a/tests/client/notifications_api/test_direct_notification.py +++ b/tests/client/notifications_api/test_direct_notification.py @@ -19,7 +19,7 @@ HandlerCollector, IncomingMessage, KeyboardMarkup, - Mention, + MentionBuilder, OutgoingAttachment, OutgoingMessage, StealthModeDisabledError, @@ -622,7 +622,7 @@ async def test__send_message__maximum_filled_succeed( lambda: UUID("f3e176d5-ff46-4b18-b260-25008338c06e"), ) - body = f"Hi, {Mention.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!" + body = f"Hi, {MentionBuilder.user(UUID('8f3abcc8-ba00-4c89-88e0-b786beb8ec24'))}!" formatted_body = "Hi, @{mention:f3e176d5-ff46-4b18-b260-25008338c06e}!" endpoint = respx_mock.post( @@ -781,14 +781,14 @@ async def test__send_message__all_mentions_types_succeed( ) mentioned_user_huid = UUID("8f3abcc8-ba00-4c89-88e0-b786beb8ec24") - user_mention = Mention.user(mentioned_user_huid) + user_mention = MentionBuilder.user(mentioned_user_huid) mentioned_contact_huid = UUID("1e0529fd-f091-4be9-93cc-6704a8957432") - contact_mention = Mention.contact(mentioned_contact_huid) + contact_mention = MentionBuilder.contact(mentioned_contact_huid) mentioned_chat_huid = UUID("454d73ad-1d32-4939-a708-e14b77414e86") - chat_mention = Mention.chat(mentioned_chat_huid, "Our chat") + chat_mention = MentionBuilder.chat(mentioned_chat_huid, "Our chat") mentioned_channel_huid = UUID("78198bec-3285-48d0-9fe2-c0eb3afaffd7") - channel_mention = Mention.channel(mentioned_channel_huid) - all_mention = Mention.all() + channel_mention = MentionBuilder.channel(mentioned_channel_huid) + all_mention = MentionBuilder.all() body = ( f"Hi, {user_mention}, want you to know, " diff --git a/tests/models/test_mentions_list.py b/tests/models/test_mentions_list.py index c071069b..c6782207 100644 --- a/tests/models/test_mentions_list.py +++ b/tests/models/test_mentions_list.py @@ -1,59 +1,34 @@ -from typing import Callable, Optional -from uuid import UUID, uuid4 +from uuid import uuid4 -import pytest +from pybotx import MentionBuilder, MentionList -from pybotx import Mention, MentionList, MentionTypes - -@pytest.fixture -def mention_factory() -> Callable[..., Mention]: - def factory( - mention_type: MentionTypes, - huid: UUID, - name: Optional[str] = None, - ) -> Mention: - return Mention( - type=mention_type, - entity_id=huid, - name=name, - ) - - return factory - - -def test__mentions_list_properties__filled( - mention_factory: Callable[..., Mention], -) -> None: +def test__mentions_list_properties__filled() -> None: # - Arrange - contacts = [ - mention_factory( - mention_type=MentionTypes.CONTACT, - huid=uuid4(), + MentionBuilder.contact( + entity_id=uuid4(), name=str(name), ) for name in range(2) ] chats = [ - mention_factory( - mention_type=MentionTypes.CHAT, - huid=uuid4(), + MentionBuilder.chat( + entity_id=uuid4(), name=str(name), ) for name in range(2) ] channels = [ - mention_factory( - mention_type=MentionTypes.CHANNEL, - huid=uuid4(), + MentionBuilder.channel( + entity_id=uuid4(), name=str(name), ) for name in range(2) ] users = [ - mention_factory( - mention_type=MentionTypes.USER, - huid=uuid4(), + MentionBuilder.user( + entity_id=uuid4(), name=str(name), ) for name in range(2) @@ -68,15 +43,12 @@ def test__mentions_list_properties__filled( assert mentions.users == users -def test__mentions_list_all_users_mentioned__filled( - mention_factory: Callable[..., Mention], -) -> None: +def test__mentions_list_all_users_mentioned__filled() -> None: # - Arrange - - user_mention = mention_factory( - mention_type=MentionTypes.CONTACT, - huid=uuid4(), + user_mention = MentionBuilder.contact( + entity_id=uuid4(), ) - all_mention = Mention(type=MentionTypes.ALL) + all_mention = MentionBuilder.all() one_all_mention = MentionList([user_mention, all_mention]) two_all_mentions = MentionList([all_mention, all_mention]) diff --git a/tests/test_incoming_message.py b/tests/test_incoming_message.py index 60682a02..95c9ceba 100644 --- a/tests/test_incoming_message.py +++ b/tests/test_incoming_message.py @@ -16,9 +16,8 @@ HandlerCollector, Image, IncomingMessage, - Mention, + MentionBuilder, MentionList, - MentionTypes, Reply, UserDevice, UserSender, @@ -299,8 +298,7 @@ async def default_handler(message: IncomingMessage, bot: Bot) -> None: ), mentions=MentionList( [ - Mention( - type=MentionTypes.CONTACT, + MentionBuilder.contact( entity_id=UUID("ab103983-6001-44e9-889e-d55feb295494"), name="Вася Иванов", ), @@ -317,8 +315,7 @@ async def default_handler(message: IncomingMessage, bot: Bot) -> None: body="все равно документацию никто не читает...", mentions=MentionList( [ - Mention( - type=MentionTypes.CONTACT, + MentionBuilder.contact( entity_id=UUID("ab103983-6001-44e9-889e-d55feb295494"), name="Вася Иванов", ), @@ -446,31 +443,23 @@ async def default_handler(message: IncomingMessage, bot: Bot) -> None: assert incoming_message assert incoming_message.mentions == MentionList( [ - Mention( - type=MentionTypes.CONTACT, + MentionBuilder.contact( entity_id=UUID("ab103983-6001-44e9-889e-d55feb295494"), name="Вася Иванов", ), - Mention( - type=MentionTypes.USER, + MentionBuilder.user( entity_id=UUID("ab103983-6001-44e9-889e-d55feb295494"), name="Вася Иванов", ), - Mention( - type=MentionTypes.CHANNEL, + MentionBuilder.channel( entity_id=UUID("ab103983-6001-44e9-889e-d55feb295494"), name="Вася Иванов", ), - Mention( - type=MentionTypes.CHAT, + MentionBuilder.chat( entity_id=UUID("ab103983-6001-44e9-889e-d55feb295494"), name="Вася Иванов", ), - Mention( - type=MentionTypes.ALL, - entity_id=None, - name=None, - ), + MentionBuilder.all(), ], )