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,275 @@
1
+ """Async Poll model."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ # Imports from core
8
+ from pararamio_aio._core import (
9
+ PararamioRequestException,
10
+ PararamioServerResponseException,
11
+ PararamioValidationException,
12
+ )
13
+
14
+ from .base import BaseModel
15
+
16
+ if TYPE_CHECKING:
17
+ from ..client import AsyncPararamio
18
+ from .chat import Chat
19
+
20
+ __all__ = ("PollOption", "Poll")
21
+
22
+
23
+ class PollOption:
24
+ """Represents a poll option object."""
25
+
26
+ def __init__(self, id: int, text: str, count: int, vote_users: list[int]) -> None:
27
+ """Initialize poll option.
28
+
29
+ Args:
30
+ id: Option ID
31
+ text: Option text
32
+ count: Vote count
33
+ vote_users: List of user IDs who voted
34
+ """
35
+ self.id = id
36
+ self.text = text
37
+ self.count = count
38
+ self.vote_users = vote_users
39
+
40
+ @classmethod
41
+ def from_response_data(cls, data: dict[str, Any]) -> PollOption:
42
+ """Create PollOption from API response data.
43
+
44
+ Args:
45
+ data: Response data containing poll option information
46
+
47
+ Returns:
48
+ PollOption instance
49
+
50
+ Raises:
51
+ PararamioServerResponseException: If required fields are missing
52
+ """
53
+ required_fields = ["id", "text", "count", "vote_users"]
54
+ for field in required_fields:
55
+ if field not in data:
56
+ raise PararamioServerResponseException(
57
+ f"invalid server vote option response, missing {field}",
58
+ data,
59
+ )
60
+ return cls(**data)
61
+
62
+ def __str__(self) -> str:
63
+ """String representation."""
64
+ return f"{self.text} ({self.count} votes)"
65
+
66
+
67
+ class Poll(BaseModel):
68
+ """Async Poll model with explicit loading."""
69
+
70
+ def __init__(
71
+ self,
72
+ client: AsyncPararamio,
73
+ vote_uid: str,
74
+ **kwargs: Any,
75
+ ) -> None:
76
+ """Initialize async poll.
77
+
78
+ Args:
79
+ client: AsyncPararamio client
80
+ vote_uid: Poll unique ID
81
+ **kwargs: Additional poll data
82
+ """
83
+ super().__init__(client, vote_uid=vote_uid, **kwargs)
84
+ self.vote_uid = vote_uid
85
+
86
+ @property
87
+ def chat_id(self) -> int:
88
+ """Get chat ID where poll is posted."""
89
+ value = self._data.get("chat_id", 0)
90
+ return int(value) if not isinstance(value, list) else 0
91
+
92
+ @property
93
+ def anonymous(self) -> bool:
94
+ """Check if poll is anonymous."""
95
+ return bool(self._data.get("anonymous", False))
96
+
97
+ @property
98
+ def mode(self) -> str:
99
+ """Get poll mode ('one' for single choice, 'more' for multiple)."""
100
+ return str(self._data.get("mode", "one"))
101
+
102
+ @property
103
+ def options(self) -> list[PollOption]:
104
+ """Get poll options."""
105
+ raw_options = self._data.get("options", [])
106
+ if raw_options and isinstance(raw_options[0], dict):
107
+ return [PollOption.from_response_data(opt) for opt in raw_options]
108
+ return raw_options if isinstance(raw_options, list) else []
109
+
110
+ @property
111
+ def question(self) -> str:
112
+ """Get poll question."""
113
+ return str(self._data.get("question", ""))
114
+
115
+ @property
116
+ def total_user(self) -> int:
117
+ """Get total number of users who voted."""
118
+ value = self._data.get("total_user", 0)
119
+ return int(value) if not isinstance(value, list) else 0
120
+
121
+ @property
122
+ def total_answer(self) -> int:
123
+ """Get total number of answers."""
124
+ value = self._data.get("total_answer", 0)
125
+ return int(value) if not isinstance(value, list) else 0
126
+
127
+ @property
128
+ def user_id(self) -> int:
129
+ """Get poll creator user ID."""
130
+ value = self._data.get("user_id", 0)
131
+ return int(value) if not isinstance(value, list) else 0
132
+
133
+ async def load(self) -> Poll:
134
+ """Load full poll data from API.
135
+
136
+ Returns:
137
+ Self with updated data
138
+ """
139
+ response = await self.client.api_get(f"/msg/vote/{self.vote_uid}")
140
+ return self._update(response)
141
+
142
+ def _update(self, response: dict[str, Any]) -> Poll:
143
+ """Update the Poll object with response data.
144
+
145
+ Args:
146
+ response: API response data
147
+
148
+ Returns:
149
+ Updated Poll object
150
+
151
+ Raises:
152
+ PararamioServerResponseException: If response is invalid
153
+ """
154
+ if "vote" not in response:
155
+ raise PararamioServerResponseException(
156
+ f"failed to load data for vote {self.vote_uid} in chat {self.chat_id}",
157
+ response,
158
+ )
159
+
160
+ # Process response data
161
+ vote_data = response["vote"]
162
+ self._data = {
163
+ k: v if k != "options" else [PollOption.from_response_data(opt) for opt in v]
164
+ for k, v in vote_data.items()
165
+ }
166
+ return self
167
+
168
+ @classmethod
169
+ async def create(
170
+ cls, chat: Chat, question: str, *, mode: str, anonymous: bool, options: list[str]
171
+ ) -> Poll:
172
+ """Create a new poll in the specified chat.
173
+
174
+ Args:
175
+ chat: The chat where the poll will be created
176
+ question: The poll question
177
+ mode: Options select mode ('one' for single, 'more' for multiple)
178
+ anonymous: Whether the poll should be anonymous
179
+ options: List of option texts
180
+
181
+ Returns:
182
+ Created Poll object
183
+
184
+ Raises:
185
+ PararamioRequestException: If poll creation fails
186
+ """
187
+ response = await chat.client.api_post(
188
+ "/msg/vote",
189
+ {
190
+ "chat_id": chat.id,
191
+ "question": question,
192
+ "options": options,
193
+ "mode": mode,
194
+ "anonymous": anonymous,
195
+ },
196
+ )
197
+
198
+ if not response:
199
+ raise PararamioRequestException("Failed to create poll")
200
+
201
+ poll = cls(chat.client, response["vote_uid"])
202
+ await poll.load()
203
+ return poll
204
+
205
+ async def _vote(self, option_ids: list[int]) -> Poll:
206
+ """Vote on the poll with selected option IDs.
207
+
208
+ Args:
209
+ option_ids: List of option IDs to vote for
210
+
211
+ Returns:
212
+ Updated Poll object
213
+
214
+ Raises:
215
+ PararamioValidationException: If option IDs are invalid
216
+ """
217
+ valid_ids = [opt.id for opt in self.options]
218
+ if not all(opt_id in valid_ids for opt_id in option_ids):
219
+ raise PararamioValidationException("incorrect option")
220
+
221
+ response = await self.client.api_put(
222
+ f"/msg/vote/{self.vote_uid}",
223
+ {"variants": option_ids},
224
+ )
225
+ return self._update(response)
226
+
227
+ async def vote(self, option_id: int) -> Poll:
228
+ """Vote for a single option.
229
+
230
+ Args:
231
+ option_id: The option ID to vote for
232
+
233
+ Returns:
234
+ Updated Poll object
235
+
236
+ Raises:
237
+ PararamioValidationException: If option_id is invalid
238
+ """
239
+ return await self._vote([option_id])
240
+
241
+ async def vote_multi(self, option_ids: list[int]) -> Poll:
242
+ """Vote for multiple options.
243
+
244
+ Args:
245
+ option_ids: List of option IDs to vote for
246
+
247
+ Returns:
248
+ Updated Poll object
249
+
250
+ Raises:
251
+ PararamioValidationException: If poll mode is not 'more' or option IDs are invalid
252
+ """
253
+ if self.mode != "more":
254
+ raise PararamioValidationException(
255
+ f"incorrect poll mode ({self.mode}) for multi voting"
256
+ )
257
+ return await self._vote(option_ids)
258
+
259
+ async def retract(self) -> Poll:
260
+ """Retract vote from the poll.
261
+
262
+ Returns:
263
+ Updated Poll object
264
+ """
265
+ return await self._vote([])
266
+
267
+ def __str__(self) -> str:
268
+ """String representation."""
269
+ return self.question
270
+
271
+ def __eq__(self, other) -> bool:
272
+ """Check equality."""
273
+ if not isinstance(other, Poll):
274
+ return False
275
+ return self.vote_uid == other.vote_uid