Development (#62)
- fixed /user tracks & /settings tracks. Added presets to /server
buttons
- prettiered
diff --git a/src/commands/server/buttons.ts b/src/commands/server/buttons.ts
index 74c255c..f07f3ce 100644
--- a/src/commands/server/buttons.ts
+++ b/src/commands/server/buttons.ts
@@ -20,6 +20,7 @@
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 @@
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<void> => {
const m = await interaction.reply({
embeds: LoadingEmbed,
@@ -58,7 +80,7 @@
});
let closed = false;
- const data: Data = {
+ let data: Data = {
buttons: [],
title: null,
description: null,
@@ -71,7 +93,7 @@
.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 @@
)
);
+ const presetSelect = new ActionRowBuilder<StringSelectMenuBuilder>().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<StringSelectMenuBuilder>().addComponents(
new StringSelectMenuBuilder()
.setCustomId("button")
@@ -141,7 +179,7 @@
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 @@
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..b79f54d 100644
--- a/src/commands/settings/tracks.ts
+++ b/src/commands/settings/tracks.ts
@@ -171,6 +171,7 @@
const isAdmin = (interaction.member!.permissions as PermissionsBitField).has("Administrator");
if (!current) {
current = _.cloneDeep(defaultTrackData);
+ current.name = "Default";
}
const roleSelect = new ActionRowBuilder<RoleSelectMenuBuilder>().addComponents(
@@ -348,16 +349,15 @@
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 @@
.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 @@
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 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..1ce05ee 100644
--- a/src/commands/user/track.ts
+++ b/src/commands/user/track.ts
@@ -97,7 +97,12 @@
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 +120,13 @@
.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 +193,7 @@
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..1b9d740 100644
--- a/src/reflex/scanners.ts
+++ b/src/reflex/scanners.ts
@@ -210,18 +210,14 @@
export async function doMemberChecks(member: Discord.GuildMember): Promise<void> {
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 @@
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,42 @@
`**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<ButtonBuilder>[] = [];
+
+ for (let i = 0; i < buttons.length; i += 5) {
+ components.push(
+ new ActionRowBuilder<ButtonBuilder>().addComponents(
+ buttons.slice(i, Math.min(buttons.length - 1, i + 5))
+ )
+ );
+ }
+
await channel.send({
embeds: [embed],
- components: [
- new ActionRowBuilder<ButtonBuilder>().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 @@
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 @@
if (id === undefined) {
return "";
} else if (id.toString().startsWith("a")) {
- return `<a:_:${id.toString().slice(1, id.toString().length)}>`;
+ return `<a:N:${id.toString().slice(1, id.toString().length)}>`;
}
- return `<:_:${id}>`;
+ return `<:N:${id}>`;
}
export default getEmojiByName;