import { CommandInteraction, GuildMember } from "discord.js"; import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import confirmationMessage from "../../utils/confirmationMessage.js"; import EmojiEmbed from "../../utils/generateEmojiEmbed.js"; import keyValueList from "../../utils/generateKeyValueList.js"; import client from "../../utils/client.js"; const command = (builder: SlashCommandSubcommandBuilder) => builder .setName("nick") .setDescription("Changes a users nickname") .addUserOption((option) => option.setName("user").setDescription("The user to change").setRequired(true)) .addStringOption((option) => option.setName("name").setDescription("The name to set | Leave blank to clear").setRequired(false) ); const callback = async (interaction: CommandInteraction): Promise => { const { renderUser } = client.logger; // TODO:[Modals] Replace this with a modal let notify = true; let confirmation; let timedOut = false; let success = false; while (!timedOut && !success) { confirmation = await new confirmationMessage(interaction) .setEmoji("PUNISH.NICKNAME.RED") .setTitle("Nickname") .setDescription( keyValueList({ user: renderUser(interaction.options.getUser("user")), "new nickname": `${ interaction.options.getString("name") ? interaction.options.getString("name") : "*No nickname*" }` }) + `The user **will${notify ? "" : " not"}** be notified\n\n` + `Are you sure you want to ${interaction.options.getString("name") ? "change" : "clear"} <@!${ (interaction.options.getMember("user") as GuildMember).id }>'s nickname?` ) .setColor("Danger") .addCustomBoolean( "notify", "Notify user", false, null, null, "ICONS.NOTIFY." + (notify ? "ON" : "OFF"), notify ) .send(interaction.options.getString("name") !== null); if (confirmation.cancelled) timedOut = true; else if (confirmation.success) success = true; else if (confirmation.components) { notify = confirmation.components.notify.active; } } if (timedOut) { return await interaction.editReply({ embeds: [ new EmojiEmbed() .setEmoji("PUNISH.NICKNAME.GREEN") .setTitle("Nickname") .setDescription("No changes were made") .setStatus("Success") ], components: [] }); } let dmd = false; let dm; try { if (notify) { dm = await (interaction.options.getMember("user") as GuildMember).send({ embeds: [ new EmojiEmbed() .setEmoji("PUNISH.NICKNAME.RED") .setTitle("Nickname changed") .setDescription( `Your nickname was ${interaction.options.getString("name") ? "changed" : "cleared"} in ${ interaction.guild.name }.` + (interaction.options.getString("name") ? ` it is now: ${interaction.options.getString("name")}` : "") + "\n\n" + (confirmation.components.appeal.response ? `You can appeal this here: <#${confirmation.components.appeal.response}>` : "") ) .setStatus("Danger") ] }); dmd = true; } } catch { dmd = false; } try { const member = interaction.options.getMember("user") as GuildMember; const before = member.nickname; const nickname = interaction.options.getString("name"); member.setNickname(nickname ?? null, "Nucleus Nickname command"); await client.database.history.create( "nickname", interaction.guild.id, member.user, interaction.user, null, before, nickname ); const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger; const data = { meta: { type: "memberUpdate", displayName: "Member Updated", calculateType: "guildMemberUpdate", color: NucleusColors.yellow, emoji: "PUNISH.NICKNAME.YELLOW", timestamp: new Date().getTime() }, list: { memberId: entry(member.id, `\`${member.id}\``), before: entry(before, before ? before : "*None*"), after: entry(nickname, nickname ? nickname : "*None*"), updated: entry(new Date().getTime(), renderDelta(new Date().getTime())), updatedBy: entry(interaction.user.id, renderUser(interaction.user)) }, hidden: { guild: interaction.guild.id } }; log(data); } catch { await interaction.editReply({ embeds: [ new EmojiEmbed() .setEmoji("PUNISH.NICKNAME.RED") .setTitle("Nickname") .setDescription("Something went wrong and the users nickname could not be changed.") .setStatus("Danger") ], components: [] }); if (dmd) await dm.delete(); return; } const failed = !dmd && notify; await interaction.editReply({ embeds: [ new EmojiEmbed() .setEmoji(`PUNISH.NICKNAME.${failed ? "YELLOW" : "GREEN"}`) .setTitle("Nickname") .setDescription( "The members nickname was changed" + (failed ? ", but was not notified" : "") + (confirmation.components.appeal.response ? ` and an appeal ticket was opened in <#${confirmation.components.appeal.response}>` : "") ) .setStatus(failed ? "Warning" : "Success") ], components: [] }); }; const check = (interaction: CommandInteraction) => { const member = interaction.member as GuildMember; const me = interaction.guild.me!; const apply = interaction.options.getMember("user") as GuildMember; if (member === null || me === null || apply === null) throw new Error("That member is not in the server"); const memberPos = member.roles.cache.size ? member.roles.highest.position : 0; const mePos = me.roles.cache.size ? me.roles.highest.position : 0; const applyPos = apply.roles.cache.size ? apply.roles.highest.position : 0; // Do not allow any changing of the owner if (member.id === interaction.guild.ownerId) throw new Error("You cannot change the owner's nickname"); // Check if Nucleus can change the nickname if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member"); // Check if Nucleus has permission to change the nickname if (!me.permissions.has("MANAGE_NICKNAMES")) throw new Error("I do not have the *Manage Nicknames* permission"); // Allow the owner to change anyone's nickname if (member.id === interaction.guild.ownerId) return true; // Check if the user has manage_nicknames permission if (!member.permissions.has("MANAGE_NICKNAMES")) throw new Error("You do not have the *Manage Nicknames* permission"); // Allow changing your own nickname if (member === apply) return true; // Check if the user is below on the role list if (!(memberPos > applyPos)) throw new Error("You do not have a role higher than that member"); // Allow change return true; }; export { command, callback, check };