mirror of
https://github.com/ReVanced/revanced-bots.git
synced 2026-01-11 21:56:17 +00:00
fix(bots/discord/commands): refactor and add checks
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { SlashCommandBuilder, type TextBasedChannel } from 'discord.js'
|
import { SlashCommandBuilder, type TextBasedChannel } from 'discord.js'
|
||||||
|
|
||||||
|
import { config } from '$/context'
|
||||||
import type { Command } from '..'
|
import type { Command } from '..'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -16,7 +17,7 @@ export default {
|
|||||||
.toJSON(),
|
.toJSON(),
|
||||||
|
|
||||||
memberRequirements: {
|
memberRequirements: {
|
||||||
roles: ['955220417969262612', '973886585294704640'],
|
roles: config.moderation?.roles ?? [],
|
||||||
},
|
},
|
||||||
|
|
||||||
global: false,
|
global: false,
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import { SlashCommandBuilder } from 'discord.js'
|
|||||||
|
|
||||||
import type { Command } from '..'
|
import type { Command } from '..'
|
||||||
|
|
||||||
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
import { config } from '$/context'
|
import { config } from '$/context'
|
||||||
import { applyReferenceToModerationActionEmbed, createModerationActionEmbed } from '$/utils/discord/embeds'
|
import { createModerationActionEmbed } from '$/utils/discord/embeds'
|
||||||
|
import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
|
||||||
import { parseDuration } from '$/utils/duration'
|
import { parseDuration } from '$/utils/duration'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -23,27 +25,34 @@ export default {
|
|||||||
|
|
||||||
global: false,
|
global: false,
|
||||||
|
|
||||||
async execute({ config, logger }, interaction) {
|
async execute({ logger }, interaction) {
|
||||||
const user = interaction.options.getUser('member', true)
|
const user = interaction.options.getUser('user', true)
|
||||||
const reason = interaction.options.getString('reason') ?? undefined
|
const reason = interaction.options.getString('reason') ?? 'No reason provided'
|
||||||
const dmd = interaction.options.getString('dmd')
|
const dmd = interaction.options.getString('dmd')
|
||||||
|
|
||||||
|
const member = await interaction.guild!.members.fetch(user.id)
|
||||||
|
const moderator = await interaction.guild!.members.fetch(interaction.user.id)
|
||||||
|
|
||||||
|
if (member.bannable) throw new CommandError(CommandErrorType.Generic, 'This user cannot be banned by the bot.')
|
||||||
|
|
||||||
|
if (moderator.roles.highest.comparePositionTo(member.roles.highest) <= 0)
|
||||||
|
throw new CommandError(
|
||||||
|
CommandErrorType.InvalidUser,
|
||||||
|
'You cannot ban a user with a role equal to or higher than yours.',
|
||||||
|
)
|
||||||
|
|
||||||
const dms = Math.floor(dmd ? parseDuration(dmd) : 0 / 1000)
|
const dms = Math.floor(dmd ? parseDuration(dmd) : 0 / 1000)
|
||||||
await interaction.guild!.members.ban(user, {
|
await interaction.guild!.members.ban(user, {
|
||||||
reason: `Banned by moderator ${interaction.user.tag} (${interaction.user.id}): ${reason}`,
|
reason: `Banned by moderator ${interaction.user.tag} (${interaction.user.id}): ${reason}`,
|
||||||
deleteMessageSeconds: dms,
|
deleteMessageSeconds: dms,
|
||||||
})
|
})
|
||||||
|
|
||||||
const embed = createModerationActionEmbed('Banned', user, interaction.user, reason ?? 'No reason provided')
|
await sendModerationReplyAndLogs(
|
||||||
const reply = await interaction.reply({ embeds: [embed] }).then(it => it.fetch())
|
interaction,
|
||||||
|
createModerationActionEmbed('Banned', user, interaction.user, reason),
|
||||||
const logConfig = config.moderation?.log
|
)
|
||||||
if (logConfig) {
|
logger.info(
|
||||||
const channel = await interaction.guild!.channels.fetch(logConfig.thread ?? logConfig.channel)
|
`${interaction.user.tag} (${interaction.user.id}) banned ${user.tag} (${user.id}) because ${reason}, deleting their messages sent in the previous ${dms}s`,
|
||||||
if (!channel || !channel.isTextBased())
|
)
|
||||||
return void logger.warn('The moderation log channel does not exist, skipping logging')
|
|
||||||
|
|
||||||
await channel.send({ embeds: [applyReferenceToModerationActionEmbed(embed, reply.url)] })
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
} satisfies Command
|
} satisfies Command
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { applyRolePreset } from '$/utils/discord/rolePresets'
|
|||||||
import type { Command } from '..'
|
import type { Command } from '..'
|
||||||
|
|
||||||
import { config } from '$/context'
|
import { config } from '$/context'
|
||||||
import { applyReferenceToModerationActionEmbed, createModerationActionEmbed } from '$/utils/discord/embeds'
|
import { createModerationActionEmbed } from '$/utils/discord/embeds'
|
||||||
|
import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
|
||||||
import { parseDuration } from '$/utils/duration'
|
import { parseDuration } from '$/utils/duration'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -23,9 +24,9 @@ export default {
|
|||||||
|
|
||||||
global: false,
|
global: false,
|
||||||
|
|
||||||
async execute({ config, logger }, interaction) {
|
async execute({ logger }, interaction) {
|
||||||
const user = interaction.options.getUser('member', true)
|
const user = interaction.options.getUser('member', true)
|
||||||
const reason = interaction.options.getString('reason')
|
const reason = interaction.options.getString('reason') ?? 'No reason provided'
|
||||||
const duration = interaction.options.getString('duration')
|
const duration = interaction.options.getString('duration')
|
||||||
const durationMs = duration ? parseDuration(duration) : null
|
const durationMs = duration ? parseDuration(duration) : null
|
||||||
|
|
||||||
@@ -35,6 +36,8 @@ export default {
|
|||||||
'The duration must be at least 1 millisecond long.',
|
'The duration must be at least 1 millisecond long.',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const expires = durationMs ? Date.now() + durationMs : null
|
||||||
|
const moderator = await interaction.guild!.members.fetch(interaction.user.id)
|
||||||
const member = await interaction.guild!.members.fetch(user.id)
|
const member = await interaction.guild!.members.fetch(user.id)
|
||||||
if (!member)
|
if (!member)
|
||||||
throw new CommandError(
|
throw new CommandError(
|
||||||
@@ -42,25 +45,23 @@ export default {
|
|||||||
'The provided member is not in the server or does not exist.',
|
'The provided member is not in the server or does not exist.',
|
||||||
)
|
)
|
||||||
|
|
||||||
await applyRolePreset(member, 'mute', durationMs ? Date.now() + durationMs : null)
|
if (member.manageable)
|
||||||
|
throw new CommandError(CommandErrorType.Generic, 'This user cannot be managed by the bot.')
|
||||||
|
|
||||||
const embed = createModerationActionEmbed(
|
if (moderator.roles.highest.comparePositionTo(member.roles.highest) <= 0)
|
||||||
'Muted',
|
throw new CommandError(
|
||||||
user,
|
CommandErrorType.InvalidUser,
|
||||||
interaction.user,
|
'You cannot mute a user with a role equal to or higher than yours.',
|
||||||
reason ?? 'No reason provided',
|
)
|
||||||
durationMs,
|
|
||||||
|
await applyRolePreset(member, 'mute', durationMs ? Date.now() + durationMs : null)
|
||||||
|
await sendModerationReplyAndLogs(
|
||||||
|
interaction,
|
||||||
|
createModerationActionEmbed('Muted', user, interaction.user, reason, durationMs),
|
||||||
)
|
)
|
||||||
|
|
||||||
const reply = await interaction.reply({ embeds: [embed] }).then(it => it.fetch())
|
logger.info(
|
||||||
|
`Moderator ${interaction.user.tag} (${interaction.user.id}) muted ${user.tag} (${user.id}) until ${expires} because ${reason}`,
|
||||||
const logConfig = config.moderation?.log
|
)
|
||||||
if (logConfig) {
|
|
||||||
const channel = await interaction.guild!.channels.fetch(logConfig.thread ?? logConfig.channel)
|
|
||||||
if (!channel || !channel.isTextBased())
|
|
||||||
return void logger.warn('The moderation log channel does not exist, skipping logging')
|
|
||||||
|
|
||||||
await channel.send({ embeds: [applyReferenceToModerationActionEmbed(embed, reply.url)] })
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
} satisfies Command
|
} satisfies Command
|
||||||
|
|||||||
@@ -48,12 +48,18 @@ export default {
|
|||||||
|
|
||||||
logger.info(`Setting slowmode to ${duration}ms on ${channel.id}`)
|
logger.info(`Setting slowmode to ${duration}ms on ${channel.id}`)
|
||||||
|
|
||||||
await channel.setRateLimitPerUser(
|
await channel.setRateLimitPerUser(duration / 1000, `Set by ${interaction.user.tag} (${interaction.user.id})`)
|
||||||
duration / 1000,
|
|
||||||
`Slowmode set by @${interaction.user.username} (${interaction.user.id})`,
|
|
||||||
)
|
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
embeds: [createSuccessEmbed(`Slowmode set to ${durationToString(duration)} on ${channel.toString()}`)],
|
embeds: [
|
||||||
|
createSuccessEmbed(
|
||||||
|
`Slowmode ${duration ? `set to ${durationToString(duration)}` : 'removed'} on ${channel.toString()}`,
|
||||||
|
),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
`${interaction.user.tag} (${interaction.user.id}) set the slowmode on ${channel.name} (${channel.id}) to ${duration}ms`,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
} satisfies Command
|
} satisfies Command
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { SlashCommandBuilder } from 'discord.js'
|
|||||||
import type { Command } from '..'
|
import type { Command } from '..'
|
||||||
|
|
||||||
import { config } from '$/context'
|
import { config } from '$/context'
|
||||||
import { applyReferenceToModerationActionEmbed, createModerationActionEmbed } from '$/utils/discord/embeds'
|
import { createModerationActionEmbed } from '$/utils/discord/embeds'
|
||||||
|
import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
@@ -18,24 +19,15 @@ export default {
|
|||||||
|
|
||||||
global: false,
|
global: false,
|
||||||
|
|
||||||
async execute({ config, logger }, interaction) {
|
async execute({ logger }, interaction) {
|
||||||
const user = interaction.options.getUser('member', true)
|
const user = interaction.options.getUser('user', true)
|
||||||
|
|
||||||
await interaction.guild!.members.unban(
|
await interaction.guild!.members.unban(
|
||||||
user,
|
user,
|
||||||
`Unbanned by moderator ${interaction.user.tag} (${interaction.user.id})`,
|
`Unbanned by moderator ${interaction.user.tag} (${interaction.user.id})`,
|
||||||
)
|
)
|
||||||
|
|
||||||
const embed = createModerationActionEmbed('Unbanned', user, interaction.user)
|
await sendModerationReplyAndLogs(interaction, createModerationActionEmbed('Unbanned', user, interaction.user))
|
||||||
const reply = await interaction.reply({ embeds: [embed] }).then(it => it.fetch())
|
logger.info(`${interaction.user.tag} (${interaction.user.id}) unbanned ${user.tag} (${user.id})`)
|
||||||
|
|
||||||
const logConfig = config.moderation?.log
|
|
||||||
if (logConfig) {
|
|
||||||
const channel = await interaction.guild!.channels.fetch(logConfig.thread ?? logConfig.channel)
|
|
||||||
if (!channel || !channel.isTextBased())
|
|
||||||
return void logger.warn('The moderation log channel does not exist, skipping logging')
|
|
||||||
|
|
||||||
await channel.send({ embeds: [applyReferenceToModerationActionEmbed(embed, reply.url)] })
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
} satisfies Command
|
} satisfies Command
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ import { SlashCommandBuilder } from 'discord.js'
|
|||||||
|
|
||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
import { config } from '$/context'
|
import { config } from '$/context'
|
||||||
import { applyReferenceToModerationActionEmbed, createModerationActionEmbed } from '$/utils/discord/embeds'
|
import { appliedPresets } from '$/database/schemas'
|
||||||
|
import { createModerationActionEmbed } from '$/utils/discord/embeds'
|
||||||
|
import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
|
||||||
import { removeRolePreset } from '$/utils/discord/rolePresets'
|
import { removeRolePreset } from '$/utils/discord/rolePresets'
|
||||||
|
import { and, eq } from 'drizzle-orm'
|
||||||
import type { Command } from '..'
|
import type { Command } from '..'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -19,7 +22,7 @@ export default {
|
|||||||
|
|
||||||
global: false,
|
global: false,
|
||||||
|
|
||||||
async execute({ config, logger }, interaction) {
|
async execute({ logger, database }, interaction) {
|
||||||
const user = interaction.options.getUser('member', true)
|
const user = interaction.options.getUser('member', true)
|
||||||
const member = await interaction.guild!.members.fetch(user.id)
|
const member = await interaction.guild!.members.fetch(user.id)
|
||||||
if (!member)
|
if (!member)
|
||||||
@@ -28,18 +31,16 @@ export default {
|
|||||||
'The provided member is not in the server or does not exist.',
|
'The provided member is not in the server or does not exist.',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(await database.query.appliedPresets.findFirst({
|
||||||
|
where: and(eq(appliedPresets.memberId, member.id), eq(appliedPresets.preset, 'mute')),
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
throw new CommandError(CommandErrorType.Generic, 'This user is not muted.')
|
||||||
|
|
||||||
await removeRolePreset(member, 'mute')
|
await removeRolePreset(member, 'mute')
|
||||||
const embed = createModerationActionEmbed('Unmuted', user, interaction.user)
|
await sendModerationReplyAndLogs(interaction, createModerationActionEmbed('Unmuted', user, interaction.user))
|
||||||
|
|
||||||
const reply = await interaction.reply({ embeds: [embed] }).then(it => it.fetch())
|
logger.info(`Moderator ${interaction.user.tag} (${interaction.user.id}) unmuted ${user.tag} (${user.id})`)
|
||||||
|
|
||||||
const logConfig = config.moderation?.log
|
|
||||||
if (logConfig) {
|
|
||||||
const channel = await interaction.guild!.channels.fetch(logConfig.thread ?? logConfig.channel)
|
|
||||||
if (!channel || !channel.isTextBased())
|
|
||||||
return void logger.warn('The moderation log channel does not exist, skipping logging')
|
|
||||||
|
|
||||||
await channel.send({ embeds: [applyReferenceToModerationActionEmbed(embed, reply.url)] })
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
} satisfies Command
|
} satisfies Command
|
||||||
|
|||||||
Reference in New Issue
Block a user