pararamio-aio 2.1.1__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 (57) hide show
  1. pararamio_aio/__init__.py +78 -0
  2. pararamio_aio/_core/__init__.py +125 -0
  3. pararamio_aio/_core/_types.py +120 -0
  4. pararamio_aio/_core/base.py +143 -0
  5. pararamio_aio/_core/client_protocol.py +90 -0
  6. pararamio_aio/_core/constants/__init__.py +7 -0
  7. pararamio_aio/_core/constants/base.py +9 -0
  8. pararamio_aio/_core/constants/endpoints.py +84 -0
  9. pararamio_aio/_core/cookie_decorator.py +208 -0
  10. pararamio_aio/_core/cookie_manager.py +1222 -0
  11. pararamio_aio/_core/endpoints.py +67 -0
  12. pararamio_aio/_core/exceptions/__init__.py +6 -0
  13. pararamio_aio/_core/exceptions/auth.py +91 -0
  14. pararamio_aio/_core/exceptions/base.py +124 -0
  15. pararamio_aio/_core/models/__init__.py +17 -0
  16. pararamio_aio/_core/models/base.py +66 -0
  17. pararamio_aio/_core/models/chat.py +92 -0
  18. pararamio_aio/_core/models/post.py +65 -0
  19. pararamio_aio/_core/models/user.py +54 -0
  20. pararamio_aio/_core/py.typed +2 -0
  21. pararamio_aio/_core/utils/__init__.py +73 -0
  22. pararamio_aio/_core/utils/async_requests.py +417 -0
  23. pararamio_aio/_core/utils/auth_flow.py +202 -0
  24. pararamio_aio/_core/utils/authentication.py +235 -0
  25. pararamio_aio/_core/utils/captcha.py +92 -0
  26. pararamio_aio/_core/utils/helpers.py +336 -0
  27. pararamio_aio/_core/utils/http_client.py +199 -0
  28. pararamio_aio/_core/utils/requests.py +424 -0
  29. pararamio_aio/_core/validators.py +78 -0
  30. pararamio_aio/_types.py +29 -0
  31. pararamio_aio/client.py +989 -0
  32. pararamio_aio/constants/__init__.py +16 -0
  33. pararamio_aio/cookie_manager.py +15 -0
  34. pararamio_aio/exceptions/__init__.py +31 -0
  35. pararamio_aio/exceptions/base.py +1 -0
  36. pararamio_aio/file_operations.py +232 -0
  37. pararamio_aio/models/__init__.py +32 -0
  38. pararamio_aio/models/activity.py +127 -0
  39. pararamio_aio/models/attachment.py +141 -0
  40. pararamio_aio/models/base.py +83 -0
  41. pararamio_aio/models/bot.py +274 -0
  42. pararamio_aio/models/chat.py +722 -0
  43. pararamio_aio/models/deferred_post.py +174 -0
  44. pararamio_aio/models/file.py +103 -0
  45. pararamio_aio/models/group.py +361 -0
  46. pararamio_aio/models/poll.py +275 -0
  47. pararamio_aio/models/post.py +643 -0
  48. pararamio_aio/models/team.py +403 -0
  49. pararamio_aio/models/user.py +239 -0
  50. pararamio_aio/py.typed +2 -0
  51. pararamio_aio/utils/__init__.py +18 -0
  52. pararamio_aio/utils/authentication.py +383 -0
  53. pararamio_aio/utils/requests.py +75 -0
  54. pararamio_aio-2.1.1.dist-info/METADATA +269 -0
  55. pararamio_aio-2.1.1.dist-info/RECORD +57 -0
  56. pararamio_aio-2.1.1.dist-info/WHEEL +5 -0
  57. pararamio_aio-2.1.1.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