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,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
|