pararamio-aio 3.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.
- pararamio_aio/__init__.py +26 -0
- pararamio_aio/_core/__init__.py +125 -0
- pararamio_aio/_core/_types.py +120 -0
- pararamio_aio/_core/base.py +143 -0
- pararamio_aio/_core/client_protocol.py +90 -0
- pararamio_aio/_core/constants/__init__.py +7 -0
- pararamio_aio/_core/constants/base.py +9 -0
- pararamio_aio/_core/constants/endpoints.py +84 -0
- pararamio_aio/_core/cookie_decorator.py +208 -0
- pararamio_aio/_core/cookie_manager.py +1222 -0
- pararamio_aio/_core/endpoints.py +67 -0
- pararamio_aio/_core/exceptions/__init__.py +6 -0
- pararamio_aio/_core/exceptions/auth.py +91 -0
- pararamio_aio/_core/exceptions/base.py +124 -0
- pararamio_aio/_core/models/__init__.py +17 -0
- pararamio_aio/_core/models/base.py +66 -0
- pararamio_aio/_core/models/chat.py +92 -0
- pararamio_aio/_core/models/post.py +65 -0
- pararamio_aio/_core/models/user.py +54 -0
- pararamio_aio/_core/py.typed +2 -0
- pararamio_aio/_core/utils/__init__.py +73 -0
- pararamio_aio/_core/utils/async_requests.py +417 -0
- pararamio_aio/_core/utils/auth_flow.py +202 -0
- pararamio_aio/_core/utils/authentication.py +235 -0
- pararamio_aio/_core/utils/captcha.py +92 -0
- pararamio_aio/_core/utils/helpers.py +336 -0
- pararamio_aio/_core/utils/http_client.py +199 -0
- pararamio_aio/_core/utils/requests.py +424 -0
- pararamio_aio/_core/validators.py +78 -0
- pararamio_aio/_types.py +29 -0
- pararamio_aio/client.py +989 -0
- pararamio_aio/constants/__init__.py +16 -0
- pararamio_aio/exceptions/__init__.py +31 -0
- pararamio_aio/exceptions/base.py +1 -0
- pararamio_aio/file_operations.py +232 -0
- pararamio_aio/models/__init__.py +31 -0
- pararamio_aio/models/activity.py +127 -0
- pararamio_aio/models/attachment.py +141 -0
- pararamio_aio/models/base.py +83 -0
- pararamio_aio/models/bot.py +274 -0
- pararamio_aio/models/chat.py +722 -0
- pararamio_aio/models/deferred_post.py +174 -0
- pararamio_aio/models/file.py +103 -0
- pararamio_aio/models/group.py +361 -0
- pararamio_aio/models/poll.py +275 -0
- pararamio_aio/models/post.py +643 -0
- pararamio_aio/models/team.py +403 -0
- pararamio_aio/models/user.py +239 -0
- pararamio_aio/py.typed +2 -0
- pararamio_aio/utils/__init__.py +18 -0
- pararamio_aio/utils/authentication.py +383 -0
- pararamio_aio/utils/requests.py +75 -0
- pararamio_aio-3.0.0.dist-info/METADATA +269 -0
- pararamio_aio-3.0.0.dist-info/RECORD +56 -0
- pararamio_aio-3.0.0.dist-info/WHEEL +5 -0
- pararamio_aio-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,274 @@
|
|
1
|
+
"""Async Bot model."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from datetime import datetime
|
6
|
+
from typing import Any
|
7
|
+
|
8
|
+
# Imports from core
|
9
|
+
from pararamio_aio._core.utils.helpers import join_ids, unescape_dict
|
10
|
+
|
11
|
+
from ..utils import async_bot_request
|
12
|
+
|
13
|
+
__all__ = ("AsyncPararamioBot",)
|
14
|
+
|
15
|
+
|
16
|
+
class AsyncPararamioBot:
|
17
|
+
"""Async bot client for Pararamio API."""
|
18
|
+
|
19
|
+
def __init__(self, key: str):
|
20
|
+
"""Initialize bot with API key.
|
21
|
+
|
22
|
+
Args:
|
23
|
+
key: Bot API key
|
24
|
+
"""
|
25
|
+
if len(key) > 50:
|
26
|
+
key = key[20:]
|
27
|
+
self.key = key
|
28
|
+
|
29
|
+
async def request(
|
30
|
+
self,
|
31
|
+
url: str,
|
32
|
+
method: str = "GET",
|
33
|
+
data: dict | None = None,
|
34
|
+
headers: dict | None = None,
|
35
|
+
) -> dict:
|
36
|
+
"""Send an authenticated HTTP request.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
url: API endpoint
|
40
|
+
method: HTTP method (GET, POST, PUT, DELETE)
|
41
|
+
data: Request payload for POST/PUT
|
42
|
+
headers: Additional headers
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
Response data as dictionary
|
46
|
+
"""
|
47
|
+
return await async_bot_request(url, self.key, method=method, data=data, headers=headers)
|
48
|
+
|
49
|
+
async def get_profile(self) -> dict[str, Any]:
|
50
|
+
"""Get bot profile information.
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
Bot profile data with unescaped name fields
|
54
|
+
"""
|
55
|
+
url = "/user/me"
|
56
|
+
response = await self.request(url)
|
57
|
+
return unescape_dict(response, keys=["name"])
|
58
|
+
|
59
|
+
async def post_message(
|
60
|
+
self, chat_id: int, text: str, reply_no: int | None = None
|
61
|
+
) -> dict[str, str | int]:
|
62
|
+
"""Send a message to a chat.
|
63
|
+
|
64
|
+
Args:
|
65
|
+
chat_id: Target chat ID
|
66
|
+
text: Message text
|
67
|
+
reply_no: Optional message number to reply to
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
Response data with post information
|
71
|
+
"""
|
72
|
+
url = "/bot/message"
|
73
|
+
return await self.request(
|
74
|
+
url,
|
75
|
+
method="POST",
|
76
|
+
data={"chat_id": chat_id, "text": text, "reply_no": reply_no},
|
77
|
+
)
|
78
|
+
|
79
|
+
async def post_private_message_by_user_id(
|
80
|
+
self,
|
81
|
+
user_id: int,
|
82
|
+
text: str,
|
83
|
+
) -> dict[str, str | int]:
|
84
|
+
"""Send a private message to a user by ID.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
user_id: Target user ID
|
88
|
+
text: Message text
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
Response data with message information
|
92
|
+
"""
|
93
|
+
url = "/msg/post/private"
|
94
|
+
return await self.request(url, method="POST", data={"text": text, "user_id": user_id})
|
95
|
+
|
96
|
+
async def post_private_message_by_user_email(
|
97
|
+
self, email: str, text: str
|
98
|
+
) -> dict[str, str | int]:
|
99
|
+
"""Send a private message to a user by email.
|
100
|
+
|
101
|
+
Args:
|
102
|
+
email: Target user email
|
103
|
+
text: Message text
|
104
|
+
|
105
|
+
Returns:
|
106
|
+
Response data with message information
|
107
|
+
"""
|
108
|
+
url = "/msg/post/private"
|
109
|
+
return await self.request(url, method="POST", data={"text": text, "user_email": email})
|
110
|
+
|
111
|
+
async def post_private_message_by_user_unique_name(
|
112
|
+
self, unique_name: str, text: str
|
113
|
+
) -> dict[str, str | int]:
|
114
|
+
"""Send a private message to a user by unique name.
|
115
|
+
|
116
|
+
Args:
|
117
|
+
unique_name: Target user unique name
|
118
|
+
text: Message text
|
119
|
+
|
120
|
+
Returns:
|
121
|
+
Response data with message information
|
122
|
+
"""
|
123
|
+
url = "/msg/post/private"
|
124
|
+
return await self.request(
|
125
|
+
url, method="POST", data={"text": text, "user_unique_name": unique_name}
|
126
|
+
)
|
127
|
+
|
128
|
+
async def get_tasks(self) -> dict[str, Any]:
|
129
|
+
"""Get bot tasks.
|
130
|
+
|
131
|
+
Returns:
|
132
|
+
Tasks data
|
133
|
+
"""
|
134
|
+
url = "/msg/task"
|
135
|
+
return await self.request(url)
|
136
|
+
|
137
|
+
async def set_task_status(self, chat_id: int, post_no: int, state: str) -> dict:
|
138
|
+
"""Set task status.
|
139
|
+
|
140
|
+
Args:
|
141
|
+
chat_id: Chat ID where task is located
|
142
|
+
post_no: Post number of the task
|
143
|
+
state: New state ('open', 'done', or 'close')
|
144
|
+
|
145
|
+
Returns:
|
146
|
+
Response data
|
147
|
+
|
148
|
+
Raises:
|
149
|
+
ValueError: If state is invalid
|
150
|
+
"""
|
151
|
+
if str.lower(state) not in ("open", "done", "close"):
|
152
|
+
raise ValueError(f"unknown state {state}")
|
153
|
+
|
154
|
+
url = f"/msg/task/{chat_id}/{post_no}"
|
155
|
+
data = {"state": state}
|
156
|
+
return await self.request(url, method="POST", data=data)
|
157
|
+
|
158
|
+
async def get_chat(self, chat_id: int) -> dict[str, Any]:
|
159
|
+
"""Get chat by ID.
|
160
|
+
|
161
|
+
Args:
|
162
|
+
chat_id: Chat ID
|
163
|
+
|
164
|
+
Returns:
|
165
|
+
Chat data
|
166
|
+
|
167
|
+
Raises:
|
168
|
+
ValueError: If chat not found
|
169
|
+
"""
|
170
|
+
url = f"/core/chat?ids={chat_id}"
|
171
|
+
response = await self.request(url)
|
172
|
+
chats = response.get("chats", [])
|
173
|
+
|
174
|
+
if not chats:
|
175
|
+
raise ValueError(f"chat with id {chat_id} is not found")
|
176
|
+
|
177
|
+
return chats[0]
|
178
|
+
|
179
|
+
async def get_chats(self) -> list[dict[str, Any]]:
|
180
|
+
"""Get all bot chats.
|
181
|
+
|
182
|
+
Returns:
|
183
|
+
List of chat data dictionaries
|
184
|
+
"""
|
185
|
+
url = "/core/chat/sync"
|
186
|
+
response = await self.request(url)
|
187
|
+
chat_ids = response.get("chats", [])
|
188
|
+
|
189
|
+
if not chat_ids:
|
190
|
+
return []
|
191
|
+
|
192
|
+
# Load chats in batches
|
193
|
+
all_chats = []
|
194
|
+
batch_size = 50
|
195
|
+
|
196
|
+
for i in range(0, len(chat_ids), batch_size):
|
197
|
+
batch_ids = chat_ids[i : i + batch_size]
|
198
|
+
url = f"/core/chat?ids={join_ids(batch_ids)}"
|
199
|
+
batch_response = await self.request(url)
|
200
|
+
all_chats.extend(batch_response.get("chats", []))
|
201
|
+
|
202
|
+
return all_chats
|
203
|
+
|
204
|
+
async def get_users(self, user_ids: list[int]) -> list[dict[str, Any]]:
|
205
|
+
"""Get users by IDs.
|
206
|
+
|
207
|
+
Args:
|
208
|
+
user_ids: List of user IDs
|
209
|
+
|
210
|
+
Returns:
|
211
|
+
List of user data with unescaped names
|
212
|
+
"""
|
213
|
+
if not user_ids:
|
214
|
+
return []
|
215
|
+
|
216
|
+
url = f"/core/user?ids={join_ids(user_ids)}"
|
217
|
+
response = await self.request(url)
|
218
|
+
return [unescape_dict(u, keys=["name"]) for u in response.get("users", [])]
|
219
|
+
|
220
|
+
async def get_user_by_id(self, user_id: int) -> dict[str, Any]:
|
221
|
+
"""Get a single user by ID.
|
222
|
+
|
223
|
+
Args:
|
224
|
+
user_id: User ID
|
225
|
+
|
226
|
+
Returns:
|
227
|
+
User data
|
228
|
+
|
229
|
+
Raises:
|
230
|
+
ValueError: If user not found
|
231
|
+
"""
|
232
|
+
users = await self.get_users([user_id])
|
233
|
+
if not users:
|
234
|
+
raise ValueError(f"user with id {user_id} is not found")
|
235
|
+
return users[0]
|
236
|
+
|
237
|
+
async def get_user_activity(
|
238
|
+
self,
|
239
|
+
user_id: int,
|
240
|
+
start: datetime,
|
241
|
+
end: datetime,
|
242
|
+
actions: list[str] | None = None,
|
243
|
+
) -> list[dict[str, Any]]:
|
244
|
+
"""Get user activity within date range.
|
245
|
+
|
246
|
+
Args:
|
247
|
+
user_id: User ID
|
248
|
+
start: Start datetime
|
249
|
+
end: End datetime
|
250
|
+
actions: Optional list of activity actions to filter
|
251
|
+
|
252
|
+
Returns:
|
253
|
+
List of activity data
|
254
|
+
|
255
|
+
Note:
|
256
|
+
This is a simplified version. The sync version uses Activity model
|
257
|
+
which is not yet implemented in async.
|
258
|
+
"""
|
259
|
+
# Simplified implementation - just fetch first page
|
260
|
+
# In full implementation, would need to handle pagination and Activity model
|
261
|
+
action_str = ",".join(actions) if actions else ""
|
262
|
+
url = f"/activity?user_id={user_id}&action={action_str}&page=1"
|
263
|
+
response = await self.request(url)
|
264
|
+
|
265
|
+
activities = response.get("activities", [])
|
266
|
+
|
267
|
+
# Filter by date range
|
268
|
+
filtered = []
|
269
|
+
for activity in activities:
|
270
|
+
activity_time = activity.get("time_created")
|
271
|
+
if activity_time and start <= activity_time <= end:
|
272
|
+
filtered.append(activity)
|
273
|
+
|
274
|
+
return filtered
|