From 7fecbc34e7db88e68bb13a84de972eac7d093d14 Mon Sep 17 00:00:00 2001 From: Kath Date: Thu, 1 Aug 2024 10:43:17 +0800 Subject: [PATCH] mute/unmute --- src/commands/automod.ts | 1 + src/commands/user.ts | 74 +++++++++++++++++++++++++++++++++++-- src/functions/Infraction.ts | 66 +++++++++++++++++++++++++++------ 3 files changed, 126 insertions(+), 15 deletions(-) diff --git a/src/commands/automod.ts b/src/commands/automod.ts index 3039f7d..f28a25c 100644 --- a/src/commands/automod.ts +++ b/src/commands/automod.ts @@ -28,6 +28,7 @@ export const data = new SlashCommandBuilder() ) .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) .setDMPermission(false); + export interface UserPermit { id: string; removeTime: number; diff --git a/src/commands/user.ts b/src/commands/user.ts index 7e82df1..054bffe 100644 --- a/src/commands/user.ts +++ b/src/commands/user.ts @@ -1,4 +1,3 @@ -// MAX MUTE TIME 2419200000 import { ChatInputCommandInteraction, SlashCommandBuilder, @@ -9,6 +8,7 @@ import { ButtonStyle } from 'discord.js'; import Infraction, { getUserInfractions } from '../functions/Infraction'; +import ms from 'ms'; export const data = new SlashCommandBuilder() .setName('user') @@ -43,6 +43,26 @@ export const data = new SlashCommandBuilder() option.setName('reason').setDescription('The reason for the kick').setRequired(false) ) ) + .addSubcommand((subcommand) => + subcommand + .setName('mute') + .setDescription('Mute a user') + .addUserOption((option) => option.setName('user').setDescription('The user to mute').setRequired(true)) + .addStringOption((option) => option.setName('time').setDescription('How long to mute').setRequired(true)) + .addStringOption((option) => + option.setName('reason').setDescription('The reason for the mute').setRequired(false) + ) + ) + .addSubcommand((subcommand) => + subcommand + .setName('unmute') + .setDescription('unmute a user') + .addUserOption((option) => option.setName('user').setDescription('The user to mute').setRequired(true)) + .addStringOption((option) => option.setName('time').setDescription('How long to mute').setRequired(true)) + .addStringOption((option) => + option.setName('reason').setDescription('The reason for the mute').setRequired(false) + ) + ) .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) .setDMPermission(false); @@ -113,8 +133,10 @@ export async function execute(interaction: ChatInputCommandInteraction): Promise automatic: false, reason: reason, type: 'WARN', + long: null, user: { id: commandUser.id, staff: false, bot: commandUser.bot }, - staff: { id: interaction.user.id, staff: true, bot: interaction.user.bot } + staff: { id: interaction.user.id, staff: true, bot: interaction.user.bot }, + timestamp: Date.now() }) .log() .save(); @@ -127,14 +149,60 @@ export async function execute(interaction: ChatInputCommandInteraction): Promise automatic: false, reason: reason, type: 'KICK', + long: null, user: { id: commandUser.id, staff: false, bot: commandUser.bot }, - staff: { id: interaction.user.id, staff: true, bot: interaction.user.bot } + staff: { id: interaction.user.id, staff: true, bot: interaction.user.bot }, + timestamp: Date.now() }) .log() .save(); await interaction.reply({ content: `<@${commandUser.id}> has been kicked`, ephemeral: true }); break; } + case 'mute': { + const time = interaction.options.getString('time'); + const reason = interaction.options.getString('reason') || 'No reason provided'; + if (!time) { + await interaction.reply({ content: 'Please provide a time', ephemeral: true }); + return; + } + const long = ms(time); + if (2419200000 < long) { + await interaction.reply({ content: 'You cannot mute someone for longer then 28d', ephemeral: true }); + return; + } + user.timeout(long, reason); + new Infraction({ + automatic: false, + reason: reason, + type: 'MUTE', + long, + user: { id: commandUser.id, staff: false, bot: commandUser.bot }, + staff: { id: interaction.user.id, staff: true, bot: interaction.user.bot }, + timestamp: Date.now() + }) + .log() + .save(); + await interaction.reply({ content: `<@${commandUser.id}> has been muted`, ephemeral: true }); + break; + } + case 'unmute': { + const reason = interaction.options.getString('reason') || 'No reason provided'; + user.timeout(null, reason); + new Infraction({ + automatic: false, + reason: reason, + type: 'UNMUTE', + long: null, + user: { id: commandUser.id, staff: false, bot: commandUser.bot }, + staff: { id: interaction.user.id, staff: true, bot: interaction.user.bot }, + timestamp: Date.now() + }) + .log() + .save(); + await interaction.reply({ content: `<@${commandUser.id}> has been unmuted`, ephemeral: true }); + break; + } default: { await interaction.reply({ content: 'Invalid subcommand Please provide a valid subcommand', ephemeral: true }); } diff --git a/src/functions/Infraction.ts b/src/functions/Infraction.ts index 0d9531a..03854f4 100644 --- a/src/functions/Infraction.ts +++ b/src/functions/Infraction.ts @@ -8,23 +8,30 @@ export interface InfractionUser { bot: boolean; } -export type InfractionType = 'EVENT' | 'WARN' | 'KICK' | 'BAN'; +export type InfractionType = 'EVENT' | 'WARN' | 'KICK' | 'BAN' | 'MUTE' | 'UNMUTE'; export interface InfractionInfomation { automatic: boolean; reason: string; + long: number | null; type: InfractionType; user: InfractionUser; staff: InfractionUser; + timestamp: number; } const InteractionUserSchema = new Schema({ id: String, staff: Boolean, bot: Boolean }); const InfractionSchema = new Schema({ automatic: Boolean, reason: String, + long: { + type: Number, + default: null + }, type: String, user: InteractionUserSchema, - staff: InteractionUserSchema + staff: InteractionUserSchema, + timestamp: Number }); const InfractionModel = model('infraction', InfractionSchema); @@ -33,60 +40,92 @@ class Infraction { constructor(infraction: InfractionInfomation) { this.infraction = infraction; } + public save() { return new InfractionModel({ automatic: this.infraction.automatic, reason: this.infraction.reason, + long: this.infraction.long, type: this.infraction.type, user: this.infraction.user, - staff: this.infraction.staff + staff: this.infraction.staff, + timestamp: this.infraction.timestamp }).save(); } + public setAutomatic(automatic: boolean): this { this.infraction.automatic = automatic; return this; } + public setReason(reason: string): this { this.infraction.reason = reason; return this; } + + public setLong(long: number | null): this { + this.infraction.long = long; + return this; + } + public setType(type: InfractionType): this { this.infraction.type = type; return this; } + public setUser(user: InfractionUser): this { this.infraction.user = user; return this; } + public setStaff(staff: InfractionUser): this { this.infraction.staff = staff; return this; } - public getInfraction(): InfractionInfomation { - return this.infraction; + + public setTimestamp(timestamp: number): this { + this.infraction.timestamp = timestamp; + return this; + } + + public getAutomatic(): boolean { + return this.infraction.automatic; } + public getReason(): string { return this.infraction.reason; } + + public getLong(): number | null { + return this.infraction.long; + } + public getType(): InfractionType { return this.infraction.type; } + public getUser(): InfractionUser { return this.infraction.user; } - public getStaff(): InfractionUser | null { + + public getStaff(): InfractionUser { return this.infraction.staff; } - public isAutomatic(): boolean { - return this.infraction.automatic; + + public getTimestamp(): number { + return this.infraction.timestamp; } + public toString(): string { - return `Infraction: ${this.infraction.reason}\nType: ${this.infraction.type}\nAutomatic: ${ - this.infraction.automatic ? 'Yes' : 'No' - }\nUser: <@${this.infraction.user.id}>\nStaff: ${ + return `Infraction: ${this.infraction.reason}\nType: ${this.infraction.type}\nLong: ${ + this.infraction.long + }\nAutomatic: ${this.infraction.automatic ? 'Yes' : 'No'}\nUser: <@${this.infraction.user.id}>\nStaff: ${ this.infraction.staff ? `<@${this.infraction.staff.id}>` : 'None' - }`; + }\nTimestamp: ()`; } + public log(): this { const channel = guild.channels.cache.get(infractionLogchannel); if (!channel || channel.type !== ChannelType.GuildText) return this; @@ -94,12 +133,14 @@ class Infraction { return this; } } + export interface InfractionReturn { success: boolean; info: string; infraction?: Infraction; infractions?: Infraction[]; } + export async function getUserInfractions(id: string): Promise { const userInfractions = await InfractionModel.find({ 'user.id': id }); if (!userInfractions) return { success: false, info: 'No infractions found' }; @@ -109,4 +150,5 @@ export async function getUserInfractions(id: string): Promise userInfractions.forEach((infraction) => foundInfraction.push(new Infraction(infraction))); return { success: true, info: `User has ${foundInfraction.length} infractions`, infractions: foundInfraction }; } + export default Infraction;