djs-builder 0.7.8 → 0.7.10

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
@@ -211,6 +211,12 @@ const actionRow = new CreateRow([
211
211
  emoji: "🚀",
212
212
  disabled: true, // Button is disabled
213
213
  },
214
+ {
215
+ style: 5,
216
+ label: "link",
217
+ emoji: "🔗"
218
+ url : "https://discord.gg/z9GpYsYF" // for url button
219
+ }
214
220
  ],
215
221
 
216
222
  // 🔹 Row #2: Select Menu
@@ -245,7 +251,7 @@ const actionRow = new CreateRow([
245
251
  disabled: false, // Disable the entire menu
246
252
  defaultValues: [
247
253
  // For role/user/channel menus
248
- { id: "123456789012345678", type: "user" }, // Pre-selected
254
+ { id: "123456789012345678" }, // Pre-selected
249
255
  ],
250
256
  channelTypes: [0, 2], // Only for ChannelSelectMenu (0 = Text, 2 = Voice)
251
257
  },
@@ -264,6 +270,7 @@ const actionRow = new CreateRow([
264
270
  - `label` → Button text
265
271
  - `emoji` → Displayed emoji
266
272
  - `disabled` → true = button is unclickable
273
+ - `url` → requiier for like button (style : 5)
267
274
 
268
275
  #### 🔹 Select Menus
269
276
 
@@ -474,9 +481,9 @@ const modal = CreateModal({
474
481
  },
475
482
  },
476
483
  {
477
- type: "label",
484
+ type: "text",
478
485
  components: {
479
- label: "Thank you for your input!",
486
+ content: "Thank you for your input!",
480
487
  },
481
488
  },
482
489
  ],
@@ -519,6 +526,8 @@ await interaction.showModal(modal);
519
526
  type: "string",
520
527
  options: {
521
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
522
531
  placeholder: "Select your country",
523
532
  min: 1,
524
533
  max: 1,
@@ -564,9 +573,9 @@ await interaction.showModal(modal);
564
573
 
565
574
  ```js
566
575
  {
567
- type: "label",
576
+ type: "text",
568
577
  components: {
569
- label: "Please fill out the form above.",
578
+ content: "Please fill out the form above.",
570
579
  },
571
580
  },
572
581
  ```
@@ -591,6 +600,8 @@ Same as CreateRow select menus.
591
600
 
592
601
  - `type` → `"string" | "user" | "role" | "channel"`
593
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)
594
605
  - `placeholder` → Text shown before selection
595
606
  - `min` / `max` → Min/Max selectable values
596
607
  - `data` → Options array (for string select only)
@@ -615,9 +626,9 @@ Same as CreateRow select menus.
615
626
  - `label` → Label
616
627
  - `description` → Description
617
628
 
618
- #### 🔹 Label
629
+ #### 🔹 text
619
630
 
620
- - `label` → Text to display
631
+ - `content` → Text to display
621
632
 
622
633
  ---
623
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
  }