maxapi-python 2.4.0__py3-none-any.whl → 2.5.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.4.0.dist-info → maxapi_python-2.5.0.dist-info}/METADATA +22 -12
- maxapi_python-2.5.0.dist-info/RECORD +195 -0
- {maxapi_python-2.4.0.dist-info → maxapi_python-2.5.0.dist-info}/WHEEL +1 -1
- pymax/__init__.py +8 -2
- pymax/_data/apk_fingerprints.json +374 -17
- pymax/_data/rootca_ssl_rsa2022.crt +33 -0
- pymax/api/auth/service.py +15 -2
- pymax/api/auth/types.py +3 -0
- pymax/api/bots/payloads.py +8 -0
- pymax/api/bots/service.py +13 -1
- pymax/api/chats/enums.py +1 -0
- pymax/api/chats/payloads.py +21 -1
- pymax/api/chats/service.py +41 -0
- pymax/api/facade.py +2 -0
- pymax/api/messages/__init__.py +1 -1
- pymax/api/messages/enums.py +1 -0
- pymax/api/messages/payloads.py +56 -4
- pymax/api/messages/service.py +405 -27
- pymax/api/response.py +1 -1
- pymax/api/stories/__init__.py +2 -0
- pymax/api/stories/enums.py +19 -0
- pymax/api/stories/payloads.py +64 -0
- pymax/api/stories/service.py +198 -0
- pymax/api/uploads/payloads.py +42 -1
- pymax/api/uploads/service.py +171 -69
- pymax/app.py +39 -8
- pymax/auth/__init__.py +2 -0
- pymax/auth/exceptions.py +9 -0
- pymax/auth/providers.py +6 -2
- pymax/auth/qr.py +11 -1
- pymax/auth/sms.py +11 -1
- pymax/base.py +146 -27
- pymax/client.py +39 -11
- pymax/client_web.py +15 -12
- pymax/config.py +101 -53
- pymax/di/__init__.py +2 -0
- pymax/di/context.py +18 -0
- pymax/di/resolver.py +38 -0
- pymax/dispatch/__init__.py +7 -0
- pymax/dispatch/dispatcher.py +143 -40
- pymax/dispatch/enums.py +1 -0
- pymax/dispatch/mapping.py +23 -3
- pymax/dispatch/middleware.py +32 -0
- pymax/dispatch/resolvers.py +4 -0
- pymax/dispatch/router.py +86 -34
- pymax/files/base.py +58 -1
- pymax/files/video.py +32 -40
- pymax/files/voice.py +18 -4
- pymax/filters/__init__.py +15 -0
- pymax/filters/base.py +218 -0
- pymax/filters/containers/__init__.py +2 -0
- pymax/filters/containers/chat.py +240 -0
- pymax/filters/containers/message.py +147 -0
- pymax/filters/filters.py +211 -0
- pymax/filters/magic.py +13 -0
- pymax/filters/presets.py +88 -0
- pymax/filters/refs.py +56 -0
- pymax/fingerprint/fingerprint.py +5 -22
- pymax/fingerprint/models.py +1 -0
- pymax/formatting/markdown.py +55 -1
- pymax/fsm/__init__.py +3 -0
- pymax/fsm/context.py +30 -0
- pymax/fsm/protocol.py +14 -0
- pymax/fsm/state.py +70 -0
- pymax/fsm/storage.py +151 -0
- pymax/infra/base.py +2 -0
- pymax/infra/bots.py +20 -0
- pymax/infra/chat.py +37 -5
- pymax/infra/message.py +204 -9
- pymax/infra/protocol.py +5 -1
- pymax/infra/stories.py +205 -0
- pymax/integrations/__init__.py +0 -0
- pymax/integrations/dishka.py +109 -0
- pymax/protocol/enums.py +2 -0
- pymax/protocol/tcp/payload.py +0 -2
- pymax/session/__init__.py +1 -1
- pymax/session/models.py +30 -0
- pymax/session/protocol.py +33 -7
- pymax/session/store.py +73 -5
- pymax/transport/tcp.py +11 -3
- pymax/types/domain/__init__.py +23 -1
- pymax/types/domain/attachments/__init__.py +1 -1
- pymax/types/domain/attachments/call.py +7 -1
- pymax/types/domain/attachments/contact.py +3 -3
- pymax/types/domain/attachments/control.py +3 -0
- pymax/types/domain/attachments/enums.py +16 -0
- pymax/types/domain/attachments/keyboards/__init__.py +1 -1
- pymax/types/domain/attachments/keyboards/enums.py +12 -0
- pymax/types/domain/attachments/keyboards/inline.py +74 -3
- pymax/types/domain/attachments/video.py +3 -3
- pymax/types/domain/callback.py +19 -0
- pymax/types/domain/comment.py +24 -0
- pymax/types/domain/enums.py +7 -0
- pymax/types/domain/message.py +158 -9
- pymax/types/domain/story.py +126 -0
- pymax/types/events/reaction.py +28 -4
- pymax/versions/__init__.py +2 -0
- pymax/versions/catalog.py +104 -0
- pymax/versions/exceptions.py +10 -0
- maxapi_python-2.4.0.dist-info/RECORD +0 -161
- {maxapi_python-2.4.0.dist-info → maxapi_python-2.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -10,8 +10,8 @@ from .enums import AttachmentType
|
|
|
10
10
|
class ContactAttachment(CamelModel):
|
|
11
11
|
"""Контактное вложение сообщения.
|
|
12
12
|
|
|
13
|
-
:ivar contact_id: ID
|
|
14
|
-
:vartype contact_id: int
|
|
13
|
+
:ivar contact_id: ID контакта, если Max его прислал.
|
|
14
|
+
:vartype contact_id: int | None
|
|
15
15
|
:ivar first_name: Имя контакта.
|
|
16
16
|
:vartype first_name: str | None
|
|
17
17
|
:ivar last_name: Фамилия контакта.
|
|
@@ -24,7 +24,7 @@ class ContactAttachment(CamelModel):
|
|
|
24
24
|
:vartype type: Literal[AttachmentType.CONTACT]
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
contact_id: int
|
|
27
|
+
contact_id: int | None = None
|
|
28
28
|
first_name: str | None = None
|
|
29
29
|
last_name: str | None = None
|
|
30
30
|
name: str | None = None
|
|
@@ -14,7 +14,10 @@ class ControlAttachment(CamelModel):
|
|
|
14
14
|
:vartype type: Literal[AttachmentType.CONTROL]
|
|
15
15
|
:ivar event: Событие управления.
|
|
16
16
|
:vartype event: str
|
|
17
|
+
:ivar title: Заголовок служебного события, если он есть в payload-е.
|
|
18
|
+
:vartype title: str | None
|
|
17
19
|
"""
|
|
18
20
|
|
|
19
21
|
type: Literal[AttachmentType.CONTROL] = Field(alias="_type")
|
|
20
22
|
event: str
|
|
23
|
+
title: str | None = None
|
|
@@ -42,3 +42,19 @@ class PollFlags(IntFlag):
|
|
|
42
42
|
FLAG_SETTINGS_CLOSED = 8
|
|
43
43
|
FLAG_SETTINGS_QUIZ = 16
|
|
44
44
|
FLAG_SETTINGS_CAN_FORWARD = 32
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class CallType(str, Enum):
|
|
48
|
+
"""Тип звонка во входящем ``CallAttachment``."""
|
|
49
|
+
|
|
50
|
+
AUDIO = "AUDIO"
|
|
51
|
+
VIDEO = "VIDEO"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class HangupType(str, Enum):
|
|
55
|
+
"""Причина завершения звонка во входящем ``CallAttachment``."""
|
|
56
|
+
|
|
57
|
+
MISSED = "MISSED"
|
|
58
|
+
REJECTED = "REJECTED"
|
|
59
|
+
CANCELED = "CANCELED"
|
|
60
|
+
HUNGUP = "HUNGUP"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
from .inline import InlineKeyboardAttachment
|
|
1
|
+
from .inline import Button, ButtonType, InlineKeyboardAttachment
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ButtonType(str, Enum):
|
|
5
|
+
CALLBACK = "CALLBACK"
|
|
6
|
+
LINK = "LINK"
|
|
7
|
+
CHAT = "CHAT"
|
|
8
|
+
REQUEST_GEO_LOCATION = "REQUEST_GEO_LOCATION"
|
|
9
|
+
REQUEST_CONTACT = "REQUEST_CONTACT"
|
|
10
|
+
OPEN_APP = "OPEN_APP"
|
|
11
|
+
MESSAGE = "MESSAGE"
|
|
12
|
+
CLIPBOARD = "CLIPBOARD"
|
|
@@ -1,10 +1,78 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Annotated, Literal, TypeAlias
|
|
2
2
|
|
|
3
3
|
from pydantic import Field
|
|
4
4
|
|
|
5
5
|
from pymax.types.domain.attachments import AttachmentType
|
|
6
6
|
from pymax.types.domain.base import CamelModel
|
|
7
7
|
|
|
8
|
+
from .enums import ButtonType
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseButton(CamelModel):
|
|
12
|
+
text: str
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CallbackButton(BaseButton):
|
|
16
|
+
type: Literal[ButtonType.CALLBACK] = ButtonType.CALLBACK
|
|
17
|
+
text: str
|
|
18
|
+
payload: str
|
|
19
|
+
intent: str
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LinkButton(BaseButton):
|
|
23
|
+
type: Literal[ButtonType.LINK] = ButtonType.LINK
|
|
24
|
+
url: str
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ChatButton(BaseButton):
|
|
28
|
+
type: Literal[ButtonType.CHAT] = ButtonType.CHAT
|
|
29
|
+
payload: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class GeoLocationButton(BaseButton):
|
|
33
|
+
type: Literal[ButtonType.REQUEST_GEO_LOCATION] = ButtonType.REQUEST_GEO_LOCATION
|
|
34
|
+
quick: bool | None = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class RequestContactButton(BaseButton):
|
|
38
|
+
type: Literal[ButtonType.REQUEST_CONTACT] = ButtonType.REQUEST_CONTACT
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class OpenAppButton(BaseButton):
|
|
42
|
+
type: Literal[ButtonType.OPEN_APP] = ButtonType.OPEN_APP
|
|
43
|
+
contact_id: int | None = None
|
|
44
|
+
payload: str | None = None
|
|
45
|
+
web_app: str | None = None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class MessageButton(BaseButton):
|
|
49
|
+
type: Literal[ButtonType.MESSAGE] = ButtonType.MESSAGE
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ClipboardButton(BaseButton):
|
|
53
|
+
type: Literal[ButtonType.CLIPBOARD] = ButtonType.CLIPBOARD
|
|
54
|
+
payload: str
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
Button: TypeAlias = Annotated[
|
|
58
|
+
CallbackButton
|
|
59
|
+
| ChatButton
|
|
60
|
+
| LinkButton
|
|
61
|
+
| RequestContactButton
|
|
62
|
+
| GeoLocationButton
|
|
63
|
+
| OpenAppButton
|
|
64
|
+
| MessageButton
|
|
65
|
+
| ClipboardButton,
|
|
66
|
+
Field(discriminator="type"),
|
|
67
|
+
]
|
|
68
|
+
ButtonRow: TypeAlias = list[Button]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class InlineKeyboard(CamelModel):
|
|
72
|
+
"""Inline-клавиатура со списком строк кнопок в ``buttons``."""
|
|
73
|
+
|
|
74
|
+
buttons: list[ButtonRow]
|
|
75
|
+
|
|
8
76
|
|
|
9
77
|
class InlineKeyboardAttachment(CamelModel):
|
|
10
78
|
"""Вложение inline-клавиатуры.
|
|
@@ -12,8 +80,11 @@ class InlineKeyboardAttachment(CamelModel):
|
|
|
12
80
|
:ivar type: Тип вложения.
|
|
13
81
|
:vartype type: Literal[AttachmentType.INLINE_KEYBOARD]
|
|
14
82
|
:ivar keyboard: Данные inline-клавиатуры.
|
|
15
|
-
:vartype keyboard:
|
|
83
|
+
:vartype keyboard: InlineKeyboard
|
|
84
|
+
:ivar callback_id: ID клавиатуры для ``client.send_callback()``.
|
|
85
|
+
:vartype callback_id: str
|
|
16
86
|
"""
|
|
17
87
|
|
|
18
88
|
type: Literal[AttachmentType.INLINE_KEYBOARD] = Field(alias="_type")
|
|
19
|
-
keyboard:
|
|
89
|
+
keyboard: InlineKeyboard
|
|
90
|
+
callback_id: str
|
|
@@ -32,8 +32,8 @@ class VideoAttachment(CamelModel):
|
|
|
32
32
|
:vartype video_id: int
|
|
33
33
|
:ivar duration: Длительность видео.
|
|
34
34
|
:vartype duration: int | None
|
|
35
|
-
:ivar preview_data: Данные
|
|
36
|
-
:vartype preview_data: bytes
|
|
35
|
+
:ivar preview_data: Данные превью, если Max их прислал.
|
|
36
|
+
:vartype preview_data: bytes | None
|
|
37
37
|
:ivar type: Тип вложения.
|
|
38
38
|
:vartype type: Literal[AttachmentType.VIDEO]
|
|
39
39
|
:ivar thumbnail: URL миниатюры.
|
|
@@ -48,7 +48,7 @@ class VideoAttachment(CamelModel):
|
|
|
48
48
|
width: int
|
|
49
49
|
video_id: int
|
|
50
50
|
duration: int | None = None
|
|
51
|
-
preview_data: bytes
|
|
51
|
+
preview_data: bytes | None = None
|
|
52
52
|
type: Literal[AttachmentType.VIDEO] = Field(alias="_type")
|
|
53
53
|
thumbnail: str
|
|
54
54
|
token: str
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .base import CamelModel
|
|
2
|
+
from .chat import Chat
|
|
3
|
+
from .message import Message
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CallbackResponse(CamelModel):
|
|
7
|
+
"""Результат нажатия inline-кнопки бота.
|
|
8
|
+
|
|
9
|
+
``success`` показывает результат операции. Необязательные ``message`` и
|
|
10
|
+
``chat`` содержат дополнительные данные ответа Max и поддерживают методы
|
|
11
|
+
действий, если ответ получен через клиент.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
success: bool
|
|
15
|
+
unread: int
|
|
16
|
+
mark: int
|
|
17
|
+
message: Message | None = None
|
|
18
|
+
chat: Chat | None = None
|
|
19
|
+
chat_access_token: str | None = None
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from .base import CamelModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CommentsInfo(CamelModel):
|
|
5
|
+
"""Счетчики комментариев поста.
|
|
6
|
+
|
|
7
|
+
:ivar total_count: Общее количество комментариев.
|
|
8
|
+
:vartype total_count: int
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
total_count: int = 0
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CommentsInfoUpdate(CamelModel):
|
|
15
|
+
"""Обновление счетчиков комментариев поста.
|
|
16
|
+
|
|
17
|
+
:ivar post_id: ID поста.
|
|
18
|
+
:vartype post_id: int
|
|
19
|
+
:ivar comments_info: Счетчики комментариев поста, если Max их прислал.
|
|
20
|
+
:vartype comments_info: CommentsInfo | None
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
post_id: int
|
|
24
|
+
comments_info: CommentsInfo | None
|
pymax/types/domain/enums.py
CHANGED
pymax/types/domain/message.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections.abc import Sequence
|
|
4
|
-
from typing import TYPE_CHECKING, Annotated, Any, TypeAlias
|
|
4
|
+
from typing import TYPE_CHECKING, Annotated, Any, Literal, TypeAlias
|
|
5
5
|
|
|
6
6
|
from pydantic import Field, PrivateAttr, model_validator
|
|
7
7
|
|
|
@@ -24,10 +24,10 @@ from pymax.types.domain import (
|
|
|
24
24
|
|
|
25
25
|
from .base import CamelModel
|
|
26
26
|
from .element import Element
|
|
27
|
-
from .enums import MessageStatus
|
|
27
|
+
from .enums import AccessType, LinkType, MessageStatus
|
|
28
28
|
|
|
29
29
|
if TYPE_CHECKING:
|
|
30
|
-
from pymax.api.messages
|
|
30
|
+
from pymax.api.messages import DateTimeUnion, MessageService
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
KnownAttachment: TypeAlias = Annotated[
|
|
@@ -47,6 +47,12 @@ KnownAttachment: TypeAlias = Annotated[
|
|
|
47
47
|
Attachment: TypeAlias = KnownAttachment | UnknownAttachment
|
|
48
48
|
SendAttachment: TypeAlias = Photo | File | Video | Poll | Voice | VideoNote
|
|
49
49
|
SendAttachments: TypeAlias = Sequence[SendAttachment] | None
|
|
50
|
+
Link: TypeAlias = Annotated["ReplyLink | ForwardLink", Field(discriminator="type")]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class MessageLink(CamelModel):
|
|
54
|
+
message: Message
|
|
55
|
+
chat_id: int
|
|
50
56
|
|
|
51
57
|
|
|
52
58
|
class ReactionCounter(CamelModel):
|
|
@@ -91,6 +97,48 @@ class ReadState(CamelModel):
|
|
|
91
97
|
mark: int
|
|
92
98
|
|
|
93
99
|
|
|
100
|
+
class DelayedAttributes(CamelModel):
|
|
101
|
+
time_to_fire: int
|
|
102
|
+
notify_sender: bool
|
|
103
|
+
notify_opponents: bool
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class ReplyLink(MessageLink):
|
|
107
|
+
"""Источник сообщения, отправленного как reply.
|
|
108
|
+
|
|
109
|
+
:ivar message: Сообщение, на которое ответили.
|
|
110
|
+
:vartype message: Message
|
|
111
|
+
:ivar chat_id: ID чата исходного сообщения.
|
|
112
|
+
:vartype chat_id: int
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
type: Literal[LinkType.REPLY] = LinkType.REPLY
|
|
116
|
+
message: Message
|
|
117
|
+
chat_id: int
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class ForwardLink(MessageLink):
|
|
121
|
+
"""Источник пересланного сообщения.
|
|
122
|
+
|
|
123
|
+
Помимо исходного сообщения содержит доступные в payload-е имя, ссылку,
|
|
124
|
+
тип доступа и иконку исходного чата. Для скрытого источника эти метаданные
|
|
125
|
+
могут быть ``None``.
|
|
126
|
+
|
|
127
|
+
:ivar message: Исходное сообщение.
|
|
128
|
+
:vartype message: Message
|
|
129
|
+
:ivar chat_id: ID исходного чата.
|
|
130
|
+
:vartype chat_id: int
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
type: Literal[LinkType.FORWARD] = LinkType.FORWARD
|
|
134
|
+
message: Message
|
|
135
|
+
chat_id: int
|
|
136
|
+
chat_name: str | None = None
|
|
137
|
+
chat_link: str | None = None
|
|
138
|
+
chat_access_type: AccessType | None = None
|
|
139
|
+
chat_icon_url: str | None = None
|
|
140
|
+
|
|
141
|
+
|
|
94
142
|
class Message(CamelModel):
|
|
95
143
|
"""Сообщение Max с методами для действий над ним.
|
|
96
144
|
|
|
@@ -120,6 +168,8 @@ class Message(CamelModel):
|
|
|
120
168
|
:vartype id: int
|
|
121
169
|
:ivar chat_id: ID чата, если он есть в данных сообщения.
|
|
122
170
|
:vartype chat_id: int | None
|
|
171
|
+
:ivar post_id: ID поста канала, если сообщение является комментарием.
|
|
172
|
+
:vartype post_id: int | None
|
|
123
173
|
:ivar sender: ID отправителя.
|
|
124
174
|
:vartype sender: int | None
|
|
125
175
|
:ivar text: Текст сообщения.
|
|
@@ -130,7 +180,8 @@ class Message(CamelModel):
|
|
|
130
180
|
:vartype type: str
|
|
131
181
|
:ivar cid: Клиентский ID сообщения, если он есть в payload-е.
|
|
132
182
|
:vartype cid: int | None
|
|
133
|
-
:ivar attaches: Вложения сообщения.
|
|
183
|
+
:ivar attaches: Вложения сообщения. Неизвестный ``_type`` представлен как
|
|
184
|
+
``UnknownAttachment`` с сохраненными дополнительными полями.
|
|
134
185
|
:vartype attaches: list[Attachment]
|
|
135
186
|
:ivar stats: Дополнительная статистика сообщения от Max.
|
|
136
187
|
:vartype stats: dict[str, Any] | None
|
|
@@ -150,10 +201,17 @@ class Message(CamelModel):
|
|
|
150
201
|
:vartype mark: int | None
|
|
151
202
|
:ivar elements: Форматированные элементы текста сообщения.
|
|
152
203
|
:vartype elements: list[Element]
|
|
204
|
+
:ivar delayed_attributes: Время срабатывания в миллисекундах и настройки
|
|
205
|
+
уведомлений для отложенного сообщения; ``None`` для обычного.
|
|
206
|
+
:vartype delayed_attributes: DelayedAttributes | None
|
|
207
|
+
:ivar link: Исходное сообщение и чат для reply или forward; ``None`` для
|
|
208
|
+
обычного сообщения без связи.
|
|
209
|
+
:vartype link: ReplyLink | ForwardLink | None
|
|
153
210
|
"""
|
|
154
211
|
|
|
155
212
|
id: int
|
|
156
213
|
chat_id: int | None = None
|
|
214
|
+
post_id: int | None = None
|
|
157
215
|
sender: int | None = None
|
|
158
216
|
text: str = ""
|
|
159
217
|
time: int
|
|
@@ -169,6 +227,8 @@ class Message(CamelModel):
|
|
|
169
227
|
unread: int | None = None
|
|
170
228
|
mark: int | None = None
|
|
171
229
|
elements: list[Element] = Field(default_factory=list)
|
|
230
|
+
delayed_attributes: DelayedAttributes | None = None
|
|
231
|
+
link: Link | None = None
|
|
172
232
|
|
|
173
233
|
_actions: MessageService | None = PrivateAttr(default=None)
|
|
174
234
|
|
|
@@ -189,8 +249,9 @@ class Message(CamelModel):
|
|
|
189
249
|
attachments: SendAttachments = None,
|
|
190
250
|
*,
|
|
191
251
|
notify: bool = True,
|
|
252
|
+
send_at: DateTimeUnion | None = None,
|
|
192
253
|
) -> Message:
|
|
193
|
-
"""Отправляет ответ
|
|
254
|
+
"""Отправляет ответ в тот же чат или ветку комментариев.
|
|
194
255
|
|
|
195
256
|
:param text: Текст сообщения.
|
|
196
257
|
:type text: str | None
|
|
@@ -198,19 +259,43 @@ class Message(CamelModel):
|
|
|
198
259
|
:type attachments: SendAttachments
|
|
199
260
|
:param notify: Отправить ли получателям push-уведомление.
|
|
200
261
|
:type notify: bool
|
|
262
|
+
:param send_at: Абсолютный ``datetime``, относительный ``timedelta``
|
|
263
|
+
или Unix time в секундах. ``None`` и ``0`` отправляют сразу.
|
|
264
|
+
:type send_at: DateTimeUnion | None
|
|
201
265
|
:returns: Отправленное сообщение.
|
|
202
266
|
:rtype: Message
|
|
203
267
|
:raises RuntimeError: Если сообщение не привязано к сервису или не
|
|
204
268
|
содержит ``chat_id``.
|
|
269
|
+
:raises ValueError: Если для комментария задана отложенная отправка.
|
|
205
270
|
"""
|
|
206
271
|
actions, chat_id = self._bound()
|
|
207
272
|
|
|
273
|
+
if self.post_id is not None:
|
|
274
|
+
if send_at:
|
|
275
|
+
raise ValueError("Scheduled comments are not supported")
|
|
276
|
+
|
|
277
|
+
message = await actions.send_comment(
|
|
278
|
+
chat_id=chat_id,
|
|
279
|
+
post_id=self.post_id,
|
|
280
|
+
text=text,
|
|
281
|
+
reply_to=self.id,
|
|
282
|
+
attachments=attachments,
|
|
283
|
+
notify=notify,
|
|
284
|
+
)
|
|
285
|
+
if message.chat_id is None:
|
|
286
|
+
message.chat_id = chat_id
|
|
287
|
+
if message.post_id is None:
|
|
288
|
+
message.post_id = self.post_id
|
|
289
|
+
|
|
290
|
+
return message
|
|
291
|
+
|
|
208
292
|
return await actions.send_message(
|
|
209
293
|
chat_id=chat_id,
|
|
210
294
|
text=text,
|
|
211
295
|
reply_to=self.id,
|
|
212
296
|
attachments=attachments,
|
|
213
297
|
notify=notify,
|
|
298
|
+
send_at=send_at,
|
|
214
299
|
)
|
|
215
300
|
|
|
216
301
|
async def answer(
|
|
@@ -220,8 +305,9 @@ class Message(CamelModel):
|
|
|
220
305
|
attachments: SendAttachments = None,
|
|
221
306
|
*,
|
|
222
307
|
notify: bool = True,
|
|
308
|
+
send_at: DateTimeUnion | None = None,
|
|
223
309
|
) -> Message:
|
|
224
|
-
"""Отправляет сообщение в тот же
|
|
310
|
+
"""Отправляет сообщение в тот же чат или ветку комментариев.
|
|
225
311
|
|
|
226
312
|
:param text: Текст сообщения.
|
|
227
313
|
:type text: str | None
|
|
@@ -231,19 +317,43 @@ class Message(CamelModel):
|
|
|
231
317
|
:type attachments: SendAttachments
|
|
232
318
|
:param notify: Отправить ли получателям push-уведомление.
|
|
233
319
|
:type notify: bool
|
|
320
|
+
:param send_at: Абсолютный ``datetime``, относительный ``timedelta``
|
|
321
|
+
или Unix time в секундах. ``None`` и ``0`` отправляют сразу.
|
|
322
|
+
:type send_at: DateTimeUnion | None
|
|
234
323
|
:returns: Отправленное сообщение.
|
|
235
324
|
:rtype: Message
|
|
236
325
|
:raises RuntimeError: Если сообщение не привязано к сервису или не
|
|
237
326
|
содержит ``chat_id``.
|
|
327
|
+
:raises ValueError: Если для комментария задана отложенная отправка.
|
|
238
328
|
"""
|
|
239
329
|
actions, chat_id = self._bound()
|
|
240
330
|
|
|
331
|
+
if self.post_id is not None:
|
|
332
|
+
if send_at:
|
|
333
|
+
raise ValueError("Scheduled comments are not supported")
|
|
334
|
+
|
|
335
|
+
message = await actions.send_comment(
|
|
336
|
+
chat_id=chat_id,
|
|
337
|
+
post_id=self.post_id,
|
|
338
|
+
text=text,
|
|
339
|
+
reply_to=reply_to,
|
|
340
|
+
attachments=attachments,
|
|
341
|
+
notify=notify,
|
|
342
|
+
)
|
|
343
|
+
if message.chat_id is None:
|
|
344
|
+
message.chat_id = chat_id
|
|
345
|
+
if message.post_id is None:
|
|
346
|
+
message.post_id = self.post_id
|
|
347
|
+
|
|
348
|
+
return message
|
|
349
|
+
|
|
241
350
|
return await actions.send_message(
|
|
242
351
|
chat_id=chat_id,
|
|
243
352
|
text=text,
|
|
244
353
|
reply_to=reply_to,
|
|
245
354
|
attachments=attachments,
|
|
246
355
|
notify=notify,
|
|
356
|
+
send_at=send_at,
|
|
247
357
|
)
|
|
248
358
|
|
|
249
359
|
async def forward(
|
|
@@ -308,6 +418,21 @@ class Message(CamelModel):
|
|
|
308
418
|
"""
|
|
309
419
|
actions, chat_id = self._bound()
|
|
310
420
|
|
|
421
|
+
if self.post_id is not None:
|
|
422
|
+
message = await actions.edit_comment(
|
|
423
|
+
chat_id=chat_id,
|
|
424
|
+
post_id=self.post_id,
|
|
425
|
+
message_id=self.id,
|
|
426
|
+
text=text,
|
|
427
|
+
attachments=attachments,
|
|
428
|
+
)
|
|
429
|
+
if message.chat_id is None:
|
|
430
|
+
message.chat_id = chat_id
|
|
431
|
+
if message.post_id is None:
|
|
432
|
+
message.post_id = self.post_id
|
|
433
|
+
|
|
434
|
+
return message
|
|
435
|
+
|
|
311
436
|
return await actions.edit_message(
|
|
312
437
|
chat_id=chat_id,
|
|
313
438
|
message_id=self.id,
|
|
@@ -327,6 +452,14 @@ class Message(CamelModel):
|
|
|
327
452
|
"""
|
|
328
453
|
actions, chat_id = self._bound()
|
|
329
454
|
|
|
455
|
+
if self.post_id is not None:
|
|
456
|
+
return await actions.delete_comment(
|
|
457
|
+
chat_id=chat_id,
|
|
458
|
+
post_id=self.post_id,
|
|
459
|
+
message_ids=[self.id],
|
|
460
|
+
for_me=for_me,
|
|
461
|
+
)
|
|
462
|
+
|
|
330
463
|
return await actions.delete_message(
|
|
331
464
|
chat_id=chat_id,
|
|
332
465
|
message_ids=[self.id],
|
|
@@ -360,9 +493,17 @@ class Message(CamelModel):
|
|
|
360
493
|
"""
|
|
361
494
|
actions, chat_id = self._bound()
|
|
362
495
|
|
|
496
|
+
if self.post_id is not None:
|
|
497
|
+
return await actions.add_comment_reaction(
|
|
498
|
+
chat_id=chat_id,
|
|
499
|
+
post_id=self.post_id,
|
|
500
|
+
message_id=self.id,
|
|
501
|
+
reaction=reaction,
|
|
502
|
+
)
|
|
503
|
+
|
|
363
504
|
return await actions.add_reaction(
|
|
364
505
|
chat_id=chat_id,
|
|
365
|
-
message_id=
|
|
506
|
+
message_id=self.id,
|
|
366
507
|
reaction=reaction,
|
|
367
508
|
)
|
|
368
509
|
|
|
@@ -376,9 +517,16 @@ class Message(CamelModel):
|
|
|
376
517
|
"""
|
|
377
518
|
actions, chat_id = self._bound()
|
|
378
519
|
|
|
520
|
+
if self.post_id is not None:
|
|
521
|
+
return await actions.remove_comment_reaction(
|
|
522
|
+
chat_id=chat_id,
|
|
523
|
+
post_id=self.post_id,
|
|
524
|
+
message_id=self.id,
|
|
525
|
+
)
|
|
526
|
+
|
|
379
527
|
return await actions.remove_reaction(
|
|
380
528
|
chat_id=chat_id,
|
|
381
|
-
message_id=
|
|
529
|
+
message_id=self.id,
|
|
382
530
|
)
|
|
383
531
|
|
|
384
532
|
async def get_reactions(self) -> dict[str, ReactionInfo] | None:
|
|
@@ -394,7 +542,7 @@ class Message(CamelModel):
|
|
|
394
542
|
|
|
395
543
|
return await actions.get_reactions(
|
|
396
544
|
chat_id=chat_id,
|
|
397
|
-
message_ids=[
|
|
545
|
+
message_ids=[self.id],
|
|
398
546
|
)
|
|
399
547
|
|
|
400
548
|
def _bound(self) -> tuple[MessageService, int]:
|
|
@@ -427,6 +575,7 @@ class Message(CamelModel):
|
|
|
427
575
|
return {
|
|
428
576
|
**message,
|
|
429
577
|
"chatId": value.get("chatId"),
|
|
578
|
+
"postId": value.get("postId"),
|
|
430
579
|
"prevMessageId": value.get("prevMessageId"),
|
|
431
580
|
"ttl": value.get("ttl"),
|
|
432
581
|
"unread": value.get("unread"),
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
from typing import Annotated, Literal, TypeAlias
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from .attachments.enums import AttachmentType
|
|
6
|
+
from .base import CamelModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class StoryCoordinates(CamelModel):
|
|
10
|
+
"""Положение слоя сторис в долях ширины и высоты кадра."""
|
|
11
|
+
|
|
12
|
+
x: float
|
|
13
|
+
y: float
|
|
14
|
+
w: float
|
|
15
|
+
h: float
|
|
16
|
+
rotation: float = 0
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class StoryClickableLink(CamelModel):
|
|
20
|
+
"""Ссылка слоя сторис и результат ее проверки сервером."""
|
|
21
|
+
|
|
22
|
+
url: str
|
|
23
|
+
check_result: int | None = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class StoryLayer(CamelModel):
|
|
27
|
+
"""Слой сторис со ссылкой и координатами."""
|
|
28
|
+
|
|
29
|
+
type: int = 0
|
|
30
|
+
coordinates: StoryCoordinates
|
|
31
|
+
clickable_link: StoryClickableLink
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class StoryPhotoMedia(CamelModel):
|
|
35
|
+
"""Фото сторис, полученное от Max, без обязательного токена загрузки."""
|
|
36
|
+
|
|
37
|
+
base_url: str
|
|
38
|
+
height: int
|
|
39
|
+
width: int
|
|
40
|
+
photo_id: int
|
|
41
|
+
preview_data: bytes | None = None
|
|
42
|
+
type: Literal[AttachmentType.PHOTO] = Field(alias="_type")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class StoryVideoMedia(CamelModel):
|
|
46
|
+
"""Видео сторис, полученное от Max.
|
|
47
|
+
|
|
48
|
+
В отличие от ``VideoAttachment``, не требует токен загрузки и
|
|
49
|
+
``video_type``, которые используются при публикации.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
height: int
|
|
53
|
+
width: int
|
|
54
|
+
video_id: int
|
|
55
|
+
duration: int | None = None
|
|
56
|
+
preview_data: bytes | None = None
|
|
57
|
+
type: Literal[AttachmentType.VIDEO] = Field(alias="_type")
|
|
58
|
+
thumbnail: str
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
StoryMedia: TypeAlias = Annotated[
|
|
62
|
+
StoryPhotoMedia | StoryVideoMedia,
|
|
63
|
+
Field(discriminator="type"),
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Story(CamelModel):
|
|
68
|
+
"""Сторис, возвращенная после публикации или при чтении.
|
|
69
|
+
|
|
70
|
+
:ivar id: ID сторис.
|
|
71
|
+
:ivar cid: Идентификатор публикации, сформированный клиентом.
|
|
72
|
+
:ivar media: Фото или видео сторис.
|
|
73
|
+
:ivar layers: Слои поверх кадра.
|
|
74
|
+
:ivar settings: Настройки сторис в формате Max.
|
|
75
|
+
:ivar expiration: Время жизни сторис в миллисекундах.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
id: int
|
|
79
|
+
cid: int | None = None
|
|
80
|
+
media: StoryMedia
|
|
81
|
+
layers: list[StoryLayer] = Field(default_factory=list)
|
|
82
|
+
settings: int
|
|
83
|
+
expiration: int
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class StoryOwner(CamelModel):
|
|
87
|
+
"""Владелец сторис.
|
|
88
|
+
|
|
89
|
+
:ivar owner_id: ID владельца, а не отдельной сторис.
|
|
90
|
+
:ivar type: Числовой тип владельца из Max. ``0`` — пользователь.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
owner_id: int
|
|
94
|
+
type: int = 0
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class StoryPreview(CamelModel):
|
|
98
|
+
"""Сводная информация о сторис владельца в ленте и обновлениях.
|
|
99
|
+
|
|
100
|
+
ID отдельных сторис в превью нет. Для их получения передайте
|
|
101
|
+
``owner.owner_id`` и ``owner.type`` в ``client.get_stories()``.
|
|
102
|
+
|
|
103
|
+
:ivar owner: Владелец сторис.
|
|
104
|
+
:ivar total_count: Общее количество сторис владельца.
|
|
105
|
+
:ivar read_count: Количество просмотренных сторис владельца.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
owner: StoryOwner
|
|
109
|
+
total_count: int = 0
|
|
110
|
+
read_count: int = 0
|
|
111
|
+
last_story_expiration_time: int = 0
|
|
112
|
+
settings: int = 0
|
|
113
|
+
update_time: int = 0
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class StoryDetailedStats(CamelModel):
|
|
117
|
+
"""Запись подробной статистики просмотра или реакции на сторис.
|
|
118
|
+
|
|
119
|
+
Типизировано только ``user_id``. Дополнительные поля доступны в
|
|
120
|
+
``model_extra`` с исходными именами ответа Max, без преобразования
|
|
121
|
+
camelCase. Поле ``reaction``, если оно пришло, остается словарем.
|
|
122
|
+
|
|
123
|
+
:ivar user_id: ID пользователя.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
user_id: int
|