maxapi-python 2.1.2__py3-none-any.whl → 2.2.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.1.2.dist-info → maxapi_python-2.2.0.dist-info}/METADATA +3 -11
- {maxapi_python-2.1.2.dist-info → maxapi_python-2.2.0.dist-info}/RECORD +66 -60
- pymax/__init__.py +18 -3
- pymax/api/auth/payloads.py +7 -0
- pymax/api/auth/service.py +33 -30
- pymax/api/binding.py +57 -0
- pymax/api/chats/service.py +34 -47
- pymax/api/messages/enums.py +1 -0
- pymax/api/messages/payloads.py +16 -1
- pymax/api/messages/service.py +85 -33
- pymax/api/models.py +4 -6
- pymax/api/response.py +2 -2
- pymax/api/self/service.py +17 -26
- pymax/api/session/payloads.py +2 -9
- pymax/api/session/service.py +1 -3
- pymax/api/uploads/payloads.py +3 -9
- pymax/api/uploads/service.py +33 -99
- pymax/api/users/service.py +8 -16
- pymax/app.py +20 -4
- pymax/auth/qr.py +3 -9
- pymax/auth/sms.py +23 -11
- pymax/base.py +38 -1
- pymax/client.py +3 -5
- pymax/client_web.py +1 -2
- pymax/config.py +42 -3
- pymax/connection/connection.py +48 -19
- pymax/connection/readers/tcp.py +1 -3
- pymax/dispatch/dispatcher.py +36 -18
- pymax/dispatch/enums.py +4 -0
- pymax/dispatch/mapping.py +34 -11
- pymax/dispatch/resolvers.py +18 -0
- pymax/dispatch/router.py +34 -0
- pymax/files/photo.py +4 -2
- pymax/formatting/markdown.py +22 -13
- pymax/infra/chat.py +12 -0
- pymax/infra/message.py +74 -3
- pymax/logging.py +35 -3
- pymax/protocol/tcp/compression.py +1 -3
- pymax/protocol/tcp/framing.py +1 -3
- pymax/protocol/tcp/payload.py +22 -42
- pymax/protocol/tcp/protocol.py +2 -8
- pymax/protocol/ws/protocol.py +3 -9
- pymax/session/protocol.py +2 -6
- pymax/session/store.py +8 -24
- pymax/telemetry/navigation.py +1 -3
- pymax/telemetry/service.py +5 -17
- pymax/transport/tcp.py +1 -3
- pymax/types/domain/attachments/__init__.py +1 -0
- pymax/types/domain/attachments/audio.py +4 -4
- pymax/types/domain/attachments/enums.py +1 -0
- pymax/types/domain/attachments/unknown.py +35 -0
- pymax/types/domain/attachments/video.py +2 -2
- pymax/types/domain/auth.py +24 -2
- pymax/types/domain/chat.py +38 -1
- pymax/types/domain/element.py +3 -3
- pymax/types/domain/message.py +34 -2
- pymax/types/domain/presence.py +3 -3
- pymax/types/domain/sync.py +5 -21
- pymax/types/events/__init__.py +4 -0
- pymax/types/events/mark.py +23 -0
- pymax/types/events/message.py +57 -5
- pymax/types/events/presence.py +15 -0
- pymax/types/events/reaction.py +21 -0
- pymax/types/events/typing.py +14 -0
- {maxapi_python-2.1.2.dist-info → maxapi_python-2.2.0.dist-info}/WHEEL +0 -0
- {maxapi_python-2.1.2.dist-info → maxapi_python-2.2.0.dist-info}/licenses/LICENSE +0 -0
pymax/types/domain/message.py
CHANGED
|
@@ -15,6 +15,7 @@ from pymax.types.domain import (
|
|
|
15
15
|
PhotoAttachment,
|
|
16
16
|
ShareAttachment,
|
|
17
17
|
StickerAttachment,
|
|
18
|
+
UnknownAttachment,
|
|
18
19
|
VideoAttachment,
|
|
19
20
|
)
|
|
20
21
|
|
|
@@ -26,7 +27,7 @@ if TYPE_CHECKING:
|
|
|
26
27
|
from pymax.api.messages.service import MessageService
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
KnownAttachment: TypeAlias = Annotated[
|
|
30
31
|
PhotoAttachment
|
|
31
32
|
| VideoAttachment
|
|
32
33
|
| FileAttachment
|
|
@@ -39,6 +40,7 @@ Attachment: TypeAlias = Annotated[
|
|
|
39
40
|
| CallAttachment,
|
|
40
41
|
Field(discriminator="type"),
|
|
41
42
|
]
|
|
43
|
+
Attachment: TypeAlias = KnownAttachment | UnknownAttachment
|
|
42
44
|
SendAttachment: TypeAlias = Photo | File | Video
|
|
43
45
|
SendAttachments: TypeAlias = list[SendAttachment] | None
|
|
44
46
|
|
|
@@ -90,7 +92,7 @@ class Message(CamelModel):
|
|
|
90
92
|
|
|
91
93
|
Сообщения, полученные через клиент, обычно уже привязаны к сервису
|
|
92
94
|
сообщений. После этого можно вызывать удобные методы объекта:
|
|
93
|
-
:meth:`reply`, :meth:`answer`, :meth:`pin`, :meth:`delete`,
|
|
95
|
+
:meth:`reply`, :meth:`answer`, :meth:`edit`, :meth:`pin`, :meth:`delete`,
|
|
94
96
|
:meth:`read`, :meth:`react`, :meth:`unreact` и :meth:`get_reactions`.
|
|
95
97
|
|
|
96
98
|
Используйте ``Message`` в обработчиках ``on_message`` и при работе с
|
|
@@ -259,6 +261,36 @@ class Message(CamelModel):
|
|
|
259
261
|
notify_pin=notify_pin,
|
|
260
262
|
)
|
|
261
263
|
|
|
264
|
+
async def edit(
|
|
265
|
+
self,
|
|
266
|
+
text: str,
|
|
267
|
+
attachment: SendAttachment | None = None,
|
|
268
|
+
attachments: SendAttachments = None,
|
|
269
|
+
) -> Message:
|
|
270
|
+
"""Редактирует текст и вложения этого сообщения.
|
|
271
|
+
|
|
272
|
+
:param text: Новый текст сообщения с поддержкой markdown.
|
|
273
|
+
:type text: str
|
|
274
|
+
:param attachment: Одно новое вложение.
|
|
275
|
+
:type attachment: SendAttachment | None
|
|
276
|
+
:param attachments: Список новых вложений. Имеет приоритет над
|
|
277
|
+
``attachment``.
|
|
278
|
+
:type attachments: SendAttachments
|
|
279
|
+
:returns: Отредактированное сообщение.
|
|
280
|
+
:rtype: Message
|
|
281
|
+
:raises RuntimeError: Если сообщение не привязано к сервису или не
|
|
282
|
+
содержит ``chat_id``.
|
|
283
|
+
"""
|
|
284
|
+
actions, chat_id = self._bound()
|
|
285
|
+
|
|
286
|
+
return await actions.edit_message(
|
|
287
|
+
chat_id=chat_id,
|
|
288
|
+
message_id=self.id,
|
|
289
|
+
text=text,
|
|
290
|
+
attachment=attachment,
|
|
291
|
+
attachments=attachments,
|
|
292
|
+
)
|
|
293
|
+
|
|
262
294
|
async def delete(self, for_me: bool = False) -> bool:
|
|
263
295
|
"""Удаляет это сообщение.
|
|
264
296
|
|
pymax/types/domain/presence.py
CHANGED
|
@@ -7,9 +7,9 @@ class Presence(CamelModel):
|
|
|
7
7
|
:ivar seen: Время последней активности в формате Unix time, если оно
|
|
8
8
|
передано сервером.
|
|
9
9
|
:vartype seen: int | None
|
|
10
|
-
:ivar status: Код статуса присутствия Max
|
|
11
|
-
:vartype status: int
|
|
10
|
+
:ivar status: Код статуса присутствия Max, если он передан сервером.
|
|
11
|
+
:vartype status: int | None
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
seen: int | None = None
|
|
15
|
-
status: int
|
|
15
|
+
status: int | None = None
|
pymax/types/domain/sync.py
CHANGED
|
@@ -68,29 +68,13 @@ class SyncOverrides(BaseModel):
|
|
|
68
68
|
:rtype: SyncState
|
|
69
69
|
"""
|
|
70
70
|
return SyncState(
|
|
71
|
-
chats_sync=(
|
|
72
|
-
self.chats_sync
|
|
73
|
-
if self.chats_sync is not None
|
|
74
|
-
else saved.chats_sync
|
|
75
|
-
),
|
|
71
|
+
chats_sync=(self.chats_sync if self.chats_sync is not None else saved.chats_sync),
|
|
76
72
|
contacts_sync=(
|
|
77
|
-
self.contacts_sync
|
|
78
|
-
if self.contacts_sync is not None
|
|
79
|
-
else saved.contacts_sync
|
|
80
|
-
),
|
|
81
|
-
drafts_sync=(
|
|
82
|
-
self.drafts_sync
|
|
83
|
-
if self.drafts_sync is not None
|
|
84
|
-
else saved.drafts_sync
|
|
73
|
+
self.contacts_sync if self.contacts_sync is not None else saved.contacts_sync
|
|
85
74
|
),
|
|
75
|
+
drafts_sync=(self.drafts_sync if self.drafts_sync is not None else saved.drafts_sync),
|
|
86
76
|
presence_sync=(
|
|
87
|
-
self.presence_sync
|
|
88
|
-
if self.presence_sync is not None
|
|
89
|
-
else saved.presence_sync
|
|
90
|
-
),
|
|
91
|
-
config_hash=(
|
|
92
|
-
self.config_hash
|
|
93
|
-
if self.config_hash is not None
|
|
94
|
-
else saved.config_hash
|
|
77
|
+
self.presence_sync if self.presence_sync is not None else saved.presence_sync
|
|
95
78
|
),
|
|
79
|
+
config_hash=(self.config_hash if self.config_hash is not None else saved.config_hash),
|
|
96
80
|
)
|
pymax/types/events/__init__.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
from .file import FileUploadSignal
|
|
2
|
+
from .mark import MessageReadEvent
|
|
2
3
|
from .message import MessageDeleteEvent
|
|
4
|
+
from .presence import PresenceEvent
|
|
5
|
+
from .reaction import ReactionUpdateEvent
|
|
6
|
+
from .typing import TypingEvent
|
|
3
7
|
from .video import VideoUploadSignal
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from pymax.types.domain.base import CamelModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MessageReadEvent(CamelModel):
|
|
5
|
+
"""Событие изменения отметки прочтения чата.
|
|
6
|
+
|
|
7
|
+
Handler ``on_message_read`` получает объект, когда пользователь отмечает
|
|
8
|
+
сообщения прочитанными или возвращает чат в непрочитанное состояние.
|
|
9
|
+
|
|
10
|
+
:ivar set_as_unread: Чат был явно отмечен непрочитанным.
|
|
11
|
+
:vartype set_as_unread: bool
|
|
12
|
+
:ivar chat_id: ID чата.
|
|
13
|
+
:vartype chat_id: int
|
|
14
|
+
:ivar user_id: ID пользователя, изменившего отметку.
|
|
15
|
+
:vartype user_id: int
|
|
16
|
+
:ivar mark: Временная отметка прочтения Max.
|
|
17
|
+
:vartype mark: int
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
set_as_unread: bool
|
|
21
|
+
chat_id: int
|
|
22
|
+
user_id: int
|
|
23
|
+
mark: int
|
pymax/types/events/message.py
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
|
-
from pydantic import PrivateAttr
|
|
5
|
+
from pydantic import PrivateAttr, model_validator
|
|
6
6
|
|
|
7
|
+
from pymax.logging import get_logger
|
|
7
8
|
from pymax.types.domain import Chat
|
|
8
9
|
from pymax.types.domain.base import CamelModel
|
|
10
|
+
from pymax.types.domain.message import Message
|
|
9
11
|
|
|
10
12
|
if TYPE_CHECKING:
|
|
11
13
|
from pymax.api.messages import MessageService
|
|
12
14
|
|
|
15
|
+
logger = get_logger(__name__)
|
|
16
|
+
|
|
13
17
|
|
|
14
18
|
class MessageDeleteEvent(CamelModel):
|
|
15
19
|
"""Событие удаления сообщений.
|
|
@@ -17,20 +21,68 @@ class MessageDeleteEvent(CamelModel):
|
|
|
17
21
|
Handler ``on_message_delete`` получает этот объект, когда Max сообщает об
|
|
18
22
|
удалении одного или нескольких сообщений в чате.
|
|
19
23
|
|
|
20
|
-
:ivar chat: Чат, в котором удалены сообщения.
|
|
21
|
-
:vartype chat: Chat
|
|
22
24
|
:ivar message_ids: ID удаленных сообщений.
|
|
23
25
|
:vartype message_ids: list[int]
|
|
26
|
+
:ivar chat_id: ID чата.
|
|
27
|
+
:vartype chat_id: int
|
|
28
|
+
:ivar chat: Чат, если Max прислал полный объект.
|
|
29
|
+
:vartype chat: Chat | None
|
|
30
|
+
:ivar message: Удаленное сообщение для WebSocket-события.
|
|
31
|
+
:vartype message: Message | None
|
|
24
32
|
:ivar ttl: Признак удаления из-за TTL, если Max его прислал.
|
|
25
33
|
:vartype ttl: bool
|
|
26
34
|
"""
|
|
27
35
|
|
|
28
|
-
chat: Chat
|
|
29
36
|
message_ids: list[int]
|
|
37
|
+
chat_id: int
|
|
38
|
+
chat: Chat | None = None
|
|
39
|
+
message: Message | None = None
|
|
30
40
|
ttl: bool = False
|
|
31
41
|
|
|
32
42
|
_actions: MessageService | None = PrivateAttr(default=None)
|
|
33
43
|
|
|
44
|
+
@model_validator(mode="before")
|
|
45
|
+
@classmethod
|
|
46
|
+
def normalize_payload(cls, data: Any) -> Any:
|
|
47
|
+
# i really hate it cause of stupid web version thats send other type
|
|
48
|
+
# of payload (128, expect 142)
|
|
49
|
+
# TODO: impl it in the better way maybe
|
|
50
|
+
|
|
51
|
+
if not isinstance(data, dict):
|
|
52
|
+
return data
|
|
53
|
+
|
|
54
|
+
if "chat" in data: # case opcode == 142
|
|
55
|
+
chat = data["chat"]
|
|
56
|
+
chat_id = chat.get("id") if isinstance(chat, dict) else getattr(chat, "id", None)
|
|
57
|
+
message_ids = data.get("messageIds", data.get("message_ids"))
|
|
58
|
+
if chat_id is None or message_ids is None:
|
|
59
|
+
return data
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
"chat": chat,
|
|
63
|
+
"ttl": data.get("ttl", False),
|
|
64
|
+
"messageIds": message_ids,
|
|
65
|
+
"chatId": chat_id,
|
|
66
|
+
}
|
|
67
|
+
if "message" in data: # case opcode == 128
|
|
68
|
+
message = data["message"]
|
|
69
|
+
message_id = (
|
|
70
|
+
message.get("id") if isinstance(message, dict) else getattr(message, "id", None)
|
|
71
|
+
)
|
|
72
|
+
chat_id = data.get("chatId", data.get("chat_id"))
|
|
73
|
+
if chat_id is None or message_id is None:
|
|
74
|
+
return data
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
"chatId": chat_id,
|
|
78
|
+
"message": message,
|
|
79
|
+
"ttl": data.get("ttl", False),
|
|
80
|
+
"messageIds": [message_id],
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
logger.warning("Illegal state during MessageDeleteEvent validation. Starting fallback")
|
|
84
|
+
return data # stupid fallback but who cares. Still better than KeyError
|
|
85
|
+
|
|
34
86
|
def bind(self, actions: MessageService) -> MessageDeleteEvent:
|
|
35
87
|
"""Привязывает сервис сообщений к событию удаления."""
|
|
36
88
|
self._actions = actions
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from pymax.types.domain.base import CamelModel
|
|
2
|
+
from pymax.types.domain.presence import Presence
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class PresenceEvent(CamelModel):
|
|
6
|
+
"""Событие изменения присутствия пользователя.
|
|
7
|
+
|
|
8
|
+
:ivar presence: Новое состояние присутствия.
|
|
9
|
+
:vartype presence: Presence
|
|
10
|
+
:ivar user_id: ID пользователя.
|
|
11
|
+
:vartype user_id: int
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
presence: Presence
|
|
15
|
+
user_id: int
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from pymax.types.domain.base import CamelModel
|
|
2
|
+
from pymax.types.domain.message import ReactionCounter
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ReactionUpdateEvent(CamelModel):
|
|
6
|
+
"""Событие обновления реакций сообщения.
|
|
7
|
+
|
|
8
|
+
:ivar message_id: ID сообщения.
|
|
9
|
+
:vartype message_id: str
|
|
10
|
+
:ivar chat_id: ID чата.
|
|
11
|
+
:vartype chat_id: int
|
|
12
|
+
:ivar counters: Счетчики реакций по типам.
|
|
13
|
+
:vartype counters: list[ReactionCounter]
|
|
14
|
+
:ivar total_count: Общее количество реакций.
|
|
15
|
+
:vartype total_count: int
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
message_id: str
|
|
19
|
+
chat_id: int
|
|
20
|
+
counters: list[ReactionCounter]
|
|
21
|
+
total_count: int
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from pymax.types.domain.base import CamelModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TypingEvent(CamelModel):
|
|
5
|
+
"""Событие набора текста пользователем.
|
|
6
|
+
|
|
7
|
+
:ivar chat_id: ID чата.
|
|
8
|
+
:vartype chat_id: int
|
|
9
|
+
:ivar user_id: ID пользователя, который набирает текст.
|
|
10
|
+
:vartype user_id: int
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
chat_id: int
|
|
14
|
+
user_id: int
|
|
File without changes
|
|
File without changes
|