From 1723e8cacf96e8c6bdee22cfd30e89524fdcef74 Mon Sep 17 00:00:00 2001 From: PalmDevs Date: Mon, 24 Jun 2024 22:53:21 +0700 Subject: [PATCH] feat(bots/discord): support nickname decancering --- bots/discord/config.schema.ts | 3 ++ bots/discord/config.ts | 3 ++ bots/discord/package.json | 1 + bots/discord/src/commands/moderation/cure.ts | 26 ++++++++++++++++++ .../src/events/discord/cureRequired.ts | 18 ++++++++++++ bots/discord/src/utils/discord/moderation.ts | 16 ++++++++++- bun.lockb | Bin 112792 -> 118328 bytes 7 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 bots/discord/src/commands/moderation/cure.ts create mode 100644 bots/discord/src/events/discord/cureRequired.ts diff --git a/bots/discord/config.schema.ts b/bots/discord/config.schema.ts index 9be18e2..0dbe458 100644 --- a/bots/discord/config.schema.ts +++ b/bots/discord/config.schema.ts @@ -5,6 +5,9 @@ export type Config = { guilds: string[] moderation?: { roles: string[] + cure?: { + defaultName: string + } log?: { channel: string thread?: string diff --git a/bots/discord/config.ts b/bots/discord/config.ts index c254919..d02748e 100644 --- a/bots/discord/config.ts +++ b/bots/discord/config.ts @@ -4,6 +4,9 @@ export default { owners: ['USER_ID_HERE'], guilds: ['GUILD_ID_HERE'], moderation: { + cure: { + defaultName: 'Server member', + }, roles: ['ROLE_ID_HERE'], log: { channel: 'CHANNEL_ID_HERE', diff --git a/bots/discord/package.json b/bots/discord/package.json index 6b562b2..077ac98 100644 --- a/bots/discord/package.json +++ b/bots/discord/package.json @@ -31,6 +31,7 @@ "@revanced/bot-api": "workspace:*", "@revanced/bot-shared": "workspace:*", "chalk": "^5.3.0", + "decancer": "^3.2.2", "discord.js": "^14.15.3", "drizzle-orm": "^0.31.2" }, diff --git a/bots/discord/src/commands/moderation/cure.ts b/bots/discord/src/commands/moderation/cure.ts new file mode 100644 index 0000000..e1895a6 --- /dev/null +++ b/bots/discord/src/commands/moderation/cure.ts @@ -0,0 +1,26 @@ +import { SlashCommandBuilder } from 'discord.js' + +import type { Command } from '..' + +import { config } from '$/context' +import { cureNickname } from '$/utils/discord/moderation' + +export default { + data: new SlashCommandBuilder() + .setName('cure') + .setDescription("Cure a member's nickname") + .addUserOption(option => option.setName('member').setRequired(true).setDescription('The member to cure')) + .toJSON(), + + memberRequirements: { + roles: config.moderation?.roles ?? [], + }, + + global: false, + + async execute(_, interaction) { + const user = interaction.options.getUser('user', true) + const member = await interaction.guild!.members.fetch(user.id) + await cureNickname(member) + }, +} satisfies Command diff --git a/bots/discord/src/events/discord/cureRequired.ts b/bots/discord/src/events/discord/cureRequired.ts new file mode 100644 index 0000000..c273a3a --- /dev/null +++ b/bots/discord/src/events/discord/cureRequired.ts @@ -0,0 +1,18 @@ +import { on } from '$/utils/discord/events' +import { cureNickname } from '$/utils/discord/moderation' + +on('guildMemberUpdate', async (_, oldMember, newMember) => { + if (newMember.user.bot) return + if (oldMember.nickname !== newMember.nickname) await cureNickname(newMember) +}) + +on('guildMemberAdd', (_, member) => { + if (member.user.bot) return + cureNickname(member) +}) + +on('messageCreate', async (_, msg) => { + if (msg.author.bot) return + if (!msg.member) return + await cureNickname(msg.member) +}) diff --git a/bots/discord/src/utils/discord/moderation.ts b/bots/discord/src/utils/discord/moderation.ts index d74563b..f306fea 100644 --- a/bots/discord/src/utils/discord/moderation.ts +++ b/bots/discord/src/utils/discord/moderation.ts @@ -1,5 +1,6 @@ import { config, logger } from '$/context' -import type { ChatInputCommandInteraction, EmbedBuilder, Guild, User } from 'discord.js' +import decancer from 'decancer' +import type { ChatInputCommandInteraction, EmbedBuilder, Guild, GuildMember, User } from 'discord.js' import { applyReferenceToModerationActionEmbed, createModerationActionEmbed } from './embeds' const PresetLogAction = { @@ -43,3 +44,16 @@ export const getLogChannel = async (guild: Guild) => { return } + +export const cureNickname = async (member: GuildMember) => { + if (!member.manageable) throw new Error('Member is not manageable') + const name = member.displayName + let cured = decancer(name) + .toString() + .replace(/[^a-zA-Z0-9]/g, '') + + if (!cured || !/^[a-zA-Z]/.test(cured)) cured = config.moderation?.cure?.defaultName ?? 'ReVanced member' + + await member.setNickname(cured, 'Nickname cured') + logger.log(`Cured nickname for ${member.user.tag} (${member.id}) from "${name}"`) +} diff --git a/bun.lockb b/bun.lockb index 72a95e3009309189b46a303c752d61e225883a99..6ee688bd593127a4800e3e919ceebc9f6aeee04a 100755 GIT binary patch delta 10666 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 DIK?sH delta 6927 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 X>;Rb|J3ap_qau?}^z=z*8J7V7Cr5-6