maxapi-python 1.2.5__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.5.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/protocol/enums.py +180 -0
- 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.5.dist-info/METADATA +0 -202
- maxapi_python-1.2.5.dist-info/RECORD +0 -33
- pymax/core.py +0 -398
- 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 -558
- pymax/mixins/__init__.py +0 -40
- pymax/mixins/auth.py +0 -594
- 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 -306
- pymax/mixins/telemetry.py +0 -118
- pymax/mixins/user.py +0 -219
- pymax/mixins/websocket.py +0 -151
- pymax/models.py +0 -8
- pymax/navigation.py +0 -187
- pymax/payloads.py +0 -403
- pymax/protocols.py +0 -123
- pymax/static/constant.py +0 -96
- pymax/static/enum.py +0 -231
- pymax/types.py +0 -1220
- pymax/utils.py +0 -90
- {maxapi_python-1.2.5.dist-info → maxapi_python-2.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from pydantic import Field, PrivateAttr
|
|
6
|
+
|
|
7
|
+
from .base import CamelModel
|
|
8
|
+
from .enums import AccessType, ChatType
|
|
9
|
+
from .message import Message, SendAttachments
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from pymax.api.chats import ChatService
|
|
13
|
+
from pymax.api.messages import MessageService
|
|
14
|
+
from pymax.api.messages.enums import ItemType
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Chat(CamelModel):
|
|
18
|
+
"""Чат, группа, канал или диалог Max.
|
|
19
|
+
|
|
20
|
+
Объекты чатов, полученные через клиент, обычно уже привязаны к сервисам
|
|
21
|
+
сообщений и чатов. После этого можно вызывать удобные методы объекта:
|
|
22
|
+
:meth:`answer`, :meth:`history`, :meth:`leave`, :meth:`invite`,
|
|
23
|
+
:meth:`remove_users`, :meth:`pin_message`, :meth:`update_settings` и
|
|
24
|
+
:meth:`rework_invite_link`.
|
|
25
|
+
|
|
26
|
+
Используйте ``Chat`` для работы с конкретным диалогом, группой или каналом.
|
|
27
|
+
``client.chats`` содержит чаты из login/sync, а недостающие чаты можно
|
|
28
|
+
загрузить через ``client.get_chat`` или ``client.fetch_chats``.
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
.. code-block:: python
|
|
32
|
+
|
|
33
|
+
chat = await client.get_chat(123456)
|
|
34
|
+
await chat.answer("Привет")
|
|
35
|
+
history = await chat.history(backward=20)
|
|
36
|
+
|
|
37
|
+
:ivar id: ID чата.
|
|
38
|
+
:vartype id: int
|
|
39
|
+
:ivar type: Тип чата.
|
|
40
|
+
:vartype type: ChatType | str
|
|
41
|
+
:ivar status: Статус чата.
|
|
42
|
+
:vartype status: str
|
|
43
|
+
:ivar owner: ID владельца чата.
|
|
44
|
+
:vartype owner: int
|
|
45
|
+
:ivar participants: Участники чата.
|
|
46
|
+
:vartype participants: dict[int, int]
|
|
47
|
+
:ivar title: Название чата.
|
|
48
|
+
:vartype title: str | None
|
|
49
|
+
:ivar base_raw_icon_url: Исходный URL иконки чата.
|
|
50
|
+
:vartype base_raw_icon_url: str | None
|
|
51
|
+
:ivar base_icon_url: URL иконки чата.
|
|
52
|
+
:vartype base_icon_url: str | None
|
|
53
|
+
:ivar last_message: Последнее сообщение чата.
|
|
54
|
+
:vartype last_message: Message | None
|
|
55
|
+
:ivar last_event_time: Время последнего события в формате Unix time.
|
|
56
|
+
:vartype last_event_time: int
|
|
57
|
+
:ivar last_delayed_update_time: Время последнего отложенного обновления.
|
|
58
|
+
:vartype last_delayed_update_time: int
|
|
59
|
+
:ivar last_fire_delayed_error_time: Время последней ошибки отложенного
|
|
60
|
+
события.
|
|
61
|
+
:vartype last_fire_delayed_error_time: int
|
|
62
|
+
:ivar created: Время создания чата в формате Unix time.
|
|
63
|
+
:vartype created: int
|
|
64
|
+
:ivar new_messages: Количество новых сообщений.
|
|
65
|
+
:vartype new_messages: int
|
|
66
|
+
:ivar link: Invite-ссылка чата.
|
|
67
|
+
:vartype link: str | None
|
|
68
|
+
:ivar access: Тип доступа к чату.
|
|
69
|
+
:vartype access: AccessType | str | None
|
|
70
|
+
:ivar restrictions: Битовая маска или код ограничений чата.
|
|
71
|
+
:vartype restrictions: int | None
|
|
72
|
+
:ivar pinned_message: Закрепленное сообщение.
|
|
73
|
+
:vartype pinned_message: Message | None
|
|
74
|
+
:ivar participants_count: Количество участников.
|
|
75
|
+
:vartype participants_count: int
|
|
76
|
+
:ivar description: Описание чата.
|
|
77
|
+
:vartype description: str | None
|
|
78
|
+
:ivar options: Дополнительные флаги и настройки чата от Max.
|
|
79
|
+
:vartype options: dict[str, bool] | int | None
|
|
80
|
+
:ivar join_time: Время вступления в чат в формате Unix time.
|
|
81
|
+
:vartype join_time: int
|
|
82
|
+
:ivar invited_by: ID пользователя, который пригласил текущий аккаунт.
|
|
83
|
+
:vartype invited_by: int | None
|
|
84
|
+
:ivar modified: Время последнего изменения в формате Unix time.
|
|
85
|
+
:vartype modified: int
|
|
86
|
+
:ivar messages_count: Количество сообщений.
|
|
87
|
+
:vartype messages_count: int
|
|
88
|
+
:ivar has_bots: Есть ли в чате боты, если Max прислал этот признак.
|
|
89
|
+
:vartype has_bots: bool | None
|
|
90
|
+
:ivar prev_message_id: ID предыдущего сообщения.
|
|
91
|
+
:vartype prev_message_id: int | None
|
|
92
|
+
:ivar admin_participants: Данные администраторов по ID пользователя.
|
|
93
|
+
:vartype admin_participants: dict[int, dict[Any, Any]]
|
|
94
|
+
:ivar admins: ID администраторов чата.
|
|
95
|
+
:vartype admins: list[int]
|
|
96
|
+
:ivar cid: Клиентский ID, если он есть в payload-е Max.
|
|
97
|
+
:vartype cid: int | None
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
id: int
|
|
101
|
+
type: ChatType | str
|
|
102
|
+
status: str
|
|
103
|
+
owner: int
|
|
104
|
+
participants: dict[int, int] = Field(default_factory=dict)
|
|
105
|
+
title: str | None = None
|
|
106
|
+
base_raw_icon_url: str | None = None
|
|
107
|
+
base_icon_url: str | None = None
|
|
108
|
+
last_message: Message | None = None
|
|
109
|
+
last_event_time: int = 0
|
|
110
|
+
last_delayed_update_time: int = 0
|
|
111
|
+
last_fire_delayed_error_time: int = 0
|
|
112
|
+
created: int = 0
|
|
113
|
+
new_messages: int = 0
|
|
114
|
+
link: str | None = None
|
|
115
|
+
access: AccessType | str | None = None
|
|
116
|
+
restrictions: int | None = None
|
|
117
|
+
pinned_message: Message | None = None
|
|
118
|
+
participants_count: int = 0
|
|
119
|
+
description: str | None = None
|
|
120
|
+
options: dict[str, bool] | int | None = None
|
|
121
|
+
join_time: int = 0
|
|
122
|
+
invited_by: int | None = None
|
|
123
|
+
modified: int = 0
|
|
124
|
+
messages_count: int = 0
|
|
125
|
+
has_bots: bool | None = None
|
|
126
|
+
prev_message_id: int | None = None
|
|
127
|
+
admin_participants: dict[int, dict[Any, Any]] = Field(default_factory=dict)
|
|
128
|
+
admins: list[int] = Field(default_factory=list)
|
|
129
|
+
cid: int | None = None
|
|
130
|
+
|
|
131
|
+
_message_actions: MessageService | None = PrivateAttr(default=None)
|
|
132
|
+
_chat_actions: ChatService | None = PrivateAttr(default=None)
|
|
133
|
+
|
|
134
|
+
def bind(
|
|
135
|
+
self,
|
|
136
|
+
message_actions: MessageService,
|
|
137
|
+
chat_actions: ChatService,
|
|
138
|
+
) -> Chat:
|
|
139
|
+
"""Привязывает сервисы сообщений и чатов к объекту чата.
|
|
140
|
+
|
|
141
|
+
:param message_actions: Сервис сообщений для действий с сообщениями.
|
|
142
|
+
:type message_actions: MessageService
|
|
143
|
+
:param chat_actions: Сервис чатов для действий с чатами.
|
|
144
|
+
:type chat_actions: ChatService
|
|
145
|
+
:returns: Этот же чат с привязанными сервисами.
|
|
146
|
+
:rtype: Chat
|
|
147
|
+
"""
|
|
148
|
+
self._message_actions = message_actions
|
|
149
|
+
self._chat_actions = chat_actions
|
|
150
|
+
return self
|
|
151
|
+
|
|
152
|
+
async def answer(
|
|
153
|
+
self,
|
|
154
|
+
text: str,
|
|
155
|
+
reply_to: int | None = None,
|
|
156
|
+
attachments: SendAttachments = None,
|
|
157
|
+
*,
|
|
158
|
+
notify: bool = True,
|
|
159
|
+
) -> Message | None:
|
|
160
|
+
"""Отправляет сообщение в этот чат.
|
|
161
|
+
|
|
162
|
+
:param text: Текст сообщения.
|
|
163
|
+
:type text: str
|
|
164
|
+
:param reply_to: ID сообщения для ответа.
|
|
165
|
+
:type reply_to: int | None
|
|
166
|
+
:param attachments: Файлы, фотографии или видео для отправки.
|
|
167
|
+
:type attachments: SendAttachments
|
|
168
|
+
:param notify: Отправить ли получателям push-уведомление.
|
|
169
|
+
:type notify: bool
|
|
170
|
+
:returns: Отправленное сообщение или ``None``, если сервер не вернул
|
|
171
|
+
его.
|
|
172
|
+
:rtype: Message | None
|
|
173
|
+
:raises RuntimeError: Если чат не привязан к клиенту.
|
|
174
|
+
"""
|
|
175
|
+
actions, _ = self._bound()
|
|
176
|
+
|
|
177
|
+
return await actions.send_message(
|
|
178
|
+
chat_id=self.id,
|
|
179
|
+
text=text,
|
|
180
|
+
reply_to=reply_to,
|
|
181
|
+
attachments=attachments,
|
|
182
|
+
notify=notify,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
async def history(
|
|
186
|
+
self,
|
|
187
|
+
forward: int = 0,
|
|
188
|
+
backward: int = 40,
|
|
189
|
+
backward_time: int = 0,
|
|
190
|
+
forward_time: int = 0,
|
|
191
|
+
from_time: int | None = None,
|
|
192
|
+
item_type: ItemType | None = None,
|
|
193
|
+
get_chat: bool = False,
|
|
194
|
+
get_messages: bool = True,
|
|
195
|
+
interactive: bool = False,
|
|
196
|
+
) -> list[Message] | None:
|
|
197
|
+
"""Загружает историю сообщений этого чата.
|
|
198
|
+
|
|
199
|
+
``from_time``, ``backward_time`` и ``forward_time`` передаются в
|
|
200
|
+
миллисекундах Unix time. Если ``from_time`` равен ``None``, PyMax
|
|
201
|
+
использует текущий момент.
|
|
202
|
+
|
|
203
|
+
:param forward: Сколько сообщений загрузить вперед от ``from_time``.
|
|
204
|
+
:type forward: int
|
|
205
|
+
:param backward: Сколько сообщений загрузить назад от ``from_time``.
|
|
206
|
+
:type backward: int
|
|
207
|
+
:param backward_time: Временное окно назад в миллисекундах.
|
|
208
|
+
:type backward_time: int
|
|
209
|
+
:param forward_time: Временное окно вперед в миллисекундах.
|
|
210
|
+
:type forward_time: int
|
|
211
|
+
:param from_time: Точка отсчета в миллисекундах Unix time. Если
|
|
212
|
+
``None``, используется текущий момент.
|
|
213
|
+
:type from_time: int | None
|
|
214
|
+
:param item_type: Тип элементов истории: обычные или отложенные.
|
|
215
|
+
:type item_type: ItemType | None
|
|
216
|
+
:param get_chat: Запросить данные чата вместе с историей.
|
|
217
|
+
:type get_chat: bool
|
|
218
|
+
:param get_messages: Запросить сами сообщения.
|
|
219
|
+
:type get_messages: bool
|
|
220
|
+
:param interactive: Пометить запрос как интерактивный.
|
|
221
|
+
:type interactive: bool
|
|
222
|
+
:returns: Сообщения или ``None``, если сервер не вернул список.
|
|
223
|
+
:rtype: list[Message] | None
|
|
224
|
+
:raises RuntimeError: Если чат не привязан к клиенту.
|
|
225
|
+
"""
|
|
226
|
+
actions, _ = self._bound()
|
|
227
|
+
if item_type is None:
|
|
228
|
+
from pymax.api.messages.enums import ItemType
|
|
229
|
+
|
|
230
|
+
item_type = ItemType.REGULAR
|
|
231
|
+
|
|
232
|
+
return await actions.fetch_history(
|
|
233
|
+
chat_id=self.id,
|
|
234
|
+
forward=forward,
|
|
235
|
+
backward=backward,
|
|
236
|
+
backward_time=backward_time,
|
|
237
|
+
forward_time=forward_time,
|
|
238
|
+
from_=from_time,
|
|
239
|
+
item_type=item_type,
|
|
240
|
+
get_chat=get_chat,
|
|
241
|
+
get_messages=get_messages,
|
|
242
|
+
interactive=interactive,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
async def leave(self) -> None:
|
|
246
|
+
"""Выходит из группы или канала.
|
|
247
|
+
|
|
248
|
+
Метод зависит от типа чата: для ``ChatType.CHAT`` вызывает выход из
|
|
249
|
+
группы, для ``ChatType.CHANNEL`` - выход из канала. Для личного диалога
|
|
250
|
+
``ChatType.DIALOG`` выход не поддерживается.
|
|
251
|
+
|
|
252
|
+
:returns: ``None``.
|
|
253
|
+
:rtype: None
|
|
254
|
+
:raises RuntimeError: Если чат не привязан к клиенту или является
|
|
255
|
+
личным диалогом.
|
|
256
|
+
:raises ValueError: Если тип чата неизвестен.
|
|
257
|
+
"""
|
|
258
|
+
_, chat_actions = self._bound()
|
|
259
|
+
|
|
260
|
+
if self.type == ChatType.DIALOG:
|
|
261
|
+
raise RuntimeError("Cannot leave dialog")
|
|
262
|
+
|
|
263
|
+
if self.type == ChatType.CHAT:
|
|
264
|
+
return await chat_actions.leave_group(self.id)
|
|
265
|
+
|
|
266
|
+
if self.type == ChatType.CHANNEL:
|
|
267
|
+
return await chat_actions.leave_channel(self.id)
|
|
268
|
+
|
|
269
|
+
raise ValueError("Unknown chat type=%s", self.type)
|
|
270
|
+
|
|
271
|
+
async def invite(
|
|
272
|
+
self,
|
|
273
|
+
user_ids: list[int],
|
|
274
|
+
show_history: bool = True,
|
|
275
|
+
) -> Chat | None:
|
|
276
|
+
"""Приглашает пользователей в группу или канал.
|
|
277
|
+
|
|
278
|
+
Метод зависит от типа чата: для ``ChatType.CHAT`` вызывает приглашение
|
|
279
|
+
в группу, для ``ChatType.CHANNEL`` - приглашение в канал. Для других
|
|
280
|
+
типов чатов будет ошибка.
|
|
281
|
+
|
|
282
|
+
:param user_ids: ID пользователей, которых нужно пригласить.
|
|
283
|
+
:type user_ids: list[int]
|
|
284
|
+
:param show_history: Показать ли новым участникам историю сообщений.
|
|
285
|
+
:type show_history: bool
|
|
286
|
+
:returns: Обновленный чат или ``None``, если сервер не вернул его.
|
|
287
|
+
:rtype: Chat | None
|
|
288
|
+
:raises RuntimeError: Если чат не привязан к клиенту.
|
|
289
|
+
:raises ValueError: Если тип чата неизвестен.
|
|
290
|
+
"""
|
|
291
|
+
_, chat_actions = self._bound()
|
|
292
|
+
|
|
293
|
+
if self.type == ChatType.CHAT:
|
|
294
|
+
return await chat_actions.invite_users_to_group(
|
|
295
|
+
self.id,
|
|
296
|
+
user_ids,
|
|
297
|
+
show_history,
|
|
298
|
+
)
|
|
299
|
+
if self.type == ChatType.CHANNEL:
|
|
300
|
+
return await chat_actions.invite_users_to_channel(
|
|
301
|
+
self.id,
|
|
302
|
+
user_ids,
|
|
303
|
+
show_history,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
raise ValueError("Unknown chat type=%s", self.type)
|
|
307
|
+
|
|
308
|
+
async def remove_users(
|
|
309
|
+
self,
|
|
310
|
+
user_ids: list[int],
|
|
311
|
+
clean_msg_period: int = 0,
|
|
312
|
+
) -> bool:
|
|
313
|
+
"""Удаляет пользователей из группы.
|
|
314
|
+
|
|
315
|
+
:param user_ids: ID пользователей, которых нужно удалить.
|
|
316
|
+
:type user_ids: list[int]
|
|
317
|
+
:param clean_msg_period: Период удаления сообщений пользователей.
|
|
318
|
+
:type clean_msg_period: int
|
|
319
|
+
:returns: ``True``, если сервер принял запрос.
|
|
320
|
+
:rtype: bool
|
|
321
|
+
:raises RuntimeError: Если чат не привязан к клиенту.
|
|
322
|
+
"""
|
|
323
|
+
_, chat_actions = self._bound()
|
|
324
|
+
|
|
325
|
+
return await chat_actions.remove_users_from_group(
|
|
326
|
+
self.id,
|
|
327
|
+
user_ids,
|
|
328
|
+
clean_msg_period,
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
async def pin_message(
|
|
332
|
+
self,
|
|
333
|
+
message_id: int,
|
|
334
|
+
notify_pin: bool = True,
|
|
335
|
+
) -> bool:
|
|
336
|
+
"""Закрепляет сообщение в этом чате.
|
|
337
|
+
|
|
338
|
+
:param message_id: ID сообщения.
|
|
339
|
+
:type message_id: int
|
|
340
|
+
:param notify_pin: Отправить ли уведомление о закреплении.
|
|
341
|
+
:type notify_pin: bool
|
|
342
|
+
:returns: ``True``, если сервер принял запрос.
|
|
343
|
+
:rtype: bool
|
|
344
|
+
:raises RuntimeError: Если чат не привязан к клиенту.
|
|
345
|
+
"""
|
|
346
|
+
message_actions, _ = self._bound()
|
|
347
|
+
|
|
348
|
+
return await message_actions.pin_message(
|
|
349
|
+
self.id,
|
|
350
|
+
message_id,
|
|
351
|
+
notify_pin,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
async def update_settings(
|
|
355
|
+
self,
|
|
356
|
+
all_can_pin_message: bool | None = None,
|
|
357
|
+
only_owner_can_change_icon_title: bool | None = None,
|
|
358
|
+
only_admin_can_add_member: bool | None = None,
|
|
359
|
+
only_admin_can_call: bool | None = None,
|
|
360
|
+
members_can_see_private_link: bool | None = None,
|
|
361
|
+
) -> None:
|
|
362
|
+
"""Обновляет настройки группы.
|
|
363
|
+
|
|
364
|
+
:param all_can_pin_message: Разрешить всем участникам закреплять
|
|
365
|
+
сообщения.
|
|
366
|
+
:type all_can_pin_message: bool | None
|
|
367
|
+
:param only_owner_can_change_icon_title: Разрешить менять аватар и
|
|
368
|
+
название только владельцу.
|
|
369
|
+
:type only_owner_can_change_icon_title: bool | None
|
|
370
|
+
:param only_admin_can_add_member: Разрешить добавлять участников
|
|
371
|
+
только администраторам.
|
|
372
|
+
:type only_admin_can_add_member: bool | None
|
|
373
|
+
:param only_admin_can_call: Разрешить звонки только администраторам.
|
|
374
|
+
:type only_admin_can_call: bool | None
|
|
375
|
+
:param members_can_see_private_link: Разрешить участникам видеть
|
|
376
|
+
приватную invite-ссылку.
|
|
377
|
+
:type members_can_see_private_link: bool | None
|
|
378
|
+
:returns: ``None``.
|
|
379
|
+
:rtype: None
|
|
380
|
+
:raises RuntimeError: Если чат не привязан к клиенту.
|
|
381
|
+
"""
|
|
382
|
+
_, chat_actions = self._bound()
|
|
383
|
+
|
|
384
|
+
return await chat_actions.change_group_settings(
|
|
385
|
+
self.id,
|
|
386
|
+
all_can_pin_message=all_can_pin_message,
|
|
387
|
+
only_owner_can_change_icon_title=only_owner_can_change_icon_title,
|
|
388
|
+
only_admin_can_add_member=only_admin_can_add_member,
|
|
389
|
+
only_admin_can_call=only_admin_can_call,
|
|
390
|
+
members_can_see_private_link=members_can_see_private_link,
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
async def rework_invite_link(self) -> Chat:
|
|
394
|
+
"""Перевыпускает приватную invite-ссылку группы.
|
|
395
|
+
|
|
396
|
+
:returns: Обновленный чат с новой invite-ссылкой.
|
|
397
|
+
:rtype: Chat
|
|
398
|
+
:raises RuntimeError: Если чат не привязан к клиенту.
|
|
399
|
+
"""
|
|
400
|
+
_, chat_actions = self._bound()
|
|
401
|
+
|
|
402
|
+
return await chat_actions.rework_invite_link(self.id)
|
|
403
|
+
|
|
404
|
+
def _bound(self) -> tuple[MessageService, ChatService]:
|
|
405
|
+
if self._message_actions is None:
|
|
406
|
+
raise RuntimeError("Chat is not bound to a client.")
|
|
407
|
+
|
|
408
|
+
if self._chat_actions is None:
|
|
409
|
+
raise RuntimeError("Chat is not bound to a client.")
|
|
410
|
+
|
|
411
|
+
return self._message_actions, self._chat_actions
|
|
412
|
+
|
|
413
|
+
@property
|
|
414
|
+
def is_dialog(self) -> bool:
|
|
415
|
+
"""``True``, если чат является личным диалогом."""
|
|
416
|
+
return self.type == ChatType.DIALOG
|
|
417
|
+
|
|
418
|
+
@property
|
|
419
|
+
def is_group(self) -> bool:
|
|
420
|
+
"""``True``, если чат является группой."""
|
|
421
|
+
return self.type == ChatType.CHAT
|
|
422
|
+
|
|
423
|
+
@property
|
|
424
|
+
def is_channel(self) -> bool:
|
|
425
|
+
"""``True``, если чат является каналом."""
|
|
426
|
+
return self.type == ChatType.CHANNEL
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from pydantic import Field
|
|
2
|
+
|
|
3
|
+
from .base import CamelModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ElementAttributes(CamelModel):
|
|
7
|
+
url: str
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Element(CamelModel):
|
|
11
|
+
"""Форматированный элемент текста сообщения.
|
|
12
|
+
|
|
13
|
+
:ivar type: Тип элемента.
|
|
14
|
+
:vartype type: str
|
|
15
|
+
:ivar from_: Начальная позиция элемента.
|
|
16
|
+
:vartype from_: int | None
|
|
17
|
+
:ivar length: Длина элемента.
|
|
18
|
+
:vartype length: int
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
type: str
|
|
22
|
+
from_: int | None = Field(serialization_alias="from", default=None)
|
|
23
|
+
length: int
|
|
24
|
+
attributes: ElementAttributes | None = None
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ChatType(str, Enum):
|
|
5
|
+
"""Тип чата."""
|
|
6
|
+
|
|
7
|
+
DIALOG = "DIALOG"
|
|
8
|
+
CHAT = "CHAT"
|
|
9
|
+
CHANNEL = "CHANNEL"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AccessType(str, Enum):
|
|
13
|
+
"""Тип доступа к чату."""
|
|
14
|
+
|
|
15
|
+
PUBLIC = "PUBLIC"
|
|
16
|
+
PRIVATE = "PRIVATE"
|
|
17
|
+
SECRET = "SECRET"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MessageStatus(str, Enum):
|
|
21
|
+
"""Статус сообщения."""
|
|
22
|
+
|
|
23
|
+
EDITED = "EDITED"
|
|
24
|
+
REMOVED = "REMOVED"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from .base import CamelModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MaxApiError(CamelModel):
|
|
5
|
+
"""Ошибка, возвращенная API Max.
|
|
6
|
+
|
|
7
|
+
:ivar error: Код ошибки.
|
|
8
|
+
:vartype error: str
|
|
9
|
+
:ivar message: Сообщение ошибки.
|
|
10
|
+
:vartype message: str
|
|
11
|
+
:ivar title: Заголовок ошибки.
|
|
12
|
+
:vartype title: str
|
|
13
|
+
:ivar localized_message: Локализованное сообщение ошибки.
|
|
14
|
+
:vartype localized_message: str | None
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
error: str
|
|
18
|
+
message: str
|
|
19
|
+
title: str
|
|
20
|
+
localized_message: str | None
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from collections.abc import Generator, Iterator
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
from typing_extensions import override
|
|
6
|
+
|
|
7
|
+
from .base import CamelModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Folder(CamelModel):
|
|
11
|
+
"""Папка чатов.
|
|
12
|
+
|
|
13
|
+
:ivar source_id: ID источника папки в Max.
|
|
14
|
+
:vartype source_id: int
|
|
15
|
+
:ivar include: ID чатов, включенных в папку.
|
|
16
|
+
:vartype include: list[int]
|
|
17
|
+
:ivar options: Дополнительные настройки папки.
|
|
18
|
+
:vartype options: list[Any]
|
|
19
|
+
:ivar update_time: Время обновления в формате Unix time.
|
|
20
|
+
:vartype update_time: int
|
|
21
|
+
:ivar id: ID папки.
|
|
22
|
+
:vartype id: str
|
|
23
|
+
:ivar filters: Фильтры папки.
|
|
24
|
+
:vartype filters: list[Any]
|
|
25
|
+
:ivar title: Название папки.
|
|
26
|
+
:vartype title: str
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
source_id: int = 0
|
|
30
|
+
include: list[int] = Field(default_factory=list)
|
|
31
|
+
options: list[Any] = Field(default_factory=list)
|
|
32
|
+
update_time: int = 0
|
|
33
|
+
id: str = ""
|
|
34
|
+
filters: list[Any] = Field(default_factory=list)
|
|
35
|
+
title: str = ""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class FolderUpdate(CamelModel):
|
|
39
|
+
"""Обновление папки чатов.
|
|
40
|
+
|
|
41
|
+
:ivar folders_order: Порядок папок.
|
|
42
|
+
:vartype folders_order: list[str]
|
|
43
|
+
:ivar folder: Обновленная папка.
|
|
44
|
+
:vartype folder: Folder | None
|
|
45
|
+
:ivar folder_sync: Метка синхронизации папок.
|
|
46
|
+
:vartype folder_sync: int
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
folders_order: list[str] = Field(default_factory=list)
|
|
50
|
+
folder: Folder | None = None
|
|
51
|
+
folder_sync: int = 0
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class FolderList(CamelModel):
|
|
55
|
+
"""Список папок чатов.
|
|
56
|
+
|
|
57
|
+
:ivar folders_order: Порядок папок.
|
|
58
|
+
:vartype folders_order: list[str]
|
|
59
|
+
:ivar folders: Папки чатов.
|
|
60
|
+
:vartype folders: list[Folder]
|
|
61
|
+
:ivar all_filter_exclude_folders: Папки, исключенные общими фильтрами.
|
|
62
|
+
:vartype all_filter_exclude_folders: list[Any]
|
|
63
|
+
:ivar folder_sync: Метка синхронизации папок.
|
|
64
|
+
:vartype folder_sync: int
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
folders_order: list[str] = Field(default_factory=list)
|
|
68
|
+
folders: list[Folder] = Field(default_factory=list)
|
|
69
|
+
all_filter_exclude_folders: list[Any] = Field(default_factory=list)
|
|
70
|
+
folder_sync: int = 0
|
|
71
|
+
|
|
72
|
+
@override
|
|
73
|
+
def __iter__(self) -> Iterator[Folder]: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
74
|
+
yield from self.folders
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from pydantic import Field
|
|
2
|
+
|
|
3
|
+
from pymax.types.domain.sync import ConfigHash, SyncState
|
|
4
|
+
|
|
5
|
+
from .base import CamelModel
|
|
6
|
+
from .chat import Chat
|
|
7
|
+
from .message import Message
|
|
8
|
+
from .profile import Profile
|
|
9
|
+
from .user import User
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LoginConfig(CamelModel):
|
|
13
|
+
hash: ConfigHash | None = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class LoginResponse(CamelModel):
|
|
17
|
+
chats: list[Chat] = Field(default_factory=list)
|
|
18
|
+
profile: Profile
|
|
19
|
+
messages: dict[int, list[Message]] = Field(default_factory=dict) # chat_id -> [message]
|
|
20
|
+
contacts: list[User | None] = Field(default_factory=list)
|
|
21
|
+
token: str
|
|
22
|
+
time: int | None = None
|
|
23
|
+
config: LoginConfig | None = None
|
|
24
|
+
|
|
25
|
+
def update_sync_state(self, current: SyncState) -> SyncState:
|
|
26
|
+
sync_time = self.time
|
|
27
|
+
config_hash = self.config.hash if self.config is not None else None
|
|
28
|
+
|
|
29
|
+
return SyncState(
|
|
30
|
+
chats_sync=(sync_time if sync_time is not None else current.chats_sync),
|
|
31
|
+
contacts_sync=(sync_time if sync_time is not None else current.contacts_sync),
|
|
32
|
+
drafts_sync=(sync_time if sync_time is not None else current.drafts_sync),
|
|
33
|
+
presence_sync=(sync_time if sync_time is not None else current.presence_sync),
|
|
34
|
+
config_hash=(config_hash if config_hash is not None else current.config_hash),
|
|
35
|
+
)
|