maxapi-python 1.2.4__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.
- maxapi_python-2.0.0.dist-info/METADATA +217 -0
- maxapi_python-2.0.0.dist-info/RECORD +140 -0
- {maxapi_python-1.2.4.dist-info → maxapi_python-2.0.0.dist-info}/WHEEL +1 -1
- pymax/__init__.py +50 -105
- pymax/api/__init__.py +17 -0
- pymax/api/auth/__init__.py +1 -0
- pymax/api/auth/enums.py +17 -0
- pymax/api/auth/payloads.py +129 -0
- pymax/api/auth/service.py +313 -0
- pymax/api/auth/types.py +13 -0
- pymax/api/chats/__init__.py +8 -0
- pymax/api/chats/enums.py +27 -0
- pymax/api/chats/payloads.py +103 -0
- pymax/api/chats/service.py +277 -0
- pymax/api/facade.py +32 -0
- pymax/api/messages/__init__.py +1 -0
- pymax/api/messages/enums.py +17 -0
- pymax/api/messages/payloads.py +92 -0
- pymax/api/messages/service.py +337 -0
- pymax/api/models.py +13 -0
- pymax/api/response.py +123 -0
- pymax/api/self/__init__.py +2 -0
- pymax/api/self/enums.py +11 -0
- pymax/api/self/payloads.py +41 -0
- pymax/api/self/service.py +142 -0
- pymax/api/session/__init__.py +1 -0
- pymax/api/session/enums.py +10 -0
- pymax/api/session/payloads.py +76 -0
- pymax/api/session/service.py +72 -0
- pymax/api/uploads/__init__.py +1 -0
- pymax/api/uploads/models.py +49 -0
- pymax/api/uploads/payloads.py +25 -0
- pymax/api/uploads/service.py +458 -0
- pymax/api/users/__init__.py +2 -0
- pymax/api/users/enums.py +12 -0
- pymax/api/users/payloads.py +16 -0
- pymax/api/users/service.py +124 -0
- pymax/app.py +273 -0
- pymax/auth/__init__.py +25 -0
- pymax/auth/base.py +37 -0
- pymax/auth/email.py +0 -0
- pymax/auth/models.py +5 -0
- pymax/auth/providers.py +127 -0
- pymax/auth/qr.py +135 -0
- pymax/auth/service.py +25 -0
- pymax/auth/sms.py +122 -0
- pymax/base.py +204 -0
- pymax/client.py +106 -0
- pymax/client_web.py +83 -0
- pymax/config.py +215 -0
- pymax/connection/__init__.py +1 -0
- pymax/connection/connection.py +205 -0
- pymax/connection/pending.py +46 -0
- pymax/connection/readers/__init__.py +2 -0
- pymax/connection/readers/base.py +6 -0
- pymax/connection/readers/tcp.py +29 -0
- pymax/connection/readers/ws.py +14 -0
- pymax/dispatch/__init__.py +10 -0
- pymax/dispatch/dispatcher.py +222 -0
- pymax/dispatch/enums.py +12 -0
- pymax/dispatch/mapping.py +73 -0
- pymax/dispatch/resolvers.py +52 -0
- pymax/dispatch/router.py +216 -0
- pymax/exceptions.py +22 -89
- pymax/files/__init__.py +9 -0
- pymax/files/base.py +82 -0
- pymax/files/file.py +76 -0
- pymax/files/photo.py +108 -0
- pymax/files/static.py +10 -0
- pymax/files/video.py +74 -0
- pymax/formatting/__init__.py +0 -0
- pymax/formatting/markdown.py +217 -0
- pymax/infra/__init__.py +1 -0
- pymax/infra/auth.py +55 -0
- pymax/infra/base.py +15 -0
- pymax/infra/chat.py +240 -0
- pymax/infra/message.py +252 -0
- pymax/infra/protocol.py +9 -0
- pymax/infra/self.py +139 -0
- pymax/infra/user.py +107 -0
- pymax/logging.py +129 -0
- pymax/protocol/__init__.py +11 -0
- pymax/protocol/base.py +13 -0
- pymax/{static/enum.py → protocol/enums.py} +36 -79
- pymax/protocol/models.py +33 -0
- pymax/protocol/tcp/__init__.py +1 -0
- pymax/protocol/tcp/compression.py +97 -0
- pymax/protocol/tcp/framing.py +68 -0
- pymax/protocol/tcp/payload.py +127 -0
- pymax/protocol/tcp/protocol.py +68 -0
- pymax/protocol/ws/__init__.py +1 -0
- pymax/protocol/ws/protocol.py +27 -0
- pymax/py.typed +0 -0
- pymax/routers.py +8 -0
- pymax/session/__init__.py +3 -0
- pymax/session/models.py +11 -0
- pymax/session/protocol.py +14 -0
- pymax/session/store.py +232 -0
- pymax/telemetry/__init__.py +3 -0
- pymax/telemetry/navigation.py +181 -0
- pymax/telemetry/payloads.py +142 -0
- pymax/telemetry/service.py +225 -0
- pymax/transport/__init__.py +0 -0
- pymax/transport/base.py +14 -0
- pymax/transport/tcp.py +93 -0
- pymax/transport/websocket.py +50 -0
- pymax/types/__init__.py +2 -0
- pymax/types/domain/__init__.py +11 -0
- pymax/types/domain/attachments/__init__.py +11 -0
- pymax/types/domain/attachments/audio.py +35 -0
- pymax/types/domain/attachments/call.py +26 -0
- pymax/types/domain/attachments/contact.py +32 -0
- pymax/types/domain/attachments/control.py +20 -0
- pymax/types/domain/attachments/enums.py +27 -0
- pymax/types/domain/attachments/file.py +56 -0
- pymax/types/domain/attachments/keyboards/__init__.py +1 -0
- pymax/types/domain/attachments/keyboards/inline.py +19 -0
- pymax/types/domain/attachments/photo.py +45 -0
- pymax/types/domain/attachments/share.py +29 -0
- pymax/types/domain/attachments/sticker.py +50 -0
- pymax/types/domain/attachments/video.py +90 -0
- pymax/types/domain/auth.py +161 -0
- pymax/types/domain/base.py +17 -0
- pymax/types/domain/chat.py +426 -0
- pymax/types/domain/element.py +24 -0
- pymax/types/domain/enums.py +24 -0
- pymax/types/domain/error.py +20 -0
- pymax/types/domain/folder.py +74 -0
- pymax/types/domain/login.py +35 -0
- pymax/types/domain/message.py +378 -0
- pymax/types/domain/name.py +20 -0
- pymax/types/domain/profile.py +15 -0
- pymax/types/domain/session.py +52 -0
- pymax/types/domain/sync.py +80 -0
- pymax/types/domain/user.py +117 -0
- pymax/types/events/__init__.py +3 -0
- pymax/types/events/file.py +5 -0
- pymax/types/events/message.py +37 -0
- pymax/types/events/video.py +5 -0
- maxapi_python-1.2.4.dist-info/METADATA +0 -205
- maxapi_python-1.2.4.dist-info/RECORD +0 -33
- pymax/core.py +0 -390
- pymax/crud.py +0 -96
- pymax/files.py +0 -138
- pymax/filters.py +0 -164
- pymax/formatter.py +0 -31
- pymax/formatting.py +0 -74
- pymax/interfaces.py +0 -552
- pymax/mixins/__init__.py +0 -40
- pymax/mixins/auth.py +0 -368
- pymax/mixins/channel.py +0 -130
- pymax/mixins/group.py +0 -458
- pymax/mixins/handler.py +0 -285
- pymax/mixins/message.py +0 -879
- pymax/mixins/scheduler.py +0 -28
- pymax/mixins/self.py +0 -259
- pymax/mixins/socket.py +0 -297
- pymax/mixins/telemetry.py +0 -112
- pymax/mixins/user.py +0 -219
- pymax/mixins/websocket.py +0 -142
- pymax/models.py +0 -8
- pymax/navigation.py +0 -187
- pymax/payloads.py +0 -367
- pymax/protocols.py +0 -123
- pymax/static/constant.py +0 -89
- pymax/types.py +0 -1220
- pymax/utils.py +0 -90
- {maxapi_python-1.2.4.dist-info → maxapi_python-2.0.0.dist-info}/licenses/LICENSE +0 -0
pymax/infra/chat.py
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
from pymax.types import Chat, Message
|
|
2
|
+
|
|
3
|
+
from .protocol import IClientProtocol
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ChatMixin(IClientProtocol):
|
|
7
|
+
"""Методы клиента для чатов, групп, каналов и invite-ссылок."""
|
|
8
|
+
|
|
9
|
+
async def create_group(
|
|
10
|
+
self,
|
|
11
|
+
name: str,
|
|
12
|
+
participant_ids: list[int] | None = None,
|
|
13
|
+
notify: bool = True,
|
|
14
|
+
) -> tuple[Chat, Message] | None:
|
|
15
|
+
"""Создает группу и возвращает чат со служебным сообщением.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
name: Название группы.
|
|
19
|
+
participant_ids: ID пользователей для добавления при создании.
|
|
20
|
+
notify: Отправить ли участникам уведомление.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
``(chat, message)`` или ``None``, если сервер не вернул данные
|
|
24
|
+
созданного чата.
|
|
25
|
+
"""
|
|
26
|
+
return await self._app.api.chats.create_group(
|
|
27
|
+
name=name,
|
|
28
|
+
participant_ids=participant_ids,
|
|
29
|
+
notify=notify,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
async def invite_users_to_group(
|
|
33
|
+
self,
|
|
34
|
+
chat_id: int,
|
|
35
|
+
user_ids: list[int],
|
|
36
|
+
show_history: bool = True,
|
|
37
|
+
) -> Chat | None:
|
|
38
|
+
"""Приглашает пользователей в группу.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
chat_id: ID группы.
|
|
42
|
+
user_ids: ID пользователей.
|
|
43
|
+
show_history: Показать новым участникам историю сообщений.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Обновленная группа или ``None``, если сервер не вернул чат.
|
|
47
|
+
"""
|
|
48
|
+
return await self._app.api.chats.invite_users_to_group(
|
|
49
|
+
chat_id=chat_id,
|
|
50
|
+
user_ids=user_ids,
|
|
51
|
+
show_history=show_history,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
async def invite_users_to_channel(
|
|
55
|
+
self,
|
|
56
|
+
chat_id: int,
|
|
57
|
+
user_ids: list[int],
|
|
58
|
+
show_history: bool = True,
|
|
59
|
+
) -> Chat | None:
|
|
60
|
+
"""Приглашает пользователей в канал.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
chat_id: ID канала.
|
|
64
|
+
user_ids: ID пользователей.
|
|
65
|
+
show_history: Показать новым участникам историю сообщений.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Обновленный канал или ``None``, если сервер не вернул чат.
|
|
69
|
+
"""
|
|
70
|
+
return await self._app.api.chats.invite_users_to_channel(
|
|
71
|
+
chat_id=chat_id,
|
|
72
|
+
user_ids=user_ids,
|
|
73
|
+
show_history=show_history,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
async def remove_users_from_group(
|
|
77
|
+
self,
|
|
78
|
+
chat_id: int,
|
|
79
|
+
user_ids: list[int],
|
|
80
|
+
clean_msg_period: int,
|
|
81
|
+
) -> bool:
|
|
82
|
+
"""Удаляет пользователей из группы.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
chat_id: ID группы.
|
|
86
|
+
user_ids: ID пользователей.
|
|
87
|
+
clean_msg_period: Период очистки сообщений удаляемых участников.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
``True``, если сервер принял запрос.
|
|
91
|
+
"""
|
|
92
|
+
return await self._app.api.chats.remove_users_from_group(
|
|
93
|
+
chat_id=chat_id,
|
|
94
|
+
user_ids=user_ids,
|
|
95
|
+
clean_msg_period=clean_msg_period,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
async def change_group_settings(
|
|
99
|
+
self,
|
|
100
|
+
chat_id: int,
|
|
101
|
+
all_can_pin_message: bool | None = None,
|
|
102
|
+
only_owner_can_change_icon_title: bool | None = None,
|
|
103
|
+
only_admin_can_add_member: bool | None = None,
|
|
104
|
+
only_admin_can_call: bool | None = None,
|
|
105
|
+
members_can_see_private_link: bool | None = None,
|
|
106
|
+
) -> None:
|
|
107
|
+
"""Обновляет настройки группы.
|
|
108
|
+
|
|
109
|
+
Передавайте только те настройки, которые хотите изменить. ``None``
|
|
110
|
+
оставляет конкретную настройку без изменений.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
chat_id: ID группы.
|
|
114
|
+
all_can_pin_message: Все участники могут закреплять сообщения.
|
|
115
|
+
only_owner_can_change_icon_title: Только владелец меняет иконку
|
|
116
|
+
и название.
|
|
117
|
+
only_admin_can_add_member: Только администраторы добавляют людей.
|
|
118
|
+
only_admin_can_call: Только администраторы начинают звонки.
|
|
119
|
+
members_can_see_private_link: Участники видят приватную ссылку.
|
|
120
|
+
"""
|
|
121
|
+
await self._app.api.chats.change_group_settings(
|
|
122
|
+
chat_id=chat_id,
|
|
123
|
+
all_can_pin_message=all_can_pin_message,
|
|
124
|
+
only_owner_can_change_icon_title=only_owner_can_change_icon_title,
|
|
125
|
+
only_admin_can_add_member=only_admin_can_add_member,
|
|
126
|
+
only_admin_can_call=only_admin_can_call,
|
|
127
|
+
members_can_see_private_link=members_can_see_private_link,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
async def change_group_profile(
|
|
131
|
+
self,
|
|
132
|
+
chat_id: int,
|
|
133
|
+
name: str | None,
|
|
134
|
+
description: str | None = None,
|
|
135
|
+
) -> None:
|
|
136
|
+
"""Обновляет название и описание группы.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
chat_id: ID группы.
|
|
140
|
+
name: Новое название.
|
|
141
|
+
description: Новое описание.
|
|
142
|
+
"""
|
|
143
|
+
await self._app.api.chats.change_group_profile(
|
|
144
|
+
chat_id=chat_id,
|
|
145
|
+
name=name,
|
|
146
|
+
description=description,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
async def join_group(self, link: str) -> Chat:
|
|
150
|
+
"""Вступает в группу по пригласительной ссылке.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
link: Полная invite-ссылка или ее часть с join-токеном Max.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Группа, в которую вступил клиент.
|
|
157
|
+
|
|
158
|
+
Raises:
|
|
159
|
+
ValueError: Если строка не похожа на invite-ссылку.
|
|
160
|
+
"""
|
|
161
|
+
return await self._app.api.chats.join_group(link)
|
|
162
|
+
|
|
163
|
+
async def resolve_group_by_link(self, link: str) -> Chat | None:
|
|
164
|
+
"""Возвращает информацию о группе по invite-ссылке без вступления.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
link: Полная invite-ссылка или ее часть с join-токеном Max.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Группа или ``None``, если сервер не вернул чат.
|
|
171
|
+
|
|
172
|
+
Raises:
|
|
173
|
+
ValueError: Если строка не похожа на invite-ссылку.
|
|
174
|
+
"""
|
|
175
|
+
return await self._app.api.chats.resolve_group_by_link(link)
|
|
176
|
+
|
|
177
|
+
async def rework_invite_link(self, chat_id: int) -> Chat:
|
|
178
|
+
"""Перевыпускает приватную invite-ссылку группы.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
chat_id: ID группы.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
Обновленная группа с новой ссылкой.
|
|
185
|
+
"""
|
|
186
|
+
return await self._app.api.chats.rework_invite_link(chat_id)
|
|
187
|
+
|
|
188
|
+
async def get_chats(self, chat_ids: list[int]) -> list[Chat]:
|
|
189
|
+
"""Возвращает чаты, используя кеш и догружая недостающие данные.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
chat_ids: ID чатов в нужном порядке.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Найденные чаты в порядке ``chat_ids``. Чаты, которых нет в
|
|
196
|
+
ответе сервера, пропускаются.
|
|
197
|
+
"""
|
|
198
|
+
return await self._app.api.chats.get_chats(chat_ids)
|
|
199
|
+
|
|
200
|
+
async def get_chat(self, chat_id: int) -> Chat:
|
|
201
|
+
"""Возвращает чат по ID.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
chat_id: ID чата.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Найденный чат.
|
|
208
|
+
|
|
209
|
+
Raises:
|
|
210
|
+
PyMaxError: Если сервер не вернул чат.
|
|
211
|
+
"""
|
|
212
|
+
return await self._app.api.chats.get_chat(chat_id)
|
|
213
|
+
|
|
214
|
+
async def leave_group(self, chat_id: int) -> None:
|
|
215
|
+
"""Выходит из группы.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
chat_id: ID группы.
|
|
219
|
+
"""
|
|
220
|
+
await self._app.api.chats.leave_group(chat_id)
|
|
221
|
+
|
|
222
|
+
async def leave_channel(self, chat_id: int) -> None:
|
|
223
|
+
"""Выходит из канала.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
chat_id: ID канала.
|
|
227
|
+
"""
|
|
228
|
+
await self._app.api.chats.leave_channel(chat_id)
|
|
229
|
+
|
|
230
|
+
async def fetch_chats(self, marker: int | None = None) -> list[Chat]:
|
|
231
|
+
"""Загружает список чатов с сервера и обновляет кеш клиента.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
marker: Маркер пагинации в миллисекундах. Если ``None``,
|
|
235
|
+
используется текущий момент.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Загруженные чаты.
|
|
239
|
+
"""
|
|
240
|
+
return await self._app.api.chats.fetch_chats(marker=marker)
|
pymax/infra/message.py
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
from pymax.api.messages.enums import ItemType
|
|
2
|
+
from pymax.api.messages.service import SendAttachments
|
|
3
|
+
from pymax.types import (
|
|
4
|
+
FileRequest,
|
|
5
|
+
Message,
|
|
6
|
+
ReactionInfo,
|
|
7
|
+
ReadState,
|
|
8
|
+
VideoRequest,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from .protocol import IClientProtocol
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MessageMixin(IClientProtocol):
|
|
15
|
+
"""Методы клиента для сообщений, истории, реакций и вложений."""
|
|
16
|
+
|
|
17
|
+
async def send_message(
|
|
18
|
+
self,
|
|
19
|
+
chat_id: int,
|
|
20
|
+
text: str,
|
|
21
|
+
reply_to: int | None = None,
|
|
22
|
+
attachments: SendAttachments = None,
|
|
23
|
+
*,
|
|
24
|
+
notify: bool = True,
|
|
25
|
+
) -> Message | None:
|
|
26
|
+
"""Отправляет сообщение в чат.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
chat_id: ID чата.
|
|
30
|
+
text: Текст сообщения.
|
|
31
|
+
reply_to: ID сообщения для ответа.
|
|
32
|
+
attachments: Файлы, фотографии или видео для отправки.
|
|
33
|
+
notify: Отправить ли получателям push-уведомление.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Отправленное сообщение или ``None``, если сервер не вернул его.
|
|
37
|
+
"""
|
|
38
|
+
return await self._app.api.messages.send_message(
|
|
39
|
+
chat_id,
|
|
40
|
+
text,
|
|
41
|
+
reply_to,
|
|
42
|
+
attachments,
|
|
43
|
+
notify=notify,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
async def fetch_history(
|
|
47
|
+
self,
|
|
48
|
+
chat_id: int,
|
|
49
|
+
forward: int = 0,
|
|
50
|
+
backward: int = 40,
|
|
51
|
+
backward_time: int = 0,
|
|
52
|
+
forward_time: int = 0,
|
|
53
|
+
from_time: int | None = None,
|
|
54
|
+
item_type: ItemType = ItemType.REGULAR,
|
|
55
|
+
get_chat: bool = False,
|
|
56
|
+
get_messages: bool = True,
|
|
57
|
+
interactive: bool = False,
|
|
58
|
+
) -> list[Message] | None:
|
|
59
|
+
"""Загружает историю сообщений чата.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
chat_id: ID чата.
|
|
63
|
+
forward: Сколько сообщений загрузить вперед от ``from_time``.
|
|
64
|
+
backward: Сколько сообщений загрузить назад от ``from_time``.
|
|
65
|
+
backward_time: Временное окно назад в миллисекундах.
|
|
66
|
+
forward_time: Временное окно вперед в миллисекундах.
|
|
67
|
+
from_time: Точка отсчета в миллисекундах Unix time. Если
|
|
68
|
+
``None``, используется текущий момент.
|
|
69
|
+
item_type: Тип элементов истории: обычные или отложенные.
|
|
70
|
+
get_chat: Запросить данные чата вместе с историей.
|
|
71
|
+
get_messages: Запросить сами сообщения.
|
|
72
|
+
interactive: Пометить запрос как интерактивный.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Сообщения или ``None``, если сервер не вернул список.
|
|
76
|
+
"""
|
|
77
|
+
return await self._app.api.messages.fetch_history(
|
|
78
|
+
chat_id=chat_id,
|
|
79
|
+
forward=forward,
|
|
80
|
+
backward=backward,
|
|
81
|
+
backward_time=backward_time,
|
|
82
|
+
forward_time=forward_time,
|
|
83
|
+
from_=from_time,
|
|
84
|
+
item_type=item_type,
|
|
85
|
+
get_chat=get_chat,
|
|
86
|
+
get_messages=get_messages,
|
|
87
|
+
interactive=interactive,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
async def delete_message(
|
|
91
|
+
self,
|
|
92
|
+
chat_id: int,
|
|
93
|
+
message_ids: list[int],
|
|
94
|
+
for_me: bool,
|
|
95
|
+
) -> bool:
|
|
96
|
+
"""Удаляет сообщения из чата.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
chat_id: ID чата.
|
|
100
|
+
message_ids: ID сообщений.
|
|
101
|
+
for_me: Удалить только для текущего аккаунта.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
``True``, если сервер принял запрос.
|
|
105
|
+
"""
|
|
106
|
+
return await self._app.api.messages.delete_message(
|
|
107
|
+
chat_id=chat_id,
|
|
108
|
+
message_ids=message_ids,
|
|
109
|
+
for_me=for_me,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
async def pin_message(
|
|
113
|
+
self,
|
|
114
|
+
chat_id: int,
|
|
115
|
+
message_id: int,
|
|
116
|
+
notify_pin: bool,
|
|
117
|
+
) -> bool:
|
|
118
|
+
"""Закрепляет сообщение в чате.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
chat_id: ID чата.
|
|
122
|
+
message_id: ID сообщения.
|
|
123
|
+
notify_pin: Отправить ли уведомление о закреплении.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
``True``, если сервер принял запрос.
|
|
127
|
+
"""
|
|
128
|
+
return await self._app.api.messages.pin_message(
|
|
129
|
+
chat_id=chat_id,
|
|
130
|
+
message_id=message_id,
|
|
131
|
+
notify_pin=notify_pin,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
async def get_video_by_id(
|
|
135
|
+
self,
|
|
136
|
+
chat_id: int,
|
|
137
|
+
message_id: int | str,
|
|
138
|
+
video_id: int,
|
|
139
|
+
) -> VideoRequest | None:
|
|
140
|
+
"""Возвращает данные для просмотра видео-вложения.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
chat_id: ID чата.
|
|
144
|
+
message_id: ID сообщения с видео.
|
|
145
|
+
video_id: ID видео-вложения.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Данные видео или ``None``, если сервер их не вернул.
|
|
149
|
+
"""
|
|
150
|
+
return await self._app.api.messages.get_video_by_id(
|
|
151
|
+
chat_id=chat_id,
|
|
152
|
+
message_id=message_id,
|
|
153
|
+
video_id=video_id,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
async def get_file_by_id(
|
|
157
|
+
self,
|
|
158
|
+
chat_id: int,
|
|
159
|
+
message_id: int | str,
|
|
160
|
+
file_id: int,
|
|
161
|
+
) -> FileRequest | None:
|
|
162
|
+
"""Возвращает данные для скачивания файлового вложения.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
chat_id: ID чата.
|
|
166
|
+
message_id: ID сообщения с файлом.
|
|
167
|
+
file_id: ID файлового вложения.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Данные файла или ``None``, если сервер их не вернул.
|
|
171
|
+
"""
|
|
172
|
+
return await self._app.api.messages.get_file_by_id(
|
|
173
|
+
chat_id=chat_id,
|
|
174
|
+
message_id=message_id,
|
|
175
|
+
file_id=file_id,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
async def add_reaction(
|
|
179
|
+
self,
|
|
180
|
+
chat_id: int,
|
|
181
|
+
message_id: str,
|
|
182
|
+
reaction: str,
|
|
183
|
+
) -> ReactionInfo | None:
|
|
184
|
+
"""Добавляет реакцию к сообщению.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
chat_id: ID чата.
|
|
188
|
+
message_id: ID сообщения.
|
|
189
|
+
reaction: ID emoji-реакции, поддержанный сервером.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
Обновленные реакции или ``None``, если сервер их не вернул.
|
|
193
|
+
"""
|
|
194
|
+
return await self._app.api.messages.add_reaction(
|
|
195
|
+
chat_id=chat_id,
|
|
196
|
+
message_id=message_id,
|
|
197
|
+
reaction=reaction,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
async def get_reactions(
|
|
201
|
+
self,
|
|
202
|
+
chat_id: int,
|
|
203
|
+
message_ids: list[str],
|
|
204
|
+
) -> dict[str, ReactionInfo] | None:
|
|
205
|
+
"""Возвращает реакции для нескольких сообщений.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
chat_id: ID чата.
|
|
209
|
+
message_ids: ID сообщений.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
``{message_id: ReactionInfo}`` или ``None``, если реакций нет в
|
|
213
|
+
ответе сервера.
|
|
214
|
+
"""
|
|
215
|
+
return await self._app.api.messages.get_reactions(
|
|
216
|
+
chat_id=chat_id,
|
|
217
|
+
message_ids=message_ids,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
async def remove_reaction(
|
|
221
|
+
self,
|
|
222
|
+
chat_id: int,
|
|
223
|
+
message_id: str,
|
|
224
|
+
) -> ReactionInfo | None:
|
|
225
|
+
"""Удаляет свою реакцию с сообщения.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
chat_id: ID чата.
|
|
229
|
+
message_id: ID сообщения.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Обновленные реакции или ``None``, если сервер их не вернул.
|
|
233
|
+
"""
|
|
234
|
+
return await self._app.api.messages.remove_reaction(
|
|
235
|
+
chat_id=chat_id,
|
|
236
|
+
message_id=message_id,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
async def read_message(self, message_id: int, chat_id: int) -> ReadState:
|
|
240
|
+
"""Отмечает сообщение как прочитанное.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
message_id: ID сообщения.
|
|
244
|
+
chat_id: ID чата.
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
Состояние прочтения.
|
|
248
|
+
"""
|
|
249
|
+
return await self._app.api.messages.read_message(
|
|
250
|
+
message_id=message_id,
|
|
251
|
+
chat_id=chat_id,
|
|
252
|
+
)
|
pymax/infra/protocol.py
ADDED
pymax/infra/self.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pymax.types import FolderList, FolderUpdate
|
|
4
|
+
|
|
5
|
+
from .protocol import IClientProtocol
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SelfMixin(IClientProtocol):
|
|
9
|
+
async def request_profile_photo_upload_url(self) -> str:
|
|
10
|
+
"""Запрашивает временный URL для загрузки фотографии профиля.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
URL, на который можно загрузить фото профиля.
|
|
14
|
+
"""
|
|
15
|
+
return await self._app.api.account.request_profile_photo_upload_url()
|
|
16
|
+
|
|
17
|
+
async def change_profile(
|
|
18
|
+
self,
|
|
19
|
+
first_name: str,
|
|
20
|
+
last_name: str | None = None,
|
|
21
|
+
description: str | None = None,
|
|
22
|
+
photo: Any | None = None,
|
|
23
|
+
*,
|
|
24
|
+
photo_token: str | None = None,
|
|
25
|
+
) -> bool:
|
|
26
|
+
"""Обновляет профиль текущего аккаунта.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
first_name: Имя профиля.
|
|
30
|
+
last_name: Фамилия профиля.
|
|
31
|
+
description: Описание профиля.
|
|
32
|
+
photo: Файл или объект фото. Прямая загрузка через этот
|
|
33
|
+
параметр пока не реализована.
|
|
34
|
+
photo_token: Токен фотографии, уже загруженной через API Max.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
``True`` после успешного обновления. Клиент также обновит
|
|
38
|
+
``client.me`` и кеш текущего контакта.
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
NotImplementedError: Если передан ``photo`` вместо
|
|
42
|
+
``photo_token``.
|
|
43
|
+
"""
|
|
44
|
+
return await self._app.api.account.change_profile(
|
|
45
|
+
first_name=first_name,
|
|
46
|
+
last_name=last_name,
|
|
47
|
+
description=description,
|
|
48
|
+
photo=photo,
|
|
49
|
+
photo_token=photo_token,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
async def create_folder(
|
|
53
|
+
self,
|
|
54
|
+
title: str,
|
|
55
|
+
chat_include: list[int],
|
|
56
|
+
filters: list[Any] | None = None,
|
|
57
|
+
) -> FolderUpdate:
|
|
58
|
+
"""Создает папку чатов.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
title: Название папки.
|
|
62
|
+
chat_include: ID чатов, которые попадут в папку.
|
|
63
|
+
filters: Дополнительные фильтры Max для папки.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Обновленное состояние папок.
|
|
67
|
+
"""
|
|
68
|
+
return await self._app.api.account.create_folder(
|
|
69
|
+
title=title,
|
|
70
|
+
chat_include=chat_include,
|
|
71
|
+
filters=filters,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
async def get_folders(self, folder_sync: int = 0) -> FolderList:
|
|
75
|
+
"""Возвращает папки текущего аккаунта.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
folder_sync: Маркер синхронизации. Для первой загрузки оставьте
|
|
79
|
+
``0``.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Список папок и актуальный маркер синхронизации.
|
|
83
|
+
"""
|
|
84
|
+
return await self._app.api.account.get_folders(folder_sync=folder_sync)
|
|
85
|
+
|
|
86
|
+
async def update_folder(
|
|
87
|
+
self,
|
|
88
|
+
folder_id: str,
|
|
89
|
+
title: str,
|
|
90
|
+
chat_include: list[int] | None = None,
|
|
91
|
+
filters: list[Any] | None = None,
|
|
92
|
+
options: list[Any] | None = None,
|
|
93
|
+
) -> FolderUpdate:
|
|
94
|
+
"""Обновляет папку чатов.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
folder_id: ID папки.
|
|
98
|
+
title: Новое название.
|
|
99
|
+
chat_include: Новый список ID включенных чатов.
|
|
100
|
+
filters: Новый список фильтров.
|
|
101
|
+
options: Новый список опций.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Обновленное состояние папок.
|
|
105
|
+
"""
|
|
106
|
+
return await self._app.api.account.update_folder(
|
|
107
|
+
folder_id=folder_id,
|
|
108
|
+
title=title,
|
|
109
|
+
chat_include=chat_include,
|
|
110
|
+
filters=filters,
|
|
111
|
+
options=options,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
async def delete_folder(self, folder_id: str) -> FolderUpdate:
|
|
115
|
+
"""Удаляет папку чатов.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
folder_id: ID папки.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Обновленное состояние папок.
|
|
122
|
+
"""
|
|
123
|
+
return await self._app.api.account.delete_folder(folder_id)
|
|
124
|
+
|
|
125
|
+
async def close_all_sessions(self) -> bool:
|
|
126
|
+
"""Закрывает остальные активные сессии аккаунта.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
``True``, если сервер принял запрос.
|
|
130
|
+
"""
|
|
131
|
+
return await self._app.api.account.close_all_sessions()
|
|
132
|
+
|
|
133
|
+
async def logout(self) -> bool:
|
|
134
|
+
"""Завершает текущую сессию клиента.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
``True``, если сервер принял запрос на выход.
|
|
138
|
+
"""
|
|
139
|
+
return await self._app.api.account.logout()
|