diff --git a/.eslintignore b/.eslintignore index fc767ef5..0c08df53 100644 --- a/.eslintignore +++ b/.eslintignore @@ -22,7 +22,6 @@ commands/manualVerify.js commands/manualVetVerify.js commands/memes.js commands/modmailBlacklist.js -commands/mute.js commands/parsemembers.js commands/permaSuspend.js commands/poll.js @@ -44,7 +43,6 @@ commands/suspendremove.js commands/sysinfo.js commands/test.js commands/unlock.js -commands/unmute.js commands/unverify.js commands/unvetverify.js commands/updateIP.js diff --git a/commands/mute.js b/commands/mute.js index 23084439..18e0008c 100644 --- a/commands/mute.js +++ b/commands/mute.js @@ -1,96 +1,268 @@ -const Discord = require('discord.js') -const ErrorLogger = require('../lib/logError') -const fs = require('fs') +const { EmbedBuilder, Colors } = require('discord.js'); +const moment = require('moment'); const SlashArgType = require('discord-api-types/v10').ApplicationCommandOptionType; -const { slashArg, slashChoices, slashCommandJSON } = require('../utils.js') +const { slashArg, slashCommandJSON } = require('../utils.js'); + +/** + * @typedef MuteRow + * @property {string} id + * @property {string} modid + * @property {string} guildid + * @property {string} reason + * @property {number} appliedOn + * @property {number} duration + * @property {number?} removedOn + * @property {string?} removedBy + * @property {string?} removeReason + * @property {boolean} overwritten + */ + +/** + * @param {MuteRow} row + * @param {import('discord.js').GuildMember} member + * @param {number?} duration + */ +async function attemptOverwrite(db, row, member, reason) { + await db.promise().query('UPDATE mutes SET removedOn = unix_timestamp(), removedBy = ?, removeReason = ?, overwritten = true WHERE id = ? AND guildid = ? AND removedOn IS NULL', + [member.id, reason, row.id, row.guildid]); +} + +function durationString(duration, when = Date.unix()) { + if (!duration) return 'Permanent'; + duration = parseInt(duration); + when = parseInt(when); + return `Ending \nAt `; +} + +/** + * + * @param {string} duration + * @param {number} time + */ +function processDuration(duration, time) { + duration = duration.toLowerCase(); + if (duration.startsWith('mo')) return time * 2_592_000; + switch (duration[0]) { + case 's': return time; + case 'm': return time * 60; + case 'h': return time * 3_600; + case 'd': return time * 86_400; + case 'w': return time * 604_800; + case 'y': return time * 31_536_000; + default: + } +} + +/** + * @param {import('../utils.js').BotCommandInteraction} interaction + * @param {MuteRow} row + * @returns {{ + * overwrite: boolean; + * mute: boolean + * }} +*/ +async function confirmOverwrite(interaction, member, row, duration, reason) { + const mod = interaction.guild.members.cache.get(row.modid); + const embed = new EmbedBuilder() + .setAuthor({ name: member.displayName, iconURL: member.displayAvatarURL() }) + .setTitle('Confirm Mute Override') + .setDescription(`<@${row.id}> currently has an active mute. Do you want to override this mute?`) + .setColor(Colors.Blue) + .setTimestamp() + .addFields({ name: 'Old Moderator', value: mod ? `${mod} \`${mod.displayName}\`` : `<@${row.modid}>`, inline: true }, + { name: 'Applied On', value: ``, inline: true }, + { name: 'Old Expires', value: durationString(row.duration, row.appliedOn), inline: true }, + { name: 'Old Reason', value: row.reason }, + { name: 'New Moderator', value: `${interaction.member} \`${interaction.member.displayName}\``, inline: true }, + { name: 'New Expires', value: durationString(duration), inline: true }, + { name: 'New Reason', value: reason }); + + const message = await interaction.editReply({ embeds: [embed], fetchReply: true }); + return await message.confirmButton(interaction.member.id); +} + +/** + * @param {import('../utils.js').BotCommandInteraction} interaction + * @param {import('discord.js').GuildMember} member + */ +async function confirmUnmanagedMute(interaction, member, duration, reason) { + const embed = new EmbedBuilder() + .setAuthor({ name: member.displayName, iconURL: member.displayAvatarURL() }) + .setTitle('Unmanaged Mute') + .setDescription(`${member} has a mute currently not managed by ${interaction.client.user}. Would you like to have it managed with the following information?`) + .setColor(Colors.Blue) + .addFields({ name: 'Member', value: `${member} \`${member.displayName}\``, inline: true }, + { name: 'Moderator', value: `${interaction.member} \`${interaction.member.displayName}\``, inline: true }, + { name: 'Expires', value: durationString(duration), inline: true }, + { name: 'Reason', value: reason }); + + const message = await interaction.editReply({ embeds: [embed], fetchReply: true }); + return await message.confirmButton(interaction.member.id); +} module.exports = { name: 'mute', description: 'Gives user the muted role', - args: '