diff --git a/TO REWRITE/Examples/mention.js b/TO REWRITE/Examples/mention.js deleted file mode 100644 index bfcc2d9f..00000000 --- a/TO REWRITE/Examples/mention.js +++ /dev/null @@ -1,37 +0,0 @@ -const { ApplicationCommandType } = require("discord.js"); -const BaseCommand = require("../../base/BaseCommand"); - -class Mention extends BaseCommand { - /** - * - * @param {import("../../base/JaBa")} client - */ - constructor() { - super({ - command: { - name: "mention", - type: ApplicationCommandType.User - }, - aliases: [], - dirname: __dirname, - guildOnly: true - }); - } - /** - * - * @param {import("../../base/JaBa")} client - */ - async onLoad() { - //... - } - /** - * - * @param {import("../../base/JaBa")} client - * @param {import("discord.js").ContextMenuInteraction} interaction - */ - async execute(client, interaction) { - const target = interaction.member.guild.members.cache.get(interaction.targetId); - return interaction.reply({ content: target.toString(), ephemeral: false, fetchReply: true }).then(m => setTimeout(() => m.delete(), 5000)); - } -} -module.exports = Mention; \ No newline at end of file diff --git a/TO REWRITE/Examples/repeat.js b/TO REWRITE/Examples/repeat.js deleted file mode 100644 index f3e4eed3..00000000 --- a/TO REWRITE/Examples/repeat.js +++ /dev/null @@ -1,38 +0,0 @@ -const { ApplicationCommandType } = require("discord.js"); -const BaseCommand = require("../../base/BaseCommand"); - -class Repeat extends BaseCommand { - /** - * - * @param {import("../../base/JaBa")} client - */ - constructor() { - super({ - command: { - name: "repeat", - type: ApplicationCommandType.Message - }, - aliases: [], - dirname: __dirname, - guildOnly: true - }); - } - /** - * - * @param {import("../../base/JaBa")} client - */ - async onLoad() { - //... - } - /** - * - * @param {import("../../base/JaBa")} client - * @param {import("discord.js").ContextMenuInteraction} interaction - */ - async execute(client, interaction) { - const targetChannel = interaction.member.guild.channels.cache.get(interaction.channelId); - const targetMessage = await targetChannel.messages.fetch(interaction.targetId); - return interaction.reply({ content: targetMessage.content, ephemeral: false, fetchReply: true }).then(m => setTimeout(() => m.delete(), 5000)); - } -} -module.exports = Repeat; \ No newline at end of file diff --git a/TO REWRITE/Moderation/untimeout.js b/TO REWRITE/Moderation/untimeout.js deleted file mode 100644 index 3c0747b9..00000000 --- a/TO REWRITE/Moderation/untimeout.js +++ /dev/null @@ -1,60 +0,0 @@ -const Command = require("../../base/Command"); - -class Untimeout extends Command { - constructor(client) { - super(client, { - name: "untimeout", - dirname: __dirname, - enabled: true, - guildOnly: true, - aliases: ["untimeout"], - memberPermissions: ["BAN_MEMBERS"], - botPermissions: ["SEND_MESSAGES", "EMBED_LINKS", "BAN_MEMBERS"], - nsfw: false, - ownerOnly: false, - cooldown: 1000 - }); - } - - async run(message, args) { - let user = null; - - if (!args[0]) return message.error("moderation/unban:MISSING_ID"); - - // Check if the arg is an ID or a username - const isId = !isNaN(args[0]); - - if (isId) { - // Try to find a user with that ID - await this.client.users.fetch(args[0]).then((u) => { - // if a user was found - user = u; - }).catch(() => {}); - } else if (!isId) { - const arr = args[0].split("#"); - if (arr.length < 2) { - return message.error("misc:NO_USER_FOUND_ID", { - id: args[0] - }); - } - user = this.client.users.filter((u) => u.username === arr[0]).find((u) => u.discriminator === arr[1]); - } - - if (!user) return message.error("misc:NO_USER_FOUND_ID", { id: args[0] }); - - // check if the user is banned - const banned = await message.guild.bans.fetch(); - if (!banned.some((e) => e.user.id === user.id)) return message.success("moderation/unban:NOT_BANNED", { username: user.tag }); - - // Unban user - message.guild.members.unban(user).catch(() => {}); - - // Send a success message in the current channel - message.success("moderation/unban:UNBANNED", { - username: user.tag, - server: message.guild.name - }); - } -} - -module.exports = Untimeout; \ No newline at end of file diff --git a/TO REWRITE/Moderation/warn.js b/TO REWRITE/Moderation/warn.js deleted file mode 100644 index a586d7bf..00000000 --- a/TO REWRITE/Moderation/warn.js +++ /dev/null @@ -1,156 +0,0 @@ -const Command = require("../../base/Command"), - Discord = require("discord.js"); - -class Warn extends Command { - constructor(client) { - super(client, { - name: "warn", - dirname: __dirname, - enabled: true, - guildOnly: true, - aliases: ["w"], - memberPermissions: ["MANAGE_MESSAGES"], - botPermissions: ["SEND_MESSAGES", "EMBED_LINKS"], - nsfw: false, - ownerOnly: false, - cooldown: 1000 - }); - } - - async run(message, args, data) { - const member = await this.client.resolveMember(args[0], message.guild); - if (!member) return message.error("moderation/warn:MISSING_MEMBER"); - if (member.user.bot) return message.error("misc:BOT_USER"); - - const memberData = await this.client.findOrCreateMember({ - id: member.id, - guildID: message.guild.id - }); - - if (member.id === message.author.id) return message.error("moderation/warn:YOURSELF"); - - const memberPosition = member.roles.highest.position; - const moderationPosition = message.member.roles.highest.position; - if (message.member.ownerId !== message.author.id && !(moderationPosition > memberPosition)) return message.error("moderation/ban:SUPERIOR"); - - const reason = args.slice(1).join(" "); - if (!reason) return message.error("moderation/warn:MISSING_REASON"); - - // Gets current member sanctions - const sanctions = memberData.sanctions.filter((s) => s.type === "warn").length; - const banCount = data.guild.plugins.warnsSanctions.ban; - const kickCount = data.guild.plugins.warnsSanctions.kick; - - data.guild.casesCount++; - data.guild.save(); - - const caseInfo = { - channel: message.channel.id, - moderator: message.author.id, - date: Date.now(), - type: "warn", - case: data.guild.casesCount, - reason - }; - - const embed = new Discord.EmbedBuilder() - .addFields([ - { - name: message.translate("common:USER"), - value: `\`${member.user.tag}\` (${member.user.toString()})` - }, - { - name: message.translate("common:MODERATOR"), - value: `\`${message.author.tag}\` (${message.author.toString()})` - }, - { - name: message.translate("common:REASON"), - value: reason, - inline: true - } - ]); - - if (banCount) { - if (sanctions >= banCount) { - member.send({ - content: message.translate("moderation/ban:BANNED_DM", { - username: member.user, - moderator: message.author.tag, - server: message.guild.name, - reason - }) - }); - caseInfo.type = "ban"; - embed.setAuthor({ - name: message.translate("moderation/ban:CASE", { - count: data.guild.casesCount - }) - }) - .setColor("#e02316"); - message.guild.members.ban(member).catch(() => {}); - message.success("moderation/setwarns:AUTO_BAN", { - username: member.user.tag, - count: banCount - }); - } - } - - if (kickCount) { - if (sanctions >= kickCount) { - member.send({ - content: message.translate("moderation/kick:KICKED_DM", { - username: member.user, - moderator: message.author.tag, - server: message.guild.name, - reason - }) - }); - caseInfo.type = "kick"; - embed.setAuthor({ - name: message.translate("moderation/kick:CASE", { - count: data.guild.casesCount - }) - }) - .setColor("#e88709"); - member.kick().catch(() => {}); - message.success("moderation/setwarns:AUTO_KICK", { - username: member.user.tag, - count: kickCount - }); - } - } - - member.send({ - content: message.translate("moderation/warn:WARNED_DM", { - username: member.user.tag, - server: message.guild.name, - moderator: message.author.tag, - reason - }) - }); - caseInfo.type = "warn"; - embed.setAuthor({ - name: message.translate("moderation/warn:CASE", { - caseNumber: data.guild.casesCount - }) - }) - .setColor("#8c14e2"); - message.success("moderation/warn:WARNED", { - username: member.user.tag, - reason - }); - - memberData.sanctions.push(caseInfo); - memberData.save(); - - if (data.guild.plugins.modlogs) { - const channel = message.guild.channels.cache.get(data.guild.plugins.modlogs); - if (!channel) return; - channel.send({ - embeds: [embed] - }); - } - } -} - -module.exports = Warn; \ No newline at end of file diff --git a/TO REWRITE/Moderation/warns.js b/TO REWRITE/Moderation/warns.js deleted file mode 100644 index 60d5d19d..00000000 --- a/TO REWRITE/Moderation/warns.js +++ /dev/null @@ -1,66 +0,0 @@ -const Command = require("../../base/Command"), - Discord = require("discord.js"); - -class Warns extends Command { - constructor(client) { - super(client, { - name: "warns", - dirname: __dirname, - enabled: true, - guildOnly: true, - aliases: ["ws"], - memberPermissions: ["MANAGE_MESSAGES"], - botPermissions: ["SEND_MESSAGES", "EMBED_LINKS"], - nsfw: false, - ownerOnly: false, - cooldown: 1000 - }); - } - - async run(message, args, data) { - const user = await this.client.resolveUser(args[0]); - if (!user) return message.error("moderation/warns:MISSING_MEMBER"); - - const memberData = await this.client.findOrCreateMember({ - id: user.id, - guildID: message.guild.id - }); - - const embed = new Discord.EmbedBuilder() - .setAuthor({ - name: user.tag, - iconURL: user.displayAvatarURL({ - size: 512, - format: "png" - }) - }) - .setColor(data.config.embed.color) - .setFooter({ - text: data.config.embed.footer - }); - - if (memberData.sanctions.length < 1) { - embed.setDescription(message.translate("moderation/warns:NO_SANCTION", { - username: user.tag - })); - return message.reply({ - embeds: [embed] - }); - } else { - memberData.sanctions.forEach((s) => { - embed.addFields([ - { - name: s.type + " | #" + s.case, - value: `${message.translate("common:MODERATOR")}: <@${s.moderator}>\n${message.translate("common:REASON")}: ${s.reason}`, - inline: true - } - ]); - }); - } - message.reply({ - embeds: [embed] - }); - } -} - -module.exports = Warns; \ No newline at end of file diff --git a/base/BaseCommand.js b/base/BaseCommand.js index 1bfc0513..213a6fb6 100644 --- a/base/BaseCommand.js +++ b/base/BaseCommand.js @@ -4,7 +4,7 @@ const path = require("path"); class BaseCommand { constructor(options, client) { /** - * @type {import("discord.js").SlashCommandBuilder | import("discord.js").ApplicationCommandData} + * @type {import("discord.js").SlashCommandBuilder | import("discord.js").ContextMenuCommandBuilder | import("discord.js").ApplicationCommandData} */ this.command = options.command; /** diff --git a/base/JaBa.js b/base/JaBa.js index 7212b7f1..570ca22e 100644 --- a/base/JaBa.js +++ b/base/JaBa.js @@ -1,9 +1,8 @@ -const { EmbedBuilder, Client, Collection } = require("discord.js"), +const { EmbedBuilder, Client, Collection, SlashCommandBuilder, ContextMenuCommandBuilder } = require("discord.js"), { GiveawaysManager } = require("discord-giveaways"), { SoundCloudPlugin } = require("@distube/soundcloud"), { SpotifyPlugin } = require("@distube/spotify"), { YtDlpPlugin } = require("@distube/yt-dlp"), - { SlashCommandBuilder } = require("discord.js"), { REST } = require("@discordjs/rest"), { Routes } = require("discord-api-types/v10"); @@ -142,14 +141,14 @@ class JaBa extends Client { const aliases = []; if (command.aliases && Array.isArray(command.aliases) && command.aliases.length > 0) { command.aliases.forEach((alias) => { - const command_alias = command.command instanceof SlashCommandBuilder ? { ...command.command.toJSON() } : { ...command.command }; + const command_alias = (command.command instanceof SlashCommandBuilder || command.command instanceof ContextMenuCommandBuilder) ? { ...command.command.toJSON() } : { ...command.command }; command_alias.name = alias; aliases.push(command_alias); this.commands.set(alias, command); }); } - commands.push(command.command instanceof SlashCommandBuilder ? command.command.toJSON() : command.command, ...aliases); + commands.push((command.command instanceof SlashCommandBuilder || command.command instanceof ContextMenuCommandBuilder) ? command.command.toJSON() : command.command, ...aliases); if (command.onLoad || typeof command.onLoad === "function") await command.onLoad(this); this.logger.log(`Successfully loaded "${file}" command file. (Command: ${command.command.name})`); diff --git a/commands/Moderation/warn.js b/commands/Moderation/warn.js new file mode 100644 index 00000000..475deb5a --- /dev/null +++ b/commands/Moderation/warn.js @@ -0,0 +1,190 @@ +const { ContextMenuCommandBuilder, ApplicationCommandType, PermissionFlagsBits, TextInputStyle, ModalBuilder, EmbedBuilder, ActionRowBuilder, TextInputBuilder } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); + +class Warn extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor() { + super({ + command: new ContextMenuCommandBuilder() + .setName("warn") + .setType(ApplicationCommandType.User) + .setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages), + aliases: [], + dirname: __dirname, + guildOnly: true + }); + } + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").UserContextMenuCommandInteraction} interaction + * @param {Array} data + */ + async execute(client, interaction, data) { + const member = interaction.targetMember; + if (member.user.bot) return; + + const memberData = await client.findOrCreateMember({ + id: member.id, + guildID: interaction.guildId + }); + + if (member.id === interaction.user.id) return interaction.error("moderation/warn:YOURSELF"); + + const memberPosition = member.roles.highest.position; + const moderationPosition = interaction.member.roles.highest.position; + if (interaction.guild.ownerId !== interaction.user.id && !(moderationPosition > memberPosition)) return interaction.error("moderation/ban:SUPERIOR"); + + const modal = new ModalBuilder() + .setCustomId("warn_modal") + .setTitle(interaction.translate("moderation/warn:MODAL_TITLE")); + + const reasonInput = new TextInputBuilder() + .setCustomId("reason") + .setLabel(interaction.translate("moderation/warn:REASON")) + .setStyle(TextInputStyle.Short); + + const firstActionRow = new ActionRowBuilder().addComponents(reasonInput); + + modal.addComponents(firstActionRow); + + await interaction.showModal(modal); + + const submitted = await interaction.awaitModalSubmit({ + time: 120000, + filter: i => i.user.id === interaction.user.id, + }); + + if (submitted) { + const reason = submitted.fields.getTextInputValue("reason"); + + const sanctions = memberData.sanctions.filter((s) => s.type === "warn").length; + const banCount = data.guildData.plugins.warnsSanctions.ban; + const kickCount = data.guildData.plugins.warnsSanctions.kick; + + data.guildData.casesCount++; + data.guildData.save(); + + const caseInfo = { + moderator: interaction.user.id, + date: Date.now(), + type: "warn", + case: data.guildData.casesCount, + reason + }; + + const embed = new EmbedBuilder() + .addFields([ + { + name: interaction.translate("common:USER"), + value: `\`${member.user.tag}\` (${member.user.toString()})` + }, + { + name: interaction.translate("common:MODERATOR"), + value: `\`${interaction.user.tag}\` (${interaction.user.toString()})` + }, + { + name: interaction.translate("common:REASON"), + value: reason, + inline: true + } + ]); + + if (banCount) { + if (sanctions >= banCount) { + member.send({ + content: interaction.translate("moderation/ban:BANNED_DM", { + username: member.user, + moderator: interaction.user.tag, + server: interaction.guild.name, + reason + }) + }); + caseInfo.type = "ban"; + embed.setAuthor({ + name: interaction.translate("moderation/ban:CASE", { + count: data.guildData.casesCount + }) + }) + .setColor("#e02316"); + interaction.guild.members.ban(member); + interaction.success("moderation/setwarns:AUTO_BAN", { + username: member.user.tag, + count: `${banCount} ${client.getNoun(banCount, interaction.translate("misc:NOUNS:WARNS:1"), interaction.translate("misc:NOUNS:WARNS:2"), interaction.translate("misc:NOUNS:WARNS:5"))}` + }); + } + } + + if (kickCount) { + if (sanctions >= kickCount) { + member.send({ + content: interaction.translate("moderation/kick:KICKED_DM", { + username: member.user, + moderator: interaction.user.tag, + server: interaction.guild.name, + reason + }) + }); + caseInfo.type = "kick"; + embed.setAuthor({ + name: interaction.translate("moderation/kick:CASE", { + count: data.guildData.casesCount + }) + }) + .setColor("#e88709"); + member.kick().catch(() => {}); + interaction.success("moderation/setwarns:AUTO_KICK", { + username: member.user.tag, + count: `${kickCount} ${client.getNoun(kickCount, interaction.translate("misc:NOUNS:WARNS:1"), interaction.translate("misc:NOUNS:WARNS:2"), interaction.translate("misc:NOUNS:WARNS:5"))}` + }); + } + } + + member.send({ + content: interaction.translate("moderation/warn:WARNED_DM", { + username: member.user.tag, + server: interaction.guild.name, + moderator: interaction.user.tag, + reason + }) + }); + + caseInfo.type = "warn"; + embed.setAuthor({ + name: interaction.translate("moderation/warn:CASE", { + caseNumber: data.guildData.casesCount + }) + }).setColor("#8c14e2"); + + submitted.reply({ + content: interaction.translate("moderation/warn:WARNED", { + username: member.user.tag, + reason + }) + }); + + memberData.sanctions.push(caseInfo); + memberData.save(); + + if (data.guildData.plugins.modlogs) { + const channel = interaction.guild.channels.cache.get(data.guildData.plugins.modlogs); + if (!channel) return; + channel.send({ + embeds: [embed] + }); + } + } + } +} + +module.exports = Warn; \ No newline at end of file diff --git a/commands/Moderation/warns.js b/commands/Moderation/warns.js new file mode 100644 index 00000000..0ad05d77 --- /dev/null +++ b/commands/Moderation/warns.js @@ -0,0 +1,81 @@ +const { ApplicationCommandType, PermissionFlagsBits, EmbedBuilder, ContextMenuCommandBuilder } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); + +class Warns extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor() { + super({ + command: new ContextMenuCommandBuilder() + .setName("warns") + .setType(ApplicationCommandType.User) + .setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages), + aliases: [], + dirname: __dirname, + guildOnly: true + }); + } + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").UserContextMenuCommandInteraction} interaction + * @param {Array} data + */ + async execute(client, interaction) { + const member = interaction.targetMember; + if (member.user.bot) return; + + const memberData = await client.findOrCreateMember({ + id: member.id, + guildID: interaction.guildId + }); + + const embed = new EmbedBuilder() + .setAuthor({ + name: interaction.translate("moderation/warns:SANCTIONS_OF", { + member: member.nickname || member.user.username + }), + iconURL: member.displayAvatarURL({ + size: 512, + format: "png" + }) + }) + .setColor(client.config.embed.color) + .setFooter({ + text: client.config.embed.footer + }); + + if (memberData.sanctions.length < 1) { + embed.setDescription(interaction.translate("moderation/warns:NO_SANCTION", { + member: member.nickname || member.user.username + })); + return interaction.reply({ + embeds: [embed] + }); + } else { + memberData.sanctions.forEach((s) => { + embed.addFields([ + { + name: s.type + " | #" + s.case, + value: `${interaction.translate("common:MODERATOR")}: <@${s.moderator}>\n${interaction.translate("common:REASON")}: ${s.reason}`, + inline: true + } + ]); + }); + } + interaction.reply({ + embeds: [embed] + }); + } +} + +module.exports = Warns; \ No newline at end of file diff --git a/index.js b/index.js index 7a4095c7..bf86938e 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,6 @@ const client = new JaBa({ client.on("disconnect", () => client.logger.log("Bot is disconnecting...", "warn")) .on("reconnecting", () => client.logger.log("Bot reconnecting...", "warn")) - .on("error", (e) => client.logger.log(e, "error")) .on("warn", (info) => client.logger.log(info, "warn")); +// .on("error", (e) => client.logger.log(e, "error")) process.on("unhandledRejection", (err) => console.error(err)); \ No newline at end of file diff --git a/languages/ru-RU/moderation/warn.json b/languages/ru-RU/moderation/warn.json index 87bc0e04..b216924d 100644 --- a/languages/ru-RU/moderation/warn.json +++ b/languages/ru-RU/moderation/warn.json @@ -1,11 +1,11 @@ { - "DESCRIPTION": "Выдать предупреждение пользователю в ЛС", + "DESCRIPTION": "Выдать предупреждение пользователю", "USAGE": "warn [@пользователь] (причина)", "EXAMPLES": "warn @Jonny_Bro#4226 stupid", - "MISSING_MEMBER": "Вы должны упомянуть пользователя!", "YOURSELF": "Вы не можете подать жалобу на себя!", - "MISSING_REASON": "Укажите причину!", - "WARNED_DM": "Привет {{username}},\nвы получили предупреждение на сервере **{{server}}** от пользователя **{{moderator}}** по причине **{{reason}}**!", - "WARNED": "**{{username}}** получил предупреждение в ЛС по причине **{{reason}}**!", + "MODAL_TITLE": "Выдать предупреждение {{nickname}}", + "REASON": "Причина предупреждения", + "WARNED_DM": "Вы получили предупреждение на сервере **{{server}}** от пользователя **{{moderator}}** по причине **{{reason}}**!", + "WARNED": "**{{username}}** получил предупреждение по причине **{{reason}}**!", "CASE": "Предупрежение | Номер #{{caseNumber}}" } \ No newline at end of file diff --git a/languages/ru-RU/moderation/warns.json b/languages/ru-RU/moderation/warns.json index 91d0e5e9..1419c7e6 100644 --- a/languages/ru-RU/moderation/warns.json +++ b/languages/ru-RU/moderation/warns.json @@ -2,6 +2,6 @@ "DESCRIPTION": "Показать список нарушений пользователя!", "USAGE": "sanctions [@пользователь]", "EXAMPLES": "sanctions @Jonny_Bro#4226", - "MISSING_MEMBER": "Вы должны упомянуть пользователя!", - "NO_SANCTION": "У **{{username}}** нет нарушений." + "SANCTIONS_OF": "Нарушения {{member}}", + "NO_SANCTION": "У **{{member}}** нет нарушений." } \ No newline at end of file