djs-builder 0.6.401 → 0.7.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.
@@ -0,0 +1,638 @@
1
+ /**
2
+ * DJS-Builder Dashboard
3
+ * لوحة تحكم عصرية وخفيفة متوافقة مع حزمة djs-builder
4
+ * @version 2.0.0
5
+ * @author DJS-Builder Team
6
+ */
7
+
8
+ const express = require("express");
9
+ const session = require("express-session");
10
+ const passport = require("passport");
11
+ const DiscordStrategy = require("passport-discord").Strategy;
12
+ const path = require("path");
13
+
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
+
43
+ /**
44
+ * دالة لإنشاء وتشغيل لوحة التحكم
45
+ * @param {Client} client - كائن البوت
46
+ * @param {Object} options - خيارات اللوحة
47
+ */
48
+ function dashboard(client, options) {
49
+ const app = express();
50
+ const {
51
+ clientID,
52
+ clientSecret,
53
+ callbackURL,
54
+ sessionSecret,
55
+ port = 3000,
56
+ } = options;
57
+
58
+ // إعداد المسارات
59
+ app.set("view engine", "ejs");
60
+ app.set("views", path.join(__dirname, "views"));
61
+ app.use(express.static(path.join(__dirname, "public")));
62
+ app.use(express.json());
63
+ app.use(express.urlencoded({ extended: true }));
64
+
65
+ // إعداد الجلسات
66
+ app.use(
67
+ session({
68
+ secret: sessionSecret,
69
+ resave: false,
70
+ saveUninitialized: false,
71
+ cookie: {
72
+ maxAge: 1000 * 60 * 60 * 24 * 7,
73
+ },
74
+ })
75
+ );
76
+
77
+ // إعداد Passport
78
+ app.use(passport.initialize());
79
+ app.use(passport.session());
80
+
81
+ passport.serializeUser((user, done) => done(null, user));
82
+ passport.deserializeUser((obj, done) => done(null, obj));
83
+
84
+ passport.use(
85
+ new DiscordStrategy(
86
+ {
87
+ clientID,
88
+ clientSecret,
89
+ callbackURL,
90
+ scope: ["identify", "guilds"],
91
+ },
92
+ (accessToken, refreshToken, profile, done) => {
93
+ return done(null, profile);
94
+ }
95
+ )
96
+ );
97
+
98
+ // Middleware للتحقق من تسجيل الدخول
99
+ function isAuthenticated(req, res, next) {
100
+ if (req.isAuthenticated()) return next();
101
+ res.redirect("/login");
102
+ }
103
+
104
+ // تمرير بيانات المستخدم والبوت لكل الصفحات
105
+ app.use((req, res, next) => {
106
+ res.locals.user = req.user || null;
107
+ res.locals.client = client;
108
+ res.locals.path = req.path;
109
+ next();
110
+ });
111
+
112
+ // ==================== دالة مساعدة للإحصائيات ====================
113
+ function getBotStats() {
114
+ const uniquePrefixCommands = new Set();
115
+ if (client.prefixCommands) {
116
+ client.prefixCommands.forEach((cmd) => {
117
+ uniquePrefixCommands.add(cmd.name);
118
+ });
119
+ }
120
+
121
+ // محاولة الحصول على البادئة من client
122
+ const prefix = client.prefix || options.prefix || '-';
123
+
124
+ return {
125
+ guilds: client.guilds?.cache?.size || 0,
126
+ users: client.guilds?.cache?.reduce((acc, g) => acc + g.memberCount, 0) || 0,
127
+ channels: client.channels?.cache?.size || 0,
128
+ slashCommands: client.slashCommands?.size || 0,
129
+ prefixCommands: uniquePrefixCommands.size,
130
+ events: client.djsEventListeners?.size || 0,
131
+ uptime: client.uptime || 0,
132
+ ping: client.ws?.ping || 0,
133
+ botName: client.user?.username || "Bot",
134
+ botAvatar: client.user?.displayAvatarURL({ size: 256 }) || "",
135
+ botId: client.user?.id || "",
136
+ botTag: client.user?.tag || "",
137
+ prefix: prefix,
138
+ startedAt: Date.now() - (client.uptime || 0),
139
+ };
140
+ }
141
+
142
+ // ==================== المسارات الرئيسية ====================
143
+
144
+ // الصفحة الرئيسية
145
+ app.get("/", (req, res) => {
146
+ res.render("index", {
147
+ botStats: getBotStats(),
148
+ });
149
+ });
150
+
151
+ // صفحة تسجيل الدخول
152
+ app.get("/login", (req, res) => {
153
+ if (req.isAuthenticated()) return res.redirect("/dashboard");
154
+ res.render("login", { botStats: getBotStats() });
155
+ });
156
+
157
+ // OAuth2 مع Discord
158
+ app.get("/auth/discord", passport.authenticate("discord"));
159
+
160
+ app.get(
161
+ "/auth/discord/callback",
162
+ passport.authenticate("discord", {
163
+ failureRedirect: "/login",
164
+ }),
165
+ (req, res) => {
166
+ res.redirect("/dashboard");
167
+ }
168
+ );
169
+
170
+ // تسجيل الخروج
171
+ app.get("/logout", (req, res) => {
172
+ req.logout(() => {
173
+ res.redirect("/");
174
+ });
175
+ });
176
+
177
+ // ==================== لوحة التحكم ====================
178
+
179
+ // لوحة التحكم الرئيسية
180
+ app.get("/dashboard", isAuthenticated, (req, res) => {
181
+ const userGuilds = req.user.guilds.filter(
182
+ (g) =>
183
+ (g.permissions & 0x20) === 0x20 && client.guilds.cache.has(g.id)
184
+ );
185
+ res.render("dashboard", {
186
+ guilds: userGuilds,
187
+ botStats: getBotStats()
188
+ });
189
+ });
190
+
191
+ // إدارة سيرفر معين - نظرة عامة
192
+ app.get("/dashboard/:guildId", isAuthenticated, async (req, res) => {
193
+ const guild = client.guilds.cache.get(req.params.guildId);
194
+ if (!guild) return res.redirect("/dashboard");
195
+
196
+ const userGuild = req.user.guilds.find((g) => g.id === req.params.guildId);
197
+ if (!userGuild || (userGuild.permissions & 0x20) !== 0x20) {
198
+ return res.redirect("/dashboard");
199
+ }
200
+
201
+ // جمع إحصائيات السيرفر
202
+ let levelCount = 0;
203
+ let giveawayCount = 0;
204
+ let blacklistCount = 0;
205
+
206
+ try {
207
+ if (Level) levelCount = await Level.countDocuments({ guildId: guild.id });
208
+ if (giveaway) giveawayCount = await giveaway.countDocuments({ guildId: guild.id, ended: false });
209
+ if (Blacklist) blacklistCount = await Blacklist.countDocuments({ guild: guild.id });
210
+ } catch (e) {
211
+ console.error("Stats error:", e);
212
+ }
213
+
214
+ res.render("guild", {
215
+ guild,
216
+ page: "overview",
217
+ stats: {
218
+ members: guild.memberCount,
219
+ channels: guild.channels.cache.size,
220
+ roles: guild.roles.cache.size,
221
+ emojis: guild.emojis.cache.size,
222
+ levelUsers: levelCount,
223
+ activeGiveaways: giveawayCount,
224
+ blacklisted: blacklistCount,
225
+ },
226
+ botStats: getBotStats()
227
+ });
228
+ });
229
+
230
+ // ==================== صفحة الأوامر ====================
231
+ app.get("/dashboard/:guildId/commands", isAuthenticated, async (req, res) => {
232
+ const guild = client.guilds.cache.get(req.params.guildId);
233
+ if (!guild) return res.redirect("/dashboard");
234
+
235
+ const slashCommands = client.slashCommands
236
+ ? Array.from(client.slashCommands.values())
237
+ : [];
238
+
239
+ // إزالة التكرارات من prefix commands
240
+ const uniquePrefixCommands = [];
241
+ const seen = new Set();
242
+ if (client.prefixCommands) {
243
+ client.prefixCommands.forEach((cmd) => {
244
+ if (!seen.has(cmd.name)) {
245
+ seen.add(cmd.name);
246
+ uniquePrefixCommands.push(cmd);
247
+ }
248
+ });
249
+ }
250
+
251
+ res.render("commands", {
252
+ guild,
253
+ slashCommands,
254
+ prefixCommands: uniquePrefixCommands,
255
+ page: "commands",
256
+ botStats: getBotStats()
257
+ });
258
+ });
259
+
260
+ // ==================== نظام اللفل ====================
261
+ app.get("/dashboard/:guildId/levels", isAuthenticated, async (req, res) => {
262
+ const guild = client.guilds.cache.get(req.params.guildId);
263
+ if (!guild) return res.redirect("/dashboard");
264
+
265
+ let leaderboardData = [];
266
+ if (Level) {
267
+ try {
268
+ leaderboardData = await Level.find({ guildId: guild.id })
269
+ .sort({ totalXP: -1 })
270
+ .limit(100);
271
+ } catch (e) {
272
+ console.error("Error fetching levels:", e);
273
+ }
274
+ }
275
+
276
+ res.render("levels", {
277
+ guild,
278
+ leaderboard: leaderboardData,
279
+ page: "levels",
280
+ botStats: getBotStats()
281
+ });
282
+ });
283
+
284
+ // API للحصول على بيانات مستخدم
285
+ app.get("/api/:guildId/user/:userId", isAuthenticated, async (req, res) => {
286
+ if (!Level) return res.json({ error: "Level system not available" });
287
+
288
+ try {
289
+ const userData = await Level.findOne({
290
+ guildId: req.params.guildId,
291
+ userId: req.params.userId,
292
+ });
293
+ res.json(userData || { level: 0, totalXP: 0, text: 0, voice: 0 });
294
+ } catch (e) {
295
+ res.json({ error: e.message });
296
+ }
297
+ });
298
+
299
+ // ==================== نظام الجيف اوي ====================
300
+ app.get("/dashboard/:guildId/giveaways", isAuthenticated, async (req, res) => {
301
+ const guild = client.guilds.cache.get(req.params.guildId);
302
+ if (!guild) return res.redirect("/dashboard");
303
+
304
+ let giveaways = [];
305
+ if (giveaway) {
306
+ try {
307
+ giveaways = await giveaway.find({ guildId: guild.id }).sort({ endTime: -1 });
308
+ } catch (e) {
309
+ console.error("Error fetching giveaways:", e);
310
+ }
311
+ }
312
+
313
+ res.render("giveaways", {
314
+ guild,
315
+ giveaways,
316
+ page: "giveaways",
317
+ botStats: getBotStats()
318
+ });
319
+ });
320
+
321
+ // API للجيف اوي
322
+ app.post("/api/:guildId/giveaway/:action", isAuthenticated, async (req, res) => {
323
+ const { guildId, action } = req.params;
324
+ const { messageId } = req.body;
325
+
326
+ try {
327
+ let result = { success: true };
328
+ switch (action) {
329
+ case "pause":
330
+ if (Gpause) await Gpause(client, messageId);
331
+ break;
332
+ case "resume":
333
+ // تنفيذ يدوي للاستئناف لأن Gresume في djs-builder يحتوي على خطأ
334
+ if (Gresume) await Gresume(client, messageId);
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} بنجاح` });
361
+ } catch (e) {
362
+ console.error("Giveaway action error:", e);
363
+ res.json({ success: false, error: e.message });
364
+ }
365
+ });
366
+
367
+ // ==================== نظام البلاك ليست ====================
368
+ // API لإضافة للبلاك ليست
369
+ app.post("/api/guild/:guildId/blacklist", isAuthenticated, async (req, res) => {
370
+ const { type, id } = req.body;
371
+ const guildId = req.params.guildId;
372
+
373
+ try {
374
+ if (addToBlacklist) {
375
+ const result = await addToBlacklist(guildId, type, id);
376
+ return res.json({ success: result });
377
+ } else if (Blacklist) {
378
+ const exists = await Blacklist.findOne({ guild: guildId, type, id });
379
+ if (!exists) {
380
+ await Blacklist.create({ guild: guildId, type, id });
381
+ }
382
+ return res.json({ success: true });
383
+ }
384
+ res.json({ error: "Blacklist system not available" });
385
+ } catch (e) {
386
+ res.json({ success: false, error: e.message });
387
+ }
388
+ });
389
+
390
+ // API لحذف من البلاك ليست
391
+ app.delete("/api/guild/:guildId/blacklist", isAuthenticated, async (req, res) => {
392
+ const { type, id } = req.body;
393
+ const guildId = req.params.guildId;
394
+
395
+ try {
396
+ if (removeFromBlacklist) {
397
+ const result = await removeFromBlacklist(guildId, type, id);
398
+ return res.json({ success: result });
399
+ } else if (Blacklist) {
400
+ await Blacklist.deleteOne({ guild: guildId, type, id });
401
+ return res.json({ success: true });
402
+ }
403
+ res.json({ error: "Blacklist system not available" });
404
+ } catch (e) {
405
+ res.json({ success: false, error: e.message });
406
+ }
407
+ });
408
+
409
+ // ==================== API القائمة السوداء العامة ====================
410
+ app.get("/api/blacklist/:type", isAuthenticated, async (req, res) => {
411
+ const { type } = req.params;
412
+ try {
413
+ if (Blacklist) {
414
+ const typeMap = { users: 'user', roles: 'role', channels: 'channel' };
415
+ const items = await Blacklist.find({ type: typeMap[type] || type });
416
+ return res.json({ items });
417
+ }
418
+ res.json({ items: [] });
419
+ } catch (e) {
420
+ res.json({ items: [], error: e.message });
421
+ }
422
+ });
423
+
424
+ app.post("/api/blacklist", isAuthenticated, async (req, res) => {
425
+ const { type, id } = req.body;
426
+ try {
427
+ if (Blacklist) {
428
+ const exists = await Blacklist.findOne({ type, id });
429
+ if (!exists) {
430
+ await Blacklist.create({ type, id, guild: 'global' });
431
+ }
432
+ return res.json({ success: true });
433
+ }
434
+ res.json({ error: "Blacklist not available" });
435
+ } catch (e) {
436
+ res.json({ success: false, error: e.message });
437
+ }
438
+ });
439
+
440
+ app.delete("/api/blacklist", isAuthenticated, async (req, res) => {
441
+ const { type, id } = req.body;
442
+ try {
443
+ if (Blacklist) {
444
+ await Blacklist.deleteOne({ type, id });
445
+ return res.json({ success: true });
446
+ }
447
+ res.json({ error: "Blacklist not available" });
448
+ } catch (e) {
449
+ res.json({ success: false, error: e.message });
450
+ }
451
+ });
452
+
453
+ // API لجلب بيانات مستخدم (عام)
454
+ app.get("/api/user/:userId", isAuthenticated, async (req, res) => {
455
+ try {
456
+ const user = await client.users.fetch(req.params.userId).catch(() => null);
457
+ if (user) {
458
+ return res.json({
459
+ id: user.id,
460
+ username: user.username,
461
+ global_name: user.globalName,
462
+ avatar: user.avatar,
463
+ discriminator: user.discriminator
464
+ });
465
+ }
466
+ res.json({ error: "User not found" });
467
+ } catch (e) {
468
+ res.json({ error: e.message });
469
+ }
470
+ });
471
+
472
+ // ==================== API للأعضاء ====================
473
+ // الحصول على معلومات عضو
474
+ app.get("/api/:guildId/member/:userId", isAuthenticated, async (req, res) => {
475
+ const guild = client.guilds.cache.get(req.params.guildId);
476
+ if (!guild) return res.json({ error: "Guild not found" });
477
+
478
+ try {
479
+ const member = await guild.members.fetch(req.params.userId).catch(() => null);
480
+ if (member) {
481
+ return res.json({
482
+ user: {
483
+ id: member.user.id,
484
+ username: member.user.username,
485
+ global_name: member.user.globalName,
486
+ avatar: member.user.avatar,
487
+ discriminator: member.user.discriminator
488
+ },
489
+ displayName: member.displayName
490
+ });
491
+ }
492
+ res.json({ error: "Member not found" });
493
+ } catch (e) {
494
+ res.json({ error: e.message });
495
+ }
496
+ });
497
+
498
+ // البحث عن أعضاء
499
+ app.get("/api/:guildId/members/search", isAuthenticated, async (req, res) => {
500
+ const guild = client.guilds.cache.get(req.params.guildId);
501
+ if (!guild) return res.json({ members: [] });
502
+
503
+ const query = (req.query.q || '').toLowerCase();
504
+ if (query.length < 2) return res.json({ members: [] });
505
+
506
+ try {
507
+ // جلب الأعضاء من الكاش
508
+ const members = guild.members.cache
509
+ .filter(m =>
510
+ m.user.username.toLowerCase().includes(query) ||
511
+ m.displayName.toLowerCase().includes(query) ||
512
+ m.user.id.includes(query)
513
+ )
514
+ .first(20)
515
+ .map(m => ({
516
+ id: m.user.id,
517
+ username: m.user.username,
518
+ displayName: m.displayName,
519
+ avatar: m.user.avatar,
520
+ discriminator: m.user.discriminator
521
+ }));
522
+
523
+ res.json({ members });
524
+ } catch (e) {
525
+ res.json({ members: [], error: e.message });
526
+ }
527
+ });
528
+
529
+ // ==================== API للمستويات ====================
530
+ // تحديث مستوى مستخدم
531
+ app.post("/api/:guildId/level/update", isAuthenticated, async (req, res) => {
532
+ const { userId, xp, level } = req.body;
533
+ const guildId = req.params.guildId;
534
+
535
+ try {
536
+ if (Level) {
537
+ await Level.findOneAndUpdate(
538
+ { guildId, userId },
539
+ { totalXP: xp, level, $setOnInsert: { text: 0, voice: 0 } },
540
+ { upsert: true, new: true }
541
+ );
542
+ return res.json({ success: true });
543
+ }
544
+ res.json({ error: "Level system not available" });
545
+ } catch (e) {
546
+ res.json({ success: false, error: e.message });
547
+ }
548
+ });
549
+
550
+ // إضافة XP لمستخدم
551
+ app.post("/api/:guildId/level/add", isAuthenticated, async (req, res) => {
552
+ const { userId, xp, level } = req.body;
553
+ const guildId = req.params.guildId;
554
+
555
+ try {
556
+ if (Level) {
557
+ const existing = await Level.findOne({ guildId, userId });
558
+ if (existing) {
559
+ existing.totalXP += xp;
560
+ if (level > 0) existing.level = level;
561
+ await existing.save();
562
+ } else {
563
+ await Level.create({ guildId, userId, totalXP: xp, level: level || 0, text: 0, voice: 0 });
564
+ }
565
+ return res.json({ success: true });
566
+ }
567
+ res.json({ error: "Level system not available" });
568
+ } catch (e) {
569
+ res.json({ success: false, error: e.message });
570
+ }
571
+ });
572
+
573
+ // إعادة تعيين مستوى مستخدم
574
+ app.post("/api/:guildId/level/reset", isAuthenticated, async (req, res) => {
575
+ const { userId } = req.body;
576
+ const guildId = req.params.guildId;
577
+
578
+ try {
579
+ if (Level) {
580
+ await Level.deleteOne({ guildId, userId });
581
+ return res.json({ success: true });
582
+ }
583
+ res.json({ error: "Level system not available" });
584
+ } catch (e) {
585
+ res.json({ success: false, error: e.message });
586
+ }
587
+ });
588
+
589
+ // ==================== API للإحصائيات ====================
590
+ app.get("/api/stats", (req, res) => {
591
+ res.json(getBotStats());
592
+ });
593
+
594
+ // API لإحصائيات السيرفر
595
+ app.get("/api/:guildId/stats", isAuthenticated, async (req, res) => {
596
+ const guild = client.guilds.cache.get(req.params.guildId);
597
+ if (!guild) return res.json({ error: "Guild not found" });
598
+
599
+ let levelCount = 0;
600
+ let giveawayCount = 0;
601
+ let blacklistCount = 0;
602
+
603
+ try {
604
+ if (Level) levelCount = await Level.countDocuments({ guildId: guild.id });
605
+ if (giveaway) giveawayCount = await giveaway.countDocuments({ guildId: guild.id, ended: false });
606
+ if (Blacklist) blacklistCount = await Blacklist.countDocuments({ guild: guild.id });
607
+ } catch (e) {
608
+ console.error("Stats error:", e);
609
+ }
610
+
611
+ res.json({
612
+ members: guild.memberCount,
613
+ channels: guild.channels.cache.size,
614
+ roles: guild.roles.cache.size,
615
+ emojis: guild.emojis.cache.size,
616
+ levelUsers: levelCount,
617
+ activeGiveaways: giveawayCount,
618
+ blacklisted: blacklistCount,
619
+ });
620
+ });
621
+
622
+ // ==================== صفحة 404 ====================
623
+ app.use((req, res) => {
624
+ res.status(404).render("404", { botStats: getBotStats() });
625
+ });
626
+
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
+ });
634
+
635
+ return app;
636
+ }
637
+
638
+ module.exports = { dashboard };