diff --git a/src/commands/moderation/unwarn.js b/src/commands/moderation/unwarn.js index 782c9b6..a549d2c 100644 --- a/src/commands/moderation/unwarn.js +++ b/src/commands/moderation/unwarn.js @@ -11,10 +11,19 @@ module.exports = async (client, interaction, args) => { if (perms == false) return; var member = interaction.options.getUser('user'); + var Case = interaction.options.getInteger('case'); Schema.findOne({ Guild: interaction.guild.id, User: member.id }, async (err, data) => { if (data) { - data.Warns -= 1; + var warn = data.Warnings.find(x => x.Case == Case); + if (!warn) { + client.errNormal({ + error: "This user doesn't have a warning with this case number!", + type: 'editreply' + }, interaction); + return; + } + data.Warnings.splice(data.Warnings.indexOf(warn), 1); data.save(); } else { diff --git a/src/commands/moderation/warn.js b/src/commands/moderation/warn.js index 6ee7694..a7f20c6 100644 --- a/src/commands/moderation/warn.js +++ b/src/commands/moderation/warn.js @@ -1,27 +1,59 @@ const Discord = require('discord.js'); const Schema = require("../../database/models/warnings"); - +const Case = require("../../database/models/warnCase"); module.exports = async (client, interaction, args) => { const perms = await client.checkUserPerms({ flags: [Discord.PermissionsBitField.Flags.ManageMessages], perms: [Discord.PermissionsBitField.Flags.ManageMessages] }, interaction); - if (perms == false) return; + if (perms == false) { + client.errNormal({ + error: "You don't have the required permissions to use this command!", + type: 'editreply' + }, interaction); + return; + } var member = interaction.options.getUser('user'); + var reason = interaction.options.getString('reason'); + var caseNumber; + await Case.findOne({ Guild: interaction.guild.id }).then(async data => { + if (!data) { + new Case({ + Guild: interaction.guild.id, + Case: 1 + }).save(); + caseNumber = 1; + } + else { + data.Case += 1; + data.save(); + caseNumber = data.Case; + } + }); Schema.findOne({ Guild: interaction.guild.id, User: member.id }, async (err, data) => { if (data) { - data.Warns += 1 + data.Warnings.push({ + Moderator: interaction.user.id, + Reason: reason, + Date: Date.now(), + Case: caseNumber + }); data.save(); } else { new Schema({ Guild: interaction.guild.id, User: member.id, - Warns: 1 + Warnings: [{ + Moderator: interaction.user.id, + Reason: reason, + Date: Date.now(), + Case: caseNumber + }] }).save(); } }) @@ -35,10 +67,15 @@ module.exports = async (client, interaction, args) => { value: interaction.user.tag, inline: true }, + { + name: "📄┆Reason", + value: reason, + inline: true + } ] - }, member).catch(() => {}) + }, member).catch(() => { }) - client.emit('warnAdd', member, interaction.user) + client.emit('warnAdd', member, interaction.user, reason) client.succNormal({ text: `User has received a warning!`, fields: [ @@ -46,6 +83,16 @@ module.exports = async (client, interaction, args) => { name: "👤┆User", value: `${member}`, inline: true + }, + { + name: "👤┆Moderator", + value: `${interaction.user}`, + inline: true + }, + { + name: "📄┆Reason", + value: reason, + inline: false } ], type: 'editreply' diff --git a/src/commands/moderation/warnings.js b/src/commands/moderation/warnings.js index 302d788..603eabd 100644 --- a/src/commands/moderation/warnings.js +++ b/src/commands/moderation/warnings.js @@ -8,22 +8,36 @@ module.exports = async (client, interaction, args) => { perms: [Discord.PermissionsBitField.Flags.ManageMessages] }, interaction); - if (perms == false) return; + if (perms == false) { + client.errNormal({ + error: "You don't have the required permissions to use this command!", + type: 'editreply' + }, interaction); + return; + } const member = interaction.options.getUser('user'); + Schema.findOne({ Guild: interaction.guild.id, User: member.id }, async (err, data) => { if (data) { - + var fields = []; + data.Warnings.forEach(element => { + fields.push({ + name: "Warning **" + element.Case + "**", + value: "Reason: " + element.Reason + "\nModerator <@!" + element.Moderator + ">", + inline: true + }) + }); client.embed({ title: `${client.emotes.normal.error}・Warnings`, desc: `The warnings of **${member.tag}**`, fields: [ { name: "Total", - value: `${data.Warns}`, - inline: false - } + value: `${data.Warnings.length}`, + }, + ...fields ], type: 'editreply' }, interaction) @@ -31,18 +45,10 @@ module.exports = async (client, interaction, args) => { else { client.embed({ title: `${client.emotes.normal.error}・Warnings`, - desc: `The warnings of **${member.tag}**`, - fields: [ - { - name: "Total", - value: "0", - inline: false - } - ], + desc: `User ${member.user.tag} has no warnings!`, type: 'editreply' }, interaction) } }) } - \ No newline at end of file diff --git a/src/database/models/warnCase.js b/src/database/models/warnCase.js new file mode 100644 index 0000000..30f5176 --- /dev/null +++ b/src/database/models/warnCase.js @@ -0,0 +1,8 @@ +const mongoose = require('mongoose'); + +const Schema = new mongoose.Schema({ + Guild: String, + Case: Number +}); + +module.exports = mongoose.model("warnCase", Schema); \ No newline at end of file diff --git a/src/database/models/warnings.js b/src/database/models/warnings.js index f0aa6fa..60be82d 100644 --- a/src/database/models/warnings.js +++ b/src/database/models/warnings.js @@ -3,7 +3,7 @@ const mongoose = require('mongoose'); const Schema = new mongoose.Schema({ Guild: String, User: String, - Warns: Number + Warnings: [Object] }); module.exports = mongoose.model("warnings", Schema); \ No newline at end of file diff --git a/src/events/warn/warnAdd.js b/src/events/warn/warnAdd.js index 852b372..5c0c9ce 100644 --- a/src/events/warn/warnAdd.js +++ b/src/events/warn/warnAdd.js @@ -1,6 +1,13 @@ const discord = require('discord.js'); -module.exports = async (client, user, mod) => { +/** + * @param {discord.Client} client + * @param {discord.GuildMember} user + * @param {discord.User} mod + * @param {string} reason + * @returns + */ +module.exports = async (client, user, mod, reason) => { const logsChannel = await client.getLogs(user.guild.id); if (!logsChannel) return; @@ -23,7 +30,13 @@ module.exports = async (client, user, mod) => { { name: `> Moderator`, value: `${mod} (${mod.id})` + }, + { + name: `> Reason`, + value: `${reason}` } ] - }, logsChannel).catch(() => { }) + }, logsChannel).catch(() => { + console.log + }) }; \ No newline at end of file diff --git a/src/interactions/Command/moderation.js b/src/interactions/Command/moderation.js index 9fc92f5..6477454 100644 --- a/src/interactions/Command/moderation.js +++ b/src/interactions/Command/moderation.js @@ -105,12 +105,14 @@ module.exports = { .setName('warn') .setDescription('Warn a user') .addUserOption(option => option.setName('user').setDescription('Select a user').setRequired(true)) + .addStringOption(option => option.setName('reason').setDescription('The reason for the warn').setRequired(true)) ) .addSubcommand(subcommand => subcommand .setName('unwarn') .setDescription('Unwarn a user') .addUserOption(option => option.setName('user').setDescription('Select a user').setRequired(true)) + .addIntegerOption(option => option.setName('case').setDescription('Give a case number').setRequired(true)) ) .addSubcommand(subcommand => subcommand diff --git a/src/interactions/ContextMenu/unwarn.js b/src/interactions/ContextMenu/unwarn.js index c9b79b4..eb6651d 100644 --- a/src/interactions/ContextMenu/unwarn.js +++ b/src/interactions/ContextMenu/unwarn.js @@ -16,54 +16,88 @@ module.exports = { */ run: async (client, interaction, args) => { - await interaction.deferReply({ fetchReply: true }); const perms = await client.checkPerms({ flags: [Discord.PermissionsBitField.Flags.ManageMessages], perms: [Discord.PermissionsBitField.Flags.ManageMessages] }, interaction) - if (perms == false) return; + if (perms == false) { + client.errNormal({ + error: "You don't have the required permissions to use this command!", + type: 'ephemeral' + }, interaction); + return; + } + await interaction.deferReply({ ephemeral: true }); const member = interaction.guild.members.cache.get(interaction.targetId); Schema.findOne({ Guild: interaction.guild.id, User: member.id }, async (err, data) => { if (data) { - data.Warns -= 1; - data.save(); - } - else { + const menu = new Discord.StringSelectMenuBuilder() + .setCustomId('unwarn') + .setPlaceholder('Select a warning to remove'); + // Get all warnings and add them to a stringselectmenu + data.Warnings.forEach(element => { + menu.addOptions({ + label: `Case ${element.Case}`, + value: element.Case.toString(), + description: "Reason: " + element.Reason + }) + }); + // Create a new message with the menu + client.embed({ + title: `🔨・Unwarn`, + desc: `Select a warning to remove from **${member.user.tag}**`, + components: [new Discord.ActionRowBuilder().addComponents(menu)], + type: 'ephemeraledit' + }, interaction); + + // Create a new collector for the menu + const filter = i => i.user.id === interaction.user.id; + const collector = interaction.channel.createMessageComponentCollector({ filter, time: 15000 }); + + collector.on('collect', async i => { + if (i.customId === 'unwarn') { + // Remove the warning from the database + data.Warnings.splice(data.Warnings.findIndex(element => element.Case == i.values[0]), 1); + data.save(); + // Remove the menu from the message + i.update({ + components: [] + }); + // Send a success message + client.succNormal({ + text: `The warning has been successfully removed`, + fields: [ + { + name: "👤┆User", + value: `${member}`, + inline: true + } + ], + type: 'ephemeraledit' + }, interaction); + client.emit('warnRemove', member, interaction.user) + client.embed({ + title: `🔨・Unwarn`, + desc: `You've been unwarned in **${interaction.guild.name}**`, + fields: [ + { + name: "👤┆Moderator", + value: interaction.user.tag, + inline: true + }, + ] + }, member).catch(() => { }) + } + }); + } else { client.errNormal({ error: "User has no warnings!", - type: 'editreply' + type: 'ephemeraledit' }, interaction); } }) - - client.embed({ - title: `🔨・Unwarn`, - desc: `You've been unwarned in **${interaction.guild.name}**`, - fields: [ - { - name: "👤┆Moderator", - value: interaction.user.tag, - inline: true - }, - ] - }, member).catch(() => { }) - - client.emit('warnRemove', member, interaction.user) - client.succNormal({ - text: `The user's warning has been successfully removed`, - fields: [ - { - name: "👤┆User", - value: `${member}`, - inline: true - } - ], - type: 'editreply' - }, interaction); }, -}; - - \ No newline at end of file +}; \ No newline at end of file diff --git a/src/interactions/ContextMenu/warn.js b/src/interactions/ContextMenu/warn.js index d9d7c74..176b9d7 100644 --- a/src/interactions/ContextMenu/warn.js +++ b/src/interactions/ContextMenu/warn.js @@ -3,6 +3,7 @@ const { ContextMenuCommandBuilder } = require('discord.js'); const Discord = require('discord.js'); const Schema = require("../../database/models/warnings"); +const Case = require("../../database/models/warnCase"); module.exports = { data: new ContextMenuCommandBuilder() @@ -14,28 +15,80 @@ module.exports = { * @param {CommandInteraction} interaction * @param {String[]} args */ - run: async (client, interaction, args) => { - await interaction.deferReply({ fetchReply: true }); const perms = await client.checkPerms({ flags: [Discord.PermissionsBitField.Flags.ManageMessages], perms: [Discord.PermissionsBitField.Flags.ManageMessages] }, interaction) + if (perms === false) { + client.errNormal({ + error: `You don't have the required permissions to use this command!`, + type: 'ephemeral' + }, interaction); + return; + } + // Create modal to give a reason + const modal = new Discord.ModalBuilder() + .setTitle('Warn') + .setCustomId('warn') + .addComponents( + new Discord.ActionRowBuilder().addComponents( + new Discord.TextInputBuilder() + .setCustomId('reason') + .setPlaceholder('Reason') + .setLabel('Reason') + .setMinLength(1) + .setStyle(Discord.TextInputStyle.Short) + .setMaxLength(100)), + ); + await interaction.showModal(modal); - if (perms == false) return; + const submitted = await interaction.awaitModalSubmit({ + time: 60000, + filter: i => i.user.id === interaction.user.id, + }).catch(() => { }); + + if (!submitted) { + return; + } const member = interaction.guild.members.cache.get(interaction.targetId); + var caseNumber; + await Case.findOne({ Guild: interaction.guild.id }).then(async data => { + if(!data) { + new Case({ + Guild: interaction.guild.id, + Case: 1 + }).save(); + caseNumber = 1; + } + else { + data.Case += 1; + data.save(); + caseNumber = data.Case; + } + }); Schema.findOne({ Guild: interaction.guild.id, User: member.id }, async (err, data) => { if (data) { - data.Warns += 1 + data.Warnings.push({ + Moderator: interaction.user.id, + Reason: submitted.fields.getTextInputValue("reason"), + Date: Date.now(), + Case: caseNumber + }); data.save(); } else { new Schema({ Guild: interaction.guild.id, User: member.id, - Warns: 1 + Warnings: [{ + Moderator: interaction.user.id, + Reason: submitted.fields.getTextInputValue("reason"), + Date: Date.now(), + Case: caseNumber + }] }).save(); } }) @@ -49,10 +102,15 @@ module.exports = { value: interaction.user.tag, inline: true }, + { + name: "📄┆Reason", + value: submitted.fields.getTextInputValue("reason"), + inline: true + } ] - }, member).catch(() => {}) + }, member).catch(() => { }) - client.emit('warnAdd', member, interaction.user) + client.emit('warnAdd', member, interaction.user, submitted.fields.getTextInputValue("reason")); client.succNormal({ text: `User has received a warning!`, fields: [ @@ -60,11 +118,20 @@ module.exports = { name: "👤┆User", value: `${member}`, inline: true + }, + { + name: "👤┆Moderator", + value: `${interaction.user}`, + inline: true + }, + { + name: "📄┆Reason", + value: submitted.fields.getTextInputValue("reason"), + inline: false } ], - type: 'editreply' - }, interaction); + type: 'ephemeral' + }, submitted); }, }; - \ No newline at end of file diff --git a/src/interactions/ContextMenu/warnings.js b/src/interactions/ContextMenu/warnings.js index 307c56c..b1a932e 100644 --- a/src/interactions/ContextMenu/warnings.js +++ b/src/interactions/ContextMenu/warnings.js @@ -14,29 +14,42 @@ module.exports = { * @param {CommandInteraction} interaction * @param {String[]} args */ - run: async (client, interaction, args) => { - await interaction.deferReply({ fetchReply: true }); const perms = await client.checkPerms({ flags: [Discord.PermissionsBitField.Flags.ManageMessages], perms: [Discord.PermissionsBitField.Flags.ManageMessages] }, interaction) - if (perms == false) return; + if (perms == false){ + client.errNormal({ + error: "You don't have the required permissions to use this command!", + type: 'ephemeral' + }, interaction); + return; + } + await interaction.deferReply({ ephemeral: false }); const member = interaction.guild.members.cache.get(interaction.targetId); Schema.findOne({ Guild: interaction.guild.id, User: member.id }, async (err, data) => { if (data) { + var fields = []; + data.Warnings.forEach(element => { + fields.push({ + name: "Warning **" + element.Case + "**", + value: "Reason: " + element.Reason + "\nModerator <@!" + element.Moderator + ">", + inline: true + }) + }); client.embed({ title: `${client.emotes.normal.error}・Warnings`, - desc: `The warnings of **${member.tag}**`, + desc: `The warnings of **${member.user.tag}**`, fields: [ { name: "Total", - value: `${data.Warns}`, - innline: false - } + value: `${data.Warnings.length}`, + }, + ...fields ], type: 'editreply' }, interaction) @@ -44,14 +57,7 @@ module.exports = { else { client.embed({ title: `${client.emotes.normal.error}・Warnings`, - desc: `The warnings of **${member.tag}**`, - fields: [ - { - name: "Total", - value: "0", - innline: false - } - ], + desc: `User ${member.user.tag} has no warnings!`, type: 'editreply' }, interaction) }