djs-builder 0.7.0 → 0.7.1-8.1
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.
- package/README.md +2137 -272
- package/function/dash.js +705 -210
- package/function/function.js +255 -8
- package/function/level.js +337 -10
- package/function/log.js +407 -332
- package/handler/helper.js +46 -25
- package/handler/starter.js +47 -13
- package/package.json +23 -9
- package/views/dashboard.ejs +52 -18
- package/views/giveaways.ejs +1 -0
- package/views/guild.ejs +4 -0
- package/views/levels.ejs +672 -32
- package/views/logs.ejs +624 -0
package/function/dash.js
CHANGED
|
@@ -1,68 +1,59 @@
|
|
|
1
|
-
|
|
2
|
-
* DJS-Builder Dashboard
|
|
3
|
-
* لوحة تحكم عصرية وخفيفة متوافقة مع حزمة djs-builder
|
|
4
|
-
* @version 2.0.0
|
|
5
|
-
* @author DJS-Builder Team
|
|
6
|
-
*/
|
|
1
|
+
|
|
7
2
|
|
|
8
3
|
const express = require("express");
|
|
9
4
|
const session = require("express-session");
|
|
10
5
|
const passport = require("passport");
|
|
11
6
|
const DiscordStrategy = require("passport-discord").Strategy;
|
|
12
7
|
const path = require("path");
|
|
8
|
+
const Table = require("cli-table3");
|
|
9
|
+
const chalk = require("chalk");
|
|
10
|
+
const mongoose = require("mongoose");
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
Level,
|
|
14
|
+
levelGuild,
|
|
15
|
+
resetUser,
|
|
16
|
+
xpNeeded,
|
|
17
|
+
calculateLevel,
|
|
18
|
+
getUserRank,
|
|
19
|
+
getGuildConfig,
|
|
20
|
+
updateGuildConfig,
|
|
21
|
+
deleteGuildConfig,
|
|
22
|
+
clearConfigCache,
|
|
23
|
+
} = require("./level");
|
|
24
|
+
const {
|
|
25
|
+
Blacklist,
|
|
26
|
+
addToBlacklist,
|
|
27
|
+
removeFromBlacklist,
|
|
28
|
+
} = require("./blacklist");
|
|
29
|
+
const {
|
|
30
|
+
giveaway,
|
|
31
|
+
Gcheck,
|
|
32
|
+
Greroll,
|
|
33
|
+
Gpause,
|
|
34
|
+
Gresume,
|
|
35
|
+
Gdelete,
|
|
36
|
+
} = require("./giveaway");
|
|
37
|
+
const { Log, getLogConfigData } = require("./log");
|
|
13
38
|
|
|
14
|
-
// استيراد موديلات djs-builder
|
|
15
|
-
let Level, giveaway, Blacklist, leaderboard, addXP, UserLevel;
|
|
16
|
-
let Gstart, Gcheck, Greroll, Glist, Gpause, Gresume, Gdelete, Gdata;
|
|
17
|
-
let isBlacklisted, addToBlacklist, removeFromBlacklist, getBlacklist;
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
const djsBuilder = require("djs-builder");
|
|
21
|
-
Level = djsBuilder.Level;
|
|
22
|
-
giveaway = djsBuilder.giveaway;
|
|
23
|
-
Blacklist = djsBuilder.Blacklist;
|
|
24
|
-
leaderboard = djsBuilder.leaderboard;
|
|
25
|
-
addXP = djsBuilder.addXP;
|
|
26
|
-
UserLevel = djsBuilder.UserLevel;
|
|
27
|
-
Gstart = djsBuilder.Gstart;
|
|
28
|
-
Gcheck = djsBuilder.Gcheck;
|
|
29
|
-
Greroll = djsBuilder.Greroll;
|
|
30
|
-
Glist = djsBuilder.Glist;
|
|
31
|
-
Gpause = djsBuilder.Gpause;
|
|
32
|
-
Gresume = djsBuilder.Gresume;
|
|
33
|
-
Gdelete = djsBuilder.Gdelete;
|
|
34
|
-
Gdata = djsBuilder.Gdata;
|
|
35
|
-
isBlacklisted = djsBuilder.isBlacklisted;
|
|
36
|
-
addToBlacklist = djsBuilder.addToBlacklist;
|
|
37
|
-
removeFromBlacklist = djsBuilder.removeFromBlacklist;
|
|
38
|
-
getBlacklist = djsBuilder.getBlacklist;
|
|
39
|
-
} catch (e) {
|
|
40
|
-
console.log("⚠️ djs-builder models not fully loaded:", e.message);
|
|
41
|
-
}
|
|
42
39
|
|
|
43
|
-
/**
|
|
44
|
-
* دالة لإنشاء وتشغيل لوحة التحكم
|
|
45
|
-
* @param {Client} client - كائن البوت
|
|
46
|
-
* @param {Object} options - خيارات اللوحة
|
|
47
|
-
*/
|
|
48
40
|
function dashboard(client, options) {
|
|
49
41
|
const app = express();
|
|
50
42
|
const {
|
|
51
|
-
clientID,
|
|
52
43
|
clientSecret,
|
|
53
|
-
callbackURL,
|
|
44
|
+
callbackURL = "http://localhost:3000/auth/discord/callback",
|
|
54
45
|
sessionSecret,
|
|
55
46
|
port = 3000,
|
|
56
47
|
} = options;
|
|
57
48
|
|
|
58
|
-
|
|
49
|
+
clientID = client.user.id;
|
|
50
|
+
|
|
59
51
|
app.set("view engine", "ejs");
|
|
60
|
-
app.set("views", path.join(__dirname, "views"));
|
|
61
|
-
app.use(express.static(path.join(__dirname, "public")));
|
|
52
|
+
app.set("views", path.join(__dirname, "..", "views"));
|
|
62
53
|
app.use(express.json());
|
|
63
54
|
app.use(express.urlencoded({ extended: true }));
|
|
64
55
|
|
|
65
|
-
|
|
56
|
+
|
|
66
57
|
app.use(
|
|
67
58
|
session({
|
|
68
59
|
secret: sessionSecret,
|
|
@@ -74,7 +65,7 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
74
65
|
})
|
|
75
66
|
);
|
|
76
67
|
|
|
77
|
-
|
|
68
|
+
|
|
78
69
|
app.use(passport.initialize());
|
|
79
70
|
app.use(passport.session());
|
|
80
71
|
|
|
@@ -95,21 +86,22 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
95
86
|
)
|
|
96
87
|
);
|
|
97
88
|
|
|
98
|
-
|
|
89
|
+
|
|
99
90
|
function isAuthenticated(req, res, next) {
|
|
100
91
|
if (req.isAuthenticated()) return next();
|
|
101
92
|
res.redirect("/login");
|
|
102
93
|
}
|
|
103
94
|
|
|
104
|
-
|
|
95
|
+
|
|
105
96
|
app.use((req, res, next) => {
|
|
106
97
|
res.locals.user = req.user || null;
|
|
107
98
|
res.locals.client = client;
|
|
108
99
|
res.locals.path = req.path;
|
|
100
|
+
res.locals.dashboardEnabled = options.Dashboard !== false;
|
|
109
101
|
next();
|
|
110
102
|
});
|
|
111
103
|
|
|
112
|
-
|
|
104
|
+
|
|
113
105
|
function getBotStats() {
|
|
114
106
|
const uniquePrefixCommands = new Set();
|
|
115
107
|
if (client.prefixCommands) {
|
|
@@ -118,12 +110,13 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
118
110
|
});
|
|
119
111
|
}
|
|
120
112
|
|
|
121
|
-
|
|
122
|
-
const prefix = client.prefix || options.prefix ||
|
|
113
|
+
|
|
114
|
+
const prefix = client.prefix || options.prefix || "-";
|
|
123
115
|
|
|
124
116
|
return {
|
|
125
117
|
guilds: client.guilds?.cache?.size || 0,
|
|
126
|
-
users:
|
|
118
|
+
users:
|
|
119
|
+
client.guilds?.cache?.reduce((acc, g) => acc + g.memberCount, 0) || 0,
|
|
127
120
|
channels: client.channels?.cache?.size || 0,
|
|
128
121
|
slashCommands: client.slashCommands?.size || 0,
|
|
129
122
|
prefixCommands: uniquePrefixCommands.size,
|
|
@@ -139,22 +132,20 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
139
132
|
};
|
|
140
133
|
}
|
|
141
134
|
|
|
142
|
-
// ==================== المسارات الرئيسية ====================
|
|
143
135
|
|
|
144
|
-
// الصفحة الرئيسية
|
|
145
136
|
app.get("/", (req, res) => {
|
|
146
137
|
res.render("index", {
|
|
147
138
|
botStats: getBotStats(),
|
|
148
139
|
});
|
|
149
140
|
});
|
|
150
141
|
|
|
151
|
-
|
|
142
|
+
|
|
152
143
|
app.get("/login", (req, res) => {
|
|
153
144
|
if (req.isAuthenticated()) return res.redirect("/dashboard");
|
|
154
145
|
res.render("login", { botStats: getBotStats() });
|
|
155
146
|
});
|
|
156
147
|
|
|
157
|
-
|
|
148
|
+
|
|
158
149
|
app.get("/auth/discord", passport.authenticate("discord"));
|
|
159
150
|
|
|
160
151
|
app.get(
|
|
@@ -167,28 +158,25 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
167
158
|
}
|
|
168
159
|
);
|
|
169
160
|
|
|
170
|
-
|
|
161
|
+
|
|
171
162
|
app.get("/logout", (req, res) => {
|
|
172
163
|
req.logout(() => {
|
|
173
164
|
res.redirect("/");
|
|
174
165
|
});
|
|
175
166
|
});
|
|
176
167
|
|
|
177
|
-
// ==================== لوحة التحكم ====================
|
|
178
168
|
|
|
179
|
-
// لوحة التحكم الرئيسية
|
|
180
169
|
app.get("/dashboard", isAuthenticated, (req, res) => {
|
|
181
170
|
const userGuilds = req.user.guilds.filter(
|
|
182
|
-
(g) =>
|
|
183
|
-
(g.permissions & 0x20) === 0x20 && client.guilds.cache.has(g.id)
|
|
171
|
+
(g) => (g.permissions & 0x20) === 0x20 && client.guilds.cache.has(g.id)
|
|
184
172
|
);
|
|
185
|
-
res.render("dashboard", {
|
|
173
|
+
res.render("dashboard", {
|
|
186
174
|
guilds: userGuilds,
|
|
187
|
-
botStats: getBotStats()
|
|
175
|
+
botStats: getBotStats(),
|
|
188
176
|
});
|
|
189
177
|
});
|
|
190
178
|
|
|
191
|
-
|
|
179
|
+
|
|
192
180
|
app.get("/dashboard/:guildId", isAuthenticated, async (req, res) => {
|
|
193
181
|
const guild = client.guilds.cache.get(req.params.guildId);
|
|
194
182
|
if (!guild) return res.redirect("/dashboard");
|
|
@@ -198,15 +186,20 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
198
186
|
return res.redirect("/dashboard");
|
|
199
187
|
}
|
|
200
188
|
|
|
201
|
-
|
|
189
|
+
|
|
202
190
|
let levelCount = 0;
|
|
203
191
|
let giveawayCount = 0;
|
|
204
192
|
let blacklistCount = 0;
|
|
205
193
|
|
|
206
194
|
try {
|
|
207
195
|
if (Level) levelCount = await Level.countDocuments({ guildId: guild.id });
|
|
208
|
-
if (giveaway)
|
|
209
|
-
|
|
196
|
+
if (giveaway)
|
|
197
|
+
giveawayCount = await giveaway.countDocuments({
|
|
198
|
+
guildId: guild.id,
|
|
199
|
+
ended: false,
|
|
200
|
+
});
|
|
201
|
+
if (Blacklist)
|
|
202
|
+
blacklistCount = await Blacklist.countDocuments({ guild: guild.id });
|
|
210
203
|
} catch (e) {
|
|
211
204
|
console.error("Stats error:", e);
|
|
212
205
|
}
|
|
@@ -223,11 +216,11 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
223
216
|
activeGiveaways: giveawayCount,
|
|
224
217
|
blacklisted: blacklistCount,
|
|
225
218
|
},
|
|
226
|
-
botStats: getBotStats()
|
|
219
|
+
botStats: getBotStats(),
|
|
227
220
|
});
|
|
228
221
|
});
|
|
229
222
|
|
|
230
|
-
|
|
223
|
+
|
|
231
224
|
app.get("/dashboard/:guildId/commands", isAuthenticated, async (req, res) => {
|
|
232
225
|
const guild = client.guilds.cache.get(req.params.guildId);
|
|
233
226
|
if (!guild) return res.redirect("/dashboard");
|
|
@@ -235,8 +228,8 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
235
228
|
const slashCommands = client.slashCommands
|
|
236
229
|
? Array.from(client.slashCommands.values())
|
|
237
230
|
: [];
|
|
238
|
-
|
|
239
|
-
|
|
231
|
+
|
|
232
|
+
|
|
240
233
|
const uniquePrefixCommands = [];
|
|
241
234
|
const seen = new Set();
|
|
242
235
|
if (client.prefixCommands) {
|
|
@@ -253,35 +246,99 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
253
246
|
slashCommands,
|
|
254
247
|
prefixCommands: uniquePrefixCommands,
|
|
255
248
|
page: "commands",
|
|
256
|
-
botStats: getBotStats()
|
|
249
|
+
botStats: getBotStats(),
|
|
257
250
|
});
|
|
258
251
|
});
|
|
259
252
|
|
|
260
|
-
// ==================== نظام اللفل ====================
|
|
261
253
|
app.get("/dashboard/:guildId/levels", isAuthenticated, async (req, res) => {
|
|
262
254
|
const guild = client.guilds.cache.get(req.params.guildId);
|
|
263
255
|
if (!guild) return res.redirect("/dashboard");
|
|
264
256
|
|
|
257
|
+
const mongoConnected = mongoose.connection.readyState === 1;
|
|
258
|
+
let levelConfigDb = null;
|
|
259
|
+
let configSource = null;
|
|
260
|
+
let databaseEnabled = false;
|
|
261
|
+
|
|
262
|
+
const canModify = options.Dashboard !== false;
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
const usesDashboardMode = client.levelDashboardGuilds && client.levelDashboardGuilds.has(guild.id);
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
if (mongoConnected) {
|
|
269
|
+
try {
|
|
270
|
+
levelConfigDb = await getGuildConfig(guild.id);
|
|
271
|
+
if (levelConfigDb && usesDashboardMode) {
|
|
272
|
+
configSource = "database";
|
|
273
|
+
databaseEnabled = true;
|
|
274
|
+
}
|
|
275
|
+
} catch (e) {
|
|
276
|
+
console.error("Error fetching level config:", e);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
265
280
|
let leaderboardData = [];
|
|
266
281
|
if (Level) {
|
|
267
282
|
try {
|
|
268
|
-
|
|
283
|
+
const rawLeaderboard = await Level.find({ guildId: guild.id })
|
|
269
284
|
.sort({ totalXP: -1 })
|
|
270
285
|
.limit(100);
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
const memberIds = rawLeaderboard.map(u => u.userId);
|
|
289
|
+
const fetchedMembers = await guild.members.fetch({ user: memberIds }).catch(() => new Map());
|
|
290
|
+
|
|
291
|
+
leaderboardData = rawLeaderboard.map(u => {
|
|
292
|
+
const member = fetchedMembers.get(u.userId) || guild.members.cache.get(u.userId);
|
|
293
|
+
return {
|
|
294
|
+
userId: u.userId,
|
|
295
|
+
totalXP: u.totalXP,
|
|
296
|
+
level: u.level,
|
|
297
|
+
username: member ? member.user.username : `User ${u.userId.substring(0, 5)}`,
|
|
298
|
+
avatar: member ? member.user.displayAvatarURL({ size: 64, forceStatic: true }) : `https://cdn.discordapp.com/embed/avatars/${Math.floor(Math.random() * 6)}.png`,
|
|
299
|
+
};
|
|
300
|
+
});
|
|
271
301
|
} catch (e) {
|
|
272
302
|
console.error("Error fetching levels:", e);
|
|
273
303
|
}
|
|
274
304
|
}
|
|
275
305
|
|
|
306
|
+
|
|
307
|
+
const roles = guild.roles.cache
|
|
308
|
+
.filter((r) => r.id !== guild.id && !r.managed)
|
|
309
|
+
.map((r) => ({ id: r.id, name: r.name, color: r.hexColor }))
|
|
310
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
const channels = guild.channels.cache
|
|
314
|
+
.filter((c) => c.type === 0)
|
|
315
|
+
.map((c) => ({ id: c.id, name: c.name }))
|
|
316
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
317
|
+
|
|
276
318
|
res.render("levels", {
|
|
277
319
|
guild,
|
|
278
320
|
leaderboard: leaderboardData,
|
|
279
321
|
page: "levels",
|
|
280
|
-
botStats: getBotStats()
|
|
322
|
+
botStats: getBotStats(),
|
|
323
|
+
databaseEnabled,
|
|
324
|
+
mongoConnected,
|
|
325
|
+
configSource,
|
|
326
|
+
levelConfigDb,
|
|
327
|
+
roles,
|
|
328
|
+
channels,
|
|
329
|
+
canModify,
|
|
281
330
|
});
|
|
282
331
|
});
|
|
283
332
|
|
|
284
|
-
|
|
333
|
+
|
|
334
|
+
function canModifySettings(req, res, next) {
|
|
335
|
+
if (options.Dashboard === false) {
|
|
336
|
+
return res.status(403).json({ success: false, error: "تم تعطيل التعديل من الداش بورد في ملف الإعدادات الرئيسي للبوت." });
|
|
337
|
+
}
|
|
338
|
+
next();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
285
342
|
app.get("/api/:guildId/user/:userId", isAuthenticated, async (req, res) => {
|
|
286
343
|
if (!Level) return res.json({ error: "Level system not available" });
|
|
287
344
|
|
|
@@ -296,122 +353,380 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
296
353
|
}
|
|
297
354
|
});
|
|
298
355
|
|
|
299
|
-
|
|
300
|
-
app.get(
|
|
356
|
+
|
|
357
|
+
app.get(
|
|
358
|
+
"/dashboard/:guildId/giveaways",
|
|
359
|
+
isAuthenticated,
|
|
360
|
+
async (req, res) => {
|
|
361
|
+
const guild = client.guilds.cache.get(req.params.guildId);
|
|
362
|
+
if (!guild) return res.redirect("/dashboard");
|
|
363
|
+
|
|
364
|
+
let giveaways = [];
|
|
365
|
+
if (giveaway) {
|
|
366
|
+
try {
|
|
367
|
+
giveaways = await giveaway
|
|
368
|
+
.find({ guildId: guild.id })
|
|
369
|
+
.sort({ endTime: -1 });
|
|
370
|
+
} catch (e) {
|
|
371
|
+
console.error("Error fetching giveaways:", e);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
res.render("giveaways", {
|
|
376
|
+
guild,
|
|
377
|
+
giveaways,
|
|
378
|
+
page: "giveaways",
|
|
379
|
+
botStats: getBotStats(),
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
app.post(
|
|
386
|
+
"/api/:guildId/giveaway/:action",
|
|
387
|
+
isAuthenticated,
|
|
388
|
+
async (req, res) => {
|
|
389
|
+
const { guildId, action } = req.params;
|
|
390
|
+
const { messageId } = req.body;
|
|
391
|
+
|
|
392
|
+
try {
|
|
393
|
+
let result = { success: true };
|
|
394
|
+
switch (action) {
|
|
395
|
+
case "pause":
|
|
396
|
+
if (Gpause) await Gpause(client, messageId);
|
|
397
|
+
break;
|
|
398
|
+
case "resume":
|
|
399
|
+
|
|
400
|
+
if (Gresume) await Gresume(client, messageId);
|
|
401
|
+
break;
|
|
402
|
+
case "end":
|
|
403
|
+
|
|
404
|
+
if (giveaway) {
|
|
405
|
+
const g = await giveaway.findOne({ messageId });
|
|
406
|
+
if (g && !g.ended) {
|
|
407
|
+
|
|
408
|
+
await giveaway.findOneAndUpdate(
|
|
409
|
+
{ messageId },
|
|
410
|
+
{ paused: false, endTime: Date.now().toString() }
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
setTimeout(() => Gcheck && Gcheck(client), 1000);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
break;
|
|
417
|
+
case "reroll":
|
|
418
|
+
if (Greroll) await Greroll(client, messageId);
|
|
419
|
+
break;
|
|
420
|
+
case "delete":
|
|
421
|
+
if (Gdelete) await Gdelete(messageId);
|
|
422
|
+
break;
|
|
423
|
+
default:
|
|
424
|
+
return res.json({ success: false, error: "Invalid action" });
|
|
425
|
+
}
|
|
426
|
+
res.json({ success: true, message: `تم تنفيذ ${action} بنجاح` });
|
|
427
|
+
} catch (e) {
|
|
428
|
+
console.error("Giveaway action error:", e);
|
|
429
|
+
res.json({ success: false, error: e.message });
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
const LOG_EVENT_TYPES = [
|
|
436
|
+
{ name: "حذف رسالة", value: "messageDelete", icon: "ri-delete-bin-line" },
|
|
437
|
+
{ name: "تعديل رسالة", value: "messageUpdate", icon: "ri-edit-line" },
|
|
438
|
+
{ name: "إنشاء قناة", value: "channelCreate", icon: "ri-add-circle-line" },
|
|
439
|
+
{ name: "حذف قناة", value: "channelDelete", icon: "ri-close-circle-line" },
|
|
440
|
+
{ name: "تعديل قناة", value: "channelUpdate", icon: "ri-settings-3-line" },
|
|
441
|
+
{ name: "انضمام عضو", value: "guildMemberAdd", icon: "ri-user-add-line" },
|
|
442
|
+
{
|
|
443
|
+
name: "مغادرة عضو",
|
|
444
|
+
value: "guildMemberRemove",
|
|
445
|
+
icon: "ri-user-unfollow-line",
|
|
446
|
+
},
|
|
447
|
+
{ name: "حظر عضو", value: "guildBanAdd", icon: "ri-forbid-line" },
|
|
448
|
+
{
|
|
449
|
+
name: "رفع الحظر",
|
|
450
|
+
value: "guildBanRemove",
|
|
451
|
+
icon: "ri-checkbox-circle-line",
|
|
452
|
+
},
|
|
453
|
+
{ name: "إنشاء رتبة", value: "roleCreate", icon: "ri-shield-star-line" },
|
|
454
|
+
{ name: "حذف رتبة", value: "roleDelete", icon: "ri-shield-cross-line" },
|
|
455
|
+
{ name: "تعديل رتبة", value: "roleUpdate", icon: "ri-shield-line" },
|
|
456
|
+
{
|
|
457
|
+
name: "تغيير رتب العضو",
|
|
458
|
+
value: "guildMemberUpdate",
|
|
459
|
+
icon: "ri-user-settings-line",
|
|
460
|
+
},
|
|
461
|
+
{ name: "نشاط صوتي", value: "voiceStateUpdate", icon: "ri-mic-line" },
|
|
462
|
+
{ name: "إنشاء دعوة", value: "inviteCreate", icon: "ri-links-line" },
|
|
463
|
+
{
|
|
464
|
+
name: "إضافة إيموجي",
|
|
465
|
+
value: "emojiCreate",
|
|
466
|
+
icon: "ri-emotion-happy-line",
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
name: "حذف إيموجي",
|
|
470
|
+
value: "emojiDelete",
|
|
471
|
+
icon: "ri-emotion-unhappy-line",
|
|
472
|
+
},
|
|
473
|
+
{ name: "تعديل إيموجي", value: "emojiUpdate", icon: "ri-emotion-line" },
|
|
474
|
+
{
|
|
475
|
+
name: "إضافة ستيكر",
|
|
476
|
+
value: "stickerCreate",
|
|
477
|
+
icon: "ri-sticky-note-line",
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
name: "حذف ستيكر",
|
|
481
|
+
value: "stickerDelete",
|
|
482
|
+
icon: "ri-sticky-note-2-line",
|
|
483
|
+
},
|
|
484
|
+
{ name: "تعديل ستيكر", value: "stickerUpdate", icon: "ri-file-edit-line" },
|
|
485
|
+
];
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
app.get("/dashboard/:guildId/logs", isAuthenticated, async (req, res) => {
|
|
301
489
|
const guild = client.guilds.cache.get(req.params.guildId);
|
|
302
490
|
if (!guild) return res.redirect("/dashboard");
|
|
303
491
|
|
|
304
|
-
|
|
305
|
-
if (
|
|
492
|
+
const userGuild = req.user.guilds.find((g) => g.id === req.params.guildId);
|
|
493
|
+
if (!userGuild || (userGuild.permissions & 0x20) !== 0x20) {
|
|
494
|
+
return res.redirect("/dashboard");
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
const logData = getLogConfigData();
|
|
499
|
+
const databaseEnabled = logData.databaseEnabled;
|
|
500
|
+
let logConfig = null;
|
|
501
|
+
let configSource = null;
|
|
502
|
+
|
|
503
|
+
if (databaseEnabled) {
|
|
504
|
+
|
|
306
505
|
try {
|
|
307
|
-
|
|
506
|
+
logConfig = await Log.findOne({ guildId: guild.id });
|
|
507
|
+
if (logConfig) configSource = "database";
|
|
308
508
|
} catch (e) {
|
|
309
|
-
console.error("Error fetching
|
|
509
|
+
console.error("Error fetching log config:", e);
|
|
510
|
+
}
|
|
511
|
+
} else {
|
|
512
|
+
|
|
513
|
+
const codeConfig = logData.configs.find((c) => c.guildId === guild.id);
|
|
514
|
+
if (codeConfig) {
|
|
515
|
+
logConfig = codeConfig;
|
|
516
|
+
configSource = "code";
|
|
310
517
|
}
|
|
311
518
|
}
|
|
312
519
|
|
|
313
|
-
|
|
520
|
+
|
|
521
|
+
const channels = guild.channels.cache
|
|
522
|
+
.filter((c) => c.type === 0)
|
|
523
|
+
.map((c) => ({ id: c.id, name: c.name }))
|
|
524
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
const disabledEvents = logConfig?.disable?.length || 0;
|
|
528
|
+
const enabledEvents = LOG_EVENT_TYPES.length - disabledEvents;
|
|
529
|
+
const customColors = logConfig?.colors
|
|
530
|
+
? Object.keys(logConfig.colors).length
|
|
531
|
+
: 0;
|
|
532
|
+
const customChannels = logConfig?.channels
|
|
533
|
+
? Object.keys(logConfig.channels).length
|
|
534
|
+
: 0;
|
|
535
|
+
|
|
536
|
+
res.render("logs", {
|
|
314
537
|
guild,
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
538
|
+
page: "logs",
|
|
539
|
+
botStats: getBotStats(),
|
|
540
|
+
databaseEnabled,
|
|
541
|
+
configSource,
|
|
542
|
+
logConfig,
|
|
543
|
+
channels,
|
|
544
|
+
eventTypes: LOG_EVENT_TYPES,
|
|
545
|
+
enabledEvents,
|
|
546
|
+
disabledEvents,
|
|
547
|
+
customColors,
|
|
548
|
+
customChannels,
|
|
318
549
|
});
|
|
319
550
|
});
|
|
320
551
|
|
|
321
|
-
|
|
322
|
-
app.post("/api/:guildId/
|
|
323
|
-
const
|
|
324
|
-
|
|
552
|
+
|
|
553
|
+
app.post("/api/:guildId/logs/channel", isAuthenticated, canModifySettings, async (req, res) => {
|
|
554
|
+
const logData = getLogConfigData();
|
|
555
|
+
if (!logData.databaseEnabled)
|
|
556
|
+
return res.json({ error: "يجب تفعيل وضع Database لتعديل الإعدادات" });
|
|
557
|
+
|
|
558
|
+
const { channelId } = req.body;
|
|
559
|
+
const guildId = req.params.guildId;
|
|
325
560
|
|
|
326
561
|
try {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
break;
|
|
336
|
-
case "end":
|
|
337
|
-
// إنهاء الجيف اوي فوراً بتعديل وقت الانتهاء للوقت الحالي
|
|
338
|
-
if (giveaway) {
|
|
339
|
-
const g = await giveaway.findOne({ messageId });
|
|
340
|
-
if (g && !g.ended) {
|
|
341
|
-
// إذا كان متوقفاً مؤقتاً، نلغي الإيقاف أولاً
|
|
342
|
-
await giveaway.findOneAndUpdate(
|
|
343
|
-
{ messageId },
|
|
344
|
-
{ paused: false, endTime: Date.now().toString() }
|
|
345
|
-
);
|
|
346
|
-
// إعطاء Gcheck فرصة للتشغيل
|
|
347
|
-
setTimeout(() => Gcheck && Gcheck(client), 1000);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
break;
|
|
351
|
-
case "reroll":
|
|
352
|
-
if (Greroll) await Greroll(client, messageId);
|
|
353
|
-
break;
|
|
354
|
-
case "delete":
|
|
355
|
-
if (Gdelete) await Gdelete(messageId);
|
|
356
|
-
break;
|
|
357
|
-
default:
|
|
358
|
-
return res.json({ success: false, error: "Invalid action" });
|
|
359
|
-
}
|
|
360
|
-
res.json({ success: true, message: `تم تنفيذ ${action} بنجاح` });
|
|
562
|
+
await Log.findOneAndUpdate(
|
|
563
|
+
{ guildId },
|
|
564
|
+
{ guildId, channelId },
|
|
565
|
+
{ upsert: true, new: true }
|
|
566
|
+
);
|
|
567
|
+
|
|
568
|
+
if (logData.clearCache) logData.clearCache(guildId);
|
|
569
|
+
res.json({ success: true });
|
|
361
570
|
} catch (e) {
|
|
362
|
-
console.error("Giveaway action error:", e);
|
|
363
571
|
res.json({ success: false, error: e.message });
|
|
364
572
|
}
|
|
365
573
|
});
|
|
366
574
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
575
|
+
|
|
576
|
+
app.post("/api/:guildId/logs/toggle", isAuthenticated, canModifySettings, async (req, res) => {
|
|
577
|
+
const logData = getLogConfigData();
|
|
578
|
+
if (!logData.databaseEnabled)
|
|
579
|
+
return res.json({ error: "يجب تفعيل وضع Database لتعديل الإعدادات" });
|
|
580
|
+
|
|
581
|
+
const { eventType, enable } = req.body;
|
|
371
582
|
const guildId = req.params.guildId;
|
|
372
583
|
|
|
373
584
|
try {
|
|
374
|
-
if (
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
585
|
+
if (enable) {
|
|
586
|
+
|
|
587
|
+
await Log.findOneAndUpdate(
|
|
588
|
+
{ guildId },
|
|
589
|
+
{ $pull: { disable: eventType } },
|
|
590
|
+
{ upsert: true }
|
|
591
|
+
);
|
|
592
|
+
} else {
|
|
593
|
+
|
|
594
|
+
await Log.findOneAndUpdate(
|
|
595
|
+
{ guildId },
|
|
596
|
+
{ $addToSet: { disable: eventType } },
|
|
597
|
+
{ upsert: true }
|
|
598
|
+
);
|
|
383
599
|
}
|
|
384
|
-
|
|
600
|
+
|
|
601
|
+
const logData = getLogConfigData();
|
|
602
|
+
if (logData.clearCache) logData.clearCache(guildId);
|
|
603
|
+
res.json({ success: true });
|
|
385
604
|
} catch (e) {
|
|
386
605
|
res.json({ success: false, error: e.message });
|
|
387
606
|
}
|
|
388
607
|
});
|
|
389
608
|
|
|
390
|
-
|
|
391
|
-
app.
|
|
392
|
-
const
|
|
609
|
+
|
|
610
|
+
app.post("/api/:guildId/logs/event", isAuthenticated, canModifySettings, async (req, res) => {
|
|
611
|
+
const logData = getLogConfigData();
|
|
612
|
+
if (!logData.databaseEnabled)
|
|
613
|
+
return res.json({ error: "يجب تفعيل وضع Database لتعديل الإعدادات" });
|
|
614
|
+
|
|
615
|
+
const { eventType, channel, color } = req.body;
|
|
393
616
|
const guildId = req.params.guildId;
|
|
394
617
|
|
|
395
618
|
try {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
619
|
+
const updateObj = {};
|
|
620
|
+
|
|
621
|
+
if (channel) {
|
|
622
|
+
updateObj[`channels.${eventType}`] = channel;
|
|
623
|
+
} else {
|
|
624
|
+
|
|
625
|
+
await Log.findOneAndUpdate(
|
|
626
|
+
{ guildId },
|
|
627
|
+
{ $unset: { [`channels.${eventType}`]: "" } }
|
|
628
|
+
);
|
|
402
629
|
}
|
|
403
|
-
|
|
630
|
+
|
|
631
|
+
if (color) {
|
|
632
|
+
updateObj[`colors.${eventType}`] = color;
|
|
633
|
+
} else {
|
|
634
|
+
|
|
635
|
+
await Log.findOneAndUpdate(
|
|
636
|
+
{ guildId },
|
|
637
|
+
{ $unset: { [`colors.${eventType}`]: "" } }
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
if (Object.keys(updateObj).length > 0) {
|
|
642
|
+
await Log.findOneAndUpdate(
|
|
643
|
+
{ guildId },
|
|
644
|
+
{ $set: updateObj },
|
|
645
|
+
{ upsert: true }
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
const logData2 = getLogConfigData();
|
|
651
|
+
if (logData2.clearCache) logData2.clearCache(guildId);
|
|
652
|
+
res.json({ success: true });
|
|
404
653
|
} catch (e) {
|
|
405
654
|
res.json({ success: false, error: e.message });
|
|
406
655
|
}
|
|
407
656
|
});
|
|
408
657
|
|
|
409
|
-
|
|
658
|
+
|
|
659
|
+
app.post("/api/:guildId/logs/reset", isAuthenticated, canModifySettings, async (req, res) => {
|
|
660
|
+
const logData = getLogConfigData();
|
|
661
|
+
if (!logData.databaseEnabled)
|
|
662
|
+
return res.json({ error: "يجب تفعيل وضع Database لتعديل الإعدادات" });
|
|
663
|
+
|
|
664
|
+
const guildId = req.params.guildId;
|
|
665
|
+
|
|
666
|
+
try {
|
|
667
|
+
await Log.findOneAndDelete({ guildId });
|
|
668
|
+
|
|
669
|
+
if (logData.clearCache) logData.clearCache(guildId);
|
|
670
|
+
res.json({ success: true });
|
|
671
|
+
} catch (e) {
|
|
672
|
+
res.json({ success: false, error: e.message });
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
app.post(
|
|
678
|
+
"/api/guild/:guildId/blacklist",
|
|
679
|
+
isAuthenticated,
|
|
680
|
+
async (req, res) => {
|
|
681
|
+
const { type, id } = req.body;
|
|
682
|
+
const guildId = req.params.guildId;
|
|
683
|
+
|
|
684
|
+
try {
|
|
685
|
+
if (addToBlacklist) {
|
|
686
|
+
const result = await addToBlacklist(guildId, type, id);
|
|
687
|
+
return res.json({ success: result });
|
|
688
|
+
} else if (Blacklist) {
|
|
689
|
+
const exists = await Blacklist.findOne({ guild: guildId, type, id });
|
|
690
|
+
if (!exists) {
|
|
691
|
+
await Blacklist.create({ guild: guildId, type, id });
|
|
692
|
+
}
|
|
693
|
+
return res.json({ success: true });
|
|
694
|
+
}
|
|
695
|
+
res.json({ error: "Blacklist system not available" });
|
|
696
|
+
} catch (e) {
|
|
697
|
+
res.json({ success: false, error: e.message });
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
);
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
app.delete(
|
|
704
|
+
"/api/guild/:guildId/blacklist",
|
|
705
|
+
isAuthenticated,
|
|
706
|
+
async (req, res) => {
|
|
707
|
+
const { type, id } = req.body;
|
|
708
|
+
const guildId = req.params.guildId;
|
|
709
|
+
|
|
710
|
+
try {
|
|
711
|
+
if (removeFromBlacklist) {
|
|
712
|
+
const result = await removeFromBlacklist(guildId, type, id);
|
|
713
|
+
return res.json({ success: result });
|
|
714
|
+
} else if (Blacklist) {
|
|
715
|
+
await Blacklist.deleteOne({ guild: guildId, type, id });
|
|
716
|
+
return res.json({ success: true });
|
|
717
|
+
}
|
|
718
|
+
res.json({ error: "Blacklist system not available" });
|
|
719
|
+
} catch (e) {
|
|
720
|
+
res.json({ success: false, error: e.message });
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
);
|
|
724
|
+
|
|
410
725
|
app.get("/api/blacklist/:type", isAuthenticated, async (req, res) => {
|
|
411
726
|
const { type } = req.params;
|
|
412
727
|
try {
|
|
413
728
|
if (Blacklist) {
|
|
414
|
-
const typeMap = { users:
|
|
729
|
+
const typeMap = { users: "user", roles: "role", channels: "channel" };
|
|
415
730
|
const items = await Blacklist.find({ type: typeMap[type] || type });
|
|
416
731
|
return res.json({ items });
|
|
417
732
|
}
|
|
@@ -427,7 +742,7 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
427
742
|
if (Blacklist) {
|
|
428
743
|
const exists = await Blacklist.findOne({ type, id });
|
|
429
744
|
if (!exists) {
|
|
430
|
-
await Blacklist.create({ type, id, guild:
|
|
745
|
+
await Blacklist.create({ type, id, guild: "global" });
|
|
431
746
|
}
|
|
432
747
|
return res.json({ success: true });
|
|
433
748
|
}
|
|
@@ -450,17 +765,19 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
450
765
|
}
|
|
451
766
|
});
|
|
452
767
|
|
|
453
|
-
|
|
768
|
+
|
|
454
769
|
app.get("/api/user/:userId", isAuthenticated, async (req, res) => {
|
|
455
770
|
try {
|
|
456
|
-
const user = await client.users
|
|
771
|
+
const user = await client.users
|
|
772
|
+
.fetch(req.params.userId)
|
|
773
|
+
.catch(() => null);
|
|
457
774
|
if (user) {
|
|
458
775
|
return res.json({
|
|
459
776
|
id: user.id,
|
|
460
777
|
username: user.username,
|
|
461
778
|
global_name: user.globalName,
|
|
462
779
|
avatar: user.avatar,
|
|
463
|
-
discriminator: user.discriminator
|
|
780
|
+
discriminator: user.discriminator,
|
|
464
781
|
});
|
|
465
782
|
}
|
|
466
783
|
res.json({ error: "User not found" });
|
|
@@ -469,14 +786,15 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
469
786
|
}
|
|
470
787
|
});
|
|
471
788
|
|
|
472
|
-
|
|
473
|
-
// الحصول على معلومات عضو
|
|
789
|
+
|
|
474
790
|
app.get("/api/:guildId/member/:userId", isAuthenticated, async (req, res) => {
|
|
475
791
|
const guild = client.guilds.cache.get(req.params.guildId);
|
|
476
792
|
if (!guild) return res.json({ error: "Guild not found" });
|
|
477
793
|
|
|
478
794
|
try {
|
|
479
|
-
const member = await guild.members
|
|
795
|
+
const member = await guild.members
|
|
796
|
+
.fetch(req.params.userId)
|
|
797
|
+
.catch(() => null);
|
|
480
798
|
if (member) {
|
|
481
799
|
return res.json({
|
|
482
800
|
user: {
|
|
@@ -484,9 +802,9 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
484
802
|
username: member.user.username,
|
|
485
803
|
global_name: member.user.globalName,
|
|
486
804
|
avatar: member.user.avatar,
|
|
487
|
-
discriminator: member.user.discriminator
|
|
805
|
+
discriminator: member.user.discriminator,
|
|
488
806
|
},
|
|
489
|
-
displayName: member.displayName
|
|
807
|
+
displayName: member.displayName,
|
|
490
808
|
});
|
|
491
809
|
}
|
|
492
810
|
res.json({ error: "Member not found" });
|
|
@@ -495,103 +813,280 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
495
813
|
}
|
|
496
814
|
});
|
|
497
815
|
|
|
498
|
-
|
|
816
|
+
|
|
499
817
|
app.get("/api/:guildId/members/search", isAuthenticated, async (req, res) => {
|
|
500
818
|
const guild = client.guilds.cache.get(req.params.guildId);
|
|
501
819
|
if (!guild) return res.json({ members: [] });
|
|
502
820
|
|
|
503
|
-
const query = (req.query.q ||
|
|
821
|
+
const query = (req.query.q || "").toLowerCase();
|
|
504
822
|
if (query.length < 2) return res.json({ members: [] });
|
|
505
823
|
|
|
506
824
|
try {
|
|
507
|
-
|
|
825
|
+
|
|
508
826
|
const members = guild.members.cache
|
|
509
|
-
.filter(
|
|
510
|
-
m
|
|
511
|
-
|
|
512
|
-
|
|
827
|
+
.filter(
|
|
828
|
+
(m) =>
|
|
829
|
+
m.user.username.toLowerCase().includes(query) ||
|
|
830
|
+
m.displayName.toLowerCase().includes(query) ||
|
|
831
|
+
m.user.id.includes(query)
|
|
513
832
|
)
|
|
514
833
|
.first(20)
|
|
515
|
-
.map(m => ({
|
|
834
|
+
.map((m) => ({
|
|
516
835
|
id: m.user.id,
|
|
517
836
|
username: m.user.username,
|
|
518
837
|
displayName: m.displayName,
|
|
519
838
|
avatar: m.user.avatar,
|
|
520
|
-
discriminator: m.user.discriminator
|
|
839
|
+
discriminator: m.user.discriminator,
|
|
521
840
|
}));
|
|
522
|
-
|
|
841
|
+
|
|
523
842
|
res.json({ members });
|
|
524
843
|
} catch (e) {
|
|
525
844
|
res.json({ members: [], error: e.message });
|
|
526
845
|
}
|
|
527
846
|
});
|
|
528
847
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
app.post("/api/:guildId/level/update", isAuthenticated, async (req, res) => {
|
|
848
|
+
|
|
849
|
+
app.post("/api/:guildId/level/update", isAuthenticated, canModifySettings, async (req, res) => {
|
|
532
850
|
const { userId, xp, level } = req.body;
|
|
533
851
|
const guildId = req.params.guildId;
|
|
534
852
|
|
|
535
853
|
try {
|
|
536
|
-
if (Level) {
|
|
854
|
+
if (!Level) return res.json({ error: "Level system not available" });
|
|
855
|
+
|
|
856
|
+
if (level !== undefined) {
|
|
857
|
+
|
|
858
|
+
const config = await getGuildConfig(guildId);
|
|
859
|
+
const totalXP = xpNeeded(level - 1, config || {});
|
|
537
860
|
await Level.findOneAndUpdate(
|
|
538
|
-
{
|
|
539
|
-
{
|
|
861
|
+
{ userId, guildId },
|
|
862
|
+
{ userId, guildId, level, totalXP },
|
|
863
|
+
{ upsert: true, new: true }
|
|
864
|
+
);
|
|
865
|
+
} else if (xp !== undefined) {
|
|
866
|
+
|
|
867
|
+
const config = await getGuildConfig(guildId);
|
|
868
|
+
const newLevel = calculateLevel(xp, config || {});
|
|
869
|
+
await Level.findOneAndUpdate(
|
|
870
|
+
{ userId, guildId },
|
|
871
|
+
{ userId, guildId, totalXP: xp, level: newLevel },
|
|
540
872
|
{ upsert: true, new: true }
|
|
541
873
|
);
|
|
542
|
-
return res.json({ success: true });
|
|
543
874
|
}
|
|
544
|
-
res.json({
|
|
875
|
+
return res.json({ success: true });
|
|
545
876
|
} catch (e) {
|
|
546
877
|
res.json({ success: false, error: e.message });
|
|
547
878
|
}
|
|
548
879
|
});
|
|
549
880
|
|
|
550
|
-
|
|
551
|
-
app.post("/api/:guildId/level/
|
|
552
|
-
const { userId,
|
|
881
|
+
|
|
882
|
+
app.post("/api/:guildId/level/set", isAuthenticated, canModifySettings, async (req, res) => {
|
|
883
|
+
const { userId, level } = req.body;
|
|
553
884
|
const guildId = req.params.guildId;
|
|
554
885
|
|
|
555
886
|
try {
|
|
556
|
-
if (Level) {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
887
|
+
if (!Level) return res.json({ error: "Level system not available" });
|
|
888
|
+
const config = await getGuildConfig(guildId);
|
|
889
|
+
const totalXP = xpNeeded(level - 1, config || {});
|
|
890
|
+
await Level.findOneAndUpdate(
|
|
891
|
+
{ userId, guildId },
|
|
892
|
+
{ userId, guildId, level, totalXP },
|
|
893
|
+
{ upsert: true, new: true }
|
|
894
|
+
);
|
|
895
|
+
return res.json({ success: true });
|
|
896
|
+
} catch (e) {
|
|
897
|
+
res.json({ success: false, error: e.message });
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
app.post("/api/:guildId/level/setxp", isAuthenticated, canModifySettings, async (req, res) => {
|
|
903
|
+
const { userId, xp } = req.body;
|
|
904
|
+
const guildId = req.params.guildId;
|
|
905
|
+
|
|
906
|
+
try {
|
|
907
|
+
if (!Level) return res.json({ error: "Level system not available" });
|
|
908
|
+
const config = await getGuildConfig(guildId);
|
|
909
|
+
const level = calculateLevel(xp, config || {});
|
|
910
|
+
await Level.findOneAndUpdate(
|
|
911
|
+
{ userId, guildId },
|
|
912
|
+
{ userId, guildId, totalXP: xp, level },
|
|
913
|
+
{ upsert: true, new: true }
|
|
914
|
+
);
|
|
915
|
+
return res.json({ success: true });
|
|
916
|
+
} catch (e) {
|
|
917
|
+
res.json({ success: false, error: e.message });
|
|
918
|
+
}
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
app.post("/api/:guildId/level/add", isAuthenticated, canModifySettings, async (req, res) => {
|
|
923
|
+
const { userId, xp } = req.body;
|
|
924
|
+
const guildId = req.params.guildId;
|
|
925
|
+
|
|
926
|
+
try {
|
|
927
|
+
if (!Level) return res.json({ error: "Level system not available" });
|
|
928
|
+
|
|
929
|
+
const config = await getGuildConfig(guildId);
|
|
930
|
+
const existing = await Level.findOne({ guildId, userId });
|
|
931
|
+
if (existing) {
|
|
932
|
+
existing.totalXP += xp;
|
|
933
|
+
existing.level = calculateLevel(existing.totalXP, config || {});
|
|
934
|
+
await existing.save();
|
|
935
|
+
} else {
|
|
936
|
+
await Level.create({
|
|
937
|
+
guildId,
|
|
938
|
+
userId,
|
|
939
|
+
totalXP: xp,
|
|
940
|
+
level: calculateLevel(xp, config || {}),
|
|
941
|
+
text: xp,
|
|
942
|
+
});
|
|
566
943
|
}
|
|
567
|
-
res.json({
|
|
944
|
+
return res.json({ success: true });
|
|
568
945
|
} catch (e) {
|
|
569
946
|
res.json({ success: false, error: e.message });
|
|
570
947
|
}
|
|
571
948
|
});
|
|
572
949
|
|
|
573
|
-
|
|
574
|
-
app.post("/api/:guildId/level/reset", isAuthenticated, async (req, res) => {
|
|
950
|
+
|
|
951
|
+
app.post("/api/:guildId/level/reset", isAuthenticated, canModifySettings, async (req, res) => {
|
|
575
952
|
const { userId } = req.body;
|
|
576
953
|
const guildId = req.params.guildId;
|
|
577
954
|
|
|
578
955
|
try {
|
|
579
|
-
if (Level) {
|
|
580
|
-
|
|
581
|
-
|
|
956
|
+
if (!Level) return res.json({ error: "Level system not available" });
|
|
957
|
+
await resetUser(userId, guildId);
|
|
958
|
+
return res.json({ success: true });
|
|
959
|
+
} catch (e) {
|
|
960
|
+
res.json({ success: false, error: e.message });
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
app.get("/api/:guildId/level/rank/:userId", isAuthenticated, async (req, res) => {
|
|
966
|
+
const { guildId, userId } = req.params;
|
|
967
|
+
|
|
968
|
+
try {
|
|
969
|
+
if (!Level) return res.json({ error: "Level system not available" });
|
|
970
|
+
const rank = await getUserRank(userId, guildId);
|
|
971
|
+
const userData = await Level.findOne({ guildId, userId });
|
|
972
|
+
res.json({
|
|
973
|
+
rank,
|
|
974
|
+
level: userData?.level || 0,
|
|
975
|
+
totalXP: userData?.totalXP || 0,
|
|
976
|
+
xpForNext: xpNeeded((userData?.level || 0) + 1)
|
|
977
|
+
});
|
|
978
|
+
} catch (e) {
|
|
979
|
+
res.json({ error: e.message });
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
app.get("/api/:guildId/level/config", isAuthenticated, async (req, res) => {
|
|
985
|
+
try {
|
|
986
|
+
const config = await getGuildConfig(req.params.guildId);
|
|
987
|
+
const usesDashboardMode = client.levelDashboardGuilds && client.levelDashboardGuilds.has(req.params.guildId);
|
|
988
|
+
res.json({ databaseEnabled: usesDashboardMode, config: config || null });
|
|
989
|
+
} catch (e) {
|
|
990
|
+
res.json({ error: e.message });
|
|
991
|
+
}
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
app.post("/api/:guildId/level/config/role", isAuthenticated, canModifySettings, async (req, res) => {
|
|
996
|
+
const { level, roleId } = req.body;
|
|
997
|
+
const guildId = req.params.guildId;
|
|
998
|
+
|
|
999
|
+
try {
|
|
1000
|
+
const config = await getGuildConfig(guildId) || {};
|
|
1001
|
+
const roleReward = config.roleReward || {};
|
|
1002
|
+
|
|
1003
|
+
if (roleId) {
|
|
1004
|
+
roleReward[level] = roleId;
|
|
1005
|
+
} else {
|
|
1006
|
+
delete roleReward[level];
|
|
582
1007
|
}
|
|
583
|
-
|
|
1008
|
+
|
|
1009
|
+
await updateGuildConfig(guildId, { roleReward });
|
|
1010
|
+
res.json({ success: true, roleReward });
|
|
1011
|
+
} catch (e) {
|
|
1012
|
+
res.json({ success: false, error: e.message });
|
|
1013
|
+
}
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
app.post("/api/:guildId/level/config/xp", isAuthenticated, canModifySettings, async (req, res) => {
|
|
1018
|
+
const { minXP, maxXP, xpMultiplier, maxLevel, cooldown, leveling } = req.body;
|
|
1019
|
+
const guildId = req.params.guildId;
|
|
1020
|
+
|
|
1021
|
+
try {
|
|
1022
|
+
const updates = {};
|
|
1023
|
+
if (minXP !== undefined) updates.minXP = minXP;
|
|
1024
|
+
if (maxXP !== undefined) updates.maxXP = maxXP;
|
|
1025
|
+
if (xpMultiplier !== undefined) updates.xpMultiplier = xpMultiplier;
|
|
1026
|
+
if (maxLevel !== undefined) updates.maxLevel = maxLevel;
|
|
1027
|
+
if (cooldown !== undefined) updates.cooldown = cooldown;
|
|
1028
|
+
if (leveling !== undefined) updates.leveling = leveling;
|
|
1029
|
+
|
|
1030
|
+
await updateGuildConfig(guildId, updates);
|
|
1031
|
+
res.json({ success: true });
|
|
584
1032
|
} catch (e) {
|
|
585
1033
|
res.json({ success: false, error: e.message });
|
|
586
1034
|
}
|
|
587
1035
|
});
|
|
588
1036
|
|
|
589
|
-
|
|
1037
|
+
|
|
1038
|
+
app.post("/api/:guildId/level/config/blacklist", isAuthenticated, canModifySettings, async (req, res) => {
|
|
1039
|
+
const { channelId, action } = req.body;
|
|
1040
|
+
const guildId = req.params.guildId;
|
|
1041
|
+
|
|
1042
|
+
try {
|
|
1043
|
+
const config = await getGuildConfig(guildId) || {};
|
|
1044
|
+
let blacklistedChannels = config.blacklistedChannels || [];
|
|
1045
|
+
|
|
1046
|
+
if (action === "add" && !blacklistedChannels.includes(channelId)) {
|
|
1047
|
+
blacklistedChannels.push(channelId);
|
|
1048
|
+
} else if (action === "remove") {
|
|
1049
|
+
blacklistedChannels = blacklistedChannels.filter(id => id !== channelId);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
await updateGuildConfig(guildId, { blacklistedChannels });
|
|
1053
|
+
res.json({ success: true, blacklistedChannels });
|
|
1054
|
+
} catch (e) {
|
|
1055
|
+
res.json({ success: false, error: e.message });
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
app.post("/api/:guildId/level/config/toggle", isAuthenticated, canModifySettings, async (req, res) => {
|
|
1061
|
+
const { disabled } = req.body;
|
|
1062
|
+
const guildId = req.params.guildId;
|
|
1063
|
+
|
|
1064
|
+
try {
|
|
1065
|
+
await updateGuildConfig(guildId, { disabled: !!disabled });
|
|
1066
|
+
res.json({ success: true });
|
|
1067
|
+
} catch (e) {
|
|
1068
|
+
res.json({ success: false, error: e.message });
|
|
1069
|
+
}
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
app.post("/api/:guildId/level/config/reset", isAuthenticated, canModifySettings, async (req, res) => {
|
|
1074
|
+
const guildId = req.params.guildId;
|
|
1075
|
+
|
|
1076
|
+
try {
|
|
1077
|
+
await deleteGuildConfig(guildId);
|
|
1078
|
+
res.json({ success: true });
|
|
1079
|
+
} catch (e) {
|
|
1080
|
+
res.json({ success: false, error: e.message });
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
|
|
590
1085
|
app.get("/api/stats", (req, res) => {
|
|
591
1086
|
res.json(getBotStats());
|
|
592
1087
|
});
|
|
593
1088
|
|
|
594
|
-
|
|
1089
|
+
|
|
595
1090
|
app.get("/api/:guildId/stats", isAuthenticated, async (req, res) => {
|
|
596
1091
|
const guild = client.guilds.cache.get(req.params.guildId);
|
|
597
1092
|
if (!guild) return res.json({ error: "Guild not found" });
|
|
@@ -602,8 +1097,13 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
602
1097
|
|
|
603
1098
|
try {
|
|
604
1099
|
if (Level) levelCount = await Level.countDocuments({ guildId: guild.id });
|
|
605
|
-
if (giveaway)
|
|
606
|
-
|
|
1100
|
+
if (giveaway)
|
|
1101
|
+
giveawayCount = await giveaway.countDocuments({
|
|
1102
|
+
guildId: guild.id,
|
|
1103
|
+
ended: false,
|
|
1104
|
+
});
|
|
1105
|
+
if (Blacklist)
|
|
1106
|
+
blacklistCount = await Blacklist.countDocuments({ guild: guild.id });
|
|
607
1107
|
} catch (e) {
|
|
608
1108
|
console.error("Stats error:", e);
|
|
609
1109
|
}
|
|
@@ -619,18 +1119,13 @@ app.set("views", path.join(__dirname, "views"));
|
|
|
619
1119
|
});
|
|
620
1120
|
});
|
|
621
1121
|
|
|
622
|
-
|
|
1122
|
+
|
|
623
1123
|
app.use((req, res) => {
|
|
624
1124
|
res.status(404).render("404", { botStats: getBotStats() });
|
|
625
1125
|
});
|
|
626
1126
|
|
|
627
|
-
|
|
628
|
-
app.listen(port, () => {
|
|
629
|
-
console.log(`\n🌐 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
|
|
630
|
-
console.log(` DJS-Builder Dashboard v2.0`);
|
|
631
|
-
console.log(` 🔗 http://localhost:${port}`);
|
|
632
|
-
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
|
|
633
|
-
});
|
|
1127
|
+
|
|
1128
|
+
app.listen(port, () => {});
|
|
634
1129
|
|
|
635
1130
|
return app;
|
|
636
1131
|
}
|