blob: 3b6e06b2dc9e9e81fb1797b0da16df60463cd8c9 [file] [log] [blame]
PineaFan0d06edc2023-01-17 22:10:31 +00001import { LinkWarningFooter, LoadingEmbed } from "../../utils/defaults.js";
pineafan1e462ab2023-03-07 21:34:06 +00002import Discord, {
3 CommandInteraction,
4 GuildMember,
5 ActionRowBuilder,
6 ButtonBuilder,
7 ButtonStyle,
8 ButtonInteraction
9} from "discord.js";
TheCodedProff86ba092023-01-27 17:10:07 -050010import type { SlashCommandSubcommandBuilder } from "discord.js";
pineafan4edb7762022-06-26 19:21:04 +010011import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
pineafan8b4b17f2022-02-27 20:42:52 +000012import getEmojiByName from "../../utils/getEmojiByName.js";
13import confirmationMessage from "../../utils/confirmationMessage.js";
14import keyValueList from "../../utils/generateKeyValueList.js";
pineafan62ce1922022-08-25 20:34:45 +010015// @ts-expect-error
pineafan8b4b17f2022-02-27 20:42:52 +000016import humanizeDuration from "humanize-duration";
pineafan6702cef2022-06-13 17:52:37 +010017import client from "../../utils/client.js";
Skyler Grey11236ba2022-08-08 21:13:33 +010018import { areTicketsEnabled, create } from "../../actions/createModActionTicket.js";
pineafan8b4b17f2022-02-27 20:42:52 +000019
20const command = (builder: SlashCommandSubcommandBuilder) =>
21 builder
pineafan63fc5e22022-08-04 22:04:10 +010022 .setName("mute")
PineaFan538d3752023-01-12 21:48:23 +000023 // .setNameLocalizations({"ru": "silence"})
Skyler Grey11236ba2022-08-08 21:13:33 +010024 .setDescription("Mutes a member, stopping them from talking in the server")
25 .addUserOption((option) => option.setName("user").setDescription("The user to mute").setRequired(true))
Skyler Grey75ea9172022-08-06 10:22:23 +010026 .addIntegerOption((option) =>
27 option
28 .setName("days")
Skyler Grey11236ba2022-08-08 21:13:33 +010029 .setDescription("The number of days to mute the user for | Default: 0")
Skyler Grey75ea9172022-08-06 10:22:23 +010030 .setMinValue(0)
31 .setMaxValue(27)
32 .setRequired(false)
33 )
34 .addIntegerOption((option) =>
35 option
36 .setName("hours")
Skyler Grey11236ba2022-08-08 21:13:33 +010037 .setDescription("The number of hours to mute the user for | Default: 0")
Skyler Grey75ea9172022-08-06 10:22:23 +010038 .setMinValue(0)
39 .setMaxValue(23)
40 .setRequired(false)
41 )
42 .addIntegerOption((option) =>
43 option
44 .setName("minutes")
Skyler Grey11236ba2022-08-08 21:13:33 +010045 .setDescription("The number of minutes to mute the user for | Default: 0")
Skyler Grey75ea9172022-08-06 10:22:23 +010046 .setMinValue(0)
47 .setMaxValue(59)
48 .setRequired(false)
49 )
50 .addIntegerOption((option) =>
51 option
52 .setName("seconds")
Skyler Grey11236ba2022-08-08 21:13:33 +010053 .setDescription("The number of seconds to mute the user for | Default: 0")
Skyler Grey75ea9172022-08-06 10:22:23 +010054 .setMinValue(0)
55 .setMaxValue(59)
56 .setRequired(false)
57 );
pineafan8b4b17f2022-02-27 20:42:52 +000058
pineafan1e462ab2023-03-07 21:34:06 +000059const callback = async (
60 interaction: CommandInteraction | ButtonInteraction,
61 member?: GuildMember
62): Promise<unknown> => {
PineaFana00db1b2023-01-02 15:32:54 +000063 if (!interaction.guild) return;
Skyler Grey11236ba2022-08-08 21:13:33 +010064 const { log, NucleusColors, renderUser, entry, renderDelta } = client.logger;
pineafan6de4da52023-03-07 20:43:44 +000065 let time: { days: number; hours: number; minutes: number; seconds: number } | null = null;
66 if (!interaction.isButton()) {
67 member = interaction.options.getMember("user") as GuildMember;
68 time = {
69 days: (interaction.options.get("days")?.value as number | null) ?? 0,
70 hours: (interaction.options.get("hours")?.value as number | null) ?? 0,
71 minutes: (interaction.options.get("minutes")?.value as number | null) ?? 0,
72 seconds: (interaction.options.get("seconds")?.value as number | null) ?? 0
73 };
74 } else {
pineafan1e462ab2023-03-07 21:34:06 +000075 time = { days: 0, hours: 0, minutes: 0, seconds: 0 };
pineafan6de4da52023-03-07 20:43:44 +000076 }
77 if (!member) return;
PineaFana00db1b2023-01-02 15:32:54 +000078 const config = await client.database.guilds.read(interaction.guild.id);
Skyler Grey11236ba2022-08-08 21:13:33 +010079 let serverSettingsDescription = config.moderation.mute.timeout ? "given a timeout" : "";
Skyler Grey75ea9172022-08-06 10:22:23 +010080 if (config.moderation.mute.role)
81 serverSettingsDescription +=
Skyler Grey11236ba2022-08-08 21:13:33 +010082 (serverSettingsDescription ? " and " : "") + `given the <@&${config.moderation.mute.role}> role`;
pineafane625d782022-05-09 18:04:32 +010083
Skyler Grey11236ba2022-08-08 21:13:33 +010084 let muteTime = time.days * 24 * 60 * 60 + time.hours * 60 * 60 + time.minutes * 60 + time.seconds;
pineafane23c4ec2022-07-27 21:56:27 +010085 if (muteTime === 0) {
PineaFan5bea7e12023-01-05 21:20:04 +000086 const m = await interaction.reply({
Skyler Grey75ea9172022-08-06 10:22:23 +010087 embeds: [
88 new EmojiEmbed()
89 .setEmoji("PUNISH.MUTE.GREEN")
90 .setTitle("Mute")
PineaFan5bea7e12023-01-05 21:20:04 +000091 .setDescription("How long should the user be muted for?")
Skyler Grey75ea9172022-08-06 10:22:23 +010092 .setStatus("Success")
93 ],
94 components: [
PineaFan5bea7e12023-01-05 21:20:04 +000095 new ActionRowBuilder<ButtonBuilder>().addComponents([
TheCodedProf21c08592022-09-13 14:14:43 -040096 new Discord.ButtonBuilder().setCustomId("1m").setLabel("1 Minute").setStyle(ButtonStyle.Secondary),
Skyler Greyda16adf2023-03-05 10:22:12 +000097 new Discord.ButtonBuilder()
98 .setCustomId("10m")
99 .setLabel("10 Minutes")
100 .setStyle(ButtonStyle.Secondary),
101 new Discord.ButtonBuilder()
102 .setCustomId("30m")
103 .setLabel("30 Minutes")
104 .setStyle(ButtonStyle.Secondary),
TheCodedProf21c08592022-09-13 14:14:43 -0400105 new Discord.ButtonBuilder().setCustomId("1h").setLabel("1 Hour").setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100106 ]),
PineaFan5bea7e12023-01-05 21:20:04 +0000107 new ActionRowBuilder<ButtonBuilder>().addComponents([
TheCodedProf21c08592022-09-13 14:14:43 -0400108 new Discord.ButtonBuilder().setCustomId("6h").setLabel("6 Hours").setStyle(ButtonStyle.Secondary),
109 new Discord.ButtonBuilder().setCustomId("12h").setLabel("12 Hours").setStyle(ButtonStyle.Secondary),
110 new Discord.ButtonBuilder().setCustomId("1d").setLabel("1 Day").setStyle(ButtonStyle.Secondary),
111 new Discord.ButtonBuilder().setCustomId("1w").setLabel("1 Week").setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100112 ]),
PineaFan5bea7e12023-01-05 21:20:04 +0000113 new ActionRowBuilder<ButtonBuilder>().addComponents([
TheCodedProf21c08592022-09-13 14:14:43 -0400114 new Discord.ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100115 .setCustomId("cancel")
116 .setLabel("Cancel")
TheCodedProf21c08592022-09-13 14:14:43 -0400117 .setStyle(ButtonStyle.Danger)
Skyler Grey75ea9172022-08-06 10:22:23 +0100118 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
119 ])
120 ],
121 ephemeral: true,
122 fetchReply: true
PineaFan5bea7e12023-01-05 21:20:04 +0000123 });
pineafan8b4b17f2022-02-27 20:42:52 +0000124 let component;
125 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100126 component = await m.awaitMessageComponent({
Skyler Greyda16adf2023-03-05 10:22:12 +0000127 filter: (i) => {
128 return i.user.id === interaction.user.id && i.channelId === interaction.channelId;
129 },
Skyler Grey75ea9172022-08-06 10:22:23 +0100130 time: 300000
131 });
132 } catch {
133 return;
134 }
Skyler Greyf4f21c42023-03-08 14:36:29 +0000135 await component.deferUpdate();
Skyler Grey75ea9172022-08-06 10:22:23 +0100136 if (component.customId === "cancel")
137 return interaction.editReply({
138 embeds: [
139 new EmojiEmbed()
140 .setEmoji("PUNISH.MUTE.RED")
141 .setTitle("Mute")
142 .setDescription("Mute cancelled")
143 .setStatus("Danger")
144 ]
145 });
pineafan8b4b17f2022-02-27 20:42:52 +0000146 switch (component.customId) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100147 case "1m": {
148 muteTime = 60;
149 break;
150 }
151 case "10m": {
152 muteTime = 60 * 10;
153 break;
154 }
155 case "30m": {
156 muteTime = 60 * 30;
157 break;
158 }
159 case "1h": {
160 muteTime = 60 * 60;
161 break;
162 }
163 case "6h": {
164 muteTime = 60 * 60 * 6;
165 break;
166 }
167 case "12h": {
168 muteTime = 60 * 60 * 12;
169 break;
170 }
171 case "1d": {
172 muteTime = 60 * 60 * 24;
173 break;
174 }
175 case "1w": {
176 muteTime = 60 * 60 * 24 * 7;
177 break;
178 }
pineafan8b4b17f2022-02-27 20:42:52 +0000179 }
180 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +0100181 await interaction.reply({
182 embeds: LoadingEmbed,
183 ephemeral: true,
184 fetchReply: true
185 });
pineafan8b4b17f2022-02-27 20:42:52 +0000186 }
pineafan5d1908e2022-02-28 21:34:47 +0000187 // TODO:[Modals] Replace this with a modal
pineafan62ce1922022-08-25 20:34:45 +0100188 let reason: string | null = null;
pineafan02ba0232022-07-24 22:16:15 +0100189 let notify = true;
190 let createAppealTicket = false;
pineafan73a7c4a2022-07-24 10:38:04 +0100191 let confirmation;
Skyler Greyad002172022-08-16 18:48:26 +0100192 let timedOut = false;
193 let success = false;
pineafan62ce1922022-08-25 20:34:45 +0100194 do {
pineafan73a7c4a2022-07-24 10:38:04 +0100195 confirmation = await new confirmationMessage(interaction)
196 .setEmoji("PUNISH.MUTE.RED")
197 .setTitle("Mute")
Skyler Grey75ea9172022-08-06 10:22:23 +0100198 .setDescription(
199 keyValueList({
PineaFan5bea7e12023-01-05 21:20:04 +0000200 user: renderUser(member.user),
Skyler Grey75ea9172022-08-06 10:22:23 +0100201 time: `${humanizeDuration(muteTime * 1000, {
202 round: true
203 })}`,
Skyler Greyda16adf2023-03-05 10:22:12 +0000204 reason: reason ? "\n> " + reason.replaceAll("\n", "\n> ") : "*No reason provided*"
Skyler Grey75ea9172022-08-06 10:22:23 +0100205 }) +
206 "The user will be " +
207 serverSettingsDescription +
PineaFan5bea7e12023-01-05 21:20:04 +0000208 "\n\n" +
209 `Are you sure you want to mute <@!${member.id}>?`
Skyler Grey75ea9172022-08-06 10:22:23 +0100210 )
pineafan73a7c4a2022-07-24 10:38:04 +0100211 .setColor("Danger")
212 .addCustomBoolean(
Skyler Grey75ea9172022-08-06 10:22:23 +0100213 "appeal",
214 "Create appeal ticket",
PineaFana00db1b2023-01-02 15:32:54 +0000215 !(await areTicketsEnabled(interaction.guild.id)),
pineafan1e462ab2023-03-07 21:34:06 +0000216 async () => await create(interaction.guild!, member!.user, interaction.user, reason),
Skyler Grey75ea9172022-08-06 10:22:23 +0100217 "An appeal ticket will be created when Confirm is clicked",
PineaFana34d04b2023-01-03 22:05:42 +0000218 null,
Skyler Grey75ea9172022-08-06 10:22:23 +0100219 "CONTROL.TICKET",
220 createAppealTicket
221 )
222 .addCustomBoolean(
223 "notify",
224 "Notify user",
225 false,
Skyler Grey75ea9172022-08-06 10:22:23 +0100226 null,
PineaFan5bea7e12023-01-05 21:20:04 +0000227 "The user will be sent a DM",
PineaFana34d04b2023-01-03 22:05:42 +0000228 null,
Skyler Grey75ea9172022-08-06 10:22:23 +0100229 "ICONS.NOTIFY." + (notify ? "ON" : "OFF"),
230 notify
231 )
pineafan73a7c4a2022-07-24 10:38:04 +0100232 .addReasonButton(reason ?? "")
PineaFan1dee28f2023-01-16 22:09:07 +0000233 .setFailedMessage("No changes were made", "Success", "PUNISH.MUTE.GREEN")
pineafan63fc5e22022-08-04 22:04:10 +0100234 .send(true);
235 reason = reason ?? "";
Skyler Greyad002172022-08-16 18:48:26 +0100236 if (confirmation.cancelled) timedOut = true;
PineaFan5bea7e12023-01-05 21:20:04 +0000237 else if (confirmation.success) success = true;
238 else if (confirmation.newReason) reason = confirmation.newReason;
239 else if (confirmation.components) {
pineafan62ce1922022-08-25 20:34:45 +0100240 notify = confirmation.components["notify"]!.active;
241 createAppealTicket = confirmation.components["appeal"]!.active;
pineafan02ba0232022-07-24 22:16:15 +0100242 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000243 } while (!timedOut && !success);
PineaFan1dee28f2023-01-16 22:09:07 +0000244 if (timedOut || !confirmation.success) return;
Skyler Greyda16adf2023-03-05 10:22:12 +0000245 const status: { timeout: boolean | null; role: boolean | null; dm: boolean | null } = {
246 timeout: null,
247 role: null,
248 dm: null
249 };
PineaFan5bea7e12023-01-05 21:20:04 +0000250 let dmMessage;
251 try {
252 if (notify) {
PineaFana6e37932023-09-25 22:09:08 +0100253 let formattedReason: string | null = null;
Skyler Greyda16adf2023-03-05 10:22:12 +0000254 if (reason) {
PineaFana6e37932023-09-25 22:09:08 +0100255 formattedReason = reason
Skyler Greyda16adf2023-03-05 10:22:12 +0000256 .split("\n")
257 .map((line) => "> " + line)
258 .join("\n");
259 }
PineaFan5bea7e12023-01-05 21:20:04 +0000260 const messageData: {
261 embeds: EmojiEmbed[];
262 components: ActionRowBuilder<ButtonBuilder>[];
263 } = {
264 embeds: [
265 new EmojiEmbed()
266 .setEmoji("PUNISH.MUTE.RED")
267 .setTitle("Muted")
268 .setDescription(
269 `You have been muted in ${interaction.guild.name}` +
PineaFana6e37932023-09-25 22:09:08 +0100270 (formattedReason ? ` for:\n${formattedReason}` : ".\n*No reason was provided*") +
Skyler Greyda16adf2023-03-05 10:22:12 +0000271 "\n\n" +
272 `You will be unmuted at: <t:${Math.round(Date.now() / 1000) + muteTime}:D> at ` +
273 `<t:${Math.round(Date.now() / 1000) + muteTime}:T> (<t:${
274 Math.round(Date.now() / 1000) + muteTime
275 }:R>)` +
276 "\n\n" +
277 (createAppealTicket
278 ? `You can appeal this in the ticket created in <#${
279 confirmation.components!["appeal"]!.response
280 }>`
281 : "")
PineaFan5bea7e12023-01-05 21:20:04 +0000282 )
283 .setStatus("Danger")
284 ],
285 components: []
Skyler Greyda16adf2023-03-05 10:22:12 +0000286 };
PineaFan5bea7e12023-01-05 21:20:04 +0000287 if (config.moderation.mute.text && config.moderation.mute.link) {
288 messageData.embeds[0]!.setFooter(LinkWarningFooter);
Skyler Greyda16adf2023-03-05 10:22:12 +0000289 messageData.components.push(
290 new ActionRowBuilder<Discord.ButtonBuilder>().addComponents(
291 new ButtonBuilder()
292 .setStyle(ButtonStyle.Link)
293 .setLabel(config.moderation.mute.text)
pineafan6de4da52023-03-07 20:43:44 +0000294 .setURL(config.moderation.mute.link.replaceAll("{id}", member.id))
PineaFan5bea7e12023-01-05 21:20:04 +0000295 )
Skyler Greyda16adf2023-03-05 10:22:12 +0000296 );
297 }
PineaFan5bea7e12023-01-05 21:20:04 +0000298 dmMessage = await member.send(messageData);
299 status.dm = true;
300 }
301 } catch {
302 status.dm = false;
303 }
304 try {
305 if (config.moderation.mute.timeout) {
306 await member.timeout(muteTime * 1000, reason || "*No reason provided*");
307 if (config.moderation.mute.role !== null) {
308 await member.roles.add(config.moderation.mute.role);
Skyler Greyda16adf2023-03-05 10:22:12 +0000309 await client.database.eventScheduler.schedule(
310 "naturalUnmute",
311 (Date.now() + muteTime * 1000).toString(),
312 {
313 guild: interaction.guild.id,
314 user: member.id,
315 expires: Date.now() + muteTime * 1000
316 }
317 );
PineaFan5bea7e12023-01-05 21:20:04 +0000318 }
319 } else {
320 status.timeout = true;
321 }
322 } catch {
323 status.timeout = false;
324 }
325 try {
326 if (config.moderation.mute.role !== null) {
327 await member.roles.add(config.moderation.mute.role);
TheCodedProf6ec331b2023-02-20 12:13:06 -0500328 await client.database.eventScheduler.schedule("unmuteRole", (Date.now() + muteTime * 1000).toString(), {
PineaFan5bea7e12023-01-05 21:20:04 +0000329 guild: interaction.guild.id,
330 user: member.id,
331 role: config.moderation.mute.role
332 });
333 } else {
334 status.role = true;
335 }
336 } catch {
337 status.role = false;
338 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000339 const countTrue = (items: (boolean | null)[]) => items.filter((item) => item === true).length;
PineaFan5bea7e12023-01-05 21:20:04 +0000340 const requiredPunishments = countTrue([config.moderation.mute.timeout, config.moderation.mute.role !== null]);
341 const actualPunishments = countTrue([status.timeout, status.role]);
342
343 await client.database.history.create("mute", interaction.guild.id, member.user, interaction.user, reason);
344 if (requiredPunishments !== actualPunishments) {
345 const messages = [];
346 if (config.moderation.mute.timeout) messages.push(`The member was ${status.timeout ? "" : "not "}timed out`);
Skyler Greyda16adf2023-03-05 10:22:12 +0000347 if (config.moderation.mute.role !== null)
348 messages.push(`The member was ${status.role ? "" : "not "}given the mute role`);
PineaFan5bea7e12023-01-05 21:20:04 +0000349 messages.push(`The member was not sent a DM`);
350 if (dmMessage && actualPunishments === 0) await dmMessage.delete();
351 await interaction.editReply({
352 embeds: [
353 new EmojiEmbed()
354 .setEmoji("PUNISH.MUTE." + (actualPunishments > 0 ? "YELLOW" : "RED"))
355 .setTitle("Mute")
356 .setDescription(
Skyler Greyda16adf2023-03-05 10:22:12 +0000357 "Mute " +
358 (actualPunishments > 0 ? "partially" : "failed") +
359 ":\n" +
360 messages.map((message) => `> ${message}`).join("\n")
PineaFan5bea7e12023-01-05 21:20:04 +0000361 )
362 .setStatus(actualPunishments > 0 ? "Warning" : "Danger")
363 ],
364 components: []
365 });
366 }
367 const data = {
368 meta: {
369 type: "memberMute",
370 displayName: "Member Muted",
371 calculateType: "guildMemberPunish",
372 color: NucleusColors.yellow,
373 emoji: "PUNISH.WARN.YELLOW",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500374 timestamp: Date.now()
PineaFan5bea7e12023-01-05 21:20:04 +0000375 },
376 list: {
377 memberId: entry(member.user.id, `\`${member.user.id}\``),
378 name: entry(member.user.id, renderUser(member.user)),
Skyler Greyda16adf2023-03-05 10:22:12 +0000379 mutedUntil: entry((Date.now() + muteTime * 1000).toString(), renderDelta(Date.now() + muteTime * 1000)),
TheCodedProf6ec331b2023-02-20 12:13:06 -0500380 muted: entry(new Date().getTime.toString(), renderDelta(Date.now() - 1000)),
PineaFan5bea7e12023-01-05 21:20:04 +0000381 mutedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user as Discord.User)),
382 reason: entry(reason, reason ? reason : "*No reason provided*")
383 },
TheCodedProf94ff6de2023-02-22 17:47:26 -0500384 separate: {
Skyler Greyda16adf2023-03-05 10:22:12 +0000385 end:
386 getEmojiByName("ICONS.NOTIFY." + (notify ? "ON" : "OFF")) +
387 ` The user was ${notify ? "" : "not "}notified`
TheCodedProf94ff6de2023-02-22 17:47:26 -0500388 },
PineaFan5bea7e12023-01-05 21:20:04 +0000389 hidden: {
390 guild: interaction.guild.id
391 }
392 };
Skyler Greyf4f21c42023-03-08 14:36:29 +0000393 await log(data);
PineaFan5bea7e12023-01-05 21:20:04 +0000394 const failed = !status.dm && notify;
395 await interaction.editReply({
396 embeds: [
397 new EmojiEmbed()
398 .setEmoji(`PUNISH.MUTE.${failed ? "YELLOW" : "GREEN"}`)
399 .setTitle("Mute")
400 .setDescription(
Skyler Greyda16adf2023-03-05 10:22:12 +0000401 "The member was muted" +
402 (failed ? ", but could not be notified" : "") +
403 (createAppealTicket
404 ? ` and an appeal ticket was opened in <#${confirmation.components!["appeal"]!.response}>`
405 : "")
PineaFan5bea7e12023-01-05 21:20:04 +0000406 )
407 .setStatus(failed ? "Warning" : "Success")
408 ],
409 components: []
410 });
pineafan63fc5e22022-08-04 22:04:10 +0100411};
pineafan8b4b17f2022-02-27 20:42:52 +0000412
pineafan6de4da52023-03-07 20:43:44 +0000413const check = (interaction: CommandInteraction | ButtonInteraction, partial: boolean = false, target?: GuildMember) => {
PineaFana00db1b2023-01-02 15:32:54 +0000414 if (!interaction.guild) return;
Skyler Grey75ea9172022-08-06 10:22:23 +0100415 const member = interaction.member as GuildMember;
TheCodedProff86ba092023-01-27 17:10:07 -0500416 // Check if the user has moderate_members permission
417 if (!member.permissions.has("ModerateMembers")) return "You do not have the *Moderate Members* permission";
418 if (partial) return true;
PineaFan5bea7e12023-01-05 21:20:04 +0000419 const me = interaction.guild.members.me!;
pineafan6de4da52023-03-07 20:43:44 +0000420 let apply;
421 if (interaction.isButton()) {
422 apply = target!;
423 } else {
424 apply = interaction.options.getMember("user") as GuildMember;
425 }
pineafan62ce1922022-08-25 20:34:45 +0100426 const memberPos = member.roles.cache.size > 1 ? member.roles.highest.position : 0;
427 const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
428 const applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
pineafanc1c18792022-08-03 21:41:36 +0100429 // Do not allow muting the owner
PineaFan0d06edc2023-01-17 22:10:31 +0000430 if (member.id === interaction.guild.ownerId) return "You cannot mute the owner of the server";
pineafan8b4b17f2022-02-27 20:42:52 +0000431 // Check if Nucleus can mute the member
TheCodedProf0941da42023-02-18 20:28:04 -0500432 if (!(mePos > applyPos)) return `I do not have a role higher than <@${apply.id}>`;
pineafan8b4b17f2022-02-27 20:42:52 +0000433 // Check if Nucleus has permission to mute
PineaFan0d06edc2023-01-17 22:10:31 +0000434 if (!me.permissions.has("ModerateMembers")) return "I do not have the *Moderate Members* permission";
pineafan8b4b17f2022-02-27 20:42:52 +0000435 // Do not allow muting Nucleus
PineaFan0d06edc2023-01-17 22:10:31 +0000436 if (member.id === me.id) return "I cannot mute myself";
pineafan8b4b17f2022-02-27 20:42:52 +0000437 // Allow the owner to mute anyone
PineaFana00db1b2023-01-02 15:32:54 +0000438 if (member.id === interaction.guild.ownerId) return true;
pineafan8b4b17f2022-02-27 20:42:52 +0000439 // Check if the user is below on the role list
TheCodedProf0941da42023-02-18 20:28:04 -0500440 if (!(memberPos > applyPos)) return `You do not have a role higher than <@${apply.id}>`;
pineafan8b4b17f2022-02-27 20:42:52 +0000441 // Allow mute
pineafan63fc5e22022-08-04 22:04:10 +0100442 return true;
443};
pineafan8b4b17f2022-02-27 20:42:52 +0000444
Skyler Grey75ea9172022-08-06 10:22:23 +0100445export { command, callback, check };
TheCodedProfa112f612023-01-28 18:06:45 -0500446export const metadata = {
Skyler Greyda16adf2023-03-05 10:22:12 +0000447 longDescription:
448 "Stops a member from being able to send messages or join voice channels for a specified amount of time.",
449 premiumOnly: true
450};