Skip to content

Commit 8b7ebd6

Browse files
feat: Add method to create thread to Bot
* feat: Add method to create thread to Bot * fix: linter errors * fix: remove duplicate exception * fix: docstring format * add enum value for thread chat type * Add test cases, move duplicating code to fixture, fix name of test
1 parent 9219e2e commit 8b7ebd6

File tree

7 files changed

+376
-7
lines changed

7 files changed

+376
-7
lines changed

pybotx/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
ChatCreationError,
4040
ChatCreationProhibitedError,
4141
InvalidUsersListError,
42+
ThreadCreationError,
43+
ThreadCreationProhibitedError,
4244
)
4345
from pybotx.client.exceptions.common import (
4446
ChatNotFoundError,
@@ -260,6 +262,9 @@
260262
"SyncSmartAppEventHandlerFunc",
261263
"SyncSmartAppEventHandlerNotFoundError",
262264
"SyncSourceTypes",
265+
"ThreadCreationError",
266+
"ThreadCreationEventNotFoundError",
267+
"ThreadCreationProhibitedError",
263268
"UnknownBotAccountError",
264269
"UnknownSystemEventError",
265270
"UnsupportedBotAPIVersionError",

pybotx/bot/bot.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
from asyncio import Task
2+
from collections.abc import AsyncIterable, AsyncIterator, Iterator, Mapping, Sequence
23
from contextlib import asynccontextmanager
34
from datetime import datetime
45
from types import SimpleNamespace
56
from typing import (
67
Any,
7-
AsyncIterable,
8-
AsyncIterator,
98
Dict,
10-
Iterator,
119
List,
12-
Mapping,
1310
Optional,
14-
Sequence,
1511
Set,
1612
Tuple,
1713
Union,
@@ -57,6 +53,10 @@
5753
BotXAPICreateChatRequestPayload,
5854
CreateChatMethod,
5955
)
56+
from pybotx.client.chats_api.create_thread import (
57+
BotXAPICreateThreadRequestPayload,
58+
CreateThreadMethod,
59+
)
6060
from pybotx.client.chats_api.disable_stealth import (
6161
BotXAPIDisableStealthRequestPayload,
6262
DisableStealthMethod,
@@ -1176,6 +1176,27 @@ async def create_chat(
11761176

11771177
return botx_api_chat_id.to_domain()
11781178

1179+
async def create_thread(self, bot_id: UUID, sync_id: UUID) -> UUID:
1180+
"""
1181+
Create thread.
1182+
1183+
:param bot_id: Bot which should perform the request.
1184+
:param sync_id: Message for which thread should be created
1185+
1186+
:return: Created thread uuid.
1187+
"""
1188+
1189+
method = CreateThreadMethod(
1190+
bot_id,
1191+
self._httpx_client,
1192+
self._bot_accounts_storage,
1193+
)
1194+
1195+
payload = BotXAPICreateThreadRequestPayload.from_domain(sync_id=sync_id)
1196+
botx_api_thread_id = await method.execute(payload)
1197+
1198+
return botx_api_thread_id.to_domain()
1199+
11791200
async def pin_message(
11801201
self,
11811202
*,
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from typing import Literal
2+
from uuid import UUID
3+
4+
from pybotx.client.authorized_botx_method import AuthorizedBotXMethod
5+
from pybotx.client.botx_method import response_exception_thrower
6+
from pybotx.client.exceptions.chats import (
7+
ThreadCreationError,
8+
ThreadCreationProhibitedError,
9+
)
10+
from pybotx.client.exceptions.event import EventNotFoundError
11+
from pybotx.models.api_base import UnverifiedPayloadBaseModel, VerifiedPayloadBaseModel
12+
13+
14+
class BotXAPICreateThreadRequestPayload(UnverifiedPayloadBaseModel):
15+
sync_id: UUID
16+
17+
@classmethod
18+
def from_domain(cls, sync_id: UUID) -> "BotXAPICreateThreadRequestPayload":
19+
return cls(sync_id=sync_id)
20+
21+
22+
class BotXAPIThreadIdResult(VerifiedPayloadBaseModel):
23+
thread_id: UUID
24+
25+
26+
class BotXAPICreateThreadResponsePayload(VerifiedPayloadBaseModel):
27+
status: Literal["ok"]
28+
result: BotXAPIThreadIdResult
29+
30+
def to_domain(self) -> UUID:
31+
return self.result.thread_id
32+
33+
34+
class CreateThreadMethod(AuthorizedBotXMethod):
35+
status_handlers = {
36+
**AuthorizedBotXMethod.status_handlers,
37+
403: response_exception_thrower(ThreadCreationProhibitedError),
38+
404: response_exception_thrower(EventNotFoundError),
39+
422: response_exception_thrower(ThreadCreationError),
40+
}
41+
42+
async def execute(
43+
self,
44+
payload: BotXAPICreateThreadRequestPayload,
45+
) -> BotXAPICreateThreadResponsePayload:
46+
path = "/api/v3/botx/chats/create_thread"
47+
48+
response = await self._botx_method_call(
49+
"POST",
50+
self._build_url(path),
51+
json=payload.jsonable_dict(),
52+
)
53+
54+
return self._verify_and_extract_api_model(
55+
BotXAPICreateThreadResponsePayload,
56+
response,
57+
)

pybotx/client/exceptions/chats.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,24 @@ class ChatCreationProhibitedError(BaseClientError):
1515

1616
class ChatCreationError(BaseClientError):
1717
"""Error while chat creation."""
18+
19+
20+
class ThreadCreationError(BaseClientError):
21+
"""Error while thread creation (invalid scheme)."""
22+
23+
24+
class ThreadCreationProhibitedError(BaseClientError):
25+
"""
26+
Error while permission checks.
27+
28+
1. Bot has no permissions to create thread
29+
2. Threads are not allowed for that message
30+
3. Bot is not a chat member where message is located
31+
4. Message is located in personal chat
32+
5. Usupported event type
33+
6. Unsuppoerted chat type
34+
7. Thread is already created
35+
8. No access for message
36+
9. Message in stealth mode
37+
10. Message is deleted
38+
"""

pybotx/models/enums.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class ChatTypes(AutoName):
5959
PERSONAL_CHAT = auto()
6060
GROUP_CHAT = auto()
6161
CHANNEL = auto()
62+
THREAD = auto()
6263

6364

6465
class SyncSourceTypes(AutoName):
@@ -92,6 +93,7 @@ class APIChatTypes(Enum):
9293
CHAT = "chat"
9394
GROUP_CHAT = "group_chat"
9495
CHANNEL = "channel"
96+
THREAD = "thread"
9597

9698

9799
class BotAPICommandTypes(StrEnum):
@@ -295,6 +297,7 @@ def convert_chat_type_from_domain(chat_type: ChatTypes) -> APIChatTypes:
295297
ChatTypes.PERSONAL_CHAT: APIChatTypes.CHAT,
296298
ChatTypes.GROUP_CHAT: APIChatTypes.GROUP_CHAT,
297299
ChatTypes.CHANNEL: APIChatTypes.CHANNEL,
300+
ChatTypes.THREAD: APIChatTypes.THREAD,
298301
}
299302

300303
converted_type = chat_types_mapping.get(chat_type)
@@ -323,6 +326,7 @@ def convert_chat_type_to_domain(
323326
APIChatTypes.CHAT: ChatTypes.PERSONAL_CHAT,
324327
APIChatTypes.GROUP_CHAT: ChatTypes.GROUP_CHAT,
325328
APIChatTypes.CHANNEL: ChatTypes.CHANNEL,
329+
APIChatTypes.THREAD: ChatTypes.THREAD,
326330
}
327331

328332
converted_type: Optional[IncomingChatTypes]

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
[tool.poetry]
22
name = "pybotx"
3-
version = "0.75.1"
3+
version = "0.75.2"
44
description = "A python library for interacting with eXpress BotX API"
55
authors = [
66
"Sidnev Nikolay <[email protected]>",
77
"Maxim Gorbachev <[email protected]>",
88
"Alexander Samoylenko <[email protected]>",
9-
"Arseniy Zhiltsov <[email protected]>"
9+
"Arseniy Zhiltsov <[email protected]>",
1010
]
1111
readme = "README.md"
1212
repository = "https://github.com/ExpressApp/pybotx"

0 commit comments

Comments
 (0)