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
pymax/mixins/channel.py
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
from pymax.exceptions import Error, ResponseError, ResponseStructureError
|
|
2
|
-
from pymax.payloads import (
|
|
3
|
-
GetGroupMembersPayload,
|
|
4
|
-
JoinChatPayload,
|
|
5
|
-
ResolveLinkPayload,
|
|
6
|
-
SearchGroupMembersPayload,
|
|
7
|
-
)
|
|
8
|
-
from pymax.protocols import ClientProtocol
|
|
9
|
-
from pymax.static.constant import (
|
|
10
|
-
DEFAULT_CHAT_MEMBERS_LIMIT,
|
|
11
|
-
DEFAULT_MARKER_VALUE,
|
|
12
|
-
)
|
|
13
|
-
from pymax.static.enum import Opcode
|
|
14
|
-
from pymax.types import Channel, Member
|
|
15
|
-
from pymax.utils import MixinsUtils
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class ChannelMixin(ClientProtocol):
|
|
19
|
-
async def resolve_channel_by_name(self, name: str) -> Channel | None:
|
|
20
|
-
"""
|
|
21
|
-
Получает информацию о канале по его имени
|
|
22
|
-
|
|
23
|
-
:param name: Имя канала
|
|
24
|
-
:type name: str
|
|
25
|
-
:return: Объект Channel или None, если канал не найден
|
|
26
|
-
:rtype: Channel | None
|
|
27
|
-
"""
|
|
28
|
-
payload = ResolveLinkPayload(
|
|
29
|
-
link=f"https://max.ru/{name}",
|
|
30
|
-
).model_dump(by_alias=True)
|
|
31
|
-
|
|
32
|
-
data = await self._send_and_wait(opcode=Opcode.LINK_INFO, payload=payload)
|
|
33
|
-
if data.get("payload", {}).get("error"):
|
|
34
|
-
MixinsUtils.handle_error(data)
|
|
35
|
-
|
|
36
|
-
channel = Channel.from_dict(data.get("payload", {}).get("chat", {}))
|
|
37
|
-
if channel not in self.channels:
|
|
38
|
-
self.channels.append(channel)
|
|
39
|
-
return channel
|
|
40
|
-
|
|
41
|
-
async def join_channel(self, link: str) -> Channel | None:
|
|
42
|
-
"""
|
|
43
|
-
Присоединяется к каналу по ссылке
|
|
44
|
-
|
|
45
|
-
:param link: Ссылка на канал
|
|
46
|
-
:type link: str
|
|
47
|
-
:return: Объект канала, если присоединение прошло успешно, иначе None
|
|
48
|
-
:rtype: Channel | None
|
|
49
|
-
"""
|
|
50
|
-
payload = JoinChatPayload(
|
|
51
|
-
link=link,
|
|
52
|
-
).model_dump(by_alias=True)
|
|
53
|
-
|
|
54
|
-
data = await self._send_and_wait(opcode=Opcode.CHAT_JOIN, payload=payload)
|
|
55
|
-
if data.get("payload", {}).get("error"):
|
|
56
|
-
MixinsUtils.handle_error(data)
|
|
57
|
-
|
|
58
|
-
channel = Channel.from_dict(data.get("payload", {}).get("chat", {}))
|
|
59
|
-
if channel not in self.channels:
|
|
60
|
-
self.channels.append(channel)
|
|
61
|
-
return channel
|
|
62
|
-
|
|
63
|
-
async def _query_members(
|
|
64
|
-
self, payload: GetGroupMembersPayload | SearchGroupMembersPayload
|
|
65
|
-
) -> tuple[list[Member], int | None]:
|
|
66
|
-
data = await self._send_and_wait(
|
|
67
|
-
opcode=Opcode.CHAT_MEMBERS,
|
|
68
|
-
payload=payload.model_dump(by_alias=True, exclude_none=True),
|
|
69
|
-
)
|
|
70
|
-
response_payload = data.get("payload", {})
|
|
71
|
-
if data.get("payload", {}).get("error"):
|
|
72
|
-
MixinsUtils.handle_error(data)
|
|
73
|
-
marker = response_payload.get("marker")
|
|
74
|
-
if isinstance(marker, str):
|
|
75
|
-
marker = int(marker)
|
|
76
|
-
elif isinstance(marker, int):
|
|
77
|
-
pass
|
|
78
|
-
elif marker is None:
|
|
79
|
-
# маркер может отсутствовать
|
|
80
|
-
pass
|
|
81
|
-
else:
|
|
82
|
-
raise ResponseStructureError("Invalid marker type in response")
|
|
83
|
-
members = response_payload.get("members")
|
|
84
|
-
member_list = []
|
|
85
|
-
if isinstance(members, list):
|
|
86
|
-
for item in members:
|
|
87
|
-
if not isinstance(item, dict):
|
|
88
|
-
raise ResponseStructureError("Invalid member structure in response")
|
|
89
|
-
member_list.append(Member.from_dict(item))
|
|
90
|
-
else:
|
|
91
|
-
raise ResponseStructureError("Invalid members type in response")
|
|
92
|
-
return member_list, marker
|
|
93
|
-
|
|
94
|
-
async def load_members(
|
|
95
|
-
self,
|
|
96
|
-
chat_id: int,
|
|
97
|
-
marker: int | None = DEFAULT_MARKER_VALUE,
|
|
98
|
-
count: int = DEFAULT_CHAT_MEMBERS_LIMIT,
|
|
99
|
-
) -> tuple[list[Member], int | None]:
|
|
100
|
-
"""
|
|
101
|
-
Загружает членов канала
|
|
102
|
-
|
|
103
|
-
:param chat_id: Идентификатор канала
|
|
104
|
-
:type chat_id: int
|
|
105
|
-
:param marker: Маркер для пагинации. По умолчанию DEFAULT_MARKER_VALUE
|
|
106
|
-
:type marker: int | None
|
|
107
|
-
:param count: Количество членов для загрузки. По умолчанию DEFAULT_CHAT_MEMBERS_LIMIT.
|
|
108
|
-
:type count: int
|
|
109
|
-
:return: Список участников канала и маркер для следующей страницы
|
|
110
|
-
:rtype: tuple[list[Member], int | None]
|
|
111
|
-
"""
|
|
112
|
-
|
|
113
|
-
payload = GetGroupMembersPayload(chat_id=chat_id, marker=marker, count=count)
|
|
114
|
-
return await self._query_members(payload)
|
|
115
|
-
|
|
116
|
-
async def find_members(self, chat_id: int, query: str) -> tuple[list[Member], int | None]:
|
|
117
|
-
"""
|
|
118
|
-
Поиск участников канала по строке
|
|
119
|
-
Внимание! веб-клиент всегда возвращает только определённое количество пользователей,
|
|
120
|
-
тоесть пагинация здесь не реализована!
|
|
121
|
-
|
|
122
|
-
:param chat_id: Идентификатор канала
|
|
123
|
-
:type chat_id: int
|
|
124
|
-
:param query: Строка для поиска участников
|
|
125
|
-
:type query: str
|
|
126
|
-
:return: Список участников канала
|
|
127
|
-
:rtype: tuple[list[Member], int | None]
|
|
128
|
-
"""
|
|
129
|
-
payload = SearchGroupMembersPayload(chat_id=chat_id, query=query)
|
|
130
|
-
return await self._query_members(payload)
|
pymax/mixins/group.py
DELETED
|
@@ -1,458 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
|
|
3
|
-
from pymax.exceptions import Error
|
|
4
|
-
from pymax.payloads import (
|
|
5
|
-
ChangeGroupProfilePayload,
|
|
6
|
-
ChangeGroupSettingsOptions,
|
|
7
|
-
ChangeGroupSettingsPayload,
|
|
8
|
-
CreateGroupAttach,
|
|
9
|
-
CreateGroupMessage,
|
|
10
|
-
CreateGroupPayload,
|
|
11
|
-
FetchChatsPayload,
|
|
12
|
-
GetChatInfoPayload,
|
|
13
|
-
InviteUsersPayload,
|
|
14
|
-
JoinChatPayload,
|
|
15
|
-
LeaveChatPayload,
|
|
16
|
-
RemoveUsersPayload,
|
|
17
|
-
ReworkInviteLinkPayload,
|
|
18
|
-
)
|
|
19
|
-
from pymax.protocols import ClientProtocol
|
|
20
|
-
from pymax.static.enum import Opcode
|
|
21
|
-
from pymax.types import Chat, Message
|
|
22
|
-
from pymax.utils import MixinsUtils
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class GroupMixin(ClientProtocol):
|
|
26
|
-
async def create_group(
|
|
27
|
-
self,
|
|
28
|
-
name: str,
|
|
29
|
-
participant_ids: list[int] | None = None,
|
|
30
|
-
notify: bool = True,
|
|
31
|
-
) -> tuple[Chat, Message] | None:
|
|
32
|
-
"""
|
|
33
|
-
Создает группу
|
|
34
|
-
|
|
35
|
-
Args:
|
|
36
|
-
name (str): Название группы.
|
|
37
|
-
participant_ids (list[int] | None, optional): Список идентификаторов участников. Defaults to None.
|
|
38
|
-
notify (bool, optional): Флаг оповещения. Defaults to True.
|
|
39
|
-
|
|
40
|
-
Returns:
|
|
41
|
-
tuple[Chat, Message] | None: Объект Chat и Message или None при ошибке.
|
|
42
|
-
"""
|
|
43
|
-
payload = CreateGroupPayload(
|
|
44
|
-
message=CreateGroupMessage(
|
|
45
|
-
cid=int(time.time() * 1000),
|
|
46
|
-
attaches=[
|
|
47
|
-
CreateGroupAttach(
|
|
48
|
-
_type="CONTROL",
|
|
49
|
-
title=name,
|
|
50
|
-
user_ids=(participant_ids if participant_ids else []),
|
|
51
|
-
)
|
|
52
|
-
],
|
|
53
|
-
),
|
|
54
|
-
notify=notify,
|
|
55
|
-
).model_dump(by_alias=True)
|
|
56
|
-
|
|
57
|
-
data = await self._send_and_wait(opcode=Opcode.MSG_SEND, payload=payload)
|
|
58
|
-
if data.get("payload", {}).get("error"):
|
|
59
|
-
MixinsUtils.handle_error(data)
|
|
60
|
-
|
|
61
|
-
chat = Chat.from_dict(data["payload"]["chat"])
|
|
62
|
-
message = Message.from_dict(data["payload"])
|
|
63
|
-
|
|
64
|
-
if chat:
|
|
65
|
-
cached_chat = await self._get_chat(chat.id)
|
|
66
|
-
if cached_chat is None:
|
|
67
|
-
self.chats.append(chat)
|
|
68
|
-
else:
|
|
69
|
-
idx = self.chats.index(cached_chat)
|
|
70
|
-
self.chats[idx] = chat
|
|
71
|
-
|
|
72
|
-
return chat, message
|
|
73
|
-
|
|
74
|
-
async def invite_users_to_group(
|
|
75
|
-
self,
|
|
76
|
-
chat_id: int,
|
|
77
|
-
user_ids: list[int],
|
|
78
|
-
show_history: bool = True,
|
|
79
|
-
) -> Chat | None:
|
|
80
|
-
"""
|
|
81
|
-
Приглашает пользователей в группу
|
|
82
|
-
|
|
83
|
-
Args:
|
|
84
|
-
chat_id (int): ID группы.
|
|
85
|
-
user_ids (list[int]): Список идентификаторов пользователей.
|
|
86
|
-
show_history (bool, optional): Флаг оповещения. Defaults to True.
|
|
87
|
-
|
|
88
|
-
Returns:
|
|
89
|
-
Chat | None: Объект Chat или None при ошибке.
|
|
90
|
-
"""
|
|
91
|
-
payload = InviteUsersPayload(
|
|
92
|
-
chat_id=chat_id,
|
|
93
|
-
user_ids=user_ids,
|
|
94
|
-
show_history=show_history,
|
|
95
|
-
operation="add",
|
|
96
|
-
).model_dump(by_alias=True)
|
|
97
|
-
|
|
98
|
-
data = await self._send_and_wait(opcode=Opcode.CHAT_MEMBERS_UPDATE, payload=payload)
|
|
99
|
-
|
|
100
|
-
if data.get("payload", {}).get("error"):
|
|
101
|
-
MixinsUtils.handle_error(data)
|
|
102
|
-
|
|
103
|
-
chat = Chat.from_dict(data["payload"]["chat"])
|
|
104
|
-
if chat:
|
|
105
|
-
cached_chat = await self._get_chat(chat.id)
|
|
106
|
-
if cached_chat is None:
|
|
107
|
-
self.chats.append(chat)
|
|
108
|
-
else:
|
|
109
|
-
idx = self.chats.index(cached_chat)
|
|
110
|
-
self.chats[idx] = chat
|
|
111
|
-
|
|
112
|
-
return chat
|
|
113
|
-
|
|
114
|
-
async def invite_users_to_channel(
|
|
115
|
-
self,
|
|
116
|
-
chat_id: int,
|
|
117
|
-
user_ids: list[int],
|
|
118
|
-
show_history: bool = True,
|
|
119
|
-
) -> Chat | None:
|
|
120
|
-
"""
|
|
121
|
-
Приглашает пользователей в канал
|
|
122
|
-
|
|
123
|
-
Args:
|
|
124
|
-
chat_id (int): ID канала.
|
|
125
|
-
user_ids (list[int]): Список идентификаторов пользователей.
|
|
126
|
-
show_history (bool, optional): Флаг оповещения. Defaults to True.
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
Chat | None: Объект Chat или None при ошибке.
|
|
130
|
-
"""
|
|
131
|
-
return await self.invite_users_to_group(chat_id, user_ids, show_history)
|
|
132
|
-
|
|
133
|
-
async def remove_users_from_group(
|
|
134
|
-
self,
|
|
135
|
-
chat_id: int,
|
|
136
|
-
user_ids: list[int],
|
|
137
|
-
clean_msg_period: int,
|
|
138
|
-
) -> bool:
|
|
139
|
-
"""
|
|
140
|
-
Удаляет пользователей из группы
|
|
141
|
-
|
|
142
|
-
Args:
|
|
143
|
-
chat_id (int): ID группы.
|
|
144
|
-
user_ids (list[int]): Список идентификаторов пользователей.
|
|
145
|
-
clean_msg_period (int): Период очистки сообщений.
|
|
146
|
-
|
|
147
|
-
Returns:
|
|
148
|
-
bool: True, если удаление прошло успешно, иначе False.
|
|
149
|
-
"""
|
|
150
|
-
payload = RemoveUsersPayload(
|
|
151
|
-
chat_id=chat_id,
|
|
152
|
-
user_ids=user_ids,
|
|
153
|
-
clean_msg_period=clean_msg_period,
|
|
154
|
-
).model_dump(by_alias=True)
|
|
155
|
-
|
|
156
|
-
data = await self._send_and_wait(opcode=Opcode.CHAT_MEMBERS_UPDATE, payload=payload)
|
|
157
|
-
|
|
158
|
-
if data.get("payload", {}).get("error"):
|
|
159
|
-
MixinsUtils.handle_error(data)
|
|
160
|
-
|
|
161
|
-
chat = Chat.from_dict(data["payload"]["chat"])
|
|
162
|
-
if chat:
|
|
163
|
-
cached_chat = await self._get_chat(chat.id)
|
|
164
|
-
if cached_chat is None:
|
|
165
|
-
self.chats.append(chat)
|
|
166
|
-
else:
|
|
167
|
-
idx = self.chats.index(cached_chat)
|
|
168
|
-
self.chats[idx] = chat
|
|
169
|
-
|
|
170
|
-
return True
|
|
171
|
-
|
|
172
|
-
async def change_group_settings(
|
|
173
|
-
self,
|
|
174
|
-
chat_id: int,
|
|
175
|
-
all_can_pin_message: bool | None = None,
|
|
176
|
-
only_owner_can_change_icon_title: bool | None = None,
|
|
177
|
-
only_admin_can_add_member: bool | None = None,
|
|
178
|
-
only_admin_can_call: bool | None = None,
|
|
179
|
-
members_can_see_private_link: bool | None = None,
|
|
180
|
-
) -> None:
|
|
181
|
-
"""
|
|
182
|
-
Изменяет настройки группы
|
|
183
|
-
|
|
184
|
-
Args:
|
|
185
|
-
chat_id (int): ID группы.
|
|
186
|
-
all_can_pin_message (bool | None, optional): Все могут закреплять сообщения. Defaults to None.
|
|
187
|
-
only_owner_can_change_icon_title (bool | None, optional): Только владелец может менять иконку и название. Defaults to None.
|
|
188
|
-
only_admin_can_add_member (bool | None, optional): Только администраторы могут добавлять участников. Defaults to None.
|
|
189
|
-
only_admin_can_call (bool | None, optional): Только администраторы могут звонить. Defaults to None.
|
|
190
|
-
members_can_see_private_link (bool | None, optional): Участники могут видеть приватную ссылку. Defaults to None.
|
|
191
|
-
Returns:
|
|
192
|
-
None
|
|
193
|
-
"""
|
|
194
|
-
payload = ChangeGroupSettingsPayload(
|
|
195
|
-
chat_id=chat_id,
|
|
196
|
-
options=ChangeGroupSettingsOptions(
|
|
197
|
-
ALL_CAN_PIN_MESSAGE=all_can_pin_message,
|
|
198
|
-
ONLY_OWNER_CAN_CHANGE_ICON_TITLE=only_owner_can_change_icon_title,
|
|
199
|
-
ONLY_ADMIN_CAN_ADD_MEMBER=only_admin_can_add_member,
|
|
200
|
-
ONLY_ADMIN_CAN_CALL=only_admin_can_call,
|
|
201
|
-
MEMBERS_CAN_SEE_PRIVATE_LINK=members_can_see_private_link,
|
|
202
|
-
),
|
|
203
|
-
).model_dump(by_alias=True, exclude_none=True)
|
|
204
|
-
|
|
205
|
-
data = await self._send_and_wait(opcode=Opcode.CHAT_UPDATE, payload=payload)
|
|
206
|
-
|
|
207
|
-
if data.get("payload", {}).get("error"):
|
|
208
|
-
MixinsUtils.handle_error(data)
|
|
209
|
-
|
|
210
|
-
chat = Chat.from_dict(data["payload"]["chat"])
|
|
211
|
-
if chat:
|
|
212
|
-
cached_chat = await self._get_chat(chat.id)
|
|
213
|
-
if cached_chat is None:
|
|
214
|
-
self.chats.append(chat)
|
|
215
|
-
else:
|
|
216
|
-
idx = self.chats.index(cached_chat)
|
|
217
|
-
self.chats[idx] = chat
|
|
218
|
-
|
|
219
|
-
async def change_group_profile(
|
|
220
|
-
self,
|
|
221
|
-
chat_id: int,
|
|
222
|
-
name: str | None,
|
|
223
|
-
description: str | None = None,
|
|
224
|
-
) -> None:
|
|
225
|
-
"""
|
|
226
|
-
Изменяет профиль группы
|
|
227
|
-
|
|
228
|
-
Args:
|
|
229
|
-
chat_id (int): ID группы.
|
|
230
|
-
name (str | None): Название группы.
|
|
231
|
-
description (str | None, optional): Описание группы. Defaults to None.
|
|
232
|
-
|
|
233
|
-
Returns:
|
|
234
|
-
None
|
|
235
|
-
"""
|
|
236
|
-
payload = ChangeGroupProfilePayload(
|
|
237
|
-
chat_id=chat_id,
|
|
238
|
-
theme=name,
|
|
239
|
-
description=description,
|
|
240
|
-
).model_dump(by_alias=True, exclude_none=True)
|
|
241
|
-
|
|
242
|
-
data = await self._send_and_wait(opcode=Opcode.CHAT_UPDATE, payload=payload)
|
|
243
|
-
|
|
244
|
-
if data.get("payload", {}).get("error"):
|
|
245
|
-
MixinsUtils.handle_error(data)
|
|
246
|
-
|
|
247
|
-
chat = Chat.from_dict(data["payload"]["chat"])
|
|
248
|
-
if chat:
|
|
249
|
-
cached_chat = await self._get_chat(chat.id)
|
|
250
|
-
if cached_chat is None:
|
|
251
|
-
self.chats.append(chat)
|
|
252
|
-
else:
|
|
253
|
-
idx = self.chats.index(cached_chat)
|
|
254
|
-
self.chats[idx] = chat
|
|
255
|
-
|
|
256
|
-
def _process_chat_join_link(self, link: str) -> str | None:
|
|
257
|
-
idx = link.find("join/")
|
|
258
|
-
return link[idx:] if idx != -1 else None
|
|
259
|
-
|
|
260
|
-
async def join_group(self, link: str) -> Chat:
|
|
261
|
-
"""
|
|
262
|
-
Вступает в группу по ссылке
|
|
263
|
-
|
|
264
|
-
Args:
|
|
265
|
-
link (str): Ссылка на группу.
|
|
266
|
-
|
|
267
|
-
Returns:
|
|
268
|
-
Chat: Объект чата группы
|
|
269
|
-
"""
|
|
270
|
-
proceed_link = self._process_chat_join_link(link)
|
|
271
|
-
if proceed_link is None:
|
|
272
|
-
raise ValueError("Invalid group link")
|
|
273
|
-
|
|
274
|
-
payload = JoinChatPayload(link=proceed_link).model_dump(by_alias=True)
|
|
275
|
-
|
|
276
|
-
data = await self._send_and_wait(opcode=Opcode.CHAT_JOIN, payload=payload)
|
|
277
|
-
|
|
278
|
-
if data.get("payload", {}).get("error"):
|
|
279
|
-
MixinsUtils.handle_error(data)
|
|
280
|
-
|
|
281
|
-
chat = Chat.from_dict(data["payload"]["chat"])
|
|
282
|
-
if chat:
|
|
283
|
-
cached_chat = await self._get_chat(chat.id)
|
|
284
|
-
if cached_chat is None:
|
|
285
|
-
self.chats.append(chat)
|
|
286
|
-
else:
|
|
287
|
-
idx = self.chats.index(cached_chat)
|
|
288
|
-
self.chats[idx] = chat
|
|
289
|
-
|
|
290
|
-
return chat
|
|
291
|
-
|
|
292
|
-
async def resolve_group_by_link(self, link: str) -> Chat | None:
|
|
293
|
-
"""
|
|
294
|
-
Разрешает группу по ссылке
|
|
295
|
-
|
|
296
|
-
Args:
|
|
297
|
-
link (str): Ссылка на группу.
|
|
298
|
-
|
|
299
|
-
Returns:
|
|
300
|
-
Chat | None: Объект чата группы или None, если не найдено.
|
|
301
|
-
"""
|
|
302
|
-
proceed_link = self._process_chat_join_link(link)
|
|
303
|
-
if proceed_link is None:
|
|
304
|
-
raise ValueError("Invalid group link")
|
|
305
|
-
|
|
306
|
-
data = await self._send_and_wait(
|
|
307
|
-
opcode=Opcode.LINK_INFO,
|
|
308
|
-
payload={
|
|
309
|
-
"link": proceed_link,
|
|
310
|
-
},
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
if data.get("payload", {}).get("error"):
|
|
314
|
-
MixinsUtils.handle_error(data)
|
|
315
|
-
|
|
316
|
-
chat = Chat.from_dict(data["payload"].get("chat", {}))
|
|
317
|
-
return chat
|
|
318
|
-
|
|
319
|
-
async def rework_invite_link(self, chat_id: int) -> Chat:
|
|
320
|
-
"""
|
|
321
|
-
Пересоздает ссылку для приглашения в группу
|
|
322
|
-
|
|
323
|
-
Args:
|
|
324
|
-
chat_id (int): ID группы.
|
|
325
|
-
|
|
326
|
-
Returns:
|
|
327
|
-
Chat: Обновленный объект чата с новой ссылкой.
|
|
328
|
-
"""
|
|
329
|
-
payload = ReworkInviteLinkPayload(chat_id=chat_id).model_dump(by_alias=True)
|
|
330
|
-
|
|
331
|
-
data = await self._send_and_wait(opcode=Opcode.CHAT_UPDATE, payload=payload)
|
|
332
|
-
|
|
333
|
-
if data.get("payload", {}).get("error"):
|
|
334
|
-
MixinsUtils.handle_error(data)
|
|
335
|
-
|
|
336
|
-
chat = Chat.from_dict(data["payload"].get("chat"))
|
|
337
|
-
if not chat:
|
|
338
|
-
raise Error("no_chat", "Chat data missing in response", "Chat Error")
|
|
339
|
-
|
|
340
|
-
return chat
|
|
341
|
-
|
|
342
|
-
async def get_chats(self, chat_ids: list[int]) -> list[Chat]:
|
|
343
|
-
"""
|
|
344
|
-
Получает информацию о группах по их ID
|
|
345
|
-
|
|
346
|
-
:param chat_ids: Список идентификаторов групп.
|
|
347
|
-
:type chat_ids: list[int]
|
|
348
|
-
:return: Список объектов Chat.
|
|
349
|
-
:rtype: list[Chat]
|
|
350
|
-
"""
|
|
351
|
-
missed_chat_ids = [
|
|
352
|
-
chat_id for chat_id in chat_ids if await self._get_chat(chat_id) is None
|
|
353
|
-
]
|
|
354
|
-
if missed_chat_ids:
|
|
355
|
-
payload = GetChatInfoPayload(chat_ids=missed_chat_ids).model_dump(by_alias=True)
|
|
356
|
-
else:
|
|
357
|
-
chats: list[Chat] = [
|
|
358
|
-
chat for chat_id in chat_ids if (chat := await self._get_chat(chat_id)) is not None
|
|
359
|
-
]
|
|
360
|
-
return chats
|
|
361
|
-
|
|
362
|
-
data = await self._send_and_wait(opcode=Opcode.CHAT_INFO, payload=payload)
|
|
363
|
-
|
|
364
|
-
if data.get("payload", {}).get("error"):
|
|
365
|
-
MixinsUtils.handle_error(data)
|
|
366
|
-
|
|
367
|
-
chats_data = data["payload"].get("chats", [])
|
|
368
|
-
chats: list[Chat] = []
|
|
369
|
-
for chat_dict in chats_data:
|
|
370
|
-
chat = Chat.from_dict(chat_dict)
|
|
371
|
-
chats.append(chat)
|
|
372
|
-
cached_chat = await self._get_chat(chat.id)
|
|
373
|
-
if cached_chat is None:
|
|
374
|
-
self.chats.append(chat)
|
|
375
|
-
else:
|
|
376
|
-
idx = self.chats.index(cached_chat)
|
|
377
|
-
self.chats[idx] = chat
|
|
378
|
-
|
|
379
|
-
return chats
|
|
380
|
-
|
|
381
|
-
async def get_chat(self, chat_id: int) -> Chat:
|
|
382
|
-
"""
|
|
383
|
-
Получает информацию о группе по ее ID
|
|
384
|
-
|
|
385
|
-
Args:
|
|
386
|
-
chat_id (int): Идентификатор группы.
|
|
387
|
-
|
|
388
|
-
Returns:
|
|
389
|
-
Chat: Объект Chat.
|
|
390
|
-
"""
|
|
391
|
-
chats = await self.get_chats([chat_id])
|
|
392
|
-
if not chats:
|
|
393
|
-
raise Error("no_chat", "Chat not found in response", "Chat Error")
|
|
394
|
-
return chats[0]
|
|
395
|
-
|
|
396
|
-
async def leave_group(self, chat_id: int) -> None:
|
|
397
|
-
"""
|
|
398
|
-
Покидает группу
|
|
399
|
-
|
|
400
|
-
:param chat_id: Идентификатор группы.
|
|
401
|
-
:type chat_id: int
|
|
402
|
-
:return: None
|
|
403
|
-
:rtype: None
|
|
404
|
-
"""
|
|
405
|
-
payload = LeaveChatPayload(chat_id=chat_id).model_dump(by_alias=True)
|
|
406
|
-
|
|
407
|
-
data = await self._send_and_wait(opcode=Opcode.CHAT_LEAVE, payload=payload)
|
|
408
|
-
|
|
409
|
-
if data.get("payload", {}).get("error"):
|
|
410
|
-
MixinsUtils.handle_error(data)
|
|
411
|
-
|
|
412
|
-
cached_chat = await self._get_chat(chat_id)
|
|
413
|
-
if cached_chat is not None:
|
|
414
|
-
self.chats.remove(cached_chat)
|
|
415
|
-
|
|
416
|
-
async def leave_channel(self, chat_id: int) -> None:
|
|
417
|
-
"""
|
|
418
|
-
Покидает канал
|
|
419
|
-
|
|
420
|
-
:param chat_id: Идентификатор канала.
|
|
421
|
-
:type chat_id: int
|
|
422
|
-
:return: None
|
|
423
|
-
:rtype: None
|
|
424
|
-
"""
|
|
425
|
-
await self.leave_group(chat_id)
|
|
426
|
-
|
|
427
|
-
async def fetch_chats(self, marker: int | None = None) -> list[Chat]:
|
|
428
|
-
"""
|
|
429
|
-
Загружает список чатов
|
|
430
|
-
|
|
431
|
-
:param marker: Маркер для пагинации, по умолчанию None
|
|
432
|
-
:type marker: int | None
|
|
433
|
-
:return: Список объектов Chat
|
|
434
|
-
:rtype: list[Chat]
|
|
435
|
-
"""
|
|
436
|
-
if marker is None:
|
|
437
|
-
marker = int(time.time() * 1000)
|
|
438
|
-
|
|
439
|
-
payload = FetchChatsPayload(marker=marker).model_dump(by_alias=True)
|
|
440
|
-
|
|
441
|
-
data = await self._send_and_wait(opcode=Opcode.CHATS_LIST, payload=payload)
|
|
442
|
-
|
|
443
|
-
if data.get("payload", {}).get("error"):
|
|
444
|
-
MixinsUtils.handle_error(data)
|
|
445
|
-
|
|
446
|
-
chats_data = data["payload"].get("chats", [])
|
|
447
|
-
chats: list[Chat] = []
|
|
448
|
-
for chat_dict in chats_data:
|
|
449
|
-
chat = Chat.from_dict(chat_dict)
|
|
450
|
-
chats.append(chat)
|
|
451
|
-
cached_chat = await self._get_chat(chat.id)
|
|
452
|
-
if cached_chat is None:
|
|
453
|
-
self.chats.append(chat)
|
|
454
|
-
else:
|
|
455
|
-
idx = self.chats.index(cached_chat)
|
|
456
|
-
self.chats[idx] = chat
|
|
457
|
-
|
|
458
|
-
return chats
|