blob: 379d49c91d1954ee8ba73dd18a42e39005b0360b [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";
pineafan73a7c4a2022-07-24 10:38:04 +01007import { create, areTicketsEnabled } from "../../actions/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))
pineafan73a7c4a2022-07-24 10:38:04 +010015 .addStringOption(option => option.setName("notify").setDescription("If the user should get a message when they are warned | Default: Yes").setRequired(false)
pineafan8b4b17f2022-02-27 20:42:52 +000016 .addChoices([["Yes", "yes"], ["No", "no"]])
17 )
pineafan4f164f32022-02-26 22:07:12 +000018
pineafan6702cef2022-06-13 17:52:37 +010019const callback = async (interaction: CommandInteraction): Promise<any> => {
PineappleFanb3dd83c2022-06-17 10:53:48 +010020 const { log, NucleusColors, renderUser, entry } = client.logger
pineafan8b4b17f2022-02-27 20:42:52 +000021 // TODO:[Modals] Replace this with a modal
pineafan73a7c4a2022-07-24 10:38:04 +010022 let reason = null;
23 let confirmation;
24 while (true) {
25 confirmation = await new confirmationMessage(interaction)
26 .setEmoji("PUNISH.WARN.RED")
27 .setTitle("Warn")
28 .setDescription(keyValueList({
29 "user": renderUser(interaction.options.getUser("user")),
30 "reason": reason ? ("\n> " + ((reason ?? "").replaceAll("\n", "\n> "))) : "*No reason provided*"
31 })
32 + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n`
33 + `Are you sure you want to warn <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
34 .setColor("Danger")
35 .addCustomBoolean(
36 "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)),
37 async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, reason),
38 "An appeal ticket will be created when Confirm is clicked")
39 .addReasonButton(reason)
40 .addReasonButton(reason ?? "")
41 .send(reason !== null)
42 reason = reason ?? ""
43 if (confirmation.newReason === undefined) break
44 reason = confirmation.newReason
45 }
pineafan377794f2022-04-18 19:01:01 +010046 if (confirmation.success) {
pineafan8b4b17f2022-02-27 20:42:52 +000047 let dmd = false
48 try {
49 if (interaction.options.getString("notify") != "no") {
50 await (interaction.options.getMember("user") as GuildMember).send({
pineafan4edb7762022-06-26 19:21:04 +010051 embeds: [new EmojiEmbed()
pineafan8b4b17f2022-02-27 20:42:52 +000052 .setEmoji("PUNISH.WARN.RED")
53 .setTitle("Warned")
54 .setDescription(`You have been warned in ${interaction.guild.name}` +
pineafan73a7c4a2022-07-24 10:38:04 +010055 (reason ? ` for:\n> ${reason}` : ".") + "\n\n" +
PineappleFan30b5fda2022-05-22 15:41:47 +010056 (confirmation.buttonClicked ? `You can appeal this here ticket: <#${confirmation.response}>` : ``))
pineafan8b4b17f2022-02-27 20:42:52 +000057 .setStatus("Danger")
58 ]
59 })
60 dmd = true
61 }
pineafan8b4b17f2022-02-27 20:42:52 +000062 } catch {
pineafan4edb7762022-06-26 19:21:04 +010063 await interaction.editReply({embeds: [new EmojiEmbed()
pineafan8b4b17f2022-02-27 20:42:52 +000064 .setEmoji("PUNISH.WARN.RED")
65 .setTitle(`Warn`)
66 .setDescription("Something went wrong and the user was not warned")
67 .setStatus("Danger")
68 ], components: []})
69 }
pineafan1dc15722022-03-14 21:27:34 +000070 let data = {
71 meta:{
72 type: 'memberWarn',
73 displayName: 'Member warned',
74 calculateType: 'guildMemberPunish',
75 color: NucleusColors.yellow,
76 emoji: 'PUNISH.WARN.YELLOW',
77 timestamp: new Date().getTime()
78 },
79 list: {
pineafan377794f2022-04-18 19:01:01 +010080 user: entry((interaction.options.getMember("user") as GuildMember).user.id, renderUser((interaction.options.getMember("user") as GuildMember).user)),
81 warnedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)),
pineafan73a7c4a2022-07-24 10:38:04 +010082 reason: reason ? `\n> ${reason}` : "No reason provided"
pineafan1dc15722022-03-14 21:27:34 +000083 },
84 hidden: {
85 guild: interaction.guild.id
86 }
87 }
pineafan4edb7762022-06-26 19:21:04 +010088 try { await client.database.history.create(
89 "warn", interaction.guild.id,
90 (interaction.options.getMember("user") as GuildMember).user,
pineafan73a7c4a2022-07-24 10:38:04 +010091 interaction.user, reason
pineafan4edb7762022-06-26 19:21:04 +010092 )} catch {}
93 log(data);
pineafan5d1908e2022-02-28 21:34:47 +000094 let failed = (dmd == false && interaction.options.getString("notify") != "no")
95 if (!failed) {
pineafan4edb7762022-06-26 19:21:04 +010096 await interaction.editReply({embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +000097 .setEmoji(`PUNISH.WARN.GREEN`)
98 .setTitle(`Warn`)
pineafan4092b862022-05-20 19:27:23 +010099 .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``))
pineafan5d1908e2022-02-28 21:34:47 +0000100 .setStatus("Success")
101 ], components: []})
102 } else {
103 let m = await interaction.editReply({
pineafan4edb7762022-06-26 19:21:04 +0100104 embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000105 .setEmoji(`PUNISH.WARN.RED`)
106 .setTitle(`Warn`)
107 .setDescription("The user's DMs are not open\n\nWhat would you like to do?")
108 .setStatus("Danger")
109 ], components: [
110 new MessageActionRow().addComponents([
111 new Discord.MessageButton()
112 .setCustomId("log")
113 .setLabel("Ignore and log")
114 .setStyle("SECONDARY"),
115 new Discord.MessageButton()
116 .setCustomId("here")
117 .setLabel("Warn here")
118 .setStyle("SECONDARY")
119 .setDisabled((interaction.options.getMember("user") as GuildMember).permissionsIn(interaction.channel as Discord.TextChannel).has("VIEW_CHANNEL") === false),
120 ])
121 ],
122 })
123 let component;
124 try {
pineafanc6158ab2022-06-17 16:34:07 +0100125 component = await (m as Discord.Message).awaitMessageComponent({filter: (m) => m.user.id === interaction.user.id, time: 300000});
pineafan5d1908e2022-02-28 21:34:47 +0000126 } catch (e) {
pineafan4edb7762022-06-26 19:21:04 +0100127 return await interaction.editReply({embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000128 .setEmoji(`PUNISH.WARN.GREEN`)
129 .setTitle(`Warn`)
130 .setDescription("No changes were made")
131 .setStatus("Success")
132 ], components: []})
133 }
134 if ( component.customId == "here" ) {
135 await interaction.channel.send({
pineafan4edb7762022-06-26 19:21:04 +0100136 embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000137 .setEmoji(`PUNISH.WARN.RED`)
138 .setTitle(`Warn`)
139 .setDescription(`You have been warned` +
pineafan73a7c4a2022-07-24 10:38:04 +0100140 (reason ? ` for:\n> ${reason}` : "."))
pineafan5d1908e2022-02-28 21:34:47 +0000141 .setStatus("Danger")
142 ],
143 content: `<@!${(interaction.options.getMember("user") as GuildMember).id}>`,
144 allowedMentions: {users: [(interaction.options.getMember("user") as GuildMember).id]}
145 })
pineafan4edb7762022-06-26 19:21:04 +0100146 return await interaction.editReply({embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000147 .setEmoji(`PUNISH.WARN.GREEN`)
148 .setTitle(`Warn`)
pineafan4092b862022-05-20 19:27:23 +0100149 .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``))
pineafan5d1908e2022-02-28 21:34:47 +0000150 .setStatus("Success")
151 ], components: []})
152 } else {
pineafan4edb7762022-06-26 19:21:04 +0100153 await interaction.editReply({embeds: [new EmojiEmbed()
pineafan5d1908e2022-02-28 21:34:47 +0000154 .setEmoji(`PUNISH.WARN.GREEN`)
155 .setTitle(`Warn`)
156 .setDescription("The warn was logged")
157 .setStatus("Success")
158 ], components: []})
159 }
160 }
pineafan8b4b17f2022-02-27 20:42:52 +0000161 } else {
pineafan4edb7762022-06-26 19:21:04 +0100162 await interaction.editReply({embeds: [new EmojiEmbed()
pineafan8b4b17f2022-02-27 20:42:52 +0000163 .setEmoji("PUNISH.WARN.GREEN")
164 .setTitle(`Warn`)
165 .setDescription("No changes were made")
166 .setStatus("Success")
167 ], components: []})
168 }
pineafan4f164f32022-02-26 22:07:12 +0000169}
170
171const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
pineafan5d1908e2022-02-28 21:34:47 +0000172 let member = (interaction.member as GuildMember)
173 let me = (interaction.guild.me as GuildMember)
174 let apply = (interaction.options.getMember("user") as GuildMember)
175 if (member == null || me == null || apply == null) throw "That member is not in the server"
176 let memberPos = member.roles ? member.roles.highest.position : 0
177 let mePos = me.roles ? me.roles.highest.position : 0
178 let applyPos = apply.roles ? apply.roles.highest.position : 0
pineafan8b4b17f2022-02-27 20:42:52 +0000179 // Do not allow warning bots
pineafan663dc472022-05-10 18:13:47 +0100180 if (member.user.bot) throw "I cannot warn bots"
pineafan8b4b17f2022-02-27 20:42:52 +0000181 // Allow the owner to warn anyone
pineafan663dc472022-05-10 18:13:47 +0100182 if (member.id == interaction.guild.ownerId) return true
pineafan8b4b17f2022-02-27 20:42:52 +0000183 // Check if the user has moderate_members permission
pineafan4edb7762022-06-26 19:21:04 +0100184 if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the Moderate members permission";
pineafan8b4b17f2022-02-27 20:42:52 +0000185 // Check if the user is below on the role list
pineafan5d1908e2022-02-28 21:34:47 +0000186 if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
pineafan8b4b17f2022-02-27 20:42:52 +0000187 // Allow warn
188 return true
pineafan4f164f32022-02-26 22:07:12 +0000189}
190
pineafan8b4b17f2022-02-27 20:42:52 +0000191export { command, callback, check };