taslim19
commited on
Commit
Β·
65dca5a
1
Parent(s):
6f39b38
fix: make payment and transaction links clickable in extol plugin
Browse files- DragMusic/plugins/games/extol.py +217 -0
DragMusic/plugins/games/extol.py
ADDED
@@ -0,0 +1,217 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Extol Wallet & Payment Integration for DragMusic Bot
|
3 |
+
|
4 |
+
Commands:
|
5 |
+
/addapi <api_key> (private chat only)
|
6 |
+
/addextol <address>
|
7 |
+
/removeextol
|
8 |
+
/payextol <amount>
|
9 |
+
/checkextol
|
10 |
+
/extolbal
|
11 |
+
/sendextol <to_address> <amount>
|
12 |
+
"""
|
13 |
+
|
14 |
+
import os
|
15 |
+
import httpx
|
16 |
+
from pyrogram import filters
|
17 |
+
from DragMusic import app
|
18 |
+
from DragMusic.utils.database import mongodb
|
19 |
+
from pyrogram.types import Message
|
20 |
+
from datetime import datetime
|
21 |
+
|
22 |
+
API_BASE_URL = "https://marketapi.animerealms.org"
|
23 |
+
api_keys_collection = mongodb.iac_api_keys
|
24 |
+
addresses_collection = mongodb.iac_extol_addresses
|
25 |
+
payments_collection = mongodb.iac_payments
|
26 |
+
|
27 |
+
# Async helpers for MongoDB
|
28 |
+
async def set_user_api_key(user_id: int, api_key: str):
|
29 |
+
await api_keys_collection.update_one(
|
30 |
+
{"user_id": user_id},
|
31 |
+
{"$set": {"api_key": api_key}},
|
32 |
+
upsert=True
|
33 |
+
)
|
34 |
+
|
35 |
+
async def get_user_api_key(user_id: int):
|
36 |
+
doc = await api_keys_collection.find_one({"user_id": user_id})
|
37 |
+
return doc["api_key"] if doc and "api_key" in doc else None
|
38 |
+
|
39 |
+
async def set_user_address(user_id: int, address: str):
|
40 |
+
await addresses_collection.update_one(
|
41 |
+
{"user_id": user_id},
|
42 |
+
{"$set": {"address": address}},
|
43 |
+
upsert=True
|
44 |
+
)
|
45 |
+
|
46 |
+
async def get_user_address(user_id: int):
|
47 |
+
doc = await addresses_collection.find_one({"user_id": user_id})
|
48 |
+
return doc["address"] if doc and "address" in doc else None
|
49 |
+
|
50 |
+
async def remove_user_address(user_id: int):
|
51 |
+
await addresses_collection.delete_one({"user_id": user_id})
|
52 |
+
|
53 |
+
async def set_last_payment_id(user_id: int, payment_id: str):
|
54 |
+
await payments_collection.update_one(
|
55 |
+
{"user_id": user_id},
|
56 |
+
{"$set": {"last_payment_id": payment_id}},
|
57 |
+
upsert=True
|
58 |
+
)
|
59 |
+
|
60 |
+
async def get_last_payment_id(user_id: int):
|
61 |
+
doc = await payments_collection.find_one({"user_id": user_id})
|
62 |
+
return doc["last_payment_id"] if doc and "last_payment_id" in doc else None
|
63 |
+
|
64 |
+
async def save_payment(user_id: int, payment_id: str, address: str, amount: float, payment_url: str):
|
65 |
+
await payments_collection.insert_one({
|
66 |
+
"user_id": user_id,
|
67 |
+
"payment_id": payment_id,
|
68 |
+
"address": address,
|
69 |
+
"amount": amount,
|
70 |
+
"payment_url": payment_url,
|
71 |
+
"created_at": datetime.utcnow()
|
72 |
+
})
|
73 |
+
|
74 |
+
async def get_user_payments(user_id: int, limit: int = 10):
|
75 |
+
cursor = payments_collection.find({"user_id": user_id}).sort("created_at", -1).limit(limit)
|
76 |
+
return await cursor.to_list(length=limit)
|
77 |
+
|
78 |
+
# /addapi <api_key> (private chat only)
|
79 |
+
@app.on_message(filters.command("addapi") & filters.private)
|
80 |
+
async def set_api_key_handler(client, message: Message):
|
81 |
+
args = message.text.split()
|
82 |
+
if len(args) != 2:
|
83 |
+
await message.reply_text("Usage: /addapi <your_api_key>")
|
84 |
+
return
|
85 |
+
await set_user_api_key(message.from_user.id, args[1])
|
86 |
+
await message.reply_text("β
Extol API Key set successfully.")
|
87 |
+
|
88 |
+
# Helper to check API key
|
89 |
+
async def check_api_key(message: Message):
|
90 |
+
user_id = message.from_user.id
|
91 |
+
api_key = await get_user_api_key(user_id)
|
92 |
+
if not api_key:
|
93 |
+
await message.reply_text("[IAC Marketplace] API key not set. Use /addapi <your_api_key> in bot DM to set it.")
|
94 |
+
return None
|
95 |
+
return api_key
|
96 |
+
|
97 |
+
# /addextol <address>
|
98 |
+
@app.on_message(filters.command("addextol"))
|
99 |
+
async def add_extol_handler(client, message: Message):
|
100 |
+
args = message.text.split()
|
101 |
+
if len(args) != 2 or not args[1].startswith("EXT"):
|
102 |
+
await message.reply_text("β Provide a valid Extol address starting with EXT.\n Usage: /addextol <address>")
|
103 |
+
return
|
104 |
+
await set_user_address(message.from_user.id, args[1])
|
105 |
+
await message.reply_text(f"β
Extol address saved: `{args[1]}`.")
|
106 |
+
|
107 |
+
# /removeextol
|
108 |
+
@app.on_message(filters.command("removeextol"))
|
109 |
+
async def remove_extol_handler(client, message: Message):
|
110 |
+
await remove_user_address(message.from_user.id)
|
111 |
+
await message.reply_text("β
Extol address removed.")
|
112 |
+
|
113 |
+
# /payextol <amount>
|
114 |
+
@app.on_message(filters.command("payextol"))
|
115 |
+
async def pay_extol_handler(client, message: Message):
|
116 |
+
args = message.text.split()
|
117 |
+
if len(args) != 2 or not args[1].isdigit():
|
118 |
+
await message.reply_text("β Enter a valid numeric amount.\n Usage: /payextol <amount>")
|
119 |
+
return
|
120 |
+
address = await get_user_address(message.from_user.id)
|
121 |
+
if not address:
|
122 |
+
await message.reply_text("β Use /addextol <address> to set your address first.")
|
123 |
+
return
|
124 |
+
msg = await message.reply_text("π Generating payment link...")
|
125 |
+
data = {"address": address, "amount": int(args[1])}
|
126 |
+
resp = await extol_request(message.from_user.id, "/api/create-payment", method="POST", data=data)
|
127 |
+
if not resp.get("ok"):
|
128 |
+
return await msg.edit(f"β Error: `{resp.get('error')}`")
|
129 |
+
payment_id = resp["payment_id"]
|
130 |
+
await set_last_payment_id(message.from_user.id, payment_id)
|
131 |
+
# Save payment to history for /checkextol
|
132 |
+
await save_payment(message.from_user.id, payment_id, address, int(args[1]), resp["payment_url"])
|
133 |
+
await msg.edit(f"β
<a href='{resp['payment_url']}'>Click here to pay</a>", disable_web_page_preview=True, parse_mode="html")
|
134 |
+
|
135 |
+
# /checkextol
|
136 |
+
@app.on_message(filters.command("checkextol"))
|
137 |
+
async def check_extol_handler(client, message: Message):
|
138 |
+
payments = await get_user_payments(message.from_user.id, limit=10)
|
139 |
+
if not payments:
|
140 |
+
await message.reply_text("β No recent payments found.")
|
141 |
+
return
|
142 |
+
msg = await message.reply_text("π Checking last 10 payment statuses...")
|
143 |
+
status_lines = []
|
144 |
+
for p in payments:
|
145 |
+
payment_id = p["payment_id"]
|
146 |
+
amount = p["amount"]
|
147 |
+
pay_url = p["payment_url"]
|
148 |
+
resp = await extol_request(message.from_user.id, "/api/payment-status", params={"payment_id": payment_id})
|
149 |
+
if not resp.get("ok"):
|
150 |
+
status_str = f"β Error: {resp.get('error') or 'Unknown'}"
|
151 |
+
else:
|
152 |
+
status = resp["status"]
|
153 |
+
if status == "paid":
|
154 |
+
status_str = f"β
<b>Paid</b><br>From: <code>{resp.get('from_address', '-')}", At: <code>{resp.get('paid_at', '-')}</code>"
|
155 |
+
elif status == "timeout":
|
156 |
+
status_str = f"β <b>Timeout</b><br>Expired: <code>{resp.get('expired_at', '-')}</code>"
|
157 |
+
else:
|
158 |
+
status_str = "β³ <b>Pending</b>"
|
159 |
+
status_lines.append(f"Amount: <code>{amount}</code><br>"
|
160 |
+
f'<a href="{pay_url}">Click here to pay</a><br>'
|
161 |
+
f"ID: <code>{payment_id}</code><br>{status_str}")
|
162 |
+
await msg.edit("<br><br>".join(status_lines), disable_web_page_preview=True, parse_mode="html")
|
163 |
+
|
164 |
+
# /extolbal
|
165 |
+
@app.on_message(filters.command("extolbal"))
|
166 |
+
async def extol_balance_handler(client, message: Message):
|
167 |
+
msg = await message.reply_text("π Fetching Extol balance...")
|
168 |
+
resp = await extol_request(message.from_user.id, "/api/balance")
|
169 |
+
if not resp.get("ok"):
|
170 |
+
return await msg.edit(f"β Error: `{resp.get('error')}`")
|
171 |
+
balance = resp.get("balance", 0)
|
172 |
+
address = resp.get("address", "Unknown")
|
173 |
+
await msg.edit(f"π° Balance: {balance} EXT\nπ·οΈ **Address: {address}")
|
174 |
+
|
175 |
+
# /sendextol <to_address> <amount>
|
176 |
+
@app.on_message(filters.command("sendextol"))
|
177 |
+
async def send_extol_handler(client, message: Message):
|
178 |
+
args = message.text.split()
|
179 |
+
if len(args) != 3 or not args[2].isdigit() or not args[1].startswith("EXT"):
|
180 |
+
await message.reply_text("Usage: /sendextol <to_address> <amount>")
|
181 |
+
return
|
182 |
+
to_address, amt = args[1], int(args[2])
|
183 |
+
if amt <= 0:
|
184 |
+
await message.reply_text("β Amount must be positive.")
|
185 |
+
return
|
186 |
+
msg = await message.reply_text("π Sending Extol...")
|
187 |
+
resp = await extol_request(
|
188 |
+
message.from_user.id,
|
189 |
+
"/api/withdraw",
|
190 |
+
method="GET",
|
191 |
+
params={"amount": amt, "address": to_address},
|
192 |
+
)
|
193 |
+
if not resp.get("ok"):
|
194 |
+
error_msg = resp.get('error') or 'Unknown error (no message from API)'
|
195 |
+
code = resp.get('code')
|
196 |
+
if code is not None:
|
197 |
+
error_msg = f"(code {code}) {error_msg}"
|
198 |
+
return await msg.edit(f"β Error: {error_msg}")
|
199 |
+
link = resp.get("link", "No explorer link.")
|
200 |
+
await msg.edit(f"β
Sent {amt} EXT to {to_address} \n<a href='{link}'>View Transaction</a>", disable_web_page_preview=True, parse_mode="html")
|
201 |
+
|
202 |
+
# --- HTTPX helper ---
|
203 |
+
|
204 |
+
async def extol_request(user_id, path, method="GET", data=None, params=None):
|
205 |
+
api_key = await get_user_api_key(user_id)
|
206 |
+
if not api_key:
|
207 |
+
return {"ok": False, "error": "API key not set. Use /addapi <key> in DM."}
|
208 |
+
async with httpx.AsyncClient() as client:
|
209 |
+
headers = {"api-key": api_key}
|
210 |
+
try:
|
211 |
+
if method == "GET":
|
212 |
+
r = await client.get(f"{API_BASE_URL}{path}", headers=headers, params=params, timeout=10)
|
213 |
+
else:
|
214 |
+
r = await client.post(f"{API_BASE_URL}{path}", headers=headers, json=data, timeout=10)
|
215 |
+
return r.json()
|
216 |
+
except Exception as e:
|
217 |
+
return {"ok": False, "error": str(e)}
|