procketapi 0.3.0__tar.gz
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.
- procketapi-0.3.0/PKG-INFO +79 -0
- procketapi-0.3.0/README.md +72 -0
- procketapi-0.3.0/procket_integration/__init__.py +13 -0
- procketapi-0.3.0/procket_integration_sdk/__init__.py +13 -0
- procketapi-0.3.0/procket_integration_sdk/client.py +308 -0
- procketapi-0.3.0/procketapi/__init__.py +13 -0
- procketapi-0.3.0/procketapi.egg-info/PKG-INFO +79 -0
- procketapi-0.3.0/procketapi.egg-info/SOURCES.txt +10 -0
- procketapi-0.3.0/procketapi.egg-info/dependency_links.txt +1 -0
- procketapi-0.3.0/procketapi.egg-info/top_level.txt +3 -0
- procketapi-0.3.0/pyproject.toml +13 -0
- procketapi-0.3.0/setup.cfg +4 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: procketapi
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: PRocket integration library for Telegram bots
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
|
|
8
|
+
# PRocket API Library
|
|
9
|
+
|
|
10
|
+
This package is prepared for simple installation as:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
python -m pip install procketapi
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Important:
|
|
17
|
+
this short command starts working only after you publish the package to PyPI.
|
|
18
|
+
|
|
19
|
+
## For the service owner
|
|
20
|
+
|
|
21
|
+
You run the PRocket backend on your own server:
|
|
22
|
+
|
|
23
|
+
1. `python main.py`
|
|
24
|
+
2. `python -m integration_service.api_server`
|
|
25
|
+
|
|
26
|
+
The connected bot owner does not run your backend.
|
|
27
|
+
They only:
|
|
28
|
+
|
|
29
|
+
1. get an approved API key
|
|
30
|
+
2. get your public `base_url`
|
|
31
|
+
3. install your library
|
|
32
|
+
4. add the integration into their own bot
|
|
33
|
+
|
|
34
|
+
## Recommended import
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from procketapi import PRocketAiogramIntegration
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Compatibility imports also work:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from procket_integration import PRocketAiogramIntegration
|
|
44
|
+
from procket_integration_sdk import PRocketAiogramIntegration
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Easy aiogram integration
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from aiogram import F, Router
|
|
51
|
+
from aiogram.types import CallbackQuery, Message
|
|
52
|
+
from procketapi import PRocketAiogramIntegration
|
|
53
|
+
|
|
54
|
+
router = Router()
|
|
55
|
+
integration = PRocketAiogramIntegration(
|
|
56
|
+
api_key="YOUR_API_KEY",
|
|
57
|
+
base_url="https://your-public-api.example.com",
|
|
58
|
+
callback_prefix="sponsor",
|
|
59
|
+
currency="RUB",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@router.message(F.text == "📢 Задания от спонсоров")
|
|
64
|
+
async def sponsor_tasks(message: Message):
|
|
65
|
+
await integration.show_tasks(message)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@router.callback_query(F.data.startswith("sponsor:"))
|
|
69
|
+
async def sponsor_callbacks(call: CallbackQuery):
|
|
70
|
+
await integration.handle_callback(call)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Until the package is published
|
|
74
|
+
|
|
75
|
+
Before PyPI publication, installation is possible from a local wheel:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
python -m pip install ./procketapi-0.3.0-py3-none-any.whl
|
|
79
|
+
```
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# PRocket API Library
|
|
2
|
+
|
|
3
|
+
This package is prepared for simple installation as:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
python -m pip install procketapi
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Important:
|
|
10
|
+
this short command starts working only after you publish the package to PyPI.
|
|
11
|
+
|
|
12
|
+
## For the service owner
|
|
13
|
+
|
|
14
|
+
You run the PRocket backend on your own server:
|
|
15
|
+
|
|
16
|
+
1. `python main.py`
|
|
17
|
+
2. `python -m integration_service.api_server`
|
|
18
|
+
|
|
19
|
+
The connected bot owner does not run your backend.
|
|
20
|
+
They only:
|
|
21
|
+
|
|
22
|
+
1. get an approved API key
|
|
23
|
+
2. get your public `base_url`
|
|
24
|
+
3. install your library
|
|
25
|
+
4. add the integration into their own bot
|
|
26
|
+
|
|
27
|
+
## Recommended import
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from procketapi import PRocketAiogramIntegration
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Compatibility imports also work:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from procket_integration import PRocketAiogramIntegration
|
|
37
|
+
from procket_integration_sdk import PRocketAiogramIntegration
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Easy aiogram integration
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from aiogram import F, Router
|
|
44
|
+
from aiogram.types import CallbackQuery, Message
|
|
45
|
+
from procketapi import PRocketAiogramIntegration
|
|
46
|
+
|
|
47
|
+
router = Router()
|
|
48
|
+
integration = PRocketAiogramIntegration(
|
|
49
|
+
api_key="YOUR_API_KEY",
|
|
50
|
+
base_url="https://your-public-api.example.com",
|
|
51
|
+
callback_prefix="sponsor",
|
|
52
|
+
currency="RUB",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@router.message(F.text == "📢 Задания от спонсоров")
|
|
57
|
+
async def sponsor_tasks(message: Message):
|
|
58
|
+
await integration.show_tasks(message)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@router.callback_query(F.data.startswith("sponsor:"))
|
|
62
|
+
async def sponsor_callbacks(call: CallbackQuery):
|
|
63
|
+
await integration.handle_callback(call)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Until the package is published
|
|
67
|
+
|
|
68
|
+
Before PyPI publication, installation is possible from a local wheel:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
python -m pip install ./procketapi-0.3.0-py3-none-any.whl
|
|
72
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from procket_integration_sdk import (
|
|
2
|
+
PRocketAiogramIntegration,
|
|
3
|
+
PRocketIntegrationClient,
|
|
4
|
+
build_offer_keyboard,
|
|
5
|
+
format_offer_text,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"PRocketAiogramIntegration",
|
|
10
|
+
"PRocketIntegrationClient",
|
|
11
|
+
"build_offer_keyboard",
|
|
12
|
+
"format_offer_text",
|
|
13
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .client import (
|
|
2
|
+
PRocketAiogramIntegration,
|
|
3
|
+
PRocketIntegrationClient,
|
|
4
|
+
build_offer_keyboard,
|
|
5
|
+
format_offer_text,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"PRocketAiogramIntegration",
|
|
10
|
+
"PRocketIntegrationClient",
|
|
11
|
+
"build_offer_keyboard",
|
|
12
|
+
"format_offer_text",
|
|
13
|
+
]
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
import json
|
|
6
|
+
from typing import Any
|
|
7
|
+
import urllib.error
|
|
8
|
+
import urllib.request
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(slots=True)
|
|
12
|
+
class OfferSession:
|
|
13
|
+
offers: list[dict[str, Any]]
|
|
14
|
+
index: int = 0
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PRocketIntegrationClient:
|
|
18
|
+
def __init__(self, api_key: str, base_url: str, timeout: int = 12):
|
|
19
|
+
self.api_key = api_key.strip()
|
|
20
|
+
self.base_url = base_url.rstrip("/")
|
|
21
|
+
self.timeout = max(3, int(timeout))
|
|
22
|
+
|
|
23
|
+
def _post_sync(self, path: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
24
|
+
request = urllib.request.Request(
|
|
25
|
+
f"{self.base_url}{path}",
|
|
26
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
27
|
+
headers={
|
|
28
|
+
"X-API-Key": self.api_key,
|
|
29
|
+
"Content-Type": "application/json",
|
|
30
|
+
"Accept": "application/json",
|
|
31
|
+
},
|
|
32
|
+
method="POST",
|
|
33
|
+
)
|
|
34
|
+
try:
|
|
35
|
+
with urllib.request.urlopen(request, timeout=self.timeout) as response:
|
|
36
|
+
raw_body = response.read().decode("utf-8", errors="replace")
|
|
37
|
+
status_code = getattr(response, "status", 200)
|
|
38
|
+
except urllib.error.HTTPError as exc:
|
|
39
|
+
raw_body = exc.read().decode("utf-8", errors="replace")
|
|
40
|
+
status_code = exc.code
|
|
41
|
+
except urllib.error.URLError as exc:
|
|
42
|
+
raise RuntimeError(f"connection_failed: {exc.reason}") from exc
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
data = json.loads(raw_body) if raw_body else {}
|
|
46
|
+
except json.JSONDecodeError:
|
|
47
|
+
data = {"message": raw_body}
|
|
48
|
+
|
|
49
|
+
if status_code >= 400:
|
|
50
|
+
raise RuntimeError(str(data.get("message") or data.get("error") or "request_failed"))
|
|
51
|
+
return data
|
|
52
|
+
|
|
53
|
+
async def _post(self, path: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
54
|
+
return await asyncio.to_thread(self._post_sync, path, payload)
|
|
55
|
+
|
|
56
|
+
async def get_bot_info(self) -> dict[str, Any]:
|
|
57
|
+
return await self._post("/api/v1/bot", {})
|
|
58
|
+
|
|
59
|
+
async def get_tasks(
|
|
60
|
+
self,
|
|
61
|
+
*,
|
|
62
|
+
user_id: int,
|
|
63
|
+
username: str | None = None,
|
|
64
|
+
language_code: str | None = "ru",
|
|
65
|
+
is_premium: bool = False,
|
|
66
|
+
limit: int = 5,
|
|
67
|
+
) -> list[dict[str, Any]]:
|
|
68
|
+
data = await self._post(
|
|
69
|
+
"/api/v1/tasks",
|
|
70
|
+
{
|
|
71
|
+
"user": {
|
|
72
|
+
"id": user_id,
|
|
73
|
+
"username": username,
|
|
74
|
+
"language_code": language_code,
|
|
75
|
+
"is_premium": is_premium,
|
|
76
|
+
},
|
|
77
|
+
"limit": limit,
|
|
78
|
+
},
|
|
79
|
+
)
|
|
80
|
+
return data.get("tasks", [])
|
|
81
|
+
|
|
82
|
+
async def check_task(
|
|
83
|
+
self,
|
|
84
|
+
*,
|
|
85
|
+
user_id: int,
|
|
86
|
+
offer_id: int,
|
|
87
|
+
username: str | None = None,
|
|
88
|
+
language_code: str | None = "ru",
|
|
89
|
+
is_premium: bool = False,
|
|
90
|
+
) -> dict[str, Any]:
|
|
91
|
+
return await self._post(
|
|
92
|
+
"/api/v1/tasks/check",
|
|
93
|
+
{
|
|
94
|
+
"offer_id": offer_id,
|
|
95
|
+
"user": {
|
|
96
|
+
"id": user_id,
|
|
97
|
+
"username": username,
|
|
98
|
+
"language_code": language_code,
|
|
99
|
+
"is_premium": is_premium,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def format_offer_text(offer: dict[str, Any], currency: str = "RUB") -> str:
|
|
106
|
+
resource_type = str(offer.get("resource_type") or "").strip() or "task"
|
|
107
|
+
type_titles = {
|
|
108
|
+
"channel": "Подписка на канал",
|
|
109
|
+
"group": "Вступление в группу",
|
|
110
|
+
"bot": "Переход в бота",
|
|
111
|
+
}
|
|
112
|
+
reward = float(offer.get("executor_reward") or 0)
|
|
113
|
+
hold_days = int(offer.get("required_days") or 0)
|
|
114
|
+
title = str(offer.get("title") or "").strip() or type_titles.get(resource_type, "Задание")
|
|
115
|
+
description = str(offer.get("description") or "").strip()
|
|
116
|
+
|
|
117
|
+
lines = [
|
|
118
|
+
"Задание от спонсора",
|
|
119
|
+
"",
|
|
120
|
+
title,
|
|
121
|
+
]
|
|
122
|
+
if description:
|
|
123
|
+
lines.extend(["", description])
|
|
124
|
+
lines.extend(
|
|
125
|
+
[
|
|
126
|
+
"",
|
|
127
|
+
f"Тип: {type_titles.get(resource_type, resource_type)}",
|
|
128
|
+
f"Награда: {reward:.2f} {currency}",
|
|
129
|
+
]
|
|
130
|
+
)
|
|
131
|
+
if hold_days > 0:
|
|
132
|
+
lines.append(f"Удержание: {hold_days} дн.")
|
|
133
|
+
lines.append(f"ID: {offer.get('id')}")
|
|
134
|
+
return "\n".join(lines)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def build_offer_keyboard(
|
|
138
|
+
offer: dict[str, Any],
|
|
139
|
+
*,
|
|
140
|
+
check_callback_data: str,
|
|
141
|
+
next_callback_data: str | None = None,
|
|
142
|
+
open_label: str = "Открыть",
|
|
143
|
+
check_label: str = "Проверить",
|
|
144
|
+
next_label: str = "Следующее",
|
|
145
|
+
):
|
|
146
|
+
try:
|
|
147
|
+
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
|
148
|
+
except Exception as exc:
|
|
149
|
+
raise RuntimeError("aiogram is required for build_offer_keyboard") from exc
|
|
150
|
+
|
|
151
|
+
rows = [
|
|
152
|
+
[InlineKeyboardButton(text=open_label, url=str(offer.get("resource_link") or ""))],
|
|
153
|
+
[InlineKeyboardButton(text=check_label, callback_data=check_callback_data)],
|
|
154
|
+
]
|
|
155
|
+
if next_callback_data:
|
|
156
|
+
rows.append([InlineKeyboardButton(text=next_label, callback_data=next_callback_data)])
|
|
157
|
+
return InlineKeyboardMarkup(inline_keyboard=rows)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class PRocketAiogramIntegration:
|
|
161
|
+
def __init__(
|
|
162
|
+
self,
|
|
163
|
+
*,
|
|
164
|
+
api_key: str,
|
|
165
|
+
base_url: str,
|
|
166
|
+
callback_prefix: str = "prkt",
|
|
167
|
+
currency: str = "RUB",
|
|
168
|
+
limit: int = 10,
|
|
169
|
+
empty_text: str = "Сейчас нет доступных заданий от спонсоров.",
|
|
170
|
+
open_label: str = "Открыть",
|
|
171
|
+
check_label: str = "Проверить",
|
|
172
|
+
next_label: str = "Следующее",
|
|
173
|
+
refresh_label: str = "Обновить",
|
|
174
|
+
):
|
|
175
|
+
self.client = PRocketIntegrationClient(api_key=api_key, base_url=base_url)
|
|
176
|
+
self.callback_prefix = callback_prefix
|
|
177
|
+
self.currency = currency
|
|
178
|
+
self.limit = max(1, min(limit, 25))
|
|
179
|
+
self.empty_text = empty_text
|
|
180
|
+
self.open_label = open_label
|
|
181
|
+
self.check_label = check_label
|
|
182
|
+
self.next_label = next_label
|
|
183
|
+
self.refresh_label = refresh_label
|
|
184
|
+
self._sessions: dict[int, OfferSession] = {}
|
|
185
|
+
|
|
186
|
+
def _cb(self, action: str, offer_id: int | None = None) -> str:
|
|
187
|
+
if offer_id is None:
|
|
188
|
+
return f"{self.callback_prefix}:{action}"
|
|
189
|
+
return f"{self.callback_prefix}:{action}:{offer_id}"
|
|
190
|
+
|
|
191
|
+
async def _answer_call(self, call: Any, text: str | None = None, *, show_alert: bool = False) -> None:
|
|
192
|
+
try:
|
|
193
|
+
await call.answer(text or "", show_alert=show_alert)
|
|
194
|
+
except Exception:
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
async def _load_session(self, user: Any) -> OfferSession:
|
|
198
|
+
offers = await self.client.get_tasks(
|
|
199
|
+
user_id=int(user.id),
|
|
200
|
+
username=getattr(user, "username", None),
|
|
201
|
+
language_code=getattr(user, "language_code", None) or "ru",
|
|
202
|
+
is_premium=bool(getattr(user, "is_premium", False)),
|
|
203
|
+
limit=self.limit,
|
|
204
|
+
)
|
|
205
|
+
session = OfferSession(offers=offers, index=0)
|
|
206
|
+
self._sessions[int(user.id)] = session
|
|
207
|
+
return session
|
|
208
|
+
|
|
209
|
+
async def _get_session(self, user: Any, *, force_refresh: bool = False) -> OfferSession:
|
|
210
|
+
user_id = int(user.id)
|
|
211
|
+
session = self._sessions.get(user_id)
|
|
212
|
+
if force_refresh or session is None or not session.offers:
|
|
213
|
+
session = await self._load_session(user)
|
|
214
|
+
return session
|
|
215
|
+
|
|
216
|
+
def _current_offer(self, session: OfferSession) -> dict[str, Any] | None:
|
|
217
|
+
if not session.offers:
|
|
218
|
+
return None
|
|
219
|
+
session.index %= len(session.offers)
|
|
220
|
+
return session.offers[session.index]
|
|
221
|
+
|
|
222
|
+
async def _respond(self, target: Any, text: str, reply_markup: Any) -> None:
|
|
223
|
+
if hasattr(target, "edit_text"):
|
|
224
|
+
try:
|
|
225
|
+
await target.edit_text(text, reply_markup=reply_markup)
|
|
226
|
+
return
|
|
227
|
+
except Exception:
|
|
228
|
+
pass
|
|
229
|
+
await target.answer(text, reply_markup=reply_markup)
|
|
230
|
+
|
|
231
|
+
async def _render_offer(self, target: Any, user: Any, *, force_refresh: bool = False) -> None:
|
|
232
|
+
session = await self._get_session(user, force_refresh=force_refresh)
|
|
233
|
+
offer = self._current_offer(session)
|
|
234
|
+
try:
|
|
235
|
+
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
|
236
|
+
except Exception as exc:
|
|
237
|
+
raise RuntimeError("aiogram is required for PRocketAiogramIntegration") from exc
|
|
238
|
+
|
|
239
|
+
if offer is None:
|
|
240
|
+
kb = InlineKeyboardBuilder()
|
|
241
|
+
kb.button(text=self.refresh_label, callback_data=self._cb("refresh"))
|
|
242
|
+
await self._respond(target, self.empty_text, kb.as_markup())
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
text = format_offer_text(offer, currency=self.currency)
|
|
246
|
+
markup = build_offer_keyboard(
|
|
247
|
+
offer,
|
|
248
|
+
check_callback_data=self._cb("check", int(offer["id"])),
|
|
249
|
+
next_callback_data=self._cb("next", int(offer["id"])),
|
|
250
|
+
open_label=self.open_label,
|
|
251
|
+
check_label=self.check_label,
|
|
252
|
+
next_label=self.next_label,
|
|
253
|
+
)
|
|
254
|
+
await self._respond(target, text, markup)
|
|
255
|
+
|
|
256
|
+
async def show_tasks(self, target: Any) -> None:
|
|
257
|
+
user = target.from_user
|
|
258
|
+
if hasattr(target, "answer") and hasattr(target, "message"):
|
|
259
|
+
await self._answer_call(target)
|
|
260
|
+
await self._render_offer(target.message, user, force_refresh=True)
|
|
261
|
+
return
|
|
262
|
+
await self._render_offer(target, user, force_refresh=True)
|
|
263
|
+
|
|
264
|
+
async def handle_callback(self, call: Any) -> bool:
|
|
265
|
+
data = str(getattr(call, "data", "") or "")
|
|
266
|
+
prefix = f"{self.callback_prefix}:"
|
|
267
|
+
if not data.startswith(prefix):
|
|
268
|
+
return False
|
|
269
|
+
|
|
270
|
+
user = call.from_user
|
|
271
|
+
parts = data.split(":")
|
|
272
|
+
action = parts[1] if len(parts) > 1 else ""
|
|
273
|
+
offer_id = int(parts[2]) if len(parts) > 2 and parts[2].isdigit() else None
|
|
274
|
+
|
|
275
|
+
if action == "refresh":
|
|
276
|
+
await self._answer_call(call)
|
|
277
|
+
await self._render_offer(call.message, user, force_refresh=True)
|
|
278
|
+
return True
|
|
279
|
+
|
|
280
|
+
session = await self._get_session(user)
|
|
281
|
+
current = self._current_offer(session)
|
|
282
|
+
|
|
283
|
+
if action == "next":
|
|
284
|
+
await self._answer_call(call)
|
|
285
|
+
if session.offers:
|
|
286
|
+
session.index = (session.index + 1) % len(session.offers)
|
|
287
|
+
await self._render_offer(call.message, user)
|
|
288
|
+
return True
|
|
289
|
+
|
|
290
|
+
if action == "check":
|
|
291
|
+
if offer_id is None:
|
|
292
|
+
await self._answer_call(call, "Некорректный ID задания.", show_alert=True)
|
|
293
|
+
return True
|
|
294
|
+
result = await self.client.check_task(
|
|
295
|
+
user_id=int(user.id),
|
|
296
|
+
offer_id=offer_id,
|
|
297
|
+
username=getattr(user, "username", None),
|
|
298
|
+
language_code=getattr(user, "language_code", None) or "ru",
|
|
299
|
+
is_premium=bool(getattr(user, "is_premium", False)),
|
|
300
|
+
)
|
|
301
|
+
await self._answer_call(call, str(result.get("message") or "Проверено"), show_alert=True)
|
|
302
|
+
await self._render_offer(call.message, user, force_refresh=True)
|
|
303
|
+
return True
|
|
304
|
+
|
|
305
|
+
await self._answer_call(call)
|
|
306
|
+
if current and offer_id and int(current.get("id") or 0) != offer_id:
|
|
307
|
+
await self._render_offer(call.message, user, force_refresh=True)
|
|
308
|
+
return True
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from procket_integration_sdk import (
|
|
2
|
+
PRocketAiogramIntegration,
|
|
3
|
+
PRocketIntegrationClient,
|
|
4
|
+
build_offer_keyboard,
|
|
5
|
+
format_offer_text,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"PRocketAiogramIntegration",
|
|
10
|
+
"PRocketIntegrationClient",
|
|
11
|
+
"build_offer_keyboard",
|
|
12
|
+
"format_offer_text",
|
|
13
|
+
]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: procketapi
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: PRocket integration library for Telegram bots
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
|
|
8
|
+
# PRocket API Library
|
|
9
|
+
|
|
10
|
+
This package is prepared for simple installation as:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
python -m pip install procketapi
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Important:
|
|
17
|
+
this short command starts working only after you publish the package to PyPI.
|
|
18
|
+
|
|
19
|
+
## For the service owner
|
|
20
|
+
|
|
21
|
+
You run the PRocket backend on your own server:
|
|
22
|
+
|
|
23
|
+
1. `python main.py`
|
|
24
|
+
2. `python -m integration_service.api_server`
|
|
25
|
+
|
|
26
|
+
The connected bot owner does not run your backend.
|
|
27
|
+
They only:
|
|
28
|
+
|
|
29
|
+
1. get an approved API key
|
|
30
|
+
2. get your public `base_url`
|
|
31
|
+
3. install your library
|
|
32
|
+
4. add the integration into their own bot
|
|
33
|
+
|
|
34
|
+
## Recommended import
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from procketapi import PRocketAiogramIntegration
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Compatibility imports also work:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from procket_integration import PRocketAiogramIntegration
|
|
44
|
+
from procket_integration_sdk import PRocketAiogramIntegration
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Easy aiogram integration
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from aiogram import F, Router
|
|
51
|
+
from aiogram.types import CallbackQuery, Message
|
|
52
|
+
from procketapi import PRocketAiogramIntegration
|
|
53
|
+
|
|
54
|
+
router = Router()
|
|
55
|
+
integration = PRocketAiogramIntegration(
|
|
56
|
+
api_key="YOUR_API_KEY",
|
|
57
|
+
base_url="https://your-public-api.example.com",
|
|
58
|
+
callback_prefix="sponsor",
|
|
59
|
+
currency="RUB",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@router.message(F.text == "📢 Задания от спонсоров")
|
|
64
|
+
async def sponsor_tasks(message: Message):
|
|
65
|
+
await integration.show_tasks(message)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@router.callback_query(F.data.startswith("sponsor:"))
|
|
69
|
+
async def sponsor_callbacks(call: CallbackQuery):
|
|
70
|
+
await integration.handle_callback(call)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Until the package is published
|
|
74
|
+
|
|
75
|
+
Before PyPI publication, installation is possible from a local wheel:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
python -m pip install ./procketapi-0.3.0-py3-none-any.whl
|
|
79
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
procket_integration/__init__.py
|
|
4
|
+
procket_integration_sdk/__init__.py
|
|
5
|
+
procket_integration_sdk/client.py
|
|
6
|
+
procketapi/__init__.py
|
|
7
|
+
procketapi.egg-info/PKG-INFO
|
|
8
|
+
procketapi.egg-info/SOURCES.txt
|
|
9
|
+
procketapi.egg-info/dependency_links.txt
|
|
10
|
+
procketapi.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "procketapi"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "PRocket integration library for Telegram bots"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
|
|
12
|
+
[tool.setuptools]
|
|
13
|
+
packages = ["procket_integration_sdk", "procket_integration", "procketapi"]
|