djs-builder 0.7.9 → 0.7.11

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 CHANGED
@@ -481,9 +481,9 @@ const modal = CreateModal({
481
481
  },
482
482
  },
483
483
  {
484
- type: "label",
484
+ type: "text",
485
485
  components: {
486
- label: "Thank you for your input!",
486
+ content: "Thank you for your input!",
487
487
  },
488
488
  },
489
489
  ],
@@ -526,6 +526,8 @@ await interaction.showModal(modal);
526
526
  type: "string",
527
527
  options: {
528
528
  id: "country",
529
+ mine_label: "Choose Your Country", // Label displayed above the menu
530
+ mine_description: "Please select your country from the list below", // Optional description
529
531
  placeholder: "Select your country",
530
532
  min: 1,
531
533
  max: 1,
@@ -571,9 +573,9 @@ await interaction.showModal(modal);
571
573
 
572
574
  ```js
573
575
  {
574
- type: "label",
576
+ type: "text",
575
577
  components: {
576
- label: "Please fill out the form above.",
578
+ content: "Please fill out the form above.",
577
579
  },
578
580
  },
579
581
  ```
@@ -598,6 +600,8 @@ Same as CreateRow select menus.
598
600
 
599
601
  - `type` → `"string" | "user" | "role" | "channel"`
600
602
  - `id` → customId for menu
603
+ - `mine_label` → Label displayed above the menu component (defaults to "Select an option")
604
+ - `mine_description` → Description text displayed below the menu label (optional)
601
605
  - `placeholder` → Text shown before selection
602
606
  - `min` / `max` → Min/Max selectable values
603
607
  - `data` → Options array (for string select only)
@@ -622,9 +626,9 @@ Same as CreateRow select menus.
622
626
  - `label` → Label
623
627
  - `description` → Description
624
628
 
625
- #### 🔹 Label
629
+ #### 🔹 text
626
630
 
627
- - `label` → Text to display
631
+ - `content` → Text to display
628
632
 
629
633
  ---
630
634
 
package/function/dash.js CHANGED
@@ -12,8 +12,20 @@ const DiscordStrategy = require("passport-discord").Strategy;
12
12
  const path = require("path");
13
13
  const Table = require("cli-table3");
14
14
  const chalk = require("chalk");
15
-
16
- const { Level } = require("./level");
15
+ const mongoose = require("mongoose");
16
+
17
+ const {
18
+ Level,
19
+ levelGuild,
20
+ resetUser,
21
+ xpNeeded,
22
+ calculateLevel,
23
+ getUserRank,
24
+ getGuildConfig,
25
+ updateGuildConfig,
26
+ deleteGuildConfig,
27
+ clearConfigCache,
28
+ } = require("./level");
17
29
  const {
18
30
  Blacklist,
19
31
  addToBlacklist,
@@ -94,6 +106,7 @@ function dashboard(client, options) {
94
106
  res.locals.user = req.user || null;
95
107
  res.locals.client = client;
96
108
  res.locals.path = req.path;
109
+ res.locals.dashboardEnabled = options.Dashboard !== false; // الإعداد من الكود
97
110
  next();
98
111
  });
99
112
 
@@ -255,25 +268,91 @@ function dashboard(client, options) {
255
268
  const guild = client.guilds.cache.get(req.params.guildId);
256
269
  if (!guild) return res.redirect("/dashboard");
257
270
 
271
+ const mongoConnected = mongoose.connection.readyState === 1;
272
+ let levelConfigDb = null;
273
+ let configSource = null;
274
+ let databaseEnabled = false; // Only true if guild uses Dashboard mode in setLevel
275
+
276
+ // Check if modifying via dashboard is allowed
277
+ const canModify = options.Dashboard !== false;
278
+
279
+ // Check if guild uses Dashboard mode (Dashboard: true in setLevel)
280
+ const usesDashboardMode = client.levelDashboardGuilds && client.levelDashboardGuilds.has(guild.id);
281
+
282
+ // Get guild config from database
283
+ if (mongoConnected) {
284
+ try {
285
+ levelConfigDb = await getGuildConfig(guild.id);
286
+ if (levelConfigDb && usesDashboardMode) {
287
+ configSource = "database";
288
+ databaseEnabled = true; // Config exists AND guild uses Dashboard mode
289
+ }
290
+ } catch (e) {
291
+ console.error("Error fetching level config:", e);
292
+ }
293
+ }
294
+
258
295
  let leaderboardData = [];
259
296
  if (Level) {
260
297
  try {
261
- leaderboardData = await Level.find({ guildId: guild.id })
298
+ const rawLeaderboard = await Level.find({ guildId: guild.id })
262
299
  .sort({ totalXP: -1 })
263
300
  .limit(100);
301
+
302
+ // Fetch members to ensure they are in cache/get real data
303
+ const memberIds = rawLeaderboard.map(u => u.userId);
304
+ const fetchedMembers = await guild.members.fetch({ user: memberIds }).catch(() => new Map());
305
+
306
+ leaderboardData = rawLeaderboard.map(u => {
307
+ const member = fetchedMembers.get(u.userId) || guild.members.cache.get(u.userId);
308
+ return {
309
+ userId: u.userId,
310
+ totalXP: u.totalXP,
311
+ level: u.level,
312
+ username: member ? member.user.username : `User ${u.userId.substring(0, 5)}`,
313
+ avatar: member ? member.user.displayAvatarURL({ size: 64, forceStatic: true }) : `https://cdn.discordapp.com/embed/avatars/${Math.floor(Math.random() * 6)}.png`,
314
+ };
315
+ });
264
316
  } catch (e) {
265
317
  console.error("Error fetching levels:", e);
266
318
  }
267
319
  }
268
320
 
321
+ // Get guild roles for role rewards
322
+ const roles = guild.roles.cache
323
+ .filter((r) => r.id !== guild.id && !r.managed)
324
+ .map((r) => ({ id: r.id, name: r.name, color: r.hexColor }))
325
+ .sort((a, b) => a.name.localeCompare(b.name));
326
+
327
+ // Get guild channels for level up messages
328
+ const channels = guild.channels.cache
329
+ .filter((c) => c.type === 0)
330
+ .map((c) => ({ id: c.id, name: c.name }))
331
+ .sort((a, b) => a.name.localeCompare(b.name));
332
+
269
333
  res.render("levels", {
270
334
  guild,
271
335
  leaderboard: leaderboardData,
272
336
  page: "levels",
273
337
  botStats: getBotStats(),
338
+ databaseEnabled,
339
+ mongoConnected,
340
+ configSource,
341
+ levelConfigDb,
342
+ roles,
343
+ channels,
344
+ canModify,
274
345
  });
275
346
  });
276
347
 
348
+ // Middleware للتحقق من إمكانية التعديل عبر الداش بورد
349
+ function canModifySettings(req, res, next) {
350
+ if (options.Dashboard === false) {
351
+ return res.status(403).json({ success: false, error: "تم تعطيل التعديل من الداش بورد في ملف الإعدادات الرئيسي للبوت." });
352
+ }
353
+ next();
354
+ }
355
+
277
356
  // API للحصول على بيانات مستخدم
278
357
  app.get("/api/:guildId/user/:userId", isAuthenticated, async (req, res) => {
279
358
  if (!Level) return res.json({ error: "Level system not available" });
@@ -487,7 +566,7 @@ function dashboard(client, options) {
487
566
  });
488
567
 
489
568
  // API - تحديث القناة الافتراضية
490
- app.post("/api/:guildId/logs/channel", isAuthenticated, async (req, res) => {
569
+ app.post("/api/:guildId/logs/channel", isAuthenticated, canModifySettings, async (req, res) => {
491
570
  const logData = getLogConfigData();
492
571
  if (!logData.databaseEnabled)
493
572
  return res.json({ error: "يجب تفعيل وضع Database لتعديل الإعدادات" });
@@ -510,7 +589,7 @@ function dashboard(client, options) {
510
589
  });
511
590
 
512
591
  // API - تفعيل/تعطيل حدث
513
- app.post("/api/:guildId/logs/toggle", isAuthenticated, async (req, res) => {
592
+ app.post("/api/:guildId/logs/toggle", isAuthenticated, canModifySettings, async (req, res) => {
514
593
  const logData = getLogConfigData();
515
594
  if (!logData.databaseEnabled)
516
595
  return res.json({ error: "يجب تفعيل وضع Database لتعديل الإعدادات" });
@@ -544,7 +623,7 @@ function dashboard(client, options) {
544
623
  });
545
624
 
546
625
  // API - تحديث إعدادات حدث معين
547
- app.post("/api/:guildId/logs/event", isAuthenticated, async (req, res) => {
626
+ app.post("/api/:guildId/logs/event", isAuthenticated, canModifySettings, async (req, res) => {
548
627
  const logData = getLogConfigData();
549
628
  if (!logData.databaseEnabled)
550
629
  return res.json({ error: "يجب تفعيل وضع Database لتعديل الإعدادات" });
@@ -593,7 +672,7 @@ function dashboard(client, options) {
593
672
  });
594
673
 
595
674
  // API - إعادة تعيين إعدادات السجلات
596
- app.post("/api/:guildId/logs/reset", isAuthenticated, async (req, res) => {
675
+ app.post("/api/:guildId/logs/reset", isAuthenticated, canModifySettings, async (req, res) => {
597
676
  const logData = getLogConfigData();
598
677
  if (!logData.databaseEnabled)
599
678
  return res.json({ error: "يجب تفعيل وضع Database لتعديل الإعدادات" });
@@ -787,66 +866,238 @@ function dashboard(client, options) {
787
866
 
788
867
  // ==================== API للمستويات ====================
789
868
  // تحديث مستوى مستخدم
790
- app.post("/api/:guildId/level/update", isAuthenticated, async (req, res) => {
869
+ app.post("/api/:guildId/level/update", isAuthenticated, canModifySettings, async (req, res) => {
791
870
  const { userId, xp, level } = req.body;
792
871
  const guildId = req.params.guildId;
793
872
 
794
873
  try {
795
- if (Level) {
874
+ if (!Level) return res.json({ error: "Level system not available" });
875
+
876
+ if (level !== undefined) {
877
+ // تعيين المستوى مباشرة
878
+ const config = await getGuildConfig(guildId);
879
+ const totalXP = xpNeeded(level - 1, config || {});
796
880
  await Level.findOneAndUpdate(
797
- { guildId, userId },
798
- { totalXP: xp, level, $setOnInsert: { text: 0, voice: 0 } },
881
+ { userId, guildId },
882
+ { userId, guildId, level, totalXP },
883
+ { upsert: true, new: true }
884
+ );
885
+ } else if (xp !== undefined) {
886
+ // تعيين XP مباشرة
887
+ const config = await getGuildConfig(guildId);
888
+ const newLevel = calculateLevel(xp, config || {});
889
+ await Level.findOneAndUpdate(
890
+ { userId, guildId },
891
+ { userId, guildId, totalXP: xp, level: newLevel },
799
892
  { upsert: true, new: true }
800
893
  );
801
- return res.json({ success: true });
802
894
  }
803
- res.json({ error: "Level system not available" });
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/set", isAuthenticated, canModifySettings, async (req, res) => {
903
+ const { userId, level } = 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 totalXP = xpNeeded(level - 1, config || {});
910
+ await Level.findOneAndUpdate(
911
+ { userId, guildId },
912
+ { userId, guildId, level, totalXP },
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
+ // تعيين XP مستخدم مباشرة
922
+ app.post("/api/:guildId/level/setxp", 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
+ const config = await getGuildConfig(guildId);
929
+ const level = calculateLevel(xp, config || {});
930
+ await Level.findOneAndUpdate(
931
+ { userId, guildId },
932
+ { userId, guildId, totalXP: xp, level },
933
+ { upsert: true, new: true }
934
+ );
935
+ return res.json({ success: true });
804
936
  } catch (e) {
805
937
  res.json({ success: false, error: e.message });
806
938
  }
807
939
  });
808
940
 
809
941
  // إضافة XP لمستخدم
810
- app.post("/api/:guildId/level/add", isAuthenticated, async (req, res) => {
811
- const { userId, xp, level } = req.body;
942
+ app.post("/api/:guildId/level/add", isAuthenticated, canModifySettings, async (req, res) => {
943
+ const { userId, xp } = req.body;
812
944
  const guildId = req.params.guildId;
813
945
 
814
946
  try {
815
- if (Level) {
816
- const existing = await Level.findOne({ guildId, userId });
817
- if (existing) {
818
- existing.totalXP += xp;
819
- if (level > 0) existing.level = level;
820
- await existing.save();
821
- } else {
822
- await Level.create({
823
- guildId,
824
- userId,
825
- totalXP: xp,
826
- level: level || 0,
827
- text: 0,
828
- voice: 0,
829
- });
830
- }
831
- return res.json({ success: true });
947
+ if (!Level) return res.json({ error: "Level system not available" });
948
+
949
+ const config = await getGuildConfig(guildId);
950
+ const existing = await Level.findOne({ guildId, userId });
951
+ if (existing) {
952
+ existing.totalXP += xp;
953
+ existing.level = calculateLevel(existing.totalXP, config || {});
954
+ await existing.save();
955
+ } else {
956
+ await Level.create({
957
+ guildId,
958
+ userId,
959
+ totalXP: xp,
960
+ level: calculateLevel(xp, config || {}),
961
+ text: xp,
962
+ });
832
963
  }
833
- res.json({ error: "Level system not available" });
964
+ return res.json({ success: true });
834
965
  } catch (e) {
835
966
  res.json({ success: false, error: e.message });
836
967
  }
837
968
  });
838
969
 
839
- // إعادة تعيين مستوى مستخدم
840
- app.post("/api/:guildId/level/reset", isAuthenticated, async (req, res) => {
970
+ // إعادة تعيين مستوى مستخدم (استخدام resetUser)
971
+ app.post("/api/:guildId/level/reset", isAuthenticated, canModifySettings, async (req, res) => {
841
972
  const { userId } = req.body;
842
973
  const guildId = req.params.guildId;
843
974
 
844
975
  try {
845
- if (Level) {
846
- await Level.deleteOne({ guildId, userId });
847
- return res.json({ success: true });
976
+ if (!Level) return res.json({ error: "Level system not available" });
977
+ await resetUser(userId, guildId);
978
+ return res.json({ success: true });
979
+ } catch (e) {
980
+ res.json({ success: false, error: e.message });
981
+ }
982
+ });
983
+
984
+ // الحصول على ترتيب مستخدم
985
+ app.get("/api/:guildId/level/rank/:userId", isAuthenticated, async (req, res) => {
986
+ const { guildId, userId } = req.params;
987
+
988
+ try {
989
+ if (!Level) return res.json({ error: "Level system not available" });
990
+ const rank = await getUserRank(userId, guildId);
991
+ const userData = await Level.findOne({ guildId, userId });
992
+ res.json({
993
+ rank,
994
+ level: userData?.level || 0,
995
+ totalXP: userData?.totalXP || 0,
996
+ xpForNext: xpNeeded((userData?.level || 0) + 1)
997
+ });
998
+ } catch (e) {
999
+ res.json({ error: e.message });
1000
+ }
1001
+ });
1002
+
1003
+ // ==================== API إعدادات Level System ====================
1004
+
1005
+ // الحصول على إعدادات السيرفر
1006
+ app.get("/api/:guildId/level/config", isAuthenticated, async (req, res) => {
1007
+ try {
1008
+ const config = await getGuildConfig(req.params.guildId);
1009
+ const usesDashboardMode = client.levelDashboardGuilds && client.levelDashboardGuilds.has(req.params.guildId);
1010
+ res.json({ databaseEnabled: usesDashboardMode, config: config || null });
1011
+ } catch (e) {
1012
+ res.json({ error: e.message });
1013
+ }
1014
+ });
1015
+
1016
+ // إضافة/تعديل Role Reward
1017
+ app.post("/api/:guildId/level/config/role", isAuthenticated, canModifySettings, async (req, res) => {
1018
+ const { level, roleId } = req.body;
1019
+ const guildId = req.params.guildId;
1020
+
1021
+ try {
1022
+ const config = await getGuildConfig(guildId) || {};
1023
+ const roleReward = config.roleReward || {};
1024
+
1025
+ if (roleId) {
1026
+ roleReward[level] = roleId;
1027
+ } else {
1028
+ delete roleReward[level];
1029
+ }
1030
+
1031
+ await updateGuildConfig(guildId, { roleReward });
1032
+ res.json({ success: true, roleReward });
1033
+ } catch (e) {
1034
+ res.json({ success: false, error: e.message });
1035
+ }
1036
+ });
1037
+
1038
+ // تحديث إعدادات XP
1039
+ app.post("/api/:guildId/level/config/xp", isAuthenticated, canModifySettings, async (req, res) => {
1040
+ const { minXP, maxXP, xpMultiplier, maxLevel, cooldown, leveling } = req.body;
1041
+ const guildId = req.params.guildId;
1042
+
1043
+ try {
1044
+ const updates = {};
1045
+ if (minXP !== undefined) updates.minXP = minXP;
1046
+ if (maxXP !== undefined) updates.maxXP = maxXP;
1047
+ if (xpMultiplier !== undefined) updates.xpMultiplier = xpMultiplier;
1048
+ if (maxLevel !== undefined) updates.maxLevel = maxLevel;
1049
+ if (cooldown !== undefined) updates.cooldown = cooldown;
1050
+ if (leveling !== undefined) updates.leveling = leveling;
1051
+
1052
+ await updateGuildConfig(guildId, updates);
1053
+ res.json({ success: true });
1054
+ } catch (e) {
1055
+ res.json({ success: false, error: e.message });
1056
+ }
1057
+ });
1058
+
1059
+ // إضافة/إزالة قناة من Blacklist
1060
+ app.post("/api/:guildId/level/config/blacklist", isAuthenticated, canModifySettings, async (req, res) => {
1061
+ const { channelId, action } = req.body; // action: "add" | "remove"
1062
+ const guildId = req.params.guildId;
1063
+
1064
+ try {
1065
+ const config = await getGuildConfig(guildId) || {};
1066
+ let blacklistedChannels = config.blacklistedChannels || [];
1067
+
1068
+ if (action === "add" && !blacklistedChannels.includes(channelId)) {
1069
+ blacklistedChannels.push(channelId);
1070
+ } else if (action === "remove") {
1071
+ blacklistedChannels = blacklistedChannels.filter(id => id !== channelId);
848
1072
  }
849
- res.json({ error: "Level system not available" });
1073
+
1074
+ await updateGuildConfig(guildId, { blacklistedChannels });
1075
+ res.json({ success: true, blacklistedChannels });
1076
+ } catch (e) {
1077
+ res.json({ success: false, error: e.message });
1078
+ }
1079
+ });
1080
+
1081
+ // تفعيل/تعطيل نظام Level للسيرفر
1082
+ app.post("/api/:guildId/level/config/toggle", isAuthenticated, canModifySettings, async (req, res) => {
1083
+ const { disabled } = req.body;
1084
+ const guildId = req.params.guildId;
1085
+
1086
+ try {
1087
+ await updateGuildConfig(guildId, { disabled: !!disabled });
1088
+ res.json({ success: true });
1089
+ } catch (e) {
1090
+ res.json({ success: false, error: e.message });
1091
+ }
1092
+ });
1093
+
1094
+ // إعادة تعيين إعدادات السيرفر
1095
+ app.post("/api/:guildId/level/config/reset", isAuthenticated, canModifySettings, async (req, res) => {
1096
+ const guildId = req.params.guildId;
1097
+
1098
+ try {
1099
+ await deleteGuildConfig(guildId);
1100
+ res.json({ success: true });
850
1101
  } catch (e) {
851
1102
  res.json({ success: false, error: e.message });
852
1103
  }