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.
Files changed (168) hide show
  1. maxapi_python-2.0.0.dist-info/METADATA +217 -0
  2. maxapi_python-2.0.0.dist-info/RECORD +140 -0
  3. {maxapi_python-1.2.4.dist-info → maxapi_python-2.0.0.dist-info}/WHEEL +1 -1
  4. pymax/__init__.py +50 -105
  5. pymax/api/__init__.py +17 -0
  6. pymax/api/auth/__init__.py +1 -0
  7. pymax/api/auth/enums.py +17 -0
  8. pymax/api/auth/payloads.py +129 -0
  9. pymax/api/auth/service.py +313 -0
  10. pymax/api/auth/types.py +13 -0
  11. pymax/api/chats/__init__.py +8 -0
  12. pymax/api/chats/enums.py +27 -0
  13. pymax/api/chats/payloads.py +103 -0
  14. pymax/api/chats/service.py +277 -0
  15. pymax/api/facade.py +32 -0
  16. pymax/api/messages/__init__.py +1 -0
  17. pymax/api/messages/enums.py +17 -0
  18. pymax/api/messages/payloads.py +92 -0
  19. pymax/api/messages/service.py +337 -0
  20. pymax/api/models.py +13 -0
  21. pymax/api/response.py +123 -0
  22. pymax/api/self/__init__.py +2 -0
  23. pymax/api/self/enums.py +11 -0
  24. pymax/api/self/payloads.py +41 -0
  25. pymax/api/self/service.py +142 -0
  26. pymax/api/session/__init__.py +1 -0
  27. pymax/api/session/enums.py +10 -0
  28. pymax/api/session/payloads.py +76 -0
  29. pymax/api/session/service.py +72 -0
  30. pymax/api/uploads/__init__.py +1 -0
  31. pymax/api/uploads/models.py +49 -0
  32. pymax/api/uploads/payloads.py +25 -0
  33. pymax/api/uploads/service.py +458 -0
  34. pymax/api/users/__init__.py +2 -0
  35. pymax/api/users/enums.py +12 -0
  36. pymax/api/users/payloads.py +16 -0
  37. pymax/api/users/service.py +124 -0
  38. pymax/app.py +273 -0
  39. pymax/auth/__init__.py +25 -0
  40. pymax/auth/base.py +37 -0
  41. pymax/auth/email.py +0 -0
  42. pymax/auth/models.py +5 -0
  43. pymax/auth/providers.py +127 -0
  44. pymax/auth/qr.py +135 -0
  45. pymax/auth/service.py +25 -0
  46. pymax/auth/sms.py +122 -0
  47. pymax/base.py +204 -0
  48. pymax/client.py +106 -0
  49. pymax/client_web.py +83 -0
  50. pymax/config.py +215 -0
  51. pymax/connection/__init__.py +1 -0
  52. pymax/connection/connection.py +205 -0
  53. pymax/connection/pending.py +46 -0
  54. pymax/connection/readers/__init__.py +2 -0
  55. pymax/connection/readers/base.py +6 -0
  56. pymax/connection/readers/tcp.py +29 -0
  57. pymax/connection/readers/ws.py +14 -0
  58. pymax/dispatch/__init__.py +10 -0
  59. pymax/dispatch/dispatcher.py +222 -0
  60. pymax/dispatch/enums.py +12 -0
  61. pymax/dispatch/mapping.py +73 -0
  62. pymax/dispatch/resolvers.py +52 -0
  63. pymax/dispatch/router.py +216 -0
  64. pymax/exceptions.py +22 -89
  65. pymax/files/__init__.py +9 -0
  66. pymax/files/base.py +82 -0
  67. pymax/files/file.py +76 -0
  68. pymax/files/photo.py +108 -0
  69. pymax/files/static.py +10 -0
  70. pymax/files/video.py +74 -0
  71. pymax/formatting/__init__.py +0 -0
  72. pymax/formatting/markdown.py +217 -0
  73. pymax/infra/__init__.py +1 -0
  74. pymax/infra/auth.py +55 -0
  75. pymax/infra/base.py +15 -0
  76. pymax/infra/chat.py +240 -0
  77. pymax/infra/message.py +252 -0
  78. pymax/infra/protocol.py +9 -0
  79. pymax/infra/self.py +139 -0
  80. pymax/infra/user.py +107 -0
  81. pymax/logging.py +129 -0
  82. pymax/protocol/__init__.py +11 -0
  83. pymax/protocol/base.py +13 -0
  84. pymax/{static/enum.py → protocol/enums.py} +36 -79
  85. pymax/protocol/models.py +33 -0
  86. pymax/protocol/tcp/__init__.py +1 -0
  87. pymax/protocol/tcp/compression.py +97 -0
  88. pymax/protocol/tcp/framing.py +68 -0
  89. pymax/protocol/tcp/payload.py +127 -0
  90. pymax/protocol/tcp/protocol.py +68 -0
  91. pymax/protocol/ws/__init__.py +1 -0
  92. pymax/protocol/ws/protocol.py +27 -0
  93. pymax/py.typed +0 -0
  94. pymax/routers.py +8 -0
  95. pymax/session/__init__.py +3 -0
  96. pymax/session/models.py +11 -0
  97. pymax/session/protocol.py +14 -0
  98. pymax/session/store.py +232 -0
  99. pymax/telemetry/__init__.py +3 -0
  100. pymax/telemetry/navigation.py +181 -0
  101. pymax/telemetry/payloads.py +142 -0
  102. pymax/telemetry/service.py +225 -0
  103. pymax/transport/__init__.py +0 -0
  104. pymax/transport/base.py +14 -0
  105. pymax/transport/tcp.py +93 -0
  106. pymax/transport/websocket.py +50 -0
  107. pymax/types/__init__.py +2 -0
  108. pymax/types/domain/__init__.py +11 -0
  109. pymax/types/domain/attachments/__init__.py +11 -0
  110. pymax/types/domain/attachments/audio.py +35 -0
  111. pymax/types/domain/attachments/call.py +26 -0
  112. pymax/types/domain/attachments/contact.py +32 -0
  113. pymax/types/domain/attachments/control.py +20 -0
  114. pymax/types/domain/attachments/enums.py +27 -0
  115. pymax/types/domain/attachments/file.py +56 -0
  116. pymax/types/domain/attachments/keyboards/__init__.py +1 -0
  117. pymax/types/domain/attachments/keyboards/inline.py +19 -0
  118. pymax/types/domain/attachments/photo.py +45 -0
  119. pymax/types/domain/attachments/share.py +29 -0
  120. pymax/types/domain/attachments/sticker.py +50 -0
  121. pymax/types/domain/attachments/video.py +90 -0
  122. pymax/types/domain/auth.py +161 -0
  123. pymax/types/domain/base.py +17 -0
  124. pymax/types/domain/chat.py +426 -0
  125. pymax/types/domain/element.py +24 -0
  126. pymax/types/domain/enums.py +24 -0
  127. pymax/types/domain/error.py +20 -0
  128. pymax/types/domain/folder.py +74 -0
  129. pymax/types/domain/login.py +35 -0
  130. pymax/types/domain/message.py +378 -0
  131. pymax/types/domain/name.py +20 -0
  132. pymax/types/domain/profile.py +15 -0
  133. pymax/types/domain/session.py +52 -0
  134. pymax/types/domain/sync.py +80 -0
  135. pymax/types/domain/user.py +117 -0
  136. pymax/types/events/__init__.py +3 -0
  137. pymax/types/events/file.py +5 -0
  138. pymax/types/events/message.py +37 -0
  139. pymax/types/events/video.py +5 -0
  140. maxapi_python-1.2.4.dist-info/METADATA +0 -205
  141. maxapi_python-1.2.4.dist-info/RECORD +0 -33
  142. pymax/core.py +0 -390
  143. pymax/crud.py +0 -96
  144. pymax/files.py +0 -138
  145. pymax/filters.py +0 -164
  146. pymax/formatter.py +0 -31
  147. pymax/formatting.py +0 -74
  148. pymax/interfaces.py +0 -552
  149. pymax/mixins/__init__.py +0 -40
  150. pymax/mixins/auth.py +0 -368
  151. pymax/mixins/channel.py +0 -130
  152. pymax/mixins/group.py +0 -458
  153. pymax/mixins/handler.py +0 -285
  154. pymax/mixins/message.py +0 -879
  155. pymax/mixins/scheduler.py +0 -28
  156. pymax/mixins/self.py +0 -259
  157. pymax/mixins/socket.py +0 -297
  158. pymax/mixins/telemetry.py +0 -112
  159. pymax/mixins/user.py +0 -219
  160. pymax/mixins/websocket.py +0 -142
  161. pymax/models.py +0 -8
  162. pymax/navigation.py +0 -187
  163. pymax/payloads.py +0 -367
  164. pymax/protocols.py +0 -123
  165. pymax/static/constant.py +0 -89
  166. pymax/types.py +0 -1220
  167. pymax/utils.py +0 -90
  168. {maxapi_python-1.2.4.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
+ )