mirror of
https://github.com/nx-bat/discordbot-ng.git
synced 2026-09-22 10:29:10 -04:00
141 lines
5.4 KiB
TypeScript
141 lines
5.4 KiB
TypeScript
import { ApplicationIntegrationType, ChatInputCommandInteraction, Client, Guild, GuildMember, InteractionContextType, MessageMentions, PermissionFlagsBits, SlashCommandBuilder, time, TimestampStyles, User } from 'discord.js';
|
|
import { Database } from '../shared/Database';
|
|
import { AltData, comprehensiveAltLookupFromDiscord, deferInteraction } from '../utils';
|
|
|
|
const mentionRegex = new RegExp(MessageMentions.UsersPattern);
|
|
|
|
export default {
|
|
name: 'ban',
|
|
data: new SlashCommandBuilder()
|
|
.setName('ban')
|
|
.setDescription('Bans a user.')
|
|
.setIntegrationTypes(ApplicationIntegrationType.GuildInstall)
|
|
.setContexts(InteractionContextType.Guild)
|
|
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers)
|
|
.addStringOption(option =>
|
|
option
|
|
.setName('user')
|
|
.setDescription('The discord user mention, or ID, to ban.')
|
|
.setRequired(true)
|
|
)
|
|
.addStringOption(option =>
|
|
option
|
|
.setName('reason')
|
|
.setDescription('The reason for the ban')
|
|
.setRequired(false)
|
|
.setMaxLength(400)
|
|
)
|
|
.addNumberOption(option =>
|
|
option
|
|
.setName('hours')
|
|
.setDescription('The duration of the ban, added with other options (0 for permanent).')
|
|
.setRequired(false)
|
|
)
|
|
.addNumberOption(option =>
|
|
option
|
|
.setName('minutes')
|
|
.setDescription('The duration of the ban, added with other options (0 for permanent).')
|
|
.setRequired(false)
|
|
)
|
|
.addNumberOption(option =>
|
|
option
|
|
.setName('seconds')
|
|
.setDescription('The duration of the ban, added with other options (0 for permanent).')
|
|
.setRequired(false)
|
|
)
|
|
.addNumberOption(option =>
|
|
option
|
|
.setName('delete-message-days')
|
|
.setDescription('How far back to delete messages (in days, default: 0 days).')
|
|
.setRequired(false)
|
|
.setMinValue(0)
|
|
.setMaxValue(7)
|
|
)
|
|
.addBooleanOption(option =>
|
|
option
|
|
.setName('full-ban')
|
|
.setDescription('Whether or not to prevent the user from joining on known alts (and ban all existing alts).')
|
|
.setRequired(false)
|
|
),
|
|
handler: async function (client: Client, interaction: ChatInputCommandInteraction) {
|
|
await deferInteraction(interaction);
|
|
|
|
if (!interaction.guild) return interaction.editReply('This command must be used in a server');
|
|
|
|
if (!interaction.guild.members.me) return interaction.editReply('An error has occurred. Please try again later.');
|
|
|
|
const input = interaction.options.getString('user', true);
|
|
|
|
const matches = mentionRegex.exec(input);
|
|
mentionRegex.lastIndex = 0;
|
|
|
|
const idToUse = matches ? matches.groups!.id : input;
|
|
const reason = interaction.options.getString('reason') ?? '';
|
|
|
|
const hours = (interaction.options.getNumber('hours') ?? 0) * 3.6e+6;
|
|
const minutes = (interaction.options.getNumber('minutes') ?? 0) * 60000;
|
|
const seconds = (interaction.options.getNumber('seconds') ?? 0) * 1000;
|
|
|
|
const duration = hours + minutes + seconds;
|
|
|
|
const deleteMessageDays = (interaction.options.getNumber('delete-message-days') ?? 0) * 86400;
|
|
|
|
const fullBan = interaction.options.getBoolean('full-ban') ?? false;
|
|
|
|
let banMember: GuildMember | null = null;
|
|
|
|
try {
|
|
banMember = await interaction.guild.members.fetch(idToUse);
|
|
} catch (e) {
|
|
// Member not in server.
|
|
}
|
|
|
|
const member = await interaction.guild.members.fetch(interaction.user.id);
|
|
|
|
if (banMember && member.roles.highest.comparePositionTo(banMember.roles.highest) <= 0) {
|
|
return await interaction.editReply('You do not have permission to ban this user.');
|
|
}
|
|
|
|
if (banMember && !banMember.bannable) {
|
|
return await interaction.editReply('I do not have permission to ban this user.');
|
|
}
|
|
|
|
const expiresAt = new Date(Date.now() + duration);
|
|
|
|
await Database.putBan(idToUse, duration > 0 ? expiresAt : null, fullBan);
|
|
|
|
try {
|
|
await interaction.guild.bans.create(idToUse, {
|
|
reason: (reason + ` ${fullBan ? 'Full banned' : 'Banned'} by ${interaction.user.username} (${interaction.user.id})${duration > 0 ? `. Expires at: ${time(expiresAt, TimestampStyles.ShortDateTime)}` : ''}`).trim(),
|
|
deleteMessageSeconds: deleteMessageDays
|
|
});
|
|
} catch (e) {
|
|
console.error(e);
|
|
return await interaction.editReply("Error banning user (couldn't ban).");
|
|
}
|
|
|
|
if (fullBan) {
|
|
const alts = await comprehensiveAltLookupFromDiscord(idToUse, interaction.guild);
|
|
|
|
await removeAllAlts([alts], interaction.guild, interaction.user, fullBan, reason, deleteMessageDays, duration, expiresAt);
|
|
}
|
|
|
|
await interaction.editReply(`<@${idToUse}> (${idToUse}) has been ${fullBan ? 'full banned' : 'banned'}.`);
|
|
}
|
|
};
|
|
|
|
async function removeAllAlts(altData: AltData[], guild: Guild, moderator: User, fullBan: boolean, reason: string, deleteMessageDays: number, duration: number, expiresAt: Date) {
|
|
for (const data of altData) {
|
|
if (data.type == 'discord') {
|
|
try {
|
|
if (!data.banned) {
|
|
await guild.members.kick(data.thisId as string, (reason + ` ${fullBan ? 'Full banned' : 'Banned'} by ${moderator.username} (${moderator.id})${duration > 0 ? `. Expires at: ${time(expiresAt, TimestampStyles.ShortDateTime)}` : ''}`).trim());
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
}
|
|
|
|
await removeAllAlts(data.alts, guild, moderator, fullBan, reason, deleteMessageDays, duration, expiresAt);
|
|
}
|
|
} |