From cb67858b2b2ac6f8d36858e2f230c88370c72e5c Mon Sep 17 00:00:00 2001 From: Kirill Sokolov Date: Fri, 16 Aug 2024 14:54:31 +0300 Subject: [PATCH] feature: add delete event --- pybotx/__init__.py | 2 + pybotx/bot/handler.py | 2 + pybotx/bot/handler_collector.py | 9 +++ pybotx/models/commands.py | 3 + pybotx/models/enums.py | 1 + pybotx/models/system_events/event_delete.py | 46 +++++++++++ pyproject.toml | 2 +- tests/system_events/test_event_delete.py | 87 +++++++++++++++++++++ 8 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 pybotx/models/system_events/event_delete.py create mode 100644 tests/system_events/test_event_delete.py diff --git a/pybotx/__init__.py b/pybotx/__init__.py index cb0539cb..66874755 100644 --- a/pybotx/__init__.py +++ b/pybotx/__init__.py @@ -135,6 +135,7 @@ from pybotx.models.system_events.cts_logout import CTSLogoutEvent from pybotx.models.system_events.deleted_from_chat import DeletedFromChatEvent from pybotx.models.system_events.event_edit import EventEdit +from pybotx.models.system_events.event_delete import EventDelete from pybotx.models.system_events.internal_bot_notification import ( InternalBotNotificationEvent, ) @@ -193,6 +194,7 @@ "Document", "EditMessage", "EventEdit", + "EventDelete", "EventNotFoundError", "File", "FileDeletedError", diff --git a/pybotx/bot/handler.py b/pybotx/bot/handler.py index 22345003..75ccebc9 100644 --- a/pybotx/bot/handler.py +++ b/pybotx/bot/handler.py @@ -13,6 +13,7 @@ from pybotx.models.system_events.cts_logout import CTSLogoutEvent from pybotx.models.system_events.deleted_from_chat import DeletedFromChatEvent from pybotx.models.system_events.event_edit import EventEdit +from pybotx.models.system_events.event_delete import EventDelete from pybotx.models.system_events.internal_bot_notification import ( InternalBotNotificationEvent, ) @@ -42,6 +43,7 @@ HandlerFunc[InternalBotNotificationEvent], HandlerFunc[SmartAppEvent], HandlerFunc[EventEdit], + HandlerFunc[EventDelete], ] VisibleFunc = Callable[[StatusRecipient, "Bot"], Awaitable[bool]] diff --git a/pybotx/bot/handler_collector.py b/pybotx/bot/handler_collector.py index 5b5d88ca..3f7b05bc 100644 --- a/pybotx/bot/handler_collector.py +++ b/pybotx/bot/handler_collector.py @@ -46,6 +46,7 @@ from pybotx.models.system_events.cts_logout import CTSLogoutEvent from pybotx.models.system_events.deleted_from_chat import DeletedFromChatEvent from pybotx.models.system_events.event_edit import EventEdit +from pybotx.models.system_events.event_delete import EventDelete from pybotx.models.system_events.internal_bot_notification import ( InternalBotNotificationEvent, ) @@ -301,6 +302,14 @@ def event_edit( self._system_event(EventEdit, handler_func) return handler_func + def event_delete( + self, + handler_func: HandlerFunc[EventDelete], + ) -> HandlerFunc[EventDelete]: + """Decorate `event delete` event handler.""" + self._system_event(EventDelete, handler_func) + return handler_func + def smartapp_event( self, handler_func: HandlerFunc[SmartAppEvent], diff --git a/pybotx/models/commands.py b/pybotx/models/commands.py index 3162457b..425e0d3f 100644 --- a/pybotx/models/commands.py +++ b/pybotx/models/commands.py @@ -20,6 +20,7 @@ DeletedFromChatEvent, ) from pybotx.models.system_events.event_edit import BotAPIEventEdit, EventEdit +from pybotx.models.system_events.event_delete import BotAPIEventDelete, EventDelete from pybotx.models.system_events.internal_bot_notification import ( BotAPIInternalBotNotification, InternalBotNotificationEvent, @@ -45,6 +46,7 @@ BotAPICTSLogin, BotAPICTSLogout, BotAPIEventEdit, + BotAPIEventDelete ] BotAPICommand = Union[BotAPIIncomingMessage, BotAPISystemEvent] @@ -60,5 +62,6 @@ CTSLoginEvent, CTSLogoutEvent, EventEdit, + EventDelete ] BotCommand = Union[IncomingMessage, SystemEvent] diff --git a/pybotx/models/enums.py b/pybotx/models/enums.py index fb738b4c..89ae820a 100644 --- a/pybotx/models/enums.py +++ b/pybotx/models/enums.py @@ -102,6 +102,7 @@ class BotAPISystemEventTypes(StrEnum): LEFT_FROM_CHAT = "system:left_from_chat" SMARTAPP_EVENT = "system:smartapp_event" EVENT_EDIT = "system:event_edit" + EVENT_DELETE = "system:event_delete" class BotAPIClientPlatforms(Enum): diff --git a/pybotx/models/system_events/event_delete.py b/pybotx/models/system_events/event_delete.py new file mode 100644 index 00000000..deb3d8c9 --- /dev/null +++ b/pybotx/models/system_events/event_delete.py @@ -0,0 +1,46 @@ +from dataclasses import dataclass +from typing import Dict, Any, Literal +from uuid import UUID + +from pydantic import Field + +from pybotx.models.bot_account import BotAccount +from pybotx.models.api_base import VerifiedPayloadBaseModel +from pybotx.models.base_command import BotCommandBase, BaseBotAPIContext, BotAPIBaseCommand, \ + BotAPIBaseSystemEventPayload +from pybotx.models.enums import BotAPISystemEventTypes + + +@dataclass +class EventDelete(BotCommandBase): + """Event `system:event_delete`. + + Attributes: + sync_id: ID of the deleted message. + """ + + sync_id: UUID + + +class BotAPIEventDeleteData(VerifiedPayloadBaseModel): + sync_id: UUID + + +class BotAPIEventDeletePayload(BotAPIBaseSystemEventPayload): + body: Literal[BotAPISystemEventTypes.EVENT_DELETE] + data: BotAPIEventDeleteData + + +class BotAPIEventDelete(BotAPIBaseCommand): + payload: BotAPIEventDeletePayload = Field(..., alias="command") + sender: BaseBotAPIContext = Field(..., alias="from") + + def to_domain(self, raw_command: Dict[str, Any]) -> EventDelete: + return EventDelete( + bot=BotAccount( + id=self.bot_id, + host=self.sender.host, + ), + sync_id=self.sync_id, + raw_command=raw_command + ) diff --git a/pyproject.toml b/pyproject.toml index e0d0bd79..4e012860 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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 ", diff --git a/tests/system_events/test_event_delete.py b/tests/system_events/test_event_delete.py new file mode 100644 index 00000000..8d97257f --- /dev/null +++ b/tests/system_events/test_event_delete.py @@ -0,0 +1,87 @@ +from typing import Optional +from uuid import UUID + +import pytest + +from pybotx import ( + Bot, + BotAccountWithSecret, + HandlerCollector, + lifespan_wrapper, +) +from pybotx.models.system_events.event_delete import EventDelete +from pybotx.models.bot_account import BotAccount + +pytestmark = [ + pytest.mark.asyncio, + pytest.mark.mock_authorization, + pytest.mark.usefixtures("respx_mock"), +] + + +async def test__chat_deleted_by_user__succeed( + bot_account: BotAccountWithSecret, +) -> None: + # - Arrange - + payload = { + "sync_id": "a465f0f3-1354-491c-8f11-f400164295cb", + "command": { + "body": "system:event_delete", + "data": { + "sync_id": "6fa5f1e9-1453-0ad7-2d6d-b791467e382a", + }, + "command_type": "system", + "metadata": {}, + }, + "async_files": [], + "attachments": [], + "entities": [], + "from": { + "user_huid": None, + "group_chat_id": None, + "ad_login": None, + "ad_domain": None, + "username": None, + "chat_type": None, + "manufacturer": None, + "device": None, + "device_software": None, + "device_meta": {}, + "platform": None, + "platform_package_id": None, + "is_admin": None, + "is_creator": None, + "app_version": None, + "locale": "en", + "host": "cts.example.com", + }, + "bot_id": "24348246-6791-4ac0-9d86-b948cd6a0e46", + "proto_version": 4, + "source_sync_id": None, + } + + collector = HandlerCollector() + event_deleted: Optional[EventDelete] = None + + @collector.event_delete + async def event_delete_handler(event: EventDelete, bot: Bot) -> None: + nonlocal event_deleted + event_deleted = event + # Drop `raw_command` from asserting + event_deleted.raw_command = None + + built_bot = Bot(collectors=[collector], bot_accounts=[bot_account]) + + # - Act - + async with lifespan_wrapper(built_bot) as bot: + bot.async_execute_raw_bot_command(payload, verify_request=False) + + # - Assert - + assert event_deleted == EventDelete( + sync_id=UUID("a465f0f3-1354-491c-8f11-f400164295cb"), + bot=BotAccount( + id=UUID("24348246-6791-4ac0-9d86-b948cd6a0e46"), + host="cts.example.com", + ), + raw_command=None, + )