maxbot-api-client-python 1.1.2__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- maxbot_api_client_python/__init__.py +2 -1
- maxbot_api_client_python/api.py +2 -1
- maxbot_api_client_python/client.py +80 -82
- maxbot_api_client_python/exceptions.py +1 -1
- maxbot_api_client_python/tools/bots.py +19 -15
- maxbot_api_client_python/tools/chats.py +168 -134
- maxbot_api_client_python/tools/helpers.py +87 -62
- maxbot_api_client_python/tools/messages.py +83 -67
- maxbot_api_client_python/tools/subscriptions.py +44 -36
- maxbot_api_client_python/tools/uploads.py +41 -15
- maxbot_api_client_python/types/constants.py +1 -1
- maxbot_api_client_python/types/models.py +82 -65
- maxbot_api_client_python/utils.py +3 -1
- {maxbot_api_client_python-1.1.2.dist-info → maxbot_api_client_python-2.0.0.dist-info}/METADATA +35 -46
- maxbot_api_client_python-2.0.0.dist-info/RECORD +20 -0
- maxbot_api_client_python-1.1.2.dist-info/RECORD +0 -20
- {maxbot_api_client_python-1.1.2.dist-info → maxbot_api_client_python-2.0.0.dist-info}/WHEEL +0 -0
- {maxbot_api_client_python-1.1.2.dist-info → maxbot_api_client_python-2.0.0.dist-info}/licenses/LICENSE +0 -0
- {maxbot_api_client_python-1.1.2.dist-info → maxbot_api_client_python-2.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,101 +1,109 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from maxbot_api_client_python.client import Client
|
|
2
4
|
from maxbot_api_client_python.types.constants import Paths
|
|
3
|
-
from maxbot_api_client_python.types import
|
|
5
|
+
from maxbot_api_client_python.types.models import GetSubscriptionsResp, GetUpdatesReq, GetUpdatesResp, SimpleQueryResult, SubscribeReq, UnsubscribeReq
|
|
4
6
|
|
|
5
7
|
class Subscriptions:
|
|
6
8
|
def __init__(self, client: Client):
|
|
7
9
|
self.client = client
|
|
8
10
|
|
|
9
|
-
def
|
|
11
|
+
def get_subscriptions(self) -> GetSubscriptionsResp:
|
|
10
12
|
"""
|
|
11
13
|
Returns a list of all subscriptions if your bot receives data via a Webhook.
|
|
12
14
|
|
|
13
15
|
Example:
|
|
14
|
-
response =
|
|
16
|
+
response = bot.subscriptions.get_subscriptions()
|
|
15
17
|
"""
|
|
16
|
-
return
|
|
18
|
+
return self.client.decode("GET", Paths.SUBSCRIPTIONS, GetSubscriptionsResp)
|
|
17
19
|
|
|
18
|
-
def
|
|
20
|
+
def subscribe(self, **kwargs: Any) -> SimpleQueryResult:
|
|
19
21
|
"""
|
|
20
22
|
Configures the delivery of bot events via Webhook.
|
|
21
23
|
|
|
22
24
|
Example:
|
|
23
|
-
response =
|
|
25
|
+
response = bot.subscriptions.subscribe(
|
|
24
26
|
url="https://webhook.site/endpoint"
|
|
25
27
|
)
|
|
26
28
|
"""
|
|
27
|
-
req =
|
|
28
|
-
|
|
29
|
+
req = SubscribeReq(**kwargs)
|
|
30
|
+
query, payload = self.client.split_request(req)
|
|
31
|
+
return self.client.decode("POST", Paths.SUBSCRIPTIONS, SimpleQueryResult, query=query, payload=payload)
|
|
29
32
|
|
|
30
|
-
def
|
|
33
|
+
def unsubscribe(self, **kwargs: Any) -> SimpleQueryResult:
|
|
31
34
|
"""
|
|
32
35
|
Unsubscribes the bot from receiving updates via Webhook.
|
|
33
36
|
|
|
34
37
|
Example:
|
|
35
|
-
response =
|
|
38
|
+
response = bot.subscriptions.unsubscribe(
|
|
36
39
|
url="https://webhook.site/endpoint"
|
|
37
40
|
)
|
|
38
41
|
"""
|
|
39
|
-
req =
|
|
40
|
-
|
|
42
|
+
req = UnsubscribeReq(**kwargs)
|
|
43
|
+
query, payload = self.client.split_request(req)
|
|
44
|
+
return self.client.decode("DELETE", Paths.SUBSCRIPTIONS, SimpleQueryResult, query=query, payload=payload)
|
|
41
45
|
|
|
42
|
-
def
|
|
46
|
+
def get_updates(self, **kwargs: Any) -> GetUpdatesResp:
|
|
43
47
|
"""
|
|
44
48
|
Fetches new events (incoming messages, bot additions, etc.) from the server.
|
|
45
49
|
Use this method for long-polling. Provide a Marker to acknowledge previous
|
|
46
50
|
updates and fetch only new ones.
|
|
47
51
|
|
|
48
52
|
Example:
|
|
49
|
-
response =
|
|
53
|
+
response = bot.subscriptions.get_updates(
|
|
50
54
|
marker=123456789,
|
|
51
55
|
timeout=30 # seconds to wait for new updates
|
|
52
56
|
)
|
|
53
57
|
"""
|
|
54
|
-
req =
|
|
55
|
-
|
|
58
|
+
req = GetUpdatesReq(**kwargs)
|
|
59
|
+
query, payload = self.client.split_request(req)
|
|
60
|
+
return self.client.decode("GET", Paths.UPDATES, GetUpdatesResp, query=query, payload=payload)
|
|
56
61
|
|
|
57
|
-
async def
|
|
62
|
+
async def get_subscriptions_async(self) -> GetSubscriptionsResp:
|
|
58
63
|
"""
|
|
59
|
-
Async version of
|
|
64
|
+
Async version of get_subscriptions.
|
|
60
65
|
|
|
61
66
|
Example:
|
|
62
|
-
response = await
|
|
67
|
+
response = await bot.subscriptions.get_subscriptions_async()
|
|
63
68
|
"""
|
|
64
|
-
return await
|
|
69
|
+
return await self.client.adecode("GET", Paths.SUBSCRIPTIONS, GetSubscriptionsResp)
|
|
65
70
|
|
|
66
|
-
async def
|
|
71
|
+
async def subscribe_async(self, **kwargs: Any) -> SimpleQueryResult:
|
|
67
72
|
"""
|
|
68
|
-
Async version of
|
|
73
|
+
Async version of subscribe.
|
|
69
74
|
|
|
70
75
|
Example:
|
|
71
|
-
response = await
|
|
76
|
+
response = await bot.subscriptions.subscribe_async(
|
|
72
77
|
url="https://webhook.site/endpoint"
|
|
73
78
|
)
|
|
74
79
|
"""
|
|
75
|
-
req =
|
|
76
|
-
|
|
80
|
+
req = SubscribeReq(**kwargs)
|
|
81
|
+
query, payload = self.client.split_request(req)
|
|
82
|
+
return await self.client.adecode("POST", Paths.SUBSCRIPTIONS, SimpleQueryResult, query=query, payload=payload)
|
|
77
83
|
|
|
78
|
-
async def
|
|
84
|
+
async def unsubscribe_async(self, **kwargs: Any) -> SimpleQueryResult:
|
|
79
85
|
"""
|
|
80
|
-
Async version of
|
|
86
|
+
Async version of unsubscribe.
|
|
81
87
|
|
|
82
88
|
Example:
|
|
83
|
-
response = await
|
|
89
|
+
response = await bot.subscriptions.unsubscribe_async(
|
|
84
90
|
url="https://webhook.site/endpoint"
|
|
85
91
|
)
|
|
86
92
|
"""
|
|
87
|
-
req =
|
|
88
|
-
|
|
93
|
+
req = UnsubscribeReq(**kwargs)
|
|
94
|
+
query, payload = self.client.split_request(req)
|
|
95
|
+
return await self.client.adecode("DELETE", Paths.SUBSCRIPTIONS, SimpleQueryResult, query=query, payload=payload)
|
|
89
96
|
|
|
90
|
-
async def
|
|
97
|
+
async def get_updates_async(self, **kwargs: Any) -> GetUpdatesResp:
|
|
91
98
|
"""
|
|
92
|
-
Async version of
|
|
99
|
+
Async version of get_updates.
|
|
93
100
|
|
|
94
101
|
Example:
|
|
95
|
-
response = await
|
|
102
|
+
response = await bot.subscriptions.get_updates_async(
|
|
96
103
|
marker=123456789,
|
|
97
104
|
timeout=30 # seconds to wait for new updates
|
|
98
105
|
)
|
|
99
106
|
"""
|
|
100
|
-
req =
|
|
101
|
-
|
|
107
|
+
req = GetUpdatesReq(**kwargs)
|
|
108
|
+
query, payload = self.client.split_request(req)
|
|
109
|
+
return await self.client.adecode("GET", Paths.UPDATES, GetUpdatesResp, query=query, payload=payload)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import asyncio, logging
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Optional
|
|
5
|
-
from tenacity import retry, stop_after_attempt, wait_exponential
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
from tenacity import AsyncRetrying, retry, stop_after_attempt, wait_exponential
|
|
6
6
|
|
|
7
|
-
from maxbot_api_client_python.client import Client
|
|
7
|
+
from maxbot_api_client_python.client import Client
|
|
8
8
|
from maxbot_api_client_python.types.constants import Paths, UploadType
|
|
9
9
|
from maxbot_api_client_python.types.models import UploadedInfo, UploadFileReq, PhotoAttachmentRequestPayload
|
|
10
10
|
|
|
@@ -20,13 +20,13 @@ class Uploads:
|
|
|
20
20
|
reraise=True,
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
-
def
|
|
23
|
+
def upload_file(self, **kwargs: Any) -> UploadedInfo:
|
|
24
24
|
"""
|
|
25
25
|
Uploads a file to the server and returns the upload metadata.
|
|
26
26
|
It seamlessly handles both STEP 1 (obtaining the URL) and STEP 2 (streaming the file).
|
|
27
27
|
|
|
28
28
|
Example:
|
|
29
|
-
response =
|
|
29
|
+
response = bot.uploads.upload_file(
|
|
30
30
|
type=UploadType.IMAGE,
|
|
31
31
|
file_path="/path/to/image.png"
|
|
32
32
|
)
|
|
@@ -57,35 +57,61 @@ class Uploads:
|
|
|
57
57
|
|
|
58
58
|
def get_upload_url(self, upload_type: UploadType) -> PhotoAttachmentRequestPayload:
|
|
59
59
|
"""Internal helper: Obtains the target URL for uploading."""
|
|
60
|
-
return
|
|
60
|
+
return self.client.decode("POST", Paths.UPLOADS, PhotoAttachmentRequestPayload, query={"type": upload_type.value})
|
|
61
61
|
|
|
62
62
|
def upload_multipart(self, upload_url: str, file_path: str) -> Optional[UploadedInfo]:
|
|
63
63
|
"""Internal helper: Streams the file to the obtained URL."""
|
|
64
64
|
path = Path(file_path)
|
|
65
65
|
try:
|
|
66
66
|
with open(path, "rb") as f:
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
safe_name = path.name[:255]
|
|
68
|
+
files = {"file": (safe_name, f)}
|
|
69
|
+
return self.client.decode("POST", upload_url, UploadedInfo, files=files)
|
|
69
70
|
except OSError as e:
|
|
70
71
|
logger.error(f"Failed to read file for upload: {e}")
|
|
71
72
|
return None
|
|
72
73
|
|
|
73
|
-
async def
|
|
74
|
+
async def upload_file_async(self, **kwargs: Any) -> UploadedInfo:
|
|
74
75
|
"""
|
|
75
|
-
Async version of
|
|
76
|
+
Async version of upload_file.
|
|
76
77
|
|
|
77
78
|
Example:
|
|
78
|
-
response = await
|
|
79
|
+
response = await bot.uploads.upload_file_async(
|
|
79
80
|
type=UploadType.IMAGE,
|
|
80
81
|
file_path="/path/to/image.png"
|
|
81
82
|
)
|
|
82
83
|
"""
|
|
83
|
-
|
|
84
|
+
req = UploadFileReq(**kwargs)
|
|
85
|
+
async for attempt in AsyncRetrying(
|
|
86
|
+
stop=stop_after_attempt(3),
|
|
87
|
+
wait=wait_exponential(multiplier=1, min=2, max=10),
|
|
88
|
+
reraise=True
|
|
89
|
+
):
|
|
90
|
+
with attempt:
|
|
91
|
+
init_resp = await self.get_upload_url_async(req.type)
|
|
92
|
+
if init_resp.url:
|
|
93
|
+
if not req.file_path:
|
|
94
|
+
raise ValueError("file_path must be provided for multipart uploads.")
|
|
95
|
+
|
|
96
|
+
multipart_resp = await self.upload_multipart_async(init_resp.url, req.file_path)
|
|
97
|
+
|
|
98
|
+
if multipart_resp:
|
|
99
|
+
if multipart_resp.token:
|
|
100
|
+
return multipart_resp
|
|
101
|
+
|
|
102
|
+
if multipart_resp.photos:
|
|
103
|
+
first_photo = next(iter(multipart_resp.photos.values()), None)
|
|
104
|
+
if first_photo and first_photo.token:
|
|
105
|
+
multipart_resp.token = first_photo.token
|
|
106
|
+
return multipart_resp
|
|
107
|
+
|
|
108
|
+
if init_resp.token:
|
|
109
|
+
return UploadedInfo(token=init_resp.token)
|
|
110
|
+
|
|
111
|
+
raise Exception("Server did not return token after upload")
|
|
84
112
|
|
|
85
113
|
async def get_upload_url_async(self, upload_type: UploadType) -> PhotoAttachmentRequestPayload:
|
|
86
|
-
""
|
|
87
|
-
return await asyncio.to_thread(self.get_upload_url, upload_type)
|
|
114
|
+
return await self.client.adecode("POST", Paths.UPLOADS, PhotoAttachmentRequestPayload, query={"type": upload_type.value})
|
|
88
115
|
|
|
89
116
|
async def upload_multipart_async(self, upload_url: str, file_path: str) -> Optional[UploadedInfo]:
|
|
90
|
-
"""Async version of upload_multipart."""
|
|
91
117
|
return await asyncio.to_thread(self.upload_multipart, upload_url, file_path)
|
|
@@ -87,7 +87,7 @@ class SenderAction(str, Enum):
|
|
|
87
87
|
|
|
88
88
|
class ChatAdminPermission(str, Enum):
|
|
89
89
|
READ_ALL_MESSAGES = "read_all_messages"
|
|
90
|
-
|
|
90
|
+
ADD_REMOVE_MEMBERS = "add_remove_members"
|
|
91
91
|
ADD_ADMINS = "add_admins"
|
|
92
92
|
CHANGE_CHAT_PHOTO = "change_chat_info"
|
|
93
93
|
PIN_MESSAGE = "pin_message"
|
|
@@ -6,6 +6,14 @@ from maxbot_api_client_python.types.constants import (
|
|
|
6
6
|
LinkedMessageType, SenderAction, ChatAdminPermission, ButtonType, UploadType
|
|
7
7
|
)
|
|
8
8
|
|
|
9
|
+
class Config(BaseModel):
|
|
10
|
+
base_url: str
|
|
11
|
+
token: str
|
|
12
|
+
timeout: int = 35
|
|
13
|
+
ratelimiter: int = 25
|
|
14
|
+
max_retries: int = 3
|
|
15
|
+
retry_delay_sec: int = 3
|
|
16
|
+
|
|
9
17
|
class MaxBotModel(BaseModel):
|
|
10
18
|
model_config = ConfigDict(populate_by_name=True, arbitrary_types_allowed=True)
|
|
11
19
|
|
|
@@ -14,10 +22,9 @@ class APIError(MaxBotModel):
|
|
|
14
22
|
message: str
|
|
15
23
|
|
|
16
24
|
class SimpleQueryResult(MaxBotModel):
|
|
17
|
-
success: bool = Field(
|
|
25
|
+
success: bool = Field(True, alias="success")
|
|
18
26
|
message: str | None = Field(None, alias="message")
|
|
19
27
|
|
|
20
|
-
|
|
21
28
|
class User(MaxBotModel):
|
|
22
29
|
user_id: int
|
|
23
30
|
first_name: str
|
|
@@ -59,7 +66,6 @@ class Recipient(MaxBotModel):
|
|
|
59
66
|
chat_type: ChatType
|
|
60
67
|
user_id: int | None = None
|
|
61
68
|
|
|
62
|
-
|
|
63
69
|
class Image(MaxBotModel):
|
|
64
70
|
url: str
|
|
65
71
|
|
|
@@ -76,7 +82,6 @@ class StickerData(MaxBotModel):
|
|
|
76
82
|
url: str | None = None
|
|
77
83
|
code: str | None = None
|
|
78
84
|
|
|
79
|
-
|
|
80
85
|
class MediaPayload(MaxBotModel):
|
|
81
86
|
url: str | None = None
|
|
82
87
|
token: str | None = None
|
|
@@ -142,7 +147,6 @@ class Attachment(MaxBotModel):
|
|
|
142
147
|
latitude: float | None = None
|
|
143
148
|
longitude: float | None = None
|
|
144
149
|
|
|
145
|
-
|
|
146
150
|
class BotPatch(MaxBotModel):
|
|
147
151
|
name: str | None = None
|
|
148
152
|
username: str | None = None
|
|
@@ -150,7 +154,6 @@ class BotPatch(MaxBotModel):
|
|
|
150
154
|
commands: list[BotCommand] | None = None
|
|
151
155
|
photo: PhotoAttachmentRequestPayload | None = None
|
|
152
156
|
|
|
153
|
-
|
|
154
157
|
class MarkupElement(MaxBotModel):
|
|
155
158
|
type: MarkupType
|
|
156
159
|
from_: int = Field(alias="from")
|
|
@@ -195,7 +198,6 @@ class Message(MaxBotModel):
|
|
|
195
198
|
class MessagesList(MaxBotModel):
|
|
196
199
|
messages: list[Message]
|
|
197
200
|
|
|
198
|
-
|
|
199
201
|
class Chat(MaxBotModel):
|
|
200
202
|
chat_id: int
|
|
201
203
|
type: ChatType
|
|
@@ -226,10 +228,9 @@ class ChatInfo(MaxBotModel):
|
|
|
226
228
|
is_public: bool
|
|
227
229
|
link: str | None = None
|
|
228
230
|
description: str | None = None
|
|
229
|
-
dialog_with_user:
|
|
231
|
+
dialog_with_user: DialogWithUser | None = None
|
|
230
232
|
chat_message_id: str | None = None
|
|
231
|
-
pinned_message:
|
|
232
|
-
|
|
233
|
+
pinned_message: Message | None = None
|
|
233
234
|
|
|
234
235
|
class Callback(MaxBotModel):
|
|
235
236
|
timestamp: int
|
|
@@ -258,73 +259,89 @@ class Subscription(MaxBotModel):
|
|
|
258
259
|
time: int
|
|
259
260
|
update_types: list[UpdateType] | None = None
|
|
260
261
|
|
|
261
|
-
|
|
262
262
|
class GetChatsReq(MaxBotModel):
|
|
263
|
-
count: int | None = Field(None, alias="count")
|
|
264
|
-
marker: int | None = Field(None, alias="marker")
|
|
263
|
+
count: int | None = Field(None, alias="count", json_schema_extra={"in_query": True})
|
|
264
|
+
marker: int | None = Field(None, alias="marker", json_schema_extra={"in_query": True})
|
|
265
265
|
|
|
266
266
|
class GetChatsResp(MaxBotModel):
|
|
267
267
|
chats: list[Chat]
|
|
268
268
|
marker: int | None = None
|
|
269
269
|
|
|
270
270
|
class GetChatReq(MaxBotModel):
|
|
271
|
-
|
|
271
|
+
# API Path: GET /chats/{chatId}
|
|
272
|
+
# Path parameters strictly use camelCase.
|
|
273
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
272
274
|
|
|
273
275
|
class EditChatReq(MaxBotModel):
|
|
274
|
-
|
|
276
|
+
# API Path: PATCH /chats/{chatId}
|
|
277
|
+
# Path parameters strictly use camelCase.
|
|
278
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
275
279
|
icon: Image | None = None
|
|
276
280
|
title: str | None = None
|
|
277
281
|
pin: str | None = None
|
|
278
282
|
notify: bool | None = None
|
|
279
283
|
|
|
280
284
|
class DeleteChatReq(MaxBotModel):
|
|
281
|
-
|
|
285
|
+
# API Path: DELETE /chats/{chatId}
|
|
286
|
+
# Path parameters strictly use camelCase.
|
|
287
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
282
288
|
|
|
283
289
|
class SendActionReq(MaxBotModel):
|
|
284
|
-
|
|
290
|
+
# API Path: POST /chats/{chatId}/actions
|
|
291
|
+
# Path parameters strictly use camelCase.
|
|
292
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
285
293
|
action: SenderAction
|
|
286
294
|
|
|
287
295
|
class PinMessageReq(MaxBotModel):
|
|
288
|
-
chat_id: int = Field(..., alias="chatId")
|
|
296
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
289
297
|
message_id: str
|
|
290
298
|
notify: bool | None = None
|
|
291
299
|
|
|
292
300
|
class UnpinMessageReq(MaxBotModel):
|
|
293
|
-
chat_id: int = Field(..., alias="chatId")
|
|
301
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
294
302
|
|
|
295
303
|
class GetPinnedMessageReq(MaxBotModel):
|
|
296
|
-
chat_id: int = Field(..., alias="chatId")
|
|
304
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
297
305
|
|
|
298
306
|
class GetChatMembershipReq(MaxBotModel):
|
|
299
|
-
chat_id: int = Field(..., alias="chatId")
|
|
307
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
300
308
|
|
|
301
309
|
class LeaveChatReq(MaxBotModel):
|
|
302
|
-
chat_id: int = Field(..., alias="chatId")
|
|
310
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
303
311
|
|
|
304
312
|
class GetChatAdminsReq(MaxBotModel):
|
|
305
|
-
chat_id: int = Field(..., alias="chatId")
|
|
313
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
306
314
|
|
|
307
315
|
class GetChatAdminsResp(MaxBotModel):
|
|
308
316
|
members: list[ChatMember]
|
|
309
317
|
marker: int | None = None
|
|
310
318
|
|
|
319
|
+
class GetChatMembersResp(MaxBotModel):
|
|
320
|
+
members: list[ChatMember]
|
|
321
|
+
marker: int | None = None
|
|
322
|
+
|
|
311
323
|
class SetChatAdminsReq(MaxBotModel):
|
|
312
|
-
chat_id: int = Field(..., alias="chatId")
|
|
324
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
313
325
|
admins: list[ChatAdmin]
|
|
314
326
|
marker: int | None = None
|
|
315
327
|
|
|
316
328
|
class DeleteAdminReq(MaxBotModel):
|
|
317
|
-
|
|
318
|
-
|
|
329
|
+
# API Path: DELETE /chats/{chatId}/members/admins/{userId}
|
|
330
|
+
# Both path parameters require camelCase according to the API specification.
|
|
331
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
332
|
+
user_id: int = Field(..., alias="userId", json_schema_extra={"in_path": True})
|
|
319
333
|
|
|
320
334
|
class GetChatMembersReq(MaxBotModel):
|
|
321
|
-
chat_id: int = Field(..., alias="chatId")
|
|
322
|
-
user_ids: list[int] | None = Field(None, alias="user_ids")
|
|
323
|
-
marker: int | None = Field(None, alias="marker")
|
|
324
|
-
count: int | None = Field(None, alias="count")
|
|
335
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
336
|
+
user_ids: list[int] | None = Field(None, alias="user_ids", json_schema_extra={"in_query": True})
|
|
337
|
+
marker: int | None = Field(None, alias="marker", json_schema_extra={"in_query": True})
|
|
338
|
+
count: int | None = Field(None, alias="count", json_schema_extra={"in_query": True})
|
|
325
339
|
|
|
326
340
|
class AddMembersReq(MaxBotModel):
|
|
327
|
-
|
|
341
|
+
# API Path: POST /chats/{chatId}/members
|
|
342
|
+
# Path uses camelCase ('chatId').
|
|
343
|
+
# Payload array must be strictly serialized as 'user_ids' (snake_case).
|
|
344
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
328
345
|
user_ids: list[int] | None = None
|
|
329
346
|
|
|
330
347
|
class FailedUserDetails(MaxBotModel):
|
|
@@ -336,33 +353,28 @@ class AddMembersResp(SimpleQueryResult):
|
|
|
336
353
|
failed_user_details: list[FailedUserDetails] | None = Field(None, alias="failed_user_details")
|
|
337
354
|
|
|
338
355
|
class DeleteMemberReq(MaxBotModel):
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
chat_id: int | None = Field(None, alias="chat_id")
|
|
346
|
-
message_ids: list[str] | None = Field(None, alias="message_ids")
|
|
347
|
-
from_: int | None = Field(None, alias="from")
|
|
348
|
-
to: int | None = Field(None, alias="to")
|
|
349
|
-
count: int | None = Field(None, alias="count")
|
|
356
|
+
# API Path: DELETE /chats/{chatId}/members?user_id={user_id}&block=true
|
|
357
|
+
# Mixed conventions: Path parameter is camelCase ('chatId'),
|
|
358
|
+
# but query parameters use snake_case ('user_id').
|
|
359
|
+
chat_id: int = Field(..., alias="chatId", json_schema_extra={"in_path": True})
|
|
360
|
+
user_id: int = Field(..., alias="user_id", json_schema_extra={"in_query": True})
|
|
361
|
+
block: bool | None = Field(None, alias="block", json_schema_extra={"in_query": True})
|
|
350
362
|
|
|
351
363
|
class SendMessageReq(MaxBotModel):
|
|
352
|
-
user_id: int | None = Field(None, alias="user_id")
|
|
353
|
-
chat_id: int | None = Field(None, alias="chat_id")
|
|
364
|
+
user_id: int | None = Field(None, alias="user_id", json_schema_extra={"in_query": True})
|
|
365
|
+
chat_id: int | None = Field(None, alias="chat_id", json_schema_extra={"in_query": True})
|
|
354
366
|
text: str | None = None
|
|
355
367
|
format: Format | None = None
|
|
356
368
|
notify: bool | None = None
|
|
357
369
|
attachments: list[Attachment] | None = None
|
|
358
370
|
link: NewMessageLink | None = None
|
|
359
|
-
disable_link_preview: bool | None = Field(None, alias="disable_link_preview")
|
|
371
|
+
disable_link_preview: bool | None = Field(None, alias="disable_link_preview", json_schema_extra={"in_query": True})
|
|
360
372
|
|
|
361
373
|
class SendMessageResp(MaxBotModel):
|
|
362
374
|
message: Message
|
|
363
375
|
|
|
364
376
|
class EditMessageReq(MaxBotModel):
|
|
365
|
-
message_id: str = Field(..., alias="message_id")
|
|
377
|
+
message_id: str = Field(..., alias="message_id", json_schema_extra={"in_query": True})
|
|
366
378
|
text: str | None = None
|
|
367
379
|
attachments: list[Attachment] | None = None
|
|
368
380
|
link: NewMessageLink | None = None
|
|
@@ -370,10 +382,17 @@ class EditMessageReq(MaxBotModel):
|
|
|
370
382
|
format: Format | None = None
|
|
371
383
|
|
|
372
384
|
class DeleteMessageReq(MaxBotModel):
|
|
373
|
-
message_id: str = Field(..., alias="message_id")
|
|
385
|
+
message_id: str = Field(..., alias="message_id", json_schema_extra={"in_query": True})
|
|
374
386
|
|
|
375
387
|
class GetMessageReq(MaxBotModel):
|
|
376
|
-
message_id: str = Field(..., alias="message_id")
|
|
388
|
+
message_id: str = Field(..., alias="message_id", json_schema_extra={"in_path": True})
|
|
389
|
+
|
|
390
|
+
class GetMessagesReq(MaxBotModel):
|
|
391
|
+
chat_id: int | None = Field(None, alias="chat_id", json_schema_extra={"in_query": True})
|
|
392
|
+
message_ids: list[str] | None = Field(None, alias="message_ids", json_schema_extra={"in_query": True})
|
|
393
|
+
from_: int | None = Field(None, alias="from", json_schema_extra={"in_query": True})
|
|
394
|
+
to: int | None = Field(None, alias="to", json_schema_extra={"in_query": True})
|
|
395
|
+
count: int | None = Field(None, alias="count", json_schema_extra={"in_query": True})
|
|
377
396
|
|
|
378
397
|
class VideoUrls(MaxBotModel):
|
|
379
398
|
mp4_1080: str | None = None
|
|
@@ -391,7 +410,7 @@ class VideoInfo(MaxBotModel):
|
|
|
391
410
|
url: str
|
|
392
411
|
|
|
393
412
|
class GetVideoInfoReq(MaxBotModel):
|
|
394
|
-
video_token: str = Field(..., alias="video_token")
|
|
413
|
+
video_token: str = Field(..., alias="video_token", json_schema_extra={"in_path": True})
|
|
395
414
|
|
|
396
415
|
class GetVideoInfoResp(MaxBotModel):
|
|
397
416
|
token: str
|
|
@@ -402,22 +421,21 @@ class GetVideoInfoResp(MaxBotModel):
|
|
|
402
421
|
duration: int | None = None
|
|
403
422
|
|
|
404
423
|
class AnswerCallbackReq(MaxBotModel):
|
|
405
|
-
callback_id: str = Field(..., alias="callback_id")
|
|
424
|
+
callback_id: str = Field(..., alias="callback_id", json_schema_extra={"in_query": True})
|
|
406
425
|
message: NewMessageBody | None = None
|
|
407
426
|
notification: str | None = None
|
|
408
427
|
|
|
409
428
|
class SendFileReq(MaxBotModel):
|
|
410
|
-
user_id: int | None = Field(None, alias="
|
|
411
|
-
chat_id: int | None = Field(None, alias="
|
|
429
|
+
user_id: int | None = Field(None, alias="userId", json_schema_extra={"in_query": True})
|
|
430
|
+
chat_id: int | None = Field(None, alias="chatId", json_schema_extra={"in_query": True})
|
|
412
431
|
text: str | None = None
|
|
413
432
|
format: Format | None = None
|
|
414
433
|
notify: bool | None = None
|
|
415
|
-
file_source: str
|
|
434
|
+
file_source: str = Field(..., json_schema_extra={"in_path": True})
|
|
416
435
|
link: NewMessageLink | None = None
|
|
417
|
-
disable_link_preview: bool | None = Field(None, alias="disable_link_preview")
|
|
436
|
+
disable_link_preview: bool | None = Field(None, alias="disable_link_preview", json_schema_extra={"in_query": True})
|
|
418
437
|
attachments: list[Attachment] | None = None
|
|
419
438
|
|
|
420
|
-
|
|
421
439
|
class GetSubscriptionsResp(MaxBotModel):
|
|
422
440
|
subscriptions: list[Subscription]
|
|
423
441
|
|
|
@@ -427,26 +445,25 @@ class SubscribeReq(MaxBotModel):
|
|
|
427
445
|
secret: str | None = None
|
|
428
446
|
|
|
429
447
|
class UnsubscribeReq(MaxBotModel):
|
|
430
|
-
url: str = Field(..., alias="url")
|
|
448
|
+
url: str = Field(..., alias="url", json_schema_extra={"in_query": True})
|
|
431
449
|
|
|
432
450
|
class GetUpdatesReq(MaxBotModel):
|
|
433
|
-
limit: int | None = Field(None, alias="limit")
|
|
434
|
-
timeout: int | None = Field(None, alias="timeout")
|
|
435
|
-
marker: int | None = Field(None, alias="marker")
|
|
436
|
-
types: list[UpdateType] | None = Field(None, alias="types")
|
|
451
|
+
limit: int | None = Field(None, alias="limit", json_schema_extra={"in_query": True})
|
|
452
|
+
timeout: int | None = Field(None, alias="timeout", json_schema_extra={"in_query": True})
|
|
453
|
+
marker: int | None = Field(None, alias="marker", json_schema_extra={"in_query": True})
|
|
454
|
+
types: list[UpdateType] | None = Field(None, alias="types", json_schema_extra={"in_query": True})
|
|
437
455
|
|
|
438
456
|
class GetUpdatesResp(MaxBotModel):
|
|
439
457
|
updates: list[Update]
|
|
440
458
|
marker: int
|
|
441
459
|
|
|
442
|
-
|
|
443
460
|
class UploadFileReq(MaxBotModel):
|
|
444
|
-
type: UploadType = Field(..., alias="type")
|
|
445
|
-
upload_url: str | None = None
|
|
446
|
-
file_path: str | None = None
|
|
461
|
+
type: UploadType = Field(..., alias="type", json_schema_extra={"in_query": True})
|
|
462
|
+
upload_url: str | None = Field(None, json_schema_extra={"in_path": True})
|
|
463
|
+
file_path: str | None = Field(None, json_schema_extra={"in_path": True})
|
|
447
464
|
|
|
448
465
|
class UploadTypeReq(MaxBotModel):
|
|
449
|
-
type: UploadType = Field(..., alias="type")
|
|
466
|
+
type: UploadType = Field(..., alias="type", json_schema_extra={"in_query": True})
|
|
450
467
|
|
|
451
468
|
class UploadFileMultipartReq(MaxBotModel):
|
|
452
469
|
upload_url: str
|
|
@@ -37,7 +37,9 @@ def attach_sticker(url: str | None = None, code: str | None = None) -> Attachmen
|
|
|
37
37
|
)
|
|
38
38
|
|
|
39
39
|
def attach_contact(name: str, phone: str, contact_id: int | None = None) -> Attachment:
|
|
40
|
-
|
|
40
|
+
safe_name = name.replace("\n", " ").replace("\r", "")
|
|
41
|
+
safe_phone = phone.replace("\n", "").replace("\r", "")
|
|
42
|
+
vcf_info = f"BEGIN:VCARD\nVERSION:3.0\nFN:{safe_name}\nTEL:{safe_phone}\nEND:VCARD"
|
|
41
43
|
return Attachment(
|
|
42
44
|
type=AttachmentType.CONTACT,
|
|
43
45
|
payload=ContactAttachmentPayload(
|