From 764e6c2cd095a70a357dd98fd6a2b9ba58f1ec92 Mon Sep 17 00:00:00 2001 From: TheCodedProf Date: Sat, 11 Mar 2023 16:07:09 -0500 Subject: [PATCH 1/2] fixed /user tracks & /settings tracks. Added presets to /server buttons --- src/commands/server/buttons.ts | 50 ++++++++++++++++++++-- src/commands/settings/tracks.ts | 15 ++++--- src/commands/user/track.ts | 13 ++++-- src/reflex/scanners.ts | 76 ++++++++++++++++----------------- src/utils/getEmojiByName.ts | 9 ++-- 5 files changed, 106 insertions(+), 57 deletions(-) diff --git a/src/commands/server/buttons.ts b/src/commands/server/buttons.ts index 74c255c..c89e481 100644 --- a/src/commands/server/buttons.ts +++ b/src/commands/server/buttons.ts @@ -20,6 +20,7 @@ import EmojiEmbed from "../../utils/generateEmojiEmbed.js"; import lodash from "lodash"; import getEmojiByName from "../../utils/getEmojiByName.js"; import { modalInteractionCollector } from "../../utils/dualCollector.js"; +import _ from "lodash"; export const command = new SlashCommandSubcommandBuilder() .setName("buttons") @@ -50,6 +51,27 @@ const buttonNames: Record = { createticket: "Create Ticket" }; +const presetButtons = [ + { + title: "Verify", + description: "Click the button below to get verified in the server.", + buttons: ["verifybutton"], + color: "GREEN" + }, + { + title: "Get Roles", + description: "Click the button to choose which roles you would like in the server", + buttons: ["rolemenu"], + color: "BLUE" + }, + { + title: "Create Ticket", + description: "Click the button below to create a ticket", + buttons: ["createticket"], + color: "RED" + } +] + export const callback = async (interaction: CommandInteraction): Promise => { const m = await interaction.reply({ embeds: LoadingEmbed, @@ -58,7 +80,7 @@ export const callback = async (interaction: CommandInteraction): Promise = }); let closed = false; - const data: Data = { + let data: Data = { buttons: [], title: null, description: null, @@ -71,7 +93,7 @@ export const callback = async (interaction: CommandInteraction): Promise = .setCustomId("edit") .setLabel("Edit Embed") .setStyle(ButtonStyle.Secondary) - .setEmoji(getEmojiByName("ICONS.EDIT") as APIMessageComponentEmoji), + .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji), new ButtonBuilder() .setCustomId("send") .setLabel("Send") @@ -95,6 +117,22 @@ export const callback = async (interaction: CommandInteraction): Promise = ) ); + const presetSelect = new ActionRowBuilder().addComponents( + new StringSelectMenuBuilder() + .setCustomId("preset") + .setPlaceholder("Select a preset") + .setMaxValues(1) + .addOptions( + presetButtons.map((preset, i) => { + return new StringSelectMenuOptionBuilder() + .setLabel(preset.title) + .setValue(i.toString()) + .setDescription(preset.description) + .setEmoji(getEmojiByName("COLORS." + preset.color, "id") as APIMessageComponentEmoji) + }) + ) + ) + const buttonSelect = new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() .setCustomId("button") @@ -141,7 +179,7 @@ export const callback = async (interaction: CommandInteraction): Promise = await interaction.editReply({ embeds: [embed], - components: [colorSelect, buttonSelect, channelMenu, buttons] + components: [presetSelect, colorSelect, buttonSelect, channelMenu, buttons] }); let i: Discord.ButtonInteraction | Discord.ChannelSelectMenuInteraction | Discord.StringSelectMenuInteraction; @@ -257,6 +295,12 @@ export const callback = async (interaction: CommandInteraction): Promise = console.log(err); } switch (i.customId) { + case "preset": { + const chosen = presetButtons[parseInt(i.values[0]!)]!; + const newColor = colors[chosen.color!]! + data = _.assign(data, chosen, { color: newColor }); + break; + } case "color": { data.color = colors[i.values[0]!]!; break; diff --git a/src/commands/settings/tracks.ts b/src/commands/settings/tracks.ts index 60a7eae..c81eeed 100644 --- a/src/commands/settings/tracks.ts +++ b/src/commands/settings/tracks.ts @@ -171,6 +171,7 @@ const editTrack = async ( const isAdmin = (interaction.member!.permissions as PermissionsBitField).has("Administrator"); if (!current) { current = _.cloneDeep(defaultTrackData); + current.name = "Default"; } const roleSelect = new ActionRowBuilder().addComponents( @@ -348,16 +349,15 @@ const editTrack = async ( const callback = async (interaction: CommandInteraction) => { const m = await interaction.reply({ embeds: LoadingEmbed, fetchReply: true, ephemeral: true }); const config = await client.database.guilds.read(interaction.guild!.id); - const tracks: ObjectSchema[] = config.tracks; + const tracks: ObjectSchema[] = _.cloneDeep(config.tracks); const roles = await interaction.guild!.roles.fetch(); let page = 0; let closed = false; - let modified = false; do { const embed = new EmojiEmbed().setTitle("Track Settings").setEmoji("TRACKS.ICON").setStatus("Success"); - const noTracks = config.tracks.length === 0; + const noTracks = tracks.length === 0; let current: ObjectSchema; const pageSelect = new StringSelectMenuBuilder().setCustomId("page").setPlaceholder("Select a track to manage"); @@ -398,7 +398,7 @@ const callback = async (interaction: CommandInteraction) => { .setLabel("Save") .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji) .setStyle(ButtonStyle.Success) - .setDisabled(!modified) + .setDisabled(_.isEqual(tracks, config.tracks)) ); if (noTracks) { embed.setDescription( @@ -471,13 +471,15 @@ const callback = async (interaction: CommandInteraction) => { case "add": { const newPage = await editTrack(i, m, roles); if (_.isEqual(newPage, defaultTrackData)) break; - tracks.push(); + if(!newPage) break; + console.log(newPage) + tracks.push(newPage); + console.log(tracks) page = tracks.length - 1; break; } case "save": { await client.database.guilds.write(interaction.guild!.id, { tracks: tracks }); - modified = false; await client.memory.forceUpdate(interaction.guild!.id); break; } @@ -490,7 +492,6 @@ const callback = async (interaction: CommandInteraction) => { const edited = await editTrack(i, m, roles, current!); if (!edited) break; tracks[page] = edited; - modified = true; break; } case "delete": { diff --git a/src/commands/user/track.ts b/src/commands/user/track.ts index ee69868..92553ff 100644 --- a/src/commands/user/track.ts +++ b/src/commands/user/track.ts @@ -97,7 +97,8 @@ const callback = async (interaction: CommandInteraction): Promise => { selected.length } roles from this track. `; conflictDropdown = []; - if (roles.get(selected[0]!)!.position < memberRoles.highest.position || managed) { + const yourRoles = guild.members.cache.get(interaction.user.id)!.roles; + if ((roles.get(selected[0]!)!.position < yourRoles.highest.position && roles.get(selected[0]!)!.position < guild.members.me!.roles.highest.position!) || managed) { generated += "In order to promote or demote this user, you must select which role the member should keep."; selected.forEach((role) => { @@ -115,8 +116,13 @@ const callback = async (interaction: CommandInteraction): Promise => { .setPlaceholder("Select a role to keep") ]; } else { - generated += - "You don't have permission to manage one or more of the users roles, and therefore can't select one to keep."; + if(roles.get(selected[0]!)!.position >= yourRoles.highest.position) { + generated += + "You don't have permission to manage one or more of the user's roles, and therefore can't select one to keep."; + } else { + generated += + "I don't have permission to manage one or more of the user's roles, and therefore can't select one to keep." + } } } else { currentRoleIndex = selected.length === 0 ? -1 : data.track.indexOf(selected[0]!.toString()); @@ -183,6 +189,7 @@ const callback = async (interaction: CommandInteraction): Promise => { const rolesToRemove = selected.filter( (role) => role !== (component as StringSelectMenuInteraction).values[0] ); + await member.roles.remove(rolesToRemove); } else if (component.customId === "promote") { if ( diff --git a/src/reflex/scanners.ts b/src/reflex/scanners.ts index 80ca150..b6860d1 100644 --- a/src/reflex/scanners.ts +++ b/src/reflex/scanners.ts @@ -210,18 +210,14 @@ export async function TestImage(url: string): Promise { export async function doMemberChecks(member: Discord.GuildMember): Promise { if (member.user.bot) return; - console.log("Checking member " + member.user.tag); const guild = member.guild; const guildData = await client.database.guilds.read(guild.id); if (!guildData.logging.staff.channel) return; const [loose, strict] = [guildData.filters.wordFilter.words.loose, guildData.filters.wordFilter.words.strict]; - console.log(1, loose, strict); // Does the username contain filtered words const usernameCheck = TestString(member.user.username, loose, strict, guildData.filters.wordFilter.enabled); - console.log(2, usernameCheck); // Does the nickname contain filtered words const nicknameCheck = TestString(member.nickname ?? "", loose, strict, guildData.filters.wordFilter.enabled); - console.log(3, nicknameCheck); // Does the profile picture contain filtered words const avatarTextCheck = TestString( (await TestImage(member.displayAvatarURL({ forceStatic: true }))) ?? "", @@ -229,18 +225,14 @@ export async function doMemberChecks(member: Discord.GuildMember): Promise strict, guildData.filters.wordFilter.enabled ); - console.log(4, avatarTextCheck); // Is the profile picture NSFW const avatar = member.displayAvatarURL({ extension: "png", size: 1024, forceStatic: true }); const avatarCheck = guildData.filters.images.NSFW && (await NSFWCheck(avatar)); - console.log(5, avatarCheck); // Does the username contain an invite const inviteCheck = guildData.filters.invite.enabled && /discord\.gg\/[a-zA-Z0-9]+/gi.test(member.user.username); - console.log(6, inviteCheck); // Does the nickname contain an invite const nicknameInviteCheck = guildData.filters.invite.enabled && /discord\.gg\/[a-zA-Z0-9]+/gi.test(member.nickname ?? ""); - console.log(7, nicknameInviteCheck); if ( usernameCheck !== null || nicknameCheck !== null || @@ -282,39 +274,45 @@ export async function doMemberChecks(member: Discord.GuildMember): Promise `**Member:** ${member.user.username} (<@${member.user.id}>)\n\n` + infractions.map((element) => `${filter} ${element}`).join("\n") ); + const buttons = [ + new ButtonBuilder() + .setCustomId(`mod:warn:${member.user.id}`) + .setLabel("Warn") + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId(`mod:mute:${member.user.id}`) + .setLabel("Mute") + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId(`mod:kick:${member.user.id}`) + .setLabel("Kick") + .setStyle(ButtonStyle.Danger), + new ButtonBuilder() + .setCustomId(`mod:ban:${member.user.id}`) + .setLabel("Ban") + .setStyle(ButtonStyle.Danger) + ] + if (usernameCheck !== null || nicknameCheck !== null) buttons.concat([ + new ButtonBuilder() + .setCustomId(`mod:nickname:${member.user.id}`) + .setLabel("Change Name") + .setStyle(ButtonStyle.Primary) + ]) + if (avatarCheck || avatarTextCheck !== null) buttons.concat([ + new ButtonBuilder() + .setURL(member.displayAvatarURL()) + .setLabel("View Avatar") + .setStyle(ButtonStyle.Link) + ]) + const components: ActionRowBuilder[] = [] + + for (let i = 0; i < buttons.length; i += 5) { + components.push(new ActionRowBuilder().addComponents(buttons.slice(i, Math.min(buttons.length - 1, i + 5)))) + } + await channel.send({ embeds: [embed], - components: [ - new ActionRowBuilder().addComponents( - ...[ - new ButtonBuilder() - .setCustomId(`mod:warn:${member.user.id}`) - .setLabel("Warn") - .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId(`mod:mute:${member.user.id}`) - .setLabel("Mute") - .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId(`mod:kick:${member.user.id}`) - .setLabel("Kick") - .setStyle(ButtonStyle.Danger), - new ButtonBuilder() - .setCustomId(`mod:ban:${member.user.id}`) - .setLabel("Ban") - .setStyle(ButtonStyle.Danger) - ].concat( - usernameCheck !== null || nicknameCheck !== null - ? [ - new ButtonBuilder() - .setCustomId(`mod:nickname:${member.user.id}`) - .setLabel("Change Name") - .setStyle(ButtonStyle.Primary) - ] - : [] - ) - ) - ] + components: components }); } } diff --git a/src/utils/getEmojiByName.ts b/src/utils/getEmojiByName.ts index 99d1215..9bbf61f 100644 --- a/src/utils/getEmojiByName.ts +++ b/src/utils/getEmojiByName.ts @@ -1,7 +1,6 @@ import emojis from "../config/emojis.json" assert { type: "json" }; -import lodash from "lodash"; +import _ from "lodash"; -const isArray = lodash.isArray; interface EmojisIndex { [key: string]: string | EmojisIndex | EmojisIndex[]; } @@ -14,7 +13,7 @@ function getEmojiByName(name: string | null, format?: string): string { if (typeof id === "string" || id === undefined) { throw new Error(`Emoji ${name} not found`); } - if (isArray(id)) { + if (_.isArray(id)) { id = id[parseInt(part)]; } else { id = id[part]; @@ -34,9 +33,9 @@ function getEmojiFromId(id: string | undefined, format?: string): string { if (id === undefined) { return ""; } else if (id.toString().startsWith("a")) { - return ``; + return ``; } - return `<:_:${id}>`; + return `<:N:${id}>`; } export default getEmojiByName; From 1cfa1aeaf811b67e74840730154ba86aa2b51703 Mon Sep 17 00:00:00 2001 From: TheCodedProf Date: Sat, 11 Mar 2023 16:07:37 -0500 Subject: [PATCH 2/2] prettiered --- src/commands/server/buttons.ts | 8 +++--- src/commands/settings/tracks.ts | 6 ++--- src/commands/user/track.ts | 10 +++++--- src/reflex/scanners.ts | 43 +++++++++++++++------------------ 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/commands/server/buttons.ts b/src/commands/server/buttons.ts index c89e481..f07f3ce 100644 --- a/src/commands/server/buttons.ts +++ b/src/commands/server/buttons.ts @@ -70,7 +70,7 @@ const presetButtons = [ buttons: ["createticket"], color: "RED" } -] +]; export const callback = async (interaction: CommandInteraction): Promise => { const m = await interaction.reply({ @@ -128,10 +128,10 @@ export const callback = async (interaction: CommandInteraction): Promise = .setLabel(preset.title) .setValue(i.toString()) .setDescription(preset.description) - .setEmoji(getEmojiByName("COLORS." + preset.color, "id") as APIMessageComponentEmoji) + .setEmoji(getEmojiByName("COLORS." + preset.color, "id") as APIMessageComponentEmoji); }) ) - ) + ); const buttonSelect = new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() @@ -297,7 +297,7 @@ export const callback = async (interaction: CommandInteraction): Promise = switch (i.customId) { case "preset": { const chosen = presetButtons[parseInt(i.values[0]!)]!; - const newColor = colors[chosen.color!]! + const newColor = colors[chosen.color!]!; data = _.assign(data, chosen, { color: newColor }); break; } diff --git a/src/commands/settings/tracks.ts b/src/commands/settings/tracks.ts index c81eeed..b79f54d 100644 --- a/src/commands/settings/tracks.ts +++ b/src/commands/settings/tracks.ts @@ -471,10 +471,10 @@ const callback = async (interaction: CommandInteraction) => { case "add": { const newPage = await editTrack(i, m, roles); if (_.isEqual(newPage, defaultTrackData)) break; - if(!newPage) break; - console.log(newPage) + if (!newPage) break; + console.log(newPage); tracks.push(newPage); - console.log(tracks) + console.log(tracks); page = tracks.length - 1; break; } diff --git a/src/commands/user/track.ts b/src/commands/user/track.ts index 92553ff..1ce05ee 100644 --- a/src/commands/user/track.ts +++ b/src/commands/user/track.ts @@ -98,7 +98,11 @@ const callback = async (interaction: CommandInteraction): Promise => { } roles from this track. `; conflictDropdown = []; const yourRoles = guild.members.cache.get(interaction.user.id)!.roles; - if ((roles.get(selected[0]!)!.position < yourRoles.highest.position && roles.get(selected[0]!)!.position < guild.members.me!.roles.highest.position!) || managed) { + if ( + (roles.get(selected[0]!)!.position < yourRoles.highest.position && + roles.get(selected[0]!)!.position < guild.members.me!.roles.highest.position!) || + managed + ) { generated += "In order to promote or demote this user, you must select which role the member should keep."; selected.forEach((role) => { @@ -116,12 +120,12 @@ const callback = async (interaction: CommandInteraction): Promise => { .setPlaceholder("Select a role to keep") ]; } else { - if(roles.get(selected[0]!)!.position >= yourRoles.highest.position) { + if (roles.get(selected[0]!)!.position >= yourRoles.highest.position) { generated += "You don't have permission to manage one or more of the user's roles, and therefore can't select one to keep."; } else { generated += - "I don't have permission to manage one or more of the user's roles, and therefore can't select one to keep." + "I don't have permission to manage one or more of the user's roles, and therefore can't select one to keep."; } } } else { diff --git a/src/reflex/scanners.ts b/src/reflex/scanners.ts index b6860d1..1b9d740 100644 --- a/src/reflex/scanners.ts +++ b/src/reflex/scanners.ts @@ -283,31 +283,28 @@ export async function doMemberChecks(member: Discord.GuildMember): Promise .setCustomId(`mod:mute:${member.user.id}`) .setLabel("Mute") .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId(`mod:kick:${member.user.id}`) - .setLabel("Kick") - .setStyle(ButtonStyle.Danger), - new ButtonBuilder() - .setCustomId(`mod:ban:${member.user.id}`) - .setLabel("Ban") - .setStyle(ButtonStyle.Danger) - ] - if (usernameCheck !== null || nicknameCheck !== null) buttons.concat([ - new ButtonBuilder() - .setCustomId(`mod:nickname:${member.user.id}`) - .setLabel("Change Name") - .setStyle(ButtonStyle.Primary) - ]) - if (avatarCheck || avatarTextCheck !== null) buttons.concat([ - new ButtonBuilder() - .setURL(member.displayAvatarURL()) - .setLabel("View Avatar") - .setStyle(ButtonStyle.Link) - ]) - const components: ActionRowBuilder[] = [] + new ButtonBuilder().setCustomId(`mod:kick:${member.user.id}`).setLabel("Kick").setStyle(ButtonStyle.Danger), + new ButtonBuilder().setCustomId(`mod:ban:${member.user.id}`).setLabel("Ban").setStyle(ButtonStyle.Danger) + ]; + if (usernameCheck !== null || nicknameCheck !== null) + buttons.concat([ + new ButtonBuilder() + .setCustomId(`mod:nickname:${member.user.id}`) + .setLabel("Change Name") + .setStyle(ButtonStyle.Primary) + ]); + if (avatarCheck || avatarTextCheck !== null) + buttons.concat([ + new ButtonBuilder().setURL(member.displayAvatarURL()).setLabel("View Avatar").setStyle(ButtonStyle.Link) + ]); + const components: ActionRowBuilder[] = []; for (let i = 0; i < buttons.length; i += 5) { - components.push(new ActionRowBuilder().addComponents(buttons.slice(i, Math.min(buttons.length - 1, i + 5)))) + components.push( + new ActionRowBuilder().addComponents( + buttons.slice(i, Math.min(buttons.length - 1, i + 5)) + ) + ); } await channel.send({