cordscript 1.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.
- cordscript/__init__.py +6 -0
- cordscript/client.py +590 -0
- cordscript/core/__init__.py +9 -0
- cordscript/core/context.py +33 -0
- cordscript/core/runtime.py +55 -0
- cordscript/core/variables.py +16 -0
- cordscript/exceptions/__init__.py +3 -0
- cordscript/exceptions/errors.py +9 -0
- cordscript/functions/__init__.py +45 -0
- cordscript/functions/database/__init__.py +4 -0
- cordscript/functions/database/database.py +846 -0
- cordscript/functions/database/store.py +69 -0
- cordscript/functions/discord/__init__.py +15 -0
- cordscript/functions/discord/components.py +134 -0
- cordscript/functions/discord/componentsv2.py +92 -0
- cordscript/functions/discord/embed.py +63 -0
- cordscript/functions/discord/interaction.py +48 -0
- cordscript/functions/discord/logic.py +87 -0
- cordscript/functions/discord/message.py +51 -0
- cordscript/functions/discord/moderation.py +179 -0
- cordscript/functions/discord/status.py +56 -0
- cordscript/functions/users/__init__.py +3 -0
- cordscript/functions/users/user.py +103 -0
- cordscript/functions/utility/__init__.py +14 -0
- cordscript/functions/utility/cooldown.py +35 -0
- cordscript/functions/utility/http.py +73 -0
- cordscript/functions/utility/json.py +201 -0
- cordscript/functions/utility/math.py +102 -0
- cordscript/functions/utility/random.py +27 -0
- cordscript/functions/utility/strings.py +201 -0
- cordscript/functions/utility/time.py +41 -0
- cordscript/parser.py +190 -0
- cordscript/setup.py +38 -0
- cordscript-1.0.0.dist-info/METADATA +17 -0
- cordscript-1.0.0.dist-info/RECORD +37 -0
- cordscript-1.0.0.dist-info/WHEEL +5 -0
- cordscript-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from .store import Database
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
from contextlib import redirect_stdout, redirect_stderr
|
|
6
|
+
|
|
7
|
+
class SuppressOutput:
|
|
8
|
+
def __enter__(self):
|
|
9
|
+
self._stdout = sys.stdout
|
|
10
|
+
self._stderr = sys.stderr
|
|
11
|
+
sys.stdout = open(os.devnull, 'w')
|
|
12
|
+
sys.stderr = open(os.devnull, 'w')
|
|
13
|
+
return self
|
|
14
|
+
|
|
15
|
+
def __exit__(self, *args):
|
|
16
|
+
sys.stdout.close()
|
|
17
|
+
sys.stderr.close()
|
|
18
|
+
sys.stdout = self._stdout
|
|
19
|
+
sys.stderr = self._stderr
|
|
20
|
+
|
|
21
|
+
def _detect_db(db) -> str:
|
|
22
|
+
t = type(db).__name__.lower()
|
|
23
|
+
module = type(db).__module__.lower()
|
|
24
|
+
if "motor" in module or "asynciomotorclient" in t:
|
|
25
|
+
return "motor"
|
|
26
|
+
if "mongoclient" in t or "mongo" in module:
|
|
27
|
+
return "pymongo"
|
|
28
|
+
if "asyncpg" in module:
|
|
29
|
+
return "asyncpg"
|
|
30
|
+
if "psycopg" in module:
|
|
31
|
+
return "psycopg"
|
|
32
|
+
if "bettersqlite" in t or "better_sqlite3" in module:
|
|
33
|
+
return "better_sqlite3"
|
|
34
|
+
if "connection" in t and "sqlite" in module:
|
|
35
|
+
return "sqlite3"
|
|
36
|
+
return "unknown"
|
|
37
|
+
|
|
38
|
+
async def _init_table(db):
|
|
39
|
+
kind = _detect_db(db)
|
|
40
|
+
sql = """
|
|
41
|
+
CREATE TABLE IF NOT EXISTS cordscript_vars (
|
|
42
|
+
user_id TEXT,
|
|
43
|
+
key TEXT,
|
|
44
|
+
value TEXT,
|
|
45
|
+
PRIMARY KEY (user_id, key)
|
|
46
|
+
)
|
|
47
|
+
"""
|
|
48
|
+
if kind == "motor":
|
|
49
|
+
await db["cordscript_vars"].create_index([("user_id", 1), ("key", 1)], unique=True)
|
|
50
|
+
elif kind in ("asyncpg", "psycopg"):
|
|
51
|
+
await db.execute(sql)
|
|
52
|
+
elif kind == "sqlite3":
|
|
53
|
+
cur = db.cursor()
|
|
54
|
+
cur.execute(sql)
|
|
55
|
+
db.commit()
|
|
56
|
+
elif kind == "better_sqlite3":
|
|
57
|
+
db.prepare(sql).run()
|
|
58
|
+
|
|
59
|
+
async def connect_from_url(url: str):
|
|
60
|
+
if url.startswith("mongodb"):
|
|
61
|
+
try:
|
|
62
|
+
import motor.motor_asyncio
|
|
63
|
+
client = motor.motor_asyncio.AsyncIOMotorClient(url)
|
|
64
|
+
return client.get_default_database() or client["cordscript"]
|
|
65
|
+
except ImportError:
|
|
66
|
+
raise ImportError("motor not installed: pip install motor")
|
|
67
|
+
if url.startswith("postgresql") or url.startswith("postgres"):
|
|
68
|
+
try:
|
|
69
|
+
import asyncpg
|
|
70
|
+
return await asyncpg.connect(url)
|
|
71
|
+
except ImportError:
|
|
72
|
+
raise ImportError("asyncpg not installed: pip install asyncpg")
|
|
73
|
+
if url.startswith("sqlite"):
|
|
74
|
+
path = url.replace("sqlite:///", "").replace("sqlite://", "")
|
|
75
|
+
import sqlite3
|
|
76
|
+
return sqlite3.connect(path)
|
|
77
|
+
raise ValueError(f"Unrecognized database URL: {url}")
|
|
78
|
+
|
|
79
|
+
async def _get_legacy(db, key: str, user_id: str) -> str:
|
|
80
|
+
kind = _detect_db(db)
|
|
81
|
+
try:
|
|
82
|
+
if kind == "motor":
|
|
83
|
+
doc = await db["cordscript_vars"].find_one({"user_id": user_id, "key": key})
|
|
84
|
+
return str(doc["value"]) if doc else ""
|
|
85
|
+
if kind == "pymongo":
|
|
86
|
+
doc = db["cordscript_vars"].find_one({"user_id": user_id, "key": key})
|
|
87
|
+
return str(doc["value"]) if doc else ""
|
|
88
|
+
if kind in ("asyncpg", "psycopg"):
|
|
89
|
+
row = await db.fetchrow("SELECT value FROM cordscript_vars WHERE user_id=$1 AND key=$2", user_id, key)
|
|
90
|
+
return str(row["value"]) if row else ""
|
|
91
|
+
if kind == "sqlite3":
|
|
92
|
+
cur = db.cursor()
|
|
93
|
+
cur.execute("SELECT value FROM cordscript_vars WHERE user_id=? AND key=?", (user_id, key))
|
|
94
|
+
row = cur.fetchone()
|
|
95
|
+
return str(row[0]) if row else ""
|
|
96
|
+
if kind == "better_sqlite3":
|
|
97
|
+
row = db.prepare("SELECT value FROM cordscript_vars WHERE user_id=? AND key=?").get(user_id, key)
|
|
98
|
+
return str(row["value"]) if row else ""
|
|
99
|
+
except Exception as e:
|
|
100
|
+
return f"[Error in $getVar: {e}]"
|
|
101
|
+
return ""
|
|
102
|
+
|
|
103
|
+
async def _set_legacy(db, key: str, value: str, user_id: str):
|
|
104
|
+
kind = _detect_db(db)
|
|
105
|
+
try:
|
|
106
|
+
if kind == "motor":
|
|
107
|
+
await db["cordscript_vars"].update_one(
|
|
108
|
+
{"user_id": user_id, "key": key}, {"$set": {"value": value}}, upsert=True
|
|
109
|
+
)
|
|
110
|
+
elif kind == "pymongo":
|
|
111
|
+
db["cordscript_vars"].update_one(
|
|
112
|
+
{"user_id": user_id, "key": key}, {"$set": {"value": value}}, upsert=True
|
|
113
|
+
)
|
|
114
|
+
elif kind in ("asyncpg", "psycopg"):
|
|
115
|
+
await db.execute("""
|
|
116
|
+
INSERT INTO cordscript_vars (user_id, key, value)
|
|
117
|
+
VALUES ($1, $2, $3)
|
|
118
|
+
ON CONFLICT (user_id, key) DO UPDATE SET value=$3
|
|
119
|
+
""", user_id, key, value)
|
|
120
|
+
elif kind == "sqlite3":
|
|
121
|
+
cur = db.cursor()
|
|
122
|
+
cur.execute("""
|
|
123
|
+
INSERT INTO cordscript_vars (user_id, key, value)
|
|
124
|
+
VALUES (?, ?, ?)
|
|
125
|
+
ON CONFLICT(user_id, key) DO UPDATE SET value=excluded.value
|
|
126
|
+
""", (user_id, key, value))
|
|
127
|
+
db.commit()
|
|
128
|
+
elif kind == "better_sqlite3":
|
|
129
|
+
db.prepare("""
|
|
130
|
+
INSERT INTO cordscript_vars (user_id, key, value)
|
|
131
|
+
VALUES (?, ?, ?)
|
|
132
|
+
ON CONFLICT(user_id, key) DO UPDATE SET value=excluded.value
|
|
133
|
+
""").run(user_id, key, value)
|
|
134
|
+
except Exception as e:
|
|
135
|
+
return f"[Error in $setVar: {e}]"
|
|
136
|
+
|
|
137
|
+
def _default_ids(ctx):
|
|
138
|
+
import discord
|
|
139
|
+
user_id = str(ctx.user.id) if isinstance(ctx, discord.Interaction) else str(getattr(ctx, "author", ctx).id)
|
|
140
|
+
channel = getattr(ctx, "channel", None)
|
|
141
|
+
channel_id = str(channel.id) if channel else ""
|
|
142
|
+
guild = getattr(ctx, "guild", None)
|
|
143
|
+
guild_id = str(guild.id) if guild else ""
|
|
144
|
+
return user_id, channel_id, guild_id
|
|
145
|
+
|
|
146
|
+
async def handle_database(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
147
|
+
db = getattr(parser.client, "_database", None)
|
|
148
|
+
if db is None:
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
ctx = parser.ctx
|
|
152
|
+
default_uid, default_cid, default_gid = _default_ids(ctx)
|
|
153
|
+
|
|
154
|
+
def _val(index: int) -> str:
|
|
155
|
+
return args[index] if len(args) > index else ""
|
|
156
|
+
|
|
157
|
+
def _key(index: int = 0) -> str:
|
|
158
|
+
return _val(index).strip()
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
if isinstance(db, Database):
|
|
162
|
+
match fn:
|
|
163
|
+
case "getuservar":
|
|
164
|
+
key = _key(0)
|
|
165
|
+
uid = _val(1).strip() or default_uid
|
|
166
|
+
if not key:
|
|
167
|
+
return "[Error in $getUserVar: variable name required]"
|
|
168
|
+
return db.get("user", uid, key)
|
|
169
|
+
|
|
170
|
+
case "setuservar":
|
|
171
|
+
key = _key(0)
|
|
172
|
+
value = _val(1)
|
|
173
|
+
uid = _val(2).strip() or default_uid
|
|
174
|
+
if not key:
|
|
175
|
+
return "[Error in $setUserVar: variable name required]"
|
|
176
|
+
db.set("user", uid, key, value)
|
|
177
|
+
return ""
|
|
178
|
+
|
|
179
|
+
case "getchannelvar":
|
|
180
|
+
key = _key(0)
|
|
181
|
+
cid = _val(1).strip() or default_cid
|
|
182
|
+
if not key:
|
|
183
|
+
return "[Error in $getChannelVar: variable name required]"
|
|
184
|
+
return db.get("channel", cid, key)
|
|
185
|
+
|
|
186
|
+
case "setchannelvar":
|
|
187
|
+
key = _key(0)
|
|
188
|
+
value = _val(1)
|
|
189
|
+
cid = _val(2).strip() or default_cid
|
|
190
|
+
if not key:
|
|
191
|
+
return "[Error in $setChannelVar: variable name required]"
|
|
192
|
+
db.set("channel", cid, key, value)
|
|
193
|
+
return ""
|
|
194
|
+
|
|
195
|
+
case "getguildvar":
|
|
196
|
+
key = _key(0)
|
|
197
|
+
gid = _val(1).strip() or default_gid
|
|
198
|
+
if not key:
|
|
199
|
+
return "[Error in $getGuildVar: variable name required]"
|
|
200
|
+
return db.get("guild", gid, key)
|
|
201
|
+
|
|
202
|
+
case "setguildvar":
|
|
203
|
+
key = _key(0)
|
|
204
|
+
value = _val(1)
|
|
205
|
+
gid = _val(2).strip() or default_gid
|
|
206
|
+
if not key:
|
|
207
|
+
return "[Error in $setGuildVar: variable name required]"
|
|
208
|
+
db.set("guild", gid, key, value)
|
|
209
|
+
return ""
|
|
210
|
+
|
|
211
|
+
case "getvar":
|
|
212
|
+
key = _key(0)
|
|
213
|
+
uid = _val(1).strip() or default_uid
|
|
214
|
+
if not key:
|
|
215
|
+
return "[Error in $getVar: variable name required]"
|
|
216
|
+
return db.get("user", uid, key)
|
|
217
|
+
|
|
218
|
+
case "setvar":
|
|
219
|
+
key = _key(0)
|
|
220
|
+
value = _val(1)
|
|
221
|
+
uid = _val(2).strip() or default_uid
|
|
222
|
+
if not key:
|
|
223
|
+
return "[Error in $setVar: variable name required]"
|
|
224
|
+
db.set("user", uid, key, value)
|
|
225
|
+
return ""
|
|
226
|
+
|
|
227
|
+
case "getdb":
|
|
228
|
+
import json
|
|
229
|
+
try:
|
|
230
|
+
with SuppressOutput():
|
|
231
|
+
all_data = db.get_all() if hasattr(db, 'get_all') else {}
|
|
232
|
+
return json.dumps(all_data, indent=2, ensure_ascii=False)
|
|
233
|
+
except Exception as e:
|
|
234
|
+
return f"[Error in $getDB: {e}]"
|
|
235
|
+
|
|
236
|
+
case "searchdb":
|
|
237
|
+
import json
|
|
238
|
+
try:
|
|
239
|
+
path = _key(0)
|
|
240
|
+
with SuppressOutput():
|
|
241
|
+
all_data = db.get_all() if hasattr(db, 'get_all') else {}
|
|
242
|
+
|
|
243
|
+
if not path:
|
|
244
|
+
return json.dumps(all_data, indent=2, ensure_ascii=False)
|
|
245
|
+
|
|
246
|
+
results = {}
|
|
247
|
+
def search_recursive(obj, search_term, current_path=""):
|
|
248
|
+
if isinstance(obj, dict):
|
|
249
|
+
for key, value in obj.items():
|
|
250
|
+
new_path = f"{current_path}.{key}" if current_path else key
|
|
251
|
+
if search_term.lower() in key.lower():
|
|
252
|
+
results[new_path] = value
|
|
253
|
+
search_recursive(value, search_term, new_path)
|
|
254
|
+
elif isinstance(obj, list):
|
|
255
|
+
for i, item in enumerate(obj):
|
|
256
|
+
new_path = f"{current_path}[{i}]"
|
|
257
|
+
search_recursive(item, search_term, new_path)
|
|
258
|
+
elif isinstance(obj, str) and search_term.lower() in obj.lower():
|
|
259
|
+
results[current_path] = obj
|
|
260
|
+
|
|
261
|
+
search_recursive(all_data, path)
|
|
262
|
+
|
|
263
|
+
if results:
|
|
264
|
+
return json.dumps(results, indent=2, ensure_ascii=False)
|
|
265
|
+
else:
|
|
266
|
+
return f"[No results found for '{path}']"
|
|
267
|
+
except Exception as e:
|
|
268
|
+
return f"[Error in $searchDB: {e}]"
|
|
269
|
+
|
|
270
|
+
case "wipedb":
|
|
271
|
+
try:
|
|
272
|
+
with SuppressOutput():
|
|
273
|
+
if hasattr(db, 'wipe'):
|
|
274
|
+
db.wipe()
|
|
275
|
+
return "[Database wiped successfully]"
|
|
276
|
+
else:
|
|
277
|
+
return "[Error in $wipeDB: wipe method not available]"
|
|
278
|
+
except Exception as e:
|
|
279
|
+
return f"[Error in $wipeDB: {e}]"
|
|
280
|
+
|
|
281
|
+
case "getuserleaderboardid":
|
|
282
|
+
name = _key(0)
|
|
283
|
+
sort_type = _key(1) or "DESC"
|
|
284
|
+
position = int(_key(2)) if _key(2) else 1
|
|
285
|
+
|
|
286
|
+
if not name:
|
|
287
|
+
return "[Error in $getUserLeaderboardID: name required]"
|
|
288
|
+
|
|
289
|
+
try:
|
|
290
|
+
with SuppressOutput():
|
|
291
|
+
all_data = db.get_all() if hasattr(db, 'get_all') else {}
|
|
292
|
+
|
|
293
|
+
leaderboard = {}
|
|
294
|
+
if "user" in all_data:
|
|
295
|
+
for user_id, vars_dict in all_data.get("user", {}).items():
|
|
296
|
+
if name in vars_dict:
|
|
297
|
+
try:
|
|
298
|
+
value = float(vars_dict[name])
|
|
299
|
+
leaderboard[user_id] = value
|
|
300
|
+
except (ValueError, TypeError):
|
|
301
|
+
pass
|
|
302
|
+
|
|
303
|
+
if sort_type.upper() == "ASC":
|
|
304
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1])
|
|
305
|
+
else:
|
|
306
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1], reverse=True)
|
|
307
|
+
|
|
308
|
+
if 1 <= position <= len(sorted_lb):
|
|
309
|
+
return sorted_lb[position - 1][0]
|
|
310
|
+
else:
|
|
311
|
+
return "[Position not found]"
|
|
312
|
+
except Exception as e:
|
|
313
|
+
return f"[Error in $getUserLeaderboardID: {e}]"
|
|
314
|
+
|
|
315
|
+
case "userleaderboard":
|
|
316
|
+
name = _key(0)
|
|
317
|
+
sort_type = _key(1) or "DESC"
|
|
318
|
+
max_items = int(_key(2)) if _key(2) else 10
|
|
319
|
+
page = int(_key(3)) if _key(3) else 1
|
|
320
|
+
separator = _val(4) or "\n"
|
|
321
|
+
env_value = _key(5) or "{value}"
|
|
322
|
+
env_position = _key(6) or "{position}"
|
|
323
|
+
code = _val(7) or "{position}. {user_id} - {value}"
|
|
324
|
+
|
|
325
|
+
if not name:
|
|
326
|
+
return "[Error in $userLeaderboard: name required]"
|
|
327
|
+
|
|
328
|
+
try:
|
|
329
|
+
with SuppressOutput():
|
|
330
|
+
all_data = db.get_all() if hasattr(db, 'get_all') else {}
|
|
331
|
+
|
|
332
|
+
leaderboard = {}
|
|
333
|
+
if "user" in all_data:
|
|
334
|
+
for user_id, vars_dict in all_data.get("user", {}).items():
|
|
335
|
+
if name in vars_dict:
|
|
336
|
+
try:
|
|
337
|
+
value = float(vars_dict[name])
|
|
338
|
+
leaderboard[user_id] = value
|
|
339
|
+
except (ValueError, TypeError):
|
|
340
|
+
pass
|
|
341
|
+
|
|
342
|
+
if sort_type.upper() == "ASC":
|
|
343
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1])
|
|
344
|
+
else:
|
|
345
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1], reverse=True)
|
|
346
|
+
|
|
347
|
+
start = (page - 1) * max_items
|
|
348
|
+
end = start + max_items
|
|
349
|
+
page_data = sorted_lb[start:end]
|
|
350
|
+
|
|
351
|
+
if not page_data:
|
|
352
|
+
return "[No data for this page]"
|
|
353
|
+
|
|
354
|
+
result = []
|
|
355
|
+
for pos, (user_id, value) in enumerate(page_data, start=start + 1):
|
|
356
|
+
line = code.replace(env_value, str(value))
|
|
357
|
+
line = line.replace(env_position, str(pos))
|
|
358
|
+
line = line.replace("{user_id}", user_id)
|
|
359
|
+
line = line.replace("{value}", str(value))
|
|
360
|
+
line = line.replace("{position}", str(pos))
|
|
361
|
+
result.append(line)
|
|
362
|
+
|
|
363
|
+
return separator.join(result)
|
|
364
|
+
except Exception as e:
|
|
365
|
+
return f"[Error in $userLeaderboard: {e}]"
|
|
366
|
+
|
|
367
|
+
case "getuserleaderboardlength":
|
|
368
|
+
name = _key(0)
|
|
369
|
+
length_type = _key(1) or "count"
|
|
370
|
+
decimals = int(_key(2)) if _key(2) else 0
|
|
371
|
+
|
|
372
|
+
if not name:
|
|
373
|
+
return "[Error in $getUserLeaderboardLength: name required]"
|
|
374
|
+
|
|
375
|
+
try:
|
|
376
|
+
with SuppressOutput():
|
|
377
|
+
all_data = db.get_all() if hasattr(db, 'get_all') else {}
|
|
378
|
+
|
|
379
|
+
values = []
|
|
380
|
+
if "user" in all_data:
|
|
381
|
+
for user_id, vars_dict in all_data.get("user", {}).items():
|
|
382
|
+
if name in vars_dict:
|
|
383
|
+
try:
|
|
384
|
+
value = float(vars_dict[name])
|
|
385
|
+
values.append(value)
|
|
386
|
+
except (ValueError, TypeError):
|
|
387
|
+
pass
|
|
388
|
+
|
|
389
|
+
if length_type.lower() == "count":
|
|
390
|
+
result = len(values)
|
|
391
|
+
elif length_type.lower() == "sum":
|
|
392
|
+
result = sum(values) if values else 0
|
|
393
|
+
elif length_type.lower() == "avg":
|
|
394
|
+
result = sum(values) / len(values) if values else 0
|
|
395
|
+
elif length_type.lower() == "max":
|
|
396
|
+
result = max(values) if values else 0
|
|
397
|
+
elif length_type.lower() == "min":
|
|
398
|
+
result = min(values) if values else 0
|
|
399
|
+
else:
|
|
400
|
+
result = len(values)
|
|
401
|
+
|
|
402
|
+
if decimals > 0:
|
|
403
|
+
result = round(result, decimals)
|
|
404
|
+
else:
|
|
405
|
+
result = int(result)
|
|
406
|
+
|
|
407
|
+
return str(result)
|
|
408
|
+
except Exception as e:
|
|
409
|
+
return f"[Error in $getUserLeaderboardLength: {e}]"
|
|
410
|
+
|
|
411
|
+
case "getuserleaderboardvalue":
|
|
412
|
+
name = _key(0)
|
|
413
|
+
sort_type = _key(1) or "DESC"
|
|
414
|
+
user_id = _key(2)
|
|
415
|
+
|
|
416
|
+
if not name:
|
|
417
|
+
return "[Error in $getUserLeaderboardValue: name required]"
|
|
418
|
+
|
|
419
|
+
if not user_id:
|
|
420
|
+
import discord
|
|
421
|
+
ctx = parser.ctx
|
|
422
|
+
user_id = str(ctx.user.id) if isinstance(ctx, discord.Interaction) else str(getattr(ctx, "author", ctx).id)
|
|
423
|
+
|
|
424
|
+
try:
|
|
425
|
+
with SuppressOutput():
|
|
426
|
+
all_data = db.get_all() if hasattr(db, 'get_all') else {}
|
|
427
|
+
|
|
428
|
+
leaderboard = {}
|
|
429
|
+
if "user" in all_data:
|
|
430
|
+
for uid, vars_dict in all_data.get("user", {}).items():
|
|
431
|
+
if name in vars_dict:
|
|
432
|
+
try:
|
|
433
|
+
value = float(vars_dict[name])
|
|
434
|
+
leaderboard[uid] = value
|
|
435
|
+
except (ValueError, TypeError):
|
|
436
|
+
pass
|
|
437
|
+
|
|
438
|
+
if str(user_id) not in leaderboard:
|
|
439
|
+
return "[User not in leaderboard]"
|
|
440
|
+
|
|
441
|
+
user_value = leaderboard[str(user_id)]
|
|
442
|
+
|
|
443
|
+
if sort_type.upper() == "ASC":
|
|
444
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1])
|
|
445
|
+
else:
|
|
446
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1], reverse=True)
|
|
447
|
+
|
|
448
|
+
position = next((i + 1 for i, (uid, _) in enumerate(sorted_lb) if uid == str(user_id)), None)
|
|
449
|
+
|
|
450
|
+
return f"{user_value}|{position}"
|
|
451
|
+
except Exception as e:
|
|
452
|
+
return f"[Error in $getUserLeaderboardValue: {e}]"
|
|
453
|
+
|
|
454
|
+
case _:
|
|
455
|
+
return None
|
|
456
|
+
|
|
457
|
+
match fn:
|
|
458
|
+
case "setvar":
|
|
459
|
+
key = _key(0)
|
|
460
|
+
value = _val(1)
|
|
461
|
+
uid = _val(2).strip() or default_uid
|
|
462
|
+
if not key:
|
|
463
|
+
return "[Error in $setVar: variable name required]"
|
|
464
|
+
result = await _set_legacy(db, key, value, uid)
|
|
465
|
+
return result or ""
|
|
466
|
+
|
|
467
|
+
case "getvar":
|
|
468
|
+
key = _key(0)
|
|
469
|
+
uid = _val(1).strip() or default_uid
|
|
470
|
+
if not key:
|
|
471
|
+
return "[Error in $getVar: variable name required]"
|
|
472
|
+
return await _get_legacy(db, key, uid)
|
|
473
|
+
|
|
474
|
+
case "getdb":
|
|
475
|
+
import json
|
|
476
|
+
try:
|
|
477
|
+
kind = _detect_db(db)
|
|
478
|
+
all_data = {}
|
|
479
|
+
|
|
480
|
+
with SuppressOutput():
|
|
481
|
+
if kind == "motor":
|
|
482
|
+
cursor = db["cordscript_vars"].find({})
|
|
483
|
+
async for doc in cursor:
|
|
484
|
+
doc.pop("_id", None)
|
|
485
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
486
|
+
elif kind == "pymongo":
|
|
487
|
+
for doc in db["cordscript_vars"].find({}):
|
|
488
|
+
doc.pop("_id", None)
|
|
489
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
490
|
+
elif kind in ("asyncpg", "psycopg"):
|
|
491
|
+
rows = await db.fetch("SELECT * FROM cordscript_vars")
|
|
492
|
+
for row in rows:
|
|
493
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
494
|
+
elif kind == "sqlite3":
|
|
495
|
+
cur = db.cursor()
|
|
496
|
+
cur.execute("SELECT * FROM cordscript_vars")
|
|
497
|
+
for row in cur.fetchall():
|
|
498
|
+
all_data[f"{row[0]}_{row[1]}"] = row[2]
|
|
499
|
+
elif kind == "better_sqlite3":
|
|
500
|
+
rows = db.prepare("SELECT * FROM cordscript_vars").all()
|
|
501
|
+
for row in rows:
|
|
502
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
503
|
+
|
|
504
|
+
return json.dumps(all_data, indent=2, ensure_ascii=False)
|
|
505
|
+
except Exception as e:
|
|
506
|
+
return f"[Error in $getDB: {e}]"
|
|
507
|
+
|
|
508
|
+
case "searchdb":
|
|
509
|
+
import json
|
|
510
|
+
try:
|
|
511
|
+
path = _key(0)
|
|
512
|
+
kind = _detect_db(db)
|
|
513
|
+
all_data = {}
|
|
514
|
+
|
|
515
|
+
with SuppressOutput():
|
|
516
|
+
if kind == "motor":
|
|
517
|
+
cursor = db["cordscript_vars"].find({})
|
|
518
|
+
async for doc in cursor:
|
|
519
|
+
doc.pop("_id", None)
|
|
520
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
521
|
+
elif kind == "pymongo":
|
|
522
|
+
for doc in db["cordscript_vars"].find({}):
|
|
523
|
+
doc.pop("_id", None)
|
|
524
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
525
|
+
elif kind in ("asyncpg", "psycopg"):
|
|
526
|
+
rows = await db.fetch("SELECT * FROM cordscript_vars")
|
|
527
|
+
for row in rows:
|
|
528
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
529
|
+
elif kind == "sqlite3":
|
|
530
|
+
cur = db.cursor()
|
|
531
|
+
cur.execute("SELECT * FROM cordscript_vars")
|
|
532
|
+
for row in cur.fetchall():
|
|
533
|
+
all_data[f"{row[0]}_{row[1]}"] = row[2]
|
|
534
|
+
elif kind == "better_sqlite3":
|
|
535
|
+
rows = db.prepare("SELECT * FROM cordscript_vars").all()
|
|
536
|
+
for row in rows:
|
|
537
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
538
|
+
|
|
539
|
+
if not path:
|
|
540
|
+
return json.dumps(all_data, indent=2, ensure_ascii=False)
|
|
541
|
+
|
|
542
|
+
results = {}
|
|
543
|
+
for key, value in all_data.items():
|
|
544
|
+
if path.lower() in key.lower() or path.lower() in str(value).lower():
|
|
545
|
+
results[key] = value
|
|
546
|
+
|
|
547
|
+
if results:
|
|
548
|
+
return json.dumps(results, indent=2, ensure_ascii=False)
|
|
549
|
+
else:
|
|
550
|
+
return f"[No results found for '{path}']"
|
|
551
|
+
except Exception as e:
|
|
552
|
+
return f"[Error in $searchDB: {e}]"
|
|
553
|
+
|
|
554
|
+
case "wipedb":
|
|
555
|
+
try:
|
|
556
|
+
kind = _detect_db(db)
|
|
557
|
+
with SuppressOutput():
|
|
558
|
+
if kind == "motor":
|
|
559
|
+
await db["cordscript_vars"].delete_many({})
|
|
560
|
+
elif kind == "pymongo":
|
|
561
|
+
db["cordscript_vars"].delete_many({})
|
|
562
|
+
elif kind in ("asyncpg", "psycopg"):
|
|
563
|
+
await db.execute("DELETE FROM cordscript_vars")
|
|
564
|
+
elif kind == "sqlite3":
|
|
565
|
+
cur = db.cursor()
|
|
566
|
+
cur.execute("DELETE FROM cordscript_vars")
|
|
567
|
+
db.commit()
|
|
568
|
+
elif kind == "better_sqlite3":
|
|
569
|
+
db.prepare("DELETE FROM cordscript_vars").run()
|
|
570
|
+
return "[Database wiped successfully]"
|
|
571
|
+
except Exception as e:
|
|
572
|
+
return f"[Error in $wipeDB: {e}]"
|
|
573
|
+
|
|
574
|
+
case "getuserleaderboardid":
|
|
575
|
+
name = _key(0)
|
|
576
|
+
sort_type = _key(1) or "DESC"
|
|
577
|
+
position = int(_key(2)) if _key(2) else 1
|
|
578
|
+
|
|
579
|
+
if not name:
|
|
580
|
+
return "[Error in $getUserLeaderboardID: name required]"
|
|
581
|
+
|
|
582
|
+
try:
|
|
583
|
+
kind = _detect_db(db)
|
|
584
|
+
all_data = {}
|
|
585
|
+
|
|
586
|
+
with SuppressOutput():
|
|
587
|
+
if kind == "motor":
|
|
588
|
+
cursor = db["cordscript_vars"].find({})
|
|
589
|
+
async for doc in cursor:
|
|
590
|
+
doc.pop("_id", None)
|
|
591
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
592
|
+
elif kind == "pymongo":
|
|
593
|
+
for doc in db["cordscript_vars"].find({}):
|
|
594
|
+
doc.pop("_id", None)
|
|
595
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
596
|
+
elif kind in ("asyncpg", "psycopg"):
|
|
597
|
+
rows = await db.fetch("SELECT * FROM cordscript_vars")
|
|
598
|
+
for row in rows:
|
|
599
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
600
|
+
elif kind == "sqlite3":
|
|
601
|
+
cur = db.cursor()
|
|
602
|
+
cur.execute("SELECT * FROM cordscript_vars")
|
|
603
|
+
for row in cur.fetchall():
|
|
604
|
+
all_data[f"{row[0]}_{row[1]}"] = row[2]
|
|
605
|
+
elif kind == "better_sqlite3":
|
|
606
|
+
rows = db.prepare("SELECT * FROM cordscript_vars").all()
|
|
607
|
+
for row in rows:
|
|
608
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
609
|
+
|
|
610
|
+
leaderboard = {}
|
|
611
|
+
for key, value in all_data.items():
|
|
612
|
+
if f"_{name}" in key:
|
|
613
|
+
user_id = key.split("_")[0]
|
|
614
|
+
try:
|
|
615
|
+
val = float(value)
|
|
616
|
+
leaderboard[user_id] = val
|
|
617
|
+
except (ValueError, TypeError):
|
|
618
|
+
pass
|
|
619
|
+
|
|
620
|
+
if sort_type.upper() == "ASC":
|
|
621
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1])
|
|
622
|
+
else:
|
|
623
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1], reverse=True)
|
|
624
|
+
|
|
625
|
+
if 1 <= position <= len(sorted_lb):
|
|
626
|
+
return sorted_lb[position - 1][0]
|
|
627
|
+
else:
|
|
628
|
+
return "[Position not found]"
|
|
629
|
+
except Exception as e:
|
|
630
|
+
return f"[Error in $getUserLeaderboardID: {e}]"
|
|
631
|
+
|
|
632
|
+
case "userleaderboard":
|
|
633
|
+
name = _key(0)
|
|
634
|
+
sort_type = _key(1) or "DESC"
|
|
635
|
+
max_items = int(_key(2)) if _key(2) else 10
|
|
636
|
+
page = int(_key(3)) if _key(3) else 1
|
|
637
|
+
separator = _val(4) or "\n"
|
|
638
|
+
env_value = _key(5) or "{value}"
|
|
639
|
+
env_position = _key(6) or "{position}"
|
|
640
|
+
code = _val(7) or "{position}. {user_id} - {value}"
|
|
641
|
+
|
|
642
|
+
if not name:
|
|
643
|
+
return "[Error in $userLeaderboard: name required]"
|
|
644
|
+
|
|
645
|
+
try:
|
|
646
|
+
kind = _detect_db(db)
|
|
647
|
+
all_data = {}
|
|
648
|
+
|
|
649
|
+
with SuppressOutput():
|
|
650
|
+
if kind == "motor":
|
|
651
|
+
cursor = db["cordscript_vars"].find({})
|
|
652
|
+
async for doc in cursor:
|
|
653
|
+
doc.pop("_id", None)
|
|
654
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
655
|
+
elif kind == "pymongo":
|
|
656
|
+
for doc in db["cordscript_vars"].find({}):
|
|
657
|
+
doc.pop("_id", None)
|
|
658
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
659
|
+
elif kind in ("asyncpg", "psycopg"):
|
|
660
|
+
rows = await db.fetch("SELECT * FROM cordscript_vars")
|
|
661
|
+
for row in rows:
|
|
662
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
663
|
+
elif kind == "sqlite3":
|
|
664
|
+
cur = db.cursor()
|
|
665
|
+
cur.execute("SELECT * FROM cordscript_vars")
|
|
666
|
+
for row in cur.fetchall():
|
|
667
|
+
all_data[f"{row[0]}_{row[1]}"] = row[2]
|
|
668
|
+
elif kind == "better_sqlite3":
|
|
669
|
+
rows = db.prepare("SELECT * FROM cordscript_vars").all()
|
|
670
|
+
for row in rows:
|
|
671
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
672
|
+
|
|
673
|
+
leaderboard = {}
|
|
674
|
+
for key, value in all_data.items():
|
|
675
|
+
if f"_{name}" in key:
|
|
676
|
+
user_id = key.split("_")[0]
|
|
677
|
+
try:
|
|
678
|
+
val = float(value)
|
|
679
|
+
leaderboard[user_id] = val
|
|
680
|
+
except (ValueError, TypeError):
|
|
681
|
+
pass
|
|
682
|
+
|
|
683
|
+
if sort_type.upper() == "ASC":
|
|
684
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1])
|
|
685
|
+
else:
|
|
686
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1], reverse=True)
|
|
687
|
+
|
|
688
|
+
start = (page - 1) * max_items
|
|
689
|
+
end = start + max_items
|
|
690
|
+
page_data = sorted_lb[start:end]
|
|
691
|
+
|
|
692
|
+
if not page_data:
|
|
693
|
+
return "[No data for this page]"
|
|
694
|
+
|
|
695
|
+
result = []
|
|
696
|
+
for pos, (user_id, value) in enumerate(page_data, start=start + 1):
|
|
697
|
+
line = code.replace(env_value, str(value))
|
|
698
|
+
line = line.replace(env_position, str(pos))
|
|
699
|
+
line = line.replace("{user_id}", user_id)
|
|
700
|
+
line = line.replace("{value}", str(value))
|
|
701
|
+
line = line.replace("{position}", str(pos))
|
|
702
|
+
result.append(line)
|
|
703
|
+
|
|
704
|
+
return separator.join(result)
|
|
705
|
+
except Exception as e:
|
|
706
|
+
return f"[Error in $userLeaderboard: {e}]"
|
|
707
|
+
|
|
708
|
+
case "getuserleaderboardlength":
|
|
709
|
+
name = _key(0)
|
|
710
|
+
length_type = _key(1) or "count"
|
|
711
|
+
decimals = int(_key(2)) if _key(2) else 0
|
|
712
|
+
|
|
713
|
+
if not name:
|
|
714
|
+
return "[Error in $getUserLeaderboardLength: name required]"
|
|
715
|
+
|
|
716
|
+
try:
|
|
717
|
+
kind = _detect_db(db)
|
|
718
|
+
all_data = {}
|
|
719
|
+
|
|
720
|
+
with SuppressOutput():
|
|
721
|
+
if kind == "motor":
|
|
722
|
+
cursor = db["cordscript_vars"].find({})
|
|
723
|
+
async for doc in cursor:
|
|
724
|
+
doc.pop("_id", None)
|
|
725
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
726
|
+
elif kind == "pymongo":
|
|
727
|
+
for doc in db["cordscript_vars"].find({}):
|
|
728
|
+
doc.pop("_id", None)
|
|
729
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
730
|
+
elif kind in ("asyncpg", "psycopg"):
|
|
731
|
+
rows = await db.fetch("SELECT * FROM cordscript_vars")
|
|
732
|
+
for row in rows:
|
|
733
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
734
|
+
elif kind == "sqlite3":
|
|
735
|
+
cur = db.cursor()
|
|
736
|
+
cur.execute("SELECT * FROM cordscript_vars")
|
|
737
|
+
for row in cur.fetchall():
|
|
738
|
+
all_data[f"{row[0]}_{row[1]}"] = row[2]
|
|
739
|
+
elif kind == "better_sqlite3":
|
|
740
|
+
rows = db.prepare("SELECT * FROM cordscript_vars").all()
|
|
741
|
+
for row in rows:
|
|
742
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
743
|
+
|
|
744
|
+
values = []
|
|
745
|
+
for key, value in all_data.items():
|
|
746
|
+
if f"_{name}" in key:
|
|
747
|
+
try:
|
|
748
|
+
val = float(value)
|
|
749
|
+
values.append(val)
|
|
750
|
+
except (ValueError, TypeError):
|
|
751
|
+
pass
|
|
752
|
+
|
|
753
|
+
if length_type.lower() == "count":
|
|
754
|
+
result = len(values)
|
|
755
|
+
elif length_type.lower() == "sum":
|
|
756
|
+
result = sum(values) if values else 0
|
|
757
|
+
elif length_type.lower() == "avg":
|
|
758
|
+
result = sum(values) / len(values) if values else 0
|
|
759
|
+
elif length_type.lower() == "max":
|
|
760
|
+
result = max(values) if values else 0
|
|
761
|
+
elif length_type.lower() == "min":
|
|
762
|
+
result = min(values) if values else 0
|
|
763
|
+
else:
|
|
764
|
+
result = len(values)
|
|
765
|
+
|
|
766
|
+
if decimals > 0:
|
|
767
|
+
result = round(result, decimals)
|
|
768
|
+
else:
|
|
769
|
+
result = int(result)
|
|
770
|
+
|
|
771
|
+
return str(result)
|
|
772
|
+
except Exception as e:
|
|
773
|
+
return f"[Error in $getUserLeaderboardLength: {e}]"
|
|
774
|
+
|
|
775
|
+
case "getuserleaderboardvalue":
|
|
776
|
+
name = _key(0)
|
|
777
|
+
sort_type = _key(1) or "DESC"
|
|
778
|
+
user_id = _key(2)
|
|
779
|
+
|
|
780
|
+
if not name:
|
|
781
|
+
return "[Error in $getUserLeaderboardValue: name required]"
|
|
782
|
+
|
|
783
|
+
if not user_id:
|
|
784
|
+
import discord
|
|
785
|
+
ctx = parser.ctx
|
|
786
|
+
user_id = str(ctx.user.id) if isinstance(ctx, discord.Interaction) else str(getattr(ctx, "author", ctx).id)
|
|
787
|
+
|
|
788
|
+
try:
|
|
789
|
+
kind = _detect_db(db)
|
|
790
|
+
all_data = {}
|
|
791
|
+
|
|
792
|
+
with SuppressOutput():
|
|
793
|
+
if kind == "motor":
|
|
794
|
+
cursor = db["cordscript_vars"].find({})
|
|
795
|
+
async for doc in cursor:
|
|
796
|
+
doc.pop("_id", None)
|
|
797
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
798
|
+
elif kind == "pymongo":
|
|
799
|
+
for doc in db["cordscript_vars"].find({}):
|
|
800
|
+
doc.pop("_id", None)
|
|
801
|
+
all_data[f"{doc['user_id']}_{doc['key']}"] = doc['value']
|
|
802
|
+
elif kind in ("asyncpg", "psycopg"):
|
|
803
|
+
rows = await db.fetch("SELECT * FROM cordscript_vars")
|
|
804
|
+
for row in rows:
|
|
805
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
806
|
+
elif kind == "sqlite3":
|
|
807
|
+
cur = db.cursor()
|
|
808
|
+
cur.execute("SELECT * FROM cordscript_vars")
|
|
809
|
+
for row in cur.fetchall():
|
|
810
|
+
all_data[f"{row[0]}_{row[1]}"] = row[2]
|
|
811
|
+
elif kind == "better_sqlite3":
|
|
812
|
+
rows = db.prepare("SELECT * FROM cordscript_vars").all()
|
|
813
|
+
for row in rows:
|
|
814
|
+
all_data[f"{row['user_id']}_{row['key']}"] = row['value']
|
|
815
|
+
|
|
816
|
+
leaderboard = {}
|
|
817
|
+
for key, value in all_data.items():
|
|
818
|
+
if f"_{name}" in key:
|
|
819
|
+
uid = key.split("_")[0]
|
|
820
|
+
try:
|
|
821
|
+
val = float(value)
|
|
822
|
+
leaderboard[uid] = val
|
|
823
|
+
except (ValueError, TypeError):
|
|
824
|
+
pass
|
|
825
|
+
|
|
826
|
+
if str(user_id) not in leaderboard:
|
|
827
|
+
return "[User not in leaderboard]"
|
|
828
|
+
|
|
829
|
+
user_value = leaderboard[str(user_id)]
|
|
830
|
+
|
|
831
|
+
if sort_type.upper() == "ASC":
|
|
832
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1])
|
|
833
|
+
else:
|
|
834
|
+
sorted_lb = sorted(leaderboard.items(), key=lambda x: x[1], reverse=True)
|
|
835
|
+
|
|
836
|
+
position = next((i + 1 for i, (uid, _) in enumerate(sorted_lb) if uid == str(user_id)), None)
|
|
837
|
+
|
|
838
|
+
return f"{user_value}|{position}"
|
|
839
|
+
except Exception as e:
|
|
840
|
+
return f"[Error in $getUserLeaderboardValue: {e}]"
|
|
841
|
+
|
|
842
|
+
case _:
|
|
843
|
+
return None
|
|
844
|
+
|
|
845
|
+
except Exception as e:
|
|
846
|
+
return f"[Unexpected error in ${fn}: {e}]"
|