Skip to content

Commit

Permalink
feat: add chat_deleted_by_user event
Browse files Browse the repository at this point in the history
  • Loading branch information
Kiruha01 committed Jul 2, 2024
1 parent 848971a commit aa6883e
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 244 deletions.
369 changes: 147 additions & 222 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions pybotx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
from pybotx.models.stickers import Sticker, StickerPack
from pybotx.models.system_events.added_to_chat import AddedToChatEvent
from pybotx.models.system_events.chat_created import ChatCreatedEvent, ChatCreatedMember
from pybotx.models.system_events.chat_deleted_by_user import ChatDeletedByUserEvent
from pybotx.models.system_events.cts_login import CTSLoginEvent
from pybotx.models.system_events.cts_logout import CTSLogoutEvent
from pybotx.models.system_events.deleted_from_chat import DeletedFromChatEvent
Expand Down Expand Up @@ -173,6 +174,7 @@
"CantUpdatePersonalChatError",
"Chat",
"ChatCreatedEvent",
"ChatDeletedByUserEvent",
"ChatCreatedMember",
"ChatCreationError",
"ChatCreationProhibitedError",
Expand Down
2 changes: 2 additions & 0 deletions pybotx/bot/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pybotx.models.status import StatusRecipient
from pybotx.models.system_events.added_to_chat import AddedToChatEvent
from pybotx.models.system_events.chat_created import ChatCreatedEvent
from pybotx.models.system_events.chat_deleted_by_user import ChatDeletedByUserEvent
from pybotx.models.system_events.cts_login import CTSLoginEvent
from pybotx.models.system_events.cts_logout import CTSLogoutEvent
from pybotx.models.system_events.deleted_from_chat import DeletedFromChatEvent
Expand All @@ -35,6 +36,7 @@
SystemEventHandlerFunc = Union[
HandlerFunc[AddedToChatEvent],
HandlerFunc[ChatCreatedEvent],
HandlerFunc[ChatDeletedByUserEvent],
HandlerFunc[DeletedFromChatEvent],
HandlerFunc[LeftFromChatEvent],
HandlerFunc[CTSLoginEvent],
Expand Down
27 changes: 8 additions & 19 deletions pybotx/bot/handler_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from pybotx.models.status import BotMenu, StatusRecipient
from pybotx.models.system_events.added_to_chat import AddedToChatEvent
from pybotx.models.system_events.chat_created import ChatCreatedEvent
from pybotx.models.system_events.chat_deleted_by_user import ChatDeletedByUserEvent
from pybotx.models.system_events.cts_login import CTSLoginEvent
from pybotx.models.system_events.cts_logout import CTSLogoutEvent
from pybotx.models.system_events.deleted_from_chat import DeletedFromChatEvent
Expand Down Expand Up @@ -76,7 +77,6 @@ def __init__(self, middlewares: Optional[Sequence[Middleware]] = None) -> None:

def include(self, *others: "HandlerCollector") -> None:
"""Include other `HandlerCollector`."""

for collector in others:
self._include_collector(collector)

Expand Down Expand Up @@ -166,7 +166,6 @@ def command(
middlewares: Optional[Sequence[Middleware]] = None,
) -> Callable[[IncomingMessageHandlerFunc], IncomingMessageHandlerFunc]:
"""Decorate command handler."""

if not self.VALID_COMMAND_NAME_RE.match(command_name):
raise ValueError("Command should start with '/' and doesn't include spaces")

Expand Down Expand Up @@ -237,89 +236,79 @@ def chat_created(
handler_func: HandlerFunc[ChatCreatedEvent],
) -> HandlerFunc[ChatCreatedEvent]:
"""Decorate `chat_created` event handler."""

self._system_event(ChatCreatedEvent, handler_func)
return handler_func

def chat_deleted_by_user(
self,
handler_func: HandlerFunc[ChatDeletedByUserEvent],
) -> HandlerFunc[ChatDeletedByUserEvent]:
"""Decorate `chat_deleted_by_user` event handler."""
self._system_event(ChatDeletedByUserEvent, handler_func)
return handler_func

def added_to_chat(
self,
handler_func: HandlerFunc[AddedToChatEvent],
) -> HandlerFunc[AddedToChatEvent]:
"""Decorate `added_to_chat` event handler."""

self._system_event(AddedToChatEvent, handler_func)

return handler_func

def deleted_from_chat(
self,
handler_func: HandlerFunc[DeletedFromChatEvent],
) -> HandlerFunc[DeletedFromChatEvent]:
"""Decorate `deleted_from_chat` event handler."""

self._system_event(DeletedFromChatEvent, handler_func)

return handler_func

def left_from_chat(
self,
handler_func: HandlerFunc[LeftFromChatEvent],
) -> HandlerFunc[LeftFromChatEvent]:
"""Decorate `left_from_chat` event handler."""

self._system_event(LeftFromChatEvent, handler_func)

return handler_func

def internal_bot_notification(
self,
handler_func: HandlerFunc[InternalBotNotificationEvent],
) -> HandlerFunc[InternalBotNotificationEvent]:
"""Decorate `internal_bot_notification` event handler."""

self._system_event(InternalBotNotificationEvent, handler_func)

return handler_func

def cts_login(
self,
handler_func: HandlerFunc[CTSLoginEvent],
) -> HandlerFunc[CTSLoginEvent]:
"""Decorate `cts_login` event handler."""

self._system_event(CTSLoginEvent, handler_func)

return handler_func

def cts_logout(
self,
handler_func: HandlerFunc[CTSLogoutEvent],
) -> HandlerFunc[CTSLogoutEvent]:
"""Decorate `cts_logout` event handler."""

self._system_event(CTSLogoutEvent, handler_func)

return handler_func

def event_edit(
self,
handler_func: HandlerFunc[EventEdit],
) -> HandlerFunc[EventEdit]:
"""Decorate `event edit` event handler."""

self._system_event(EventEdit, handler_func)

return handler_func

def smartapp_event(
self,
handler_func: HandlerFunc[SmartAppEvent],
) -> HandlerFunc[SmartAppEvent]:
"""Decorate `smartapp` event handler."""

self._system_event(SmartAppEvent, handler_func)

return handler_func

def sync_smartapp_event(
Expand Down
6 changes: 6 additions & 0 deletions pybotx/models/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
BotAPIAddedToChat,
)
from pybotx.models.system_events.chat_created import BotAPIChatCreated, ChatCreatedEvent
from pybotx.models.system_events.chat_deleted_by_user import (
BotAPIChatDeletedByUser,
ChatDeletedByUserEvent,
)
from pybotx.models.system_events.cts_login import BotAPICTSLogin, CTSLoginEvent
from pybotx.models.system_events.cts_logout import BotAPICTSLogout, CTSLogoutEvent
from pybotx.models.system_events.deleted_from_chat import (
Expand All @@ -34,6 +38,7 @@
BotAPISmartAppEvent,
BotAPIInternalBotNotification,
BotAPIChatCreated,
BotAPIChatDeletedByUser,
BotAPIAddedToChat,
BotAPIDeletedFromChat,
BotAPILeftFromChat,
Expand All @@ -48,6 +53,7 @@
SmartAppEvent,
InternalBotNotificationEvent,
ChatCreatedEvent,
ChatDeletedByUserEvent,
AddedToChatEvent,
DeletedFromChatEvent,
LeftFromChatEvent,
Expand Down
9 changes: 7 additions & 2 deletions pybotx/models/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class BotAPICommandTypes(StrEnum):
class BotAPISystemEventTypes(StrEnum):
ADDED_TO_CHAT = "system:added_to_chat"
CHAT_CREATED = "system:chat_created"
CHAT_DELETED_BY_USER = "system:chat_deleted_by_user"
CTS_LOGIN = "system:cts_login"
CTS_LOGOUT = "system:cts_logout"
DELETED_FROM_CHAT = "system:deleted_from_chat"
Expand Down Expand Up @@ -264,7 +265,9 @@ def convert_chat_type_from_domain(chat_type: ChatTypes) -> APIChatTypes:


@overload
def convert_chat_type_to_domain(chat_type: APIChatTypes) -> ChatTypes:
def convert_chat_type_to_domain(
chat_type: APIChatTypes,
) -> ChatTypes:
... # noqa: WPS428


Expand Down Expand Up @@ -302,7 +305,9 @@ def convert_sync_source_type_to_domain(


@overload
def convert_sync_source_type_to_domain(sync_type: str) -> UNSUPPORTED:
def convert_sync_source_type_to_domain(
sync_type: str,
) -> UNSUPPORTED:
... # noqa: WPS428


Expand Down
57 changes: 57 additions & 0 deletions pybotx/models/system_events/chat_deleted_by_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from dataclasses import dataclass
from typing import Any, Dict, Literal
from uuid import UUID

from pydantic import Field

from pybotx.models.api_base import VerifiedPayloadBaseModel
from pybotx.models.base_command import (
BaseBotAPIContext,
BotAPIBaseCommand,
BotAPIBaseSystemEventPayload,
BotCommandBase,
)
from pybotx.models.bot_account import BotAccount
from pybotx.models.enums import BotAPISystemEventTypes


@dataclass
class ChatDeletedByUserEvent(BotCommandBase):
"""Event `system:chat_deleted_by_user`.
Attributes:
sync_id: Event sync id.
chat_id: Deleted chat id.
huid: huid of the deleter.
"""

sync_id: UUID
chat_id: UUID
huid: UUID


class BotAPIChatDeletedByUserData(VerifiedPayloadBaseModel):
user_huid: UUID
group_chat_id: UUID


class BotAPIChatDeletedByUserPayload(BotAPIBaseSystemEventPayload):
body: Literal[BotAPISystemEventTypes.CHAT_DELETED_BY_USER]
data: BotAPIChatDeletedByUserData


class BotAPIChatDeletedByUser(BotAPIBaseCommand):
payload: BotAPIChatDeletedByUserPayload = Field(..., alias="command")
sender: BaseBotAPIContext = Field(..., alias="from")

def to_domain(self, raw_command: Dict[str, Any]) -> ChatDeletedByUserEvent:
return ChatDeletedByUserEvent(
sync_id=self.sync_id,
bot=BotAccount(
id=self.bot_id,
host=self.sender.host,
),
chat_id=self.payload.data.group_chat_id,
huid=self.payload.data.user_huid,
raw_command=raw_command,
)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ httpx = "^0.25.0"
httpcore = ">=1.0.0,<1.0.3"
loguru = ">=0.6.0,<0.7.0"
pydantic = ">=1.6.0,<1.11.0"
aiocsv = ">=1.2.3,<1.3.0"
aiocsv = ">=1.2.3,<1.4.0"
pyjwt = ">=2.0.0,<3.0.0"
mypy-extensions = ">=0.2.0,<0.5.0"

Expand Down
90 changes: 90 additions & 0 deletions tests/system_events/test_chat_deleted_by_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from typing import Optional
from uuid import UUID

import pytest

from pybotx import (
Bot,
BotAccount,
BotAccountWithSecret,
HandlerCollector,
lifespan_wrapper,
)
from pybotx.models.system_events.chat_deleted_by_user import ChatDeletedByUserEvent

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:chat_deleted_by_user",
"data": {
"group_chat_id": "6fa5f1e9-1453-0ad7-2d6d-b791467e382a",
"user_huid": "37b821f5-a2be-5dc1-b107-87807ce97e56",
},
"command_type": "system",
"metadata": {},
},
"async_files": [],
"attachments": [],
"entities": [],
"from": {
"user_huid": None,
"group_chat_id": "6fa5f1e9-1453-0ad7-2d6d-b791467e382a",
"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()
chat_deleted: Optional[ChatDeletedByUserEvent] = None

@collector.chat_deleted_by_user
async def chat_deleted_handler(event: ChatDeletedByUserEvent, bot: Bot) -> None:
nonlocal chat_deleted
chat_deleted = event
# Drop `raw_command` from asserting
chat_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 chat_deleted == ChatDeletedByUserEvent(
sync_id=UUID("a465f0f3-1354-491c-8f11-f400164295cb"),
bot=BotAccount(
id=UUID("24348246-6791-4ac0-9d86-b948cd6a0e46"),
host="cts.example.com",
),
chat_id=UUID("6fa5f1e9-1453-0ad7-2d6d-b791467e382a"),
huid=UUID("37b821f5-a2be-5dc1-b107-87807ce97e56"),
raw_command=None,
)

0 comments on commit aa6883e

Please sign in to comment.