blob: 3f63ccee894bc2af6e3599058b7cdacecaf3868a [file] [log] [blame]
pineafan5d1908e2022-02-28 21:34:47 +00001import Discord, { CommandInteraction, GuildMember, MessageActionRow } from "discord.js";
pineafan4f164f32022-02-26 22:07:12 +00002import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
3import { WrappedCheck } from "jshaiku";
pineafan8b4b17f2022-02-27 20:42:52 +00004import confirmationMessage from "../../utils/confirmationMessage.js";
pineafan377794f2022-04-18 19:01:01 +01005import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
pineafan8b4b17f2022-02-27 20:42:52 +00006import keyValueList from "../../utils/generateKeyValueList.js";
pineafan377794f2022-04-18 19:01:01 +01007import { create, areTicketsEnabled } from "../../automations/createModActionTicket.js";
pineafan4f164f32022-02-26 22:07:12 +00008
9const command = (builder: SlashCommandSubcommandBuilder) =>
10 builder
11 .setName("warn")
12 .setDescription("Warns a user")
pineafan8b4b17f2022-02-27 20:42:52 +000013 .addUserOption(option => option.setName("user").setDescription("The user to warn").setRequired(true))
14 .addStringOption(option => option.setName("reason").setDescription("The reason for the warn").setRequired(false))
15 .addStringOption(option => option.setName("notify").setDescription("If the user should get a message when they are warned | Default yes").setRequired(false)
16 .addChoices([["Yes", "yes"], ["No", "no"]])
17 )
pineafan4f164f32022-02-26 22:07:12 +000018
pineafan8b4b17f2022-02-27 20:42:52 +000019const callback = async (interaction: CommandInteraction) => {
pineafan1dc15722022-03-14 21:27:34 +000020 // @ts-ignore
pineafan377794f2022-04-18 19:01:01 +010021 const { log, NucleusColors, renderUser, entry } = interaction.client.logger
pineafan8b4b17f2022-02-27 20:42:52 +000022 // TODO:[Modals] Replace this with a modal
pineafan377794f2022-04-18 19:01:01 +010023 let confirmation = await new confirmationMessage(interaction)
pineafan8b4b17f2022-02-27 20:42:52 +000024 .setEmoji("PUNISH.WARN.RED")
25 .setTitle("Warn")
26 .setDescription(keyValueList({
27 "user": `<@!${(interaction.options.getMember("user") as GuildMember).id}> (${(interaction.options.getMember("user") as GuildMember).user.username})`,
28 "reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
29 })
pineafan1dc15722022-03-14 21:27:34 +000030 + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n`
31 + `Are you sure you want to warn <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
pineafan8b4b17f2022-02-27 20:42:52 +000032 .setColor("Danger")
pineafan377794f2022-04-18 19:01:01 +010033 .addCustomCallback(
34 "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)),
35 () => { create(interaction.guild, interaction.options.getUser("user"), interaction.client)},
36 "An appeal ticket was created")
pineafan8b4b17f2022-02-27 20:42:52 +000037// pluralize("day", interaction.options.getInteger("delete"))
38// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
pineafan377794f2022-04-18 19:01:01 +010039 .send()
40 if (confirmation.success) {
pineafan8b4b17f2022-02-27 20:42:52 +000041 let dmd = false
42 try {
43 if (interaction.options.getString("notify") != "no") {
44 await (interaction.options.getMember("user") as GuildMember).send({
pineafan377794f2022-04-18 19:01:01 +010045 embeds: [new generateEmojiEmbed()
pineafan8b4b17f2022-02-27 20:42:52 +000046 .setEmoji("PUNISH.WARN.RED")
47 .setTitle("Warned")
48 .setDescription(`You have been warned in ${interaction.guild.name}` +
pineafan377794f2022-04-18 19:01:01 +010049 (interaction.options.getString("reason") ? ` for:\n> ${interaction.options.getString("reason")}` : ".") + "\n\n" +
50 (confirmation.buttonClicked ? `You can appeal this in this ticket: <#${confirmation.response}>` : ``))
pineafan8b4b17f2022-02-27 20:42:52 +000051 .setStatus("Danger")
52 ]
53 })
54 dmd = true
55 }
pineafan8b4b17f2022-02-27 20:42:52 +000056 } catch {
pineafan377794f2022-04-18 19:01:01 +010057 await interaction.editReply({embeds: [new generateEmojiEmbed()
pineafan8b4b17f2022-02-27 20:42:52 +000058 .setEmoji("PUNISH.WARN.RED")
59 .setTitle(`Warn`)
60 .setDescription("Something went wrong and the user was not warned")
61 .setStatus("Danger")
62 ], components: []})
63 }
pineafan1dc15722022-03-14 21:27:34 +000064 let data = {
65 meta:{
66 type: 'memberWarn',
67 displayName: 'Member warned',
68 calculateType: 'guildMemberPunish',
69 color: NucleusColors.yellow,
70 emoji: 'PUNISH.WARN.YELLOW',
71 timestamp: new Date().getTime()
72 },
73 list: {
pineafan377794f2022-04-18 19:01:01 +010074 user: entry((interaction.options.getMember("user") as GuildMember).user.id, renderUser((interaction.options.getMember("user") as GuildMember).user)),
75 warnedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)),
pineafan1dc15722022-03-14 21:27:34 +000076 reason: (interaction.options.getString("reason") ? `\n> ${interaction.options.getString("reason")}` : "No reason provided")
77 },
78 hidden: {
79 guild: interaction.guild.id
80 }
81 }
82 log(data, interaction.client);
pineafan5d1908e2022-02-28 21:34:47 +000083 let failed = (dmd == false && interaction.options.getString("notify") != "no")
84 if (!failed) {
pineafan377794f2022-04-18 19:01:01 +010085 await interaction.editReply({embeds: [new generateEmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +000086 .setEmoji(`PUNISH.WARN.GREEN`)
87 .setTitle(`Warn`)
88 .setDescription("The user was warned")
89 .setStatus("Success")
90 ], components: []})
91 } else {
92 let m = await interaction.editReply({
pineafan377794f2022-04-18 19:01:01 +010093 embeds: [new generateEmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +000094 .setEmoji(`PUNISH.WARN.RED`)
95 .setTitle(`Warn`)
96 .setDescription("The user's DMs are not open\n\nWhat would you like to do?")
97 .setStatus("Danger")
98 ], components: [
99 new MessageActionRow().addComponents([
100 new Discord.MessageButton()
101 .setCustomId("log")
102 .setLabel("Ignore and log")
103 .setStyle("SECONDARY"),
104 new Discord.MessageButton()
105 .setCustomId("here")
106 .setLabel("Warn here")
107 .setStyle("SECONDARY")
108 .setDisabled((interaction.options.getMember("user") as GuildMember).permissionsIn(interaction.channel as Discord.TextChannel).has("VIEW_CHANNEL") === false),
109 ])
110 ],
111 })
112 let component;
113 try {
114 component = await (m as Discord.Message).awaitMessageComponent({filter: (m) => m.user.id === interaction.user.id, time: 2.5 * 60 * 1000});
115 } catch (e) {
pineafan377794f2022-04-18 19:01:01 +0100116 return await interaction.editReply({embeds: [new generateEmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000117 .setEmoji(`PUNISH.WARN.GREEN`)
118 .setTitle(`Warn`)
119 .setDescription("No changes were made")
120 .setStatus("Success")
121 ], components: []})
122 }
123 if ( component.customId == "here" ) {
124 await interaction.channel.send({
pineafan377794f2022-04-18 19:01:01 +0100125 embeds: [new generateEmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000126 .setEmoji(`PUNISH.WARN.RED`)
127 .setTitle(`Warn`)
128 .setDescription(`You have been warned` +
pineafan1dc15722022-03-14 21:27:34 +0000129 (interaction.options.getString("reason") ? ` for:\n> ${interaction.options.getString("reason")}` : "."))
pineafan5d1908e2022-02-28 21:34:47 +0000130 .setStatus("Danger")
131 ],
132 content: `<@!${(interaction.options.getMember("user") as GuildMember).id}>`,
133 allowedMentions: {users: [(interaction.options.getMember("user") as GuildMember).id]}
134 })
pineafan377794f2022-04-18 19:01:01 +0100135 return await interaction.editReply({embeds: [new generateEmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000136 .setEmoji(`PUNISH.WARN.GREEN`)
137 .setTitle(`Warn`)
138 .setDescription("The user was warned")
139 .setStatus("Success")
140 ], components: []})
141 } else {
pineafan377794f2022-04-18 19:01:01 +0100142 await interaction.editReply({embeds: [new generateEmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000143 .setEmoji(`PUNISH.WARN.GREEN`)
144 .setTitle(`Warn`)
145 .setDescription("The warn was logged")
146 .setStatus("Success")
147 ], components: []})
148 }
149 }
pineafan8b4b17f2022-02-27 20:42:52 +0000150 } else {
pineafan377794f2022-04-18 19:01:01 +0100151 await interaction.editReply({embeds: [new generateEmojiEmbed()
pineafan8b4b17f2022-02-27 20:42:52 +0000152 .setEmoji("PUNISH.WARN.GREEN")
153 .setTitle(`Warn`)
154 .setDescription("No changes were made")
155 .setStatus("Success")
156 ], components: []})
157 }
pineafan4f164f32022-02-26 22:07:12 +0000158}
159
160const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
pineafan5d1908e2022-02-28 21:34:47 +0000161 let member = (interaction.member as GuildMember)
162 let me = (interaction.guild.me as GuildMember)
163 let apply = (interaction.options.getMember("user") as GuildMember)
164 if (member == null || me == null || apply == null) throw "That member is not in the server"
165 let memberPos = member.roles ? member.roles.highest.position : 0
166 let mePos = me.roles ? me.roles.highest.position : 0
167 let applyPos = apply.roles ? apply.roles.highest.position : 0
pineafan8b4b17f2022-02-27 20:42:52 +0000168 // Do not allow warning bots
pineafan663dc472022-05-10 18:13:47 +0100169 if (member.user.bot) throw "I cannot warn bots"
pineafan8b4b17f2022-02-27 20:42:52 +0000170 // Allow the owner to warn anyone
pineafan663dc472022-05-10 18:13:47 +0100171 if (member.id == interaction.guild.ownerId) return true
pineafan8b4b17f2022-02-27 20:42:52 +0000172 // Check if the user has moderate_members permission
pineafan663dc472022-05-10 18:13:47 +0100173 if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the `moderate_members` permission";
pineafan8b4b17f2022-02-27 20:42:52 +0000174 // Check if the user is below on the role list
pineafan5d1908e2022-02-28 21:34:47 +0000175 if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
pineafan8b4b17f2022-02-27 20:42:52 +0000176 // Allow warn
177 return true
pineafan4f164f32022-02-26 22:07:12 +0000178}
179
pineafan8b4b17f2022-02-27 20:42:52 +0000180export { command, callback, check };