Skip to content

Commit

Permalink
feat: delete message method (#406)
Browse files Browse the repository at this point in the history
  • Loading branch information
vadikball committed Jul 27, 2023
1 parent 468ec08 commit 2eb8f16
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 1 deletion.
2 changes: 2 additions & 0 deletions pybotx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
InvalidBotXResponsePayloadError,
InvalidBotXStatusCodeError,
)
from pybotx.client.exceptions.message import MessageNotFoundError
from pybotx.client.exceptions.notifications import (
BotIsNotChatMemberError,
FinalRecipientsListEmptyError,
Expand Down Expand Up @@ -185,6 +186,7 @@
"MentionList",
"MentionTypes",
"MentionUser",
"MessageNotFoundError",
"MessageStatus",
"Middleware",
"OutgoingAttachment",
Expand Down
28 changes: 28 additions & 0 deletions pybotx/bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
BotXAPIUnpinMessageRequestPayload,
UnpinMessageMethod,
)
from pybotx.client.events_api.delete_event import (
BotXAPIDeleteEventRequestPayload,
DeleteEventMethod,
)
from pybotx.client.events_api.edit_event import (
BotXAPIEditEventRequestPayload,
EditEventMethod,
Expand Down Expand Up @@ -807,6 +811,30 @@ async def stop_typing(
)
await method.execute(payload)

async def delete_message(
self,
*,
bot_id: UUID,
sync_id: UUID,
) -> None:
"""Delete message.
:param bot_id: Bot which should perform the request.
:param sync_id: Target sync_id.
"""

payload = BotXAPIDeleteEventRequestPayload.from_domain(
sync_id=sync_id,
)

method = DeleteEventMethod(
bot_id,
self._httpx_client,
self._bot_accounts_storage,
)

await method.execute(payload)

# - Chats API -
async def list_chats(
self,
Expand Down
47 changes: 47 additions & 0 deletions pybotx/client/events_api/delete_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from typing import Literal
from uuid import UUID

from pybotx.client.authorized_botx_method import AuthorizedBotXMethod
from pybotx.client.botx_method import response_exception_thrower
from pybotx.client.exceptions.message import MessageNotFoundError
from pybotx.models.api_base import UnverifiedPayloadBaseModel, VerifiedPayloadBaseModel


class BotXAPIDeleteEventRequestPayload(UnverifiedPayloadBaseModel):
sync_id: UUID

@classmethod
def from_domain(
cls,
sync_id: UUID,
) -> "BotXAPIDeleteEventRequestPayload":
return cls(sync_id=sync_id)


class BotXAPIDeleteEventResponsePayload(VerifiedPayloadBaseModel):
status: Literal["ok"]
result: str


class DeleteEventMethod(AuthorizedBotXMethod):
status_handlers = {
**AuthorizedBotXMethod.status_handlers,
404: response_exception_thrower(MessageNotFoundError),
}

async def execute(
self,
payload: BotXAPIDeleteEventRequestPayload,
) -> BotXAPIDeleteEventResponsePayload:
path = "/api/v3/botx/events/delete_event"

response = await self._botx_method_call(
"POST",
self._build_url(path),
json=payload.jsonable_dict(),
)

return self._verify_and_extract_api_model(
BotXAPIDeleteEventResponsePayload,
response,
)
5 changes: 5 additions & 0 deletions pybotx/client/exceptions/message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from pybotx.client.exceptions.base import BaseClientError


class MessageNotFoundError(BaseClientError):
"""Message not found."""
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.56.0"
version = "0.57.0"
description = "A python library for interacting with eXpress BotX API"
authors = [
"Sidnev Nikolay <[email protected]>",
Expand Down
96 changes: 96 additions & 0 deletions tests/client/events_api/test_delete_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from http import HTTPStatus
from uuid import UUID

import httpx
import pytest
from respx.router import MockRouter

from pybotx import (
Bot,
BotAccountWithSecret,
HandlerCollector,
MessageNotFoundError,
lifespan_wrapper,
)

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


async def test__delete_message__succeed(
respx_mock: MockRouter,
host: str,
bot_id: UUID,
bot_account: BotAccountWithSecret,
) -> None:
# - Arrange -
endpoint = respx_mock.post(
f"https://{host}/api/v3/botx/events/delete_event",
headers={"Authorization": "Bearer token", "Content-Type": "application/json"},
json={
"sync_id": "8ba66c5b-40bf-5c77-911d-519cb4e382e9",
},
).mock(
return_value=httpx.Response(
HTTPStatus.ACCEPTED,
json={
"status": "ok",
"result": "event_deleted",
},
),
)

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

# - Act -
async with lifespan_wrapper(built_bot) as bot:
await bot.delete_message(
bot_id=bot_id,
sync_id=UUID("8ba66c5b-40bf-5c77-911d-519cb4e382e9"),
)

# - Assert -
assert endpoint.called


async def test__delete_message__message_not_found_error_raised(
respx_mock: MockRouter,
host: str,
bot_id: UUID,
bot_account: BotAccountWithSecret,
) -> None:
# - Arrange -
endpoint = respx_mock.post(
f"https://{host}/api/v3/botx/events/delete_event",
headers={"Authorization": "Bearer token", "Content-Type": "application/json"},
json={
"sync_id": "fe1f285c-073e-4231-b190-2959f28168cc",
},
).mock(
return_value=httpx.Response(
HTTPStatus.NOT_FOUND,
json={
"status": "error",
"reason": "sync_id_not_found",
"errors": [],
"error_data": {},
},
),
)

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

# - Act -
async with lifespan_wrapper(built_bot) as bot:
with pytest.raises(MessageNotFoundError) as exc:
await bot.delete_message(
bot_id=bot_id,
sync_id=UUID("fe1f285c-073e-4231-b190-2959f28168cc"),
)

# - Assert -
assert "sync_id_not_found" in str(exc.value)
assert endpoint.called

0 comments on commit 2eb8f16

Please sign in to comment.