blob: 370f3477a706a4ac158d922363797dc15726b9fc [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";
pineafan4edb7762022-06-26 19:21:04 +01005import EmojiEmbed 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";
pineafan4edb7762022-06-26 19:21:04 +01008import client from "../../utils/client.js"
pineafan4f164f32022-02-26 22:07:12 +00009
10const command = (builder: SlashCommandSubcommandBuilder) =>
11 builder
12 .setName("warn")
13 .setDescription("Warns a user")
pineafan8b4b17f2022-02-27 20:42:52 +000014 .addUserOption(option => option.setName("user").setDescription("The user to warn").setRequired(true))
15 .addStringOption(option => option.setName("reason").setDescription("The reason for the warn").setRequired(false))
16 .addStringOption(option => option.setName("notify").setDescription("If the user should get a message when they are warned | Default yes").setRequired(false)
17 .addChoices([["Yes", "yes"], ["No", "no"]])
18 )
pineafan4f164f32022-02-26 22:07:12 +000019
pineafan6702cef2022-06-13 17:52:37 +010020const callback = async (interaction: CommandInteraction): Promise<any> => {
PineappleFanb3dd83c2022-06-17 10:53:48 +010021 const { log, NucleusColors, renderUser, entry } = 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({
pineafan4edb7762022-06-26 19:21:04 +010027 "user": renderUser(interaction.options.getUser("user")),
pineafan8b4b17f2022-02-27 20:42:52 +000028 "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")
pineafan4092b862022-05-20 19:27:23 +010033 .addCustomBoolean(
pineafan377794f2022-04-18 19:01:01 +010034 "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)),
pineafan6702cef2022-06-13 17:52:37 +010035 async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.options.getString("reason")),
pineafan4092b862022-05-20 19:27:23 +010036 "An appeal ticket will be created when Confirm is clicked")
pineafan377794f2022-04-18 19:01:01 +010037 .send()
38 if (confirmation.success) {
pineafan8b4b17f2022-02-27 20:42:52 +000039 let dmd = false
40 try {
41 if (interaction.options.getString("notify") != "no") {
42 await (interaction.options.getMember("user") as GuildMember).send({
pineafan4edb7762022-06-26 19:21:04 +010043 embeds: [new EmojiEmbed()
pineafan8b4b17f2022-02-27 20:42:52 +000044 .setEmoji("PUNISH.WARN.RED")
45 .setTitle("Warned")
46 .setDescription(`You have been warned in ${interaction.guild.name}` +
pineafan377794f2022-04-18 19:01:01 +010047 (interaction.options.getString("reason") ? ` for:\n> ${interaction.options.getString("reason")}` : ".") + "\n\n" +
PineappleFan30b5fda2022-05-22 15:41:47 +010048 (confirmation.buttonClicked ? `You can appeal this here ticket: <#${confirmation.response}>` : ``))
pineafan8b4b17f2022-02-27 20:42:52 +000049 .setStatus("Danger")
50 ]
51 })
52 dmd = true
53 }
pineafan8b4b17f2022-02-27 20:42:52 +000054 } catch {
pineafan4edb7762022-06-26 19:21:04 +010055 await interaction.editReply({embeds: [new EmojiEmbed()
pineafan8b4b17f2022-02-27 20:42:52 +000056 .setEmoji("PUNISH.WARN.RED")
57 .setTitle(`Warn`)
58 .setDescription("Something went wrong and the user was not warned")
59 .setStatus("Danger")
60 ], components: []})
61 }
pineafan1dc15722022-03-14 21:27:34 +000062 let data = {
63 meta:{
64 type: 'memberWarn',
65 displayName: 'Member warned',
66 calculateType: 'guildMemberPunish',
67 color: NucleusColors.yellow,
68 emoji: 'PUNISH.WARN.YELLOW',
69 timestamp: new Date().getTime()
70 },
71 list: {
pineafan377794f2022-04-18 19:01:01 +010072 user: entry((interaction.options.getMember("user") as GuildMember).user.id, renderUser((interaction.options.getMember("user") as GuildMember).user)),
73 warnedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)),
pineafan1dc15722022-03-14 21:27:34 +000074 reason: (interaction.options.getString("reason") ? `\n> ${interaction.options.getString("reason")}` : "No reason provided")
75 },
76 hidden: {
77 guild: interaction.guild.id
78 }
79 }
pineafan4edb7762022-06-26 19:21:04 +010080 try { await client.database.history.create(
81 "warn", interaction.guild.id,
82 (interaction.options.getMember("user") as GuildMember).user,
83 interaction.user, interaction.options.getString("reason")
84 )} catch {}
85 log(data);
pineafan5d1908e2022-02-28 21:34:47 +000086 let failed = (dmd == false && interaction.options.getString("notify") != "no")
87 if (!failed) {
pineafan4edb7762022-06-26 19:21:04 +010088 await interaction.editReply({embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +000089 .setEmoji(`PUNISH.WARN.GREEN`)
90 .setTitle(`Warn`)
pineafan4092b862022-05-20 19:27:23 +010091 .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``))
pineafan5d1908e2022-02-28 21:34:47 +000092 .setStatus("Success")
93 ], components: []})
94 } else {
95 let m = await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +010096 embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +000097 .setEmoji(`PUNISH.WARN.RED`)
98 .setTitle(`Warn`)
99 .setDescription("The user's DMs are not open\n\nWhat would you like to do?")
100 .setStatus("Danger")
101 ], components: [
102 new MessageActionRow().addComponents([
103 new Discord.MessageButton()
104 .setCustomId("log")
105 .setLabel("Ignore and log")
106 .setStyle("SECONDARY"),
107 new Discord.MessageButton()
108 .setCustomId("here")
109 .setLabel("Warn here")
110 .setStyle("SECONDARY")
111 .setDisabled((interaction.options.getMember("user") as GuildMember).permissionsIn(interaction.channel as Discord.TextChannel).has("VIEW_CHANNEL") === false),
112 ])
113 ],
114 })
115 let component;
116 try {
pineafanc6158ab2022-06-17 16:34:07 +0100117 component = await (m as Discord.Message).awaitMessageComponent({filter: (m) => m.user.id === interaction.user.id, time: 300000});
pineafan5d1908e2022-02-28 21:34:47 +0000118 } catch (e) {
pineafan4edb7762022-06-26 19:21:04 +0100119 return await interaction.editReply({embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000120 .setEmoji(`PUNISH.WARN.GREEN`)
121 .setTitle(`Warn`)
122 .setDescription("No changes were made")
123 .setStatus("Success")
124 ], components: []})
125 }
126 if ( component.customId == "here" ) {
127 await interaction.channel.send({
pineafan4edb7762022-06-26 19:21:04 +0100128 embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000129 .setEmoji(`PUNISH.WARN.RED`)
130 .setTitle(`Warn`)
131 .setDescription(`You have been warned` +
pineafan1dc15722022-03-14 21:27:34 +0000132 (interaction.options.getString("reason") ? ` for:\n> ${interaction.options.getString("reason")}` : "."))
pineafan5d1908e2022-02-28 21:34:47 +0000133 .setStatus("Danger")
134 ],
135 content: `<@!${(interaction.options.getMember("user") as GuildMember).id}>`,
136 allowedMentions: {users: [(interaction.options.getMember("user") as GuildMember).id]}
137 })
pineafan4edb7762022-06-26 19:21:04 +0100138 return await interaction.editReply({embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000139 .setEmoji(`PUNISH.WARN.GREEN`)
140 .setTitle(`Warn`)
pineafan4092b862022-05-20 19:27:23 +0100141 .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``))
pineafan5d1908e2022-02-28 21:34:47 +0000142 .setStatus("Success")
143 ], components: []})
144 } else {
pineafan4edb7762022-06-26 19:21:04 +0100145 await interaction.editReply({embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000146 .setEmoji(`PUNISH.WARN.GREEN`)
147 .setTitle(`Warn`)
148 .setDescription("The warn was logged")
149 .setStatus("Success")
150 ], components: []})
151 }
152 }
pineafan8b4b17f2022-02-27 20:42:52 +0000153 } else {
pineafan4edb7762022-06-26 19:21:04 +0100154 await interaction.editReply({embeds: [new EmojiEmbed()
pineafan8b4b17f2022-02-27 20:42:52 +0000155 .setEmoji("PUNISH.WARN.GREEN")
156 .setTitle(`Warn`)
157 .setDescription("No changes were made")
158 .setStatus("Success")
159 ], components: []})
160 }
pineafan4f164f32022-02-26 22:07:12 +0000161}
162
163const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
pineafan5d1908e2022-02-28 21:34:47 +0000164 let member = (interaction.member as GuildMember)
165 let me = (interaction.guild.me as GuildMember)
166 let apply = (interaction.options.getMember("user") as GuildMember)
167 if (member == null || me == null || apply == null) throw "That member is not in the server"
168 let memberPos = member.roles ? member.roles.highest.position : 0
169 let mePos = me.roles ? me.roles.highest.position : 0
170 let applyPos = apply.roles ? apply.roles.highest.position : 0
pineafan8b4b17f2022-02-27 20:42:52 +0000171 // Do not allow warning bots
pineafan663dc472022-05-10 18:13:47 +0100172 if (member.user.bot) throw "I cannot warn bots"
pineafan8b4b17f2022-02-27 20:42:52 +0000173 // Allow the owner to warn anyone
pineafan663dc472022-05-10 18:13:47 +0100174 if (member.id == interaction.guild.ownerId) return true
pineafan8b4b17f2022-02-27 20:42:52 +0000175 // Check if the user has moderate_members permission
pineafan4edb7762022-06-26 19:21:04 +0100176 if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the Moderate members permission";
pineafan8b4b17f2022-02-27 20:42:52 +0000177 // Check if the user is below on the role list
pineafan5d1908e2022-02-28 21:34:47 +0000178 if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
pineafan8b4b17f2022-02-27 20:42:52 +0000179 // Allow warn
180 return true
pineafan4f164f32022-02-26 22:07:12 +0000181}
182
pineafan8b4b17f2022-02-27 20:42:52 +0000183export { command, callback, check };