diff --git a/.gitignore b/.gitignore index db17304..d731f0c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,4 @@ src/utils/temp/*.jpeg src/utils/temp/*.jpg ClicksMigratingProblems/oldData/ -ClicksMigratingProblems/oldData copy/ +ClicksMigratingProblems/oldData copy/ \ No newline at end of file diff --git a/src/Unfinished/categorisationTest.ts b/src/Unfinished/categorizationTest.ts similarity index 72% rename from src/Unfinished/categorisationTest.ts rename to src/Unfinished/categorizationTest.ts index dc38dfe..cbd9924 100644 --- a/src/Unfinished/categorisationTest.ts +++ b/src/Unfinished/categorizationTest.ts @@ -1,28 +1,30 @@ import { LoadingEmbed } from "../utils/defaults.js"; -import { CommandInteraction, GuildChannel, ActionRowBuilder, ButtonBuilder, SelectMenuBuilder, ButtonStyle } from "discord.js"; +import { CommandInteraction, GuildChannel, ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, StringSelectMenuBuilder, APIMessageComponentEmoji } from "discord.js"; import { SlashCommandBuilder } from "@discordjs/builders"; import EmojiEmbed from "../utils/generateEmojiEmbed.js"; import client from "../utils/client.js"; import addPlural from "../utils/plurals.js"; import getEmojiByName from "../utils/getEmojiByName.js"; -const command = new SlashCommandBuilder().setName("categorise").setDescription("Categorises your servers channels"); +const command = new SlashCommandBuilder().setName("categorize").setDescription("Categorizes your servers channels"); const callback = async (interaction: CommandInteraction): Promise => { - const channels = interaction.guild.channels.cache.filter((c) => c.type !== "GUILD_CATEGORY"); - const categorised = {}; + const channels = interaction.guild!.channels.cache.filter((c) => c.type !== ChannelType.GuildCategory); + const categorized = {}; await interaction.reply({ embeds: LoadingEmbed, ephemeral: true }); const predicted = {}; const types = { - general: ["general", "muted", "main", "topic", "discuss"], + important: ["rule", "announcement", "alert", "info"], + general: ["general", "main", "topic", "discuss"], commands: ["bot", "command", "music"], - images: ["pic", "selfies", "image"], - nsfw: ["porn", "nsfw", "sex"], - links: ["links"], - advertising: ["ads", "advert", "server", "partner"], - staff: ["staff", "mod", "admin"], - spam: ["spam"], - other: ["random"] + images: ["pic", "selfies", "image", "gallery", "meme", "media"], + nsfw: ["porn", "nsfw", "sex", "lewd", "fetish"], + links: ["link"], + advertising: ["ads", "advert", "partner", "bump"], + staff: ["staff", "mod", "admin", "helper", "train"], + spam: ["spam", "count"], + logs: ["log"], + other: ["random", "starboard"], }; for (const c of channels.values()) { for (const type in types) { @@ -38,14 +40,14 @@ const callback = async (interaction: CommandInteraction): Promise => { for (const c of channels) { // convert channel to a channel if its a string let channel: string | GuildChannel; - if (typeof c === "string") channel = interaction.guild.channels.cache.get(channel as string).id; + if (typeof c === "string") channel = interaction.guild!.channels.cache.get(c as string)!.id; else channel = (c[0] as unknown as GuildChannel).id; console.log(channel); if (!predicted[channel]) predicted[channel] = []; m = await interaction.editReply({ embeds: [ new EmojiEmbed() - .setTitle("Categorise") + .setTitle("Categorize") .setDescription( `Select all types that apply to <#${channel}>.\n\n` + `${addPlural(predicted[channel].length, "Suggestion")}: ${predicted[channel].join(", ")}` @@ -54,8 +56,8 @@ const callback = async (interaction: CommandInteraction): Promise => { .setStatus("Success") ], components: [ - new ActionRowBuilder().addComponents([ - new SelectMenuBuilder() + new ActionRowBuilder().addComponents([ + new StringSelectMenuBuilder() .setCustomId("selected") .setMaxValues(Object.keys(types).length) .setMinValues(1) @@ -67,18 +69,18 @@ const callback = async (interaction: CommandInteraction): Promise => { })) ) ]), - new ActionRowBuilder().addComponents([ + new ActionRowBuilder().addComponents([ new ButtonBuilder() .setLabel("Accept Suggestion") .setCustomId("accept") .setStyle(ButtonStyle.Success) .setDisabled(predicted[channel].length === 0) - .setEmoji(client.emojis.cache.get(getEmojiByName("ICONS.TICK", "id"))), + .setEmoji(client.emojis.cache.get(getEmojiByName("ICONS.TICK", "id")) as APIMessageComponentEmoji), new ButtonBuilder() .setLabel('Use "Other"') .setCustomId("reject") .setStyle(ButtonStyle.Secondary) - .setEmoji(client.emojis.cache.get(getEmojiByName("ICONS.CROSS", "id"))) + .setEmoji(client.emojis.cache.get(getEmojiByName("ICONS.CROSS", "id")) as APIMessageComponentEmoji) ]) ] }); @@ -86,13 +88,13 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id} }); } catch (e) { return await interaction.editReply({ embeds: [ new EmojiEmbed() - .setTitle("Categorise") + .setTitle("Categorize") .setEmoji("CHANNEL.CATEGORY.DELETE") .setStatus("Danger") .setDescription( @@ -105,7 +107,7 @@ const callback = async (interaction: CommandInteraction): Promise => { ] }); } - i.deferUpdate(); + await i.deferUpdate(); let selected; if (i.customId === "select") { selected = i.values; @@ -116,9 +118,9 @@ const callback = async (interaction: CommandInteraction): Promise => { if (i.customId === "reject") { selected = ["other"]; } - categorised[channel] = selected; + categorized[channel] = selected; } - console.log(categorised); + console.log(categorized); }; const check = () => { diff --git a/src/actions/roleMenu.ts b/src/actions/roleMenu.ts index 31a9fcf..732c94d 100644 --- a/src/actions/roleMenu.ts +++ b/src/actions/roleMenu.ts @@ -124,7 +124,7 @@ export async function callback(interaction: CommandInteraction | ButtonInteracti try { component = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id} }); } catch (e) { return; @@ -199,7 +199,7 @@ export async function callback(interaction: CommandInteraction | ButtonInteracti try { component = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id} }); } catch (e) { return; diff --git a/src/actions/tickets/create.ts b/src/actions/tickets/create.ts index 3c2dd2c..8a021d4 100644 --- a/src/actions/tickets/create.ts +++ b/src/actions/tickets/create.ts @@ -106,7 +106,7 @@ export default async function (interaction: CommandInteraction | ButtonInteracti try { component = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { return; diff --git a/src/commands/mod/about.ts b/src/commands/mod/about.ts index 1f53afb..4277918 100644 --- a/src/commands/mod/about.ts +++ b/src/commands/mod/about.ts @@ -10,7 +10,6 @@ import Discord, { MessageComponentInteraction, ModalSubmitInteraction, ButtonStyle, - StringSelectMenuInteraction, TextInputStyle, APIMessageComponentEmoji, } from "discord.js"; @@ -253,7 +252,7 @@ async function showHistory(member: Discord.GuildMember, interaction: CommandInte try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { interaction.editReply({ @@ -269,7 +268,7 @@ async function showHistory(member: Discord.GuildMember, interaction: CommandInte timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if (i.customId === "filter" && i.isStringSelectMenu()) { filteredTypes = i.values; pageIndex = null; @@ -359,7 +358,7 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; @@ -423,7 +422,7 @@ const callback = async (interaction: CommandInteraction): Promise => { continue; } } else if (i.customId === "history") { - i.deferUpdate(); + await i.deferUpdate(); if (!(await showHistory(member, interaction))) return; } } diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts index 86291e5..0e080c3 100644 --- a/src/commands/mod/mute.ts +++ b/src/commands/mod/mute.ts @@ -103,7 +103,7 @@ const callback = async (interaction: CommandInteraction): Promise => { let component; try { component = await m.awaitMessageComponent({ - filter: (m) => m.user.id === interaction.user.id, + filter: (i) => {return i.user.id === interaction.user.id && i.id === m.id}, time: 300000 }); } catch { diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts index e6b4670..cc72efb 100644 --- a/src/commands/mod/purge.ts +++ b/src/commands/mod/purge.ts @@ -94,7 +94,7 @@ const callback = async (interaction: CommandInteraction): Promise => { let component; try { component = m.awaitMessageComponent({ - filter: (m) => m.user.id === interaction.user.id && m.channel!.id === interaction.channel!.id, + filter: (i) => i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.id === m.id, time: 300000 }); } catch (e) { @@ -188,7 +188,7 @@ const callback = async (interaction: CommandInteraction): Promise => { let component; try { component = await m.awaitMessageComponent({ - filter: (m) => m.user.id === interaction.user.id && m.channel!.id === interaction.channel!.id, + filter: (i) => i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.id === m.id, time: 300000 }); } catch { @@ -358,7 +358,7 @@ const callback = async (interaction: CommandInteraction): Promise => { let component; try { component = await m.awaitMessageComponent({ - filter: (m) => m.user.id === interaction.user.id && m.channel!.id === interaction.channel!.id, + filter: (i) => i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.id === m.id, time: 300000 }); } catch { diff --git a/src/commands/mod/viewas.ts b/src/commands/mod/viewas.ts index 4b6899c..f01834c 100644 --- a/src/commands/mod/viewas.ts +++ b/src/commands/mod/viewas.ts @@ -157,12 +157,12 @@ const callback = async (interaction: CommandInteraction): Promise => { }); let i; try { - i = await m.awaitMessageComponent({filter: (i) => i.user.id === interaction.user.id, time: 30000}); + i = await m.awaitMessageComponent({filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id, time: 30000}); } catch (e) { closed = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if (i.customId === "back") page--; else if (i.customId === "right") page++; else if (i.customId === "category" && i.isStringSelectMenu()) page = parseInt(i.values[0]!); diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts index 38aa4ad..8f67477 100644 --- a/src/commands/mod/warn.ts +++ b/src/commands/mod/warn.ts @@ -186,7 +186,7 @@ const callback = async (interaction: CommandInteraction): Promise => { let component; try { component = await m.awaitMessageComponent({ - filter: (m) => m.user.id === interaction.user.id && m.channel!.id === interaction.channel!.id, + filter: (i) => i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.id === m.id, time: 300000 }); } catch (e) { diff --git a/src/commands/nucleus/premium.ts b/src/commands/nucleus/premium.ts index 745f167..2b969b9 100644 --- a/src/commands/nucleus/premium.ts +++ b/src/commands/nucleus/premium.ts @@ -1,26 +1,75 @@ -import type { CommandInteraction } from "discord.js"; +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction } from "discord.js"; import type { SlashCommandSubcommandBuilder } from "@discordjs/builders"; import EmojiEmbed from "../../utils/generateEmojiEmbed.js"; +import client from "../../utils/client.js"; +import { LoadingEmbed } from "../../utils/defaults.js"; const command = (builder: SlashCommandSubcommandBuilder) => builder.setName("premium").setDescription("Information about Nucleus Premium"); const callback = async (interaction: CommandInteraction): Promise => { - interaction.reply({ - embeds: [ + await interaction.reply({embeds: LoadingEmbed, ephemeral: true}) + const member = await (await interaction.client.guilds.fetch("684492926528651336")).members.fetch(interaction.user.id) + const firstDescription = "\n\nPremium allows your server to get access to extra features, for a fixed price per month.\nThis includes:\n" + + "- Attachment logs - Stores attachments so they can be viewed after a message is deleted.\n" + + "- Ticket Transcripts - Gives a link to view the history of a ticket after it has been closed.\n" + if(!member) { + interaction.editReply({ embeds: [ new EmojiEmbed() .setTitle("Premium") .setDescription( - "*Nucleus Premium is currently not available.*\n\n" + - "Premium allows your server to get access to extra features, for a fixed price per month.\nThis includes:\n" + - "- Attachment logs - Stores attachments so they can be viewed after a message is deleted.\n" + - "- Ticket Transcripts - Gives a link to view the history of a ticket after it has been closed.\n" + `*You are not currently in the Clicks Server. To gain access to premium please join.*` + firstDescription ) .setEmoji("NUCLEUS.LOGO") .setStatus("Danger") - ], - ephemeral: true - }); + ], components: [new ActionRowBuilder().addComponents(new ButtonBuilder().setStyle(ButtonStyle.Link).setLabel("Join").setURL("https://discord.gg/bPaNnxe"))] }); + return; + } + const dbMember = await client.database.premium.fetchTotal(interaction.user.id) + let premium; + let count = 0; + if (member.roles.cache.has("1066468879309750313")) { + premium = `You have Infinite Premium! You have been gifted this by the developers as a thank you. You can give premium to any and all servers you are in.`; + count = 200; + } else if (member.roles.cache.has("1066465491713003520")) { + premium = `You have Premium tier 1! You can give premium to ${1 - dbMember}.`; + count = 1; + } else if (member.roles.cache.has("1066439526496604194")) { + premium = `You have Premium tier 2! You can give premium to ${3 - dbMember}.`; + count = 3; + } else if (member.roles.cache.has("1066464134322978912")) { + premium = `You have Premium Mod! You already give premium to all servers you have a "manage" permission in.` + count = 3; + } + + let closed = false; + do { + interaction.editReply({ + embeds: [ + new EmojiEmbed() + .setTitle("Premium") + .setDescription( + premium + firstDescription + ) + .setEmoji("NUCLEUS.LOGO") + .setStatus("Danger") + ], + components: [ + new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setStyle(ButtonStyle.Primary) + .setLabel("Activate Premium here") + .setCustomId("premiumActivate") + .setDisabled(count <= 0) + ) + ] + }); + + const filter = (i: any) => i.customId === "premiumActivate" && i.user.id === interaction.user.id; + const collector = interaction.channel?.awaitMessageComponent({ filter, time: 60000 }); + + } while (closed); }; const check = () => { diff --git a/src/commands/privacy.ts b/src/commands/privacy.ts index 9100302..6113cc3 100644 --- a/src/commands/privacy.ts +++ b/src/commands/privacy.ts @@ -150,14 +150,14 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; continue; } nextFooter = null; - i.deferUpdate(); + await i.deferUpdate(); if (i.customId === "left") { if (page > 0) page--; selectPaneOpen = false; @@ -180,11 +180,12 @@ const callback = async (interaction: CommandInteraction): Promise => { .setColor("Danger") .send(true); if (confirmation.cancelled) { - break; + continue; } if (confirmation.success) { client.database.guilds.delete(interaction.guild!.id); client.database.history.delete(interaction.guild!.id); + client.database.notes.delete(interaction.guild!.id); nextFooter = "All data cleared"; continue; } else { diff --git a/src/commands/settings/commands.ts b/src/commands/settings/commands.ts index 5cafcc5..f3a3538 100644 --- a/src/commands/settings/commands.ts +++ b/src/commands/settings/commands.ts @@ -1,5 +1,5 @@ import { LoadingEmbed } from "../../utils/defaults.js"; -import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, Role, ButtonStyle, ButtonComponent, TextInputBuilder } from "discord.js"; +import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, Role, ButtonStyle, ButtonComponent, TextInputBuilder, Message } from "discord.js"; import EmojiEmbed from "../../utils/generateEmojiEmbed.js"; import getEmojiByName from "../../utils/getEmojiByName.js"; import type { SlashCommandSubcommandBuilder } from "@discordjs/builders"; @@ -20,7 +20,7 @@ const callback = async (interaction: CommandInteraction): Promise => { ephemeral: true, fetchReply: true }); - let m; + let m: Message; let clicked = ""; if (interaction.options.get("role")) { const confirmation = await new confirmationMessage(interaction) @@ -110,7 +110,7 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; @@ -119,7 +119,7 @@ const callback = async (interaction: CommandInteraction): Promise => { type modIDs = "mute" | "kick" | "ban" | "softban" | "warn" | "role"; let chosen = moderation[i.customId as modIDs]; if ((i.component as ButtonComponent).customId === "clearMuteRole") { - i.deferUpdate(); + await i.deferUpdate(); if (clicked === "clearMuteRole") { await client.database.guilds.write(interaction.guild!.id, { "moderation.mute.role": null diff --git a/src/commands/settings/logs/attachment.ts b/src/commands/settings/logs/attachment.ts index e9e8dce..f0ecbe9 100644 --- a/src/commands/settings/logs/attachment.ts +++ b/src/commands/settings/logs/attachment.ts @@ -150,13 +150,13 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if ((i.component as unknown as ButtonInteraction).customId === "clear") { clicks ++; if (clicks === 2) { diff --git a/src/commands/settings/logs/channel.ts b/src/commands/settings/logs/channel.ts index 0852e67..b9b593c 100644 --- a/src/commands/settings/logs/channel.ts +++ b/src/commands/settings/logs/channel.ts @@ -143,13 +143,13 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }) as ButtonInteraction; } catch (e) { timedOut = true; } i = i! - i.deferUpdate(); + await i.deferUpdate(); if ((i.component as ButtonComponent).customId === "clear") { clicks ++; if (clicks === 2) { diff --git a/src/commands/settings/logs/events.ts b/src/commands/settings/logs/events.ts index 7332c7b..40b4607 100644 --- a/src/commands/settings/logs/events.ts +++ b/src/commands/settings/logs/events.ts @@ -1,5 +1,5 @@ import { LoadingEmbed } from "../../../utils/defaults.js"; -import Discord, { CommandInteraction, Message, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, EmbedBuilder, StringSelectMenuInteraction } from "discord.js"; +import Discord, { CommandInteraction, Message, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, EmbedBuilder } from "discord.js"; import { SlashCommandSubcommandBuilder, StringSelectMenuOptionBuilder } from "@discordjs/builders"; import EmojiEmbed from "../../../utils/generateEmojiEmbed.js"; import client from "../../../utils/client.js"; @@ -76,13 +76,13 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if (i.isStringSelectMenu() && i.customId === "logs") { const selected = i.values; const newLogs = toHexInteger(selected.map((e: string) => Object.keys(logs)[parseInt(e)]!)); diff --git a/src/commands/settings/logs/staff.ts b/src/commands/settings/logs/staff.ts index d6379f0..bba6441 100644 --- a/src/commands/settings/logs/staff.ts +++ b/src/commands/settings/logs/staff.ts @@ -147,13 +147,13 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if ((i.component as ButtonComponent).customId === "clear") { clicks ++; if (clicks === 2) { diff --git a/src/commands/settings/oldStats.ts b/src/commands/settings/oldStats.ts index 475b5d3..457e705 100644 --- a/src/commands/settings/oldStats.ts +++ b/src/commands/settings/oldStats.ts @@ -139,7 +139,7 @@ const callback = async (interaction: CommandInteraction) => { }); let i: MessageComponentInteraction; try { - i = await m.awaitMessageComponent({ filter: (i) => i.user.id === interaction.user.id, time: 30000 }); + i = await m.awaitMessageComponent({ filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id, time: 30000 }); } catch (e) { closed = true; continue; @@ -148,7 +148,7 @@ const callback = async (interaction: CommandInteraction) => { switch(i.customId) { case "page": page = Object.keys(stats).indexOf(i.values[0]!); - i.deferUpdate(); + await i.deferUpdate(); break; case "action": if(!changes[currentID]) changes[currentID] = {}; @@ -243,17 +243,17 @@ const callback = async (interaction: CommandInteraction) => { break; case "delete": changes[currentID] = {}; - i.deferUpdate(); + await i.deferUpdate(); break; case "toggleEnabled": changes[currentID]!.enabled = !stats[currentID]!.enabled; - i.deferUpdate(); + await i.deferUpdate(); break; } break; } } else if (i.isButton()) { - i.deferUpdate(); + await i.deferUpdate(); switch(i.customId) { case "back": page--; diff --git a/src/commands/settings/stats.ts b/src/commands/settings/stats.ts index 7dd9cf4..2fd947b 100644 --- a/src/commands/settings/stats.ts +++ b/src/commands/settings/stats.ts @@ -73,23 +73,7 @@ const showModal = async (interaction: MessageComponentInteraction, current: { en type ObjectSchema = Record -/* -let out: Discord.ModalSubmitInteraction | null = null; -try { - out = await modalInteractionCollector( - m, - (m) => m.channel!.id === interaction.channel!.id, - (_) => true - ) as Discord.ModalSubmitInteraction | null; -} catch (e) { - continue; -} -if (!out) continue -out = out!; -if (!out.fields) continue; -if (out.isButton()) continue; -const name = out.fields.getTextInputValue("text") -*/ + const addStatsChannel = async (interaction: CommandInteraction, m: Message, currentObject: ObjectSchema): Promise => { let closed = false; @@ -99,7 +83,7 @@ const addStatsChannel = async (interaction: CommandInteraction, m: Message, curr let newChannelName: string = "{memberCount:all}-members"; let newChannelEnabled: boolean = true; do { - await interaction.editReply({ + m = await interaction.editReply({ embeds: [new EmojiEmbed() .setTitle("Stats Channel") .setDescription( @@ -114,6 +98,7 @@ const addStatsChannel = async (interaction: CommandInteraction, m: Message, curr new ActionRowBuilder().addComponents( new ChannelSelectMenuBuilder() .setCustomId("channel") + .setPlaceholder("Select a channel to use") ), new ActionRowBuilder().addComponents( new ButtonBuilder() @@ -141,7 +126,9 @@ const addStatsChannel = async (interaction: CommandInteraction, m: Message, curr }); let i: ButtonInteraction | ChannelSelectMenuInteraction; try { - i = await m.awaitMessageComponent({ time: 300000, filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }}) as ButtonInteraction | ChannelSelectMenuInteraction; + i = await m.awaitMessageComponent({ time: 300000, filter: (i) => { + return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id; + }}) as ButtonInteraction | ChannelSelectMenuInteraction; } catch (e) { closed = true; cancelled = true; @@ -150,11 +137,11 @@ const addStatsChannel = async (interaction: CommandInteraction, m: Message, curr if (i.isButton()) { switch (i.customId) { case "back": - if(!i.deferred) await i.deferUpdate(); + await i.deferUpdate(); closed = true; break; case "save": - if(!i.deferred) await i.deferUpdate(); //I'm lost... + await i.deferUpdate(); if (newChannel) { currentObject[newChannel] = { name: newChannelName, @@ -185,8 +172,8 @@ const addStatsChannel = async (interaction: CommandInteraction, m: Message, curr const out = await modalInteractionCollector( m, - (m) => m.channel!.id === interaction.channel!.id, - (_) => true + (m) => m.channel!.id === interaction.channel!.id && m.user!.id === interaction.user!.id, + (i) => i.channel!.id === interaction.channel!.id && i.user!.id === interaction.user!.id && i.message!.id === m.id ) as Discord.ModalSubmitInteraction | null; if (!out) continue; if (!out.fields) continue; @@ -194,12 +181,12 @@ const addStatsChannel = async (interaction: CommandInteraction, m: Message, curr newChannelName = out.fields.getTextInputValue("text"); break; case "toggleEnabled": - if(!i.deferred) await i.deferUpdate(); + await i.deferUpdate(); newChannelEnabled = !newChannelEnabled; break; } } else { - if(!i.deferred) await i.deferUpdate(); + await i.deferUpdate(); if (i.customId === "channel") { newChannel = i.values[0]; } @@ -207,7 +194,7 @@ const addStatsChannel = async (interaction: CommandInteraction, m: Message, curr } while (!closed) if (cancelled) return originalObject; if (!(newChannel && newChannelName && newChannelEnabled)) return originalObject; - return currentObject; // check 157 + return currentObject; } const callback = async (interaction: CommandInteraction) => { if (!interaction.guild) return; @@ -322,6 +309,7 @@ const callback = async (interaction: CommandInteraction) => { if(i.isStringSelectMenu()) { switch(i.customId) { case "page": + await i.deferUpdate(); page = Object.keys(currentObject).indexOf(i.values[0]!); break; case "action": @@ -364,14 +352,15 @@ const callback = async (interaction: CommandInteraction) => { break; } case "toggleEnabled": { - i.deferUpdate(); + await i.deferUpdate(); currentObject[Object.keys(currentObject)[page]!]!.enabled = !currentObject[Object.keys(currentObject)[page]!]!.enabled; modified = true; break; } case "delete": { - i.deferUpdate(); + await i.deferUpdate(); delete currentObject[Object.keys(currentObject)[page]!]; + page = Math.min(page, Object.keys(currentObject).length - 1); modified = true; break; } @@ -379,7 +368,7 @@ const callback = async (interaction: CommandInteraction) => { break; } } else { - i.deferUpdate(); + await i.deferUpdate(); switch(i.customId) { case "back": page--; @@ -389,6 +378,7 @@ const callback = async (interaction: CommandInteraction) => { break; case "add": currentObject = await addStatsChannel(interaction, m, currentObject); + page = Object.keys(currentObject).length - 1; break; case "save": client.database.guilds.write(interaction.guild.id, {stats: currentObject}); diff --git a/src/commands/settings/tickets.ts b/src/commands/settings/tickets.ts index 8f9f688..6c74939 100644 --- a/src/commands/settings/tickets.ts +++ b/src/commands/settings/tickets.ts @@ -279,13 +279,13 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if ((i.component as ButtonComponent).customId === "clearCategory") { if (lastClicked === "cat") { lastClicked = ""; @@ -382,14 +382,14 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { innerTimedOut = true; continue; } if (i.isStringSelectMenu() && i.customId === "template") { - i.deferUpdate(); + await i.deferUpdate(); await interaction.channel!.send({ embeds: [ new EmojiEmbed() @@ -413,7 +413,7 @@ const callback = async (interaction: CommandInteraction): Promise => { templateSelected = true; continue; } else if ((i.component as ButtonComponent).customId === "blank") { - i.deferUpdate(); + await i.deferUpdate(); await interaction.channel!.send({ components: [ new ActionRowBuilder().addComponents([ @@ -635,21 +635,21 @@ async function manageTypes(interaction: CommandInteraction, data: GuildConfig["t try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; continue; } if (i.isStringSelectMenu() && i.customId === "types") { - i.deferUpdate(); + await i.deferUpdate(); const types = toHexInteger(i.values, ticketTypes); await client.database.guilds.write(interaction.guild!.id, { "tickets.types": types }); data.types = types; } else if (i.isStringSelectMenu() && i.customId === "removeTypes") { - i.deferUpdate(); + await i.deferUpdate(); const types = i.values; let customTypes = data.customTypes; if (customTypes) { @@ -723,15 +723,15 @@ async function manageTypes(interaction: CommandInteraction, data: GuildConfig["t data.customTypes.push(toAdd); } } else if ((i.component as ButtonComponent).customId === "switchToDefault") { - i.deferUpdate(); + await i.deferUpdate(); await client.database.guilds.write(interaction.guild!.id, { "tickets.useCustom": false }, []); data.useCustom = false; } else if ((i.component as ButtonComponent).customId === "switchToCustom") { - i.deferUpdate(); + await i.deferUpdate(); await client.database.guilds.write(interaction.guild!.id, { "tickets.useCustom": true }, []); data.useCustom = true; } else { - i.deferUpdate(); + await i.deferUpdate(); backPressed = true; } } diff --git a/src/commands/settings/verify.ts b/src/commands/settings/verify.ts index d3971a8..23fc99b 100644 --- a/src/commands/settings/verify.ts +++ b/src/commands/settings/verify.ts @@ -160,13 +160,13 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if ((i.component as ButtonComponent).customId === "clear") { clicks ++; if (clicks === 2) { @@ -249,14 +249,14 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { innerTimedOut = true; continue; } if (i.isStringSelectMenu() && i.customId === "template") { - i.deferUpdate(); + await i.deferUpdate(); await interaction.channel!.send({ embeds: [ new EmojiEmbed() @@ -280,7 +280,7 @@ const callback = async (interaction: CommandInteraction): Promise => { templateSelected = true; continue; } else if ((i.component as ButtonComponent).customId === "blank") { - i.deferUpdate(); + await i.deferUpdate(); await interaction.channel!.send({ components: [ new ActionRowBuilder().addComponents([ @@ -375,7 +375,7 @@ const callback = async (interaction: CommandInteraction): Promise => { } } } else { - i.deferUpdate(); + await i.deferUpdate(); break; } } diff --git a/src/commands/settings/welcome.ts b/src/commands/settings/welcome.ts index abedec5..fcd0f76 100644 --- a/src/commands/settings/welcome.ts +++ b/src/commands/settings/welcome.ts @@ -245,13 +245,13 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if (i.customId == "clear-message") { if (lastClicked == "clear-message") { await client.database.guilds.write(interaction.guild!.id, { diff --git a/src/commands/tags/list.ts b/src/commands/tags/list.ts index f0563c7..80ee127 100644 --- a/src/commands/tags/list.ts +++ b/src/commands/tags/list.ts @@ -139,13 +139,13 @@ const callback = async (interaction: CommandInteraction): Promise => { try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if ((i.component as ButtonComponent).customId === "left") { if (page > 0) page--; selectPaneOpen = false; diff --git a/src/commands/user/about.ts b/src/commands/user/about.ts index e43ecb7..b2a3db8 100644 --- a/src/commands/user/about.ts +++ b/src/commands/user/about.ts @@ -258,13 +258,13 @@ async function userAbout(guild: Discord.Guild, member: Discord.GuildMember, inte try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch { timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if (i.customId === "left") { if (page > 0) page--; selectPaneOpen = false; diff --git a/src/commands/user/track.ts b/src/commands/user/track.ts index b7b239b..7160436 100644 --- a/src/commands/user/track.ts +++ b/src/commands/user/track.ts @@ -169,7 +169,7 @@ const callback = async (interaction: CommandInteraction): Promise => { try { component = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); } catch (e) { timedOut = true; diff --git a/src/context/messages/purgeto.ts b/src/context/messages/purgeto.ts index df52e0b..8e2cf92 100644 --- a/src/context/messages/purgeto.ts +++ b/src/context/messages/purgeto.ts @@ -13,7 +13,7 @@ const command = new ContextMenuCommandBuilder() async function waitForButton(m: Discord.Message, member: Discord.GuildMember): Promise { let component; try { - component = m.awaitMessageComponent({ time: 200000, filter: (i) => i.user.id === member.id && i.channel!.id === m.channel.id }); + component = m.awaitMessageComponent({ time: 200000, filter: (i) => i.user.id === member.id && i.channel!.id === m.channel.id && i.message.id === m.id }); } catch (e) { return false; } @@ -211,7 +211,7 @@ const callback = async (interaction: MessageContextMenuCommandInteraction) => { let component; try { component = await m.awaitMessageComponent({ - filter: (m) => m.user.id === interaction.user.id && m.channel!.id === interaction.channel!.id, + filter: (i) => i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.id === m.id, time: 300000 }); } catch { diff --git a/src/events/messageEdit.ts b/src/events/messageEdit.ts index 20624fe..caa00f6 100644 --- a/src/events/messageEdit.ts +++ b/src/events/messageEdit.ts @@ -18,7 +18,7 @@ export async function callback(client: NucleusClient, oldMessage: Message, newMe if (config) { attachmentJump = ` [[View attachments]](${config})`; } - if (newContent === oldContent && newMessage.attachments.size === oldMessage.attachments.size) { + if (newMessage.crosspostable !== oldMessage.crosspostable) { if (!replyTo) { const data = { meta: { diff --git a/src/events/roleUpdate.ts b/src/events/roleUpdate.ts index 924ec3e..a728b79 100644 --- a/src/events/roleUpdate.ts +++ b/src/events/roleUpdate.ts @@ -8,7 +8,8 @@ export async function callback(client: NucleusClient, oldRole: Role, newRole: Ro const { getAuditLog, log, NucleusColors, entry, renderDelta, renderUser, renderRole } = client.logger; const auditLog = (await getAuditLog(newRole.guild as Guild, AuditLogEvent.RoleUpdate)) - .filter((entry: GuildAuditLogsEntry) => (entry.target as Role)!.id === newRole.id)[0]!; + .filter((entry: GuildAuditLogsEntry) => (entry.target as Role)!.id === newRole.id)[0]; + if (!auditLog) return; if (auditLog.executor!.id === client.user!.id) return; const changes: Record> = { diff --git a/src/premium/createTranscript.ts b/src/premium/createTranscript.ts index 04fdc08..754a06b 100644 --- a/src/premium/createTranscript.ts +++ b/src/premium/createTranscript.ts @@ -115,9 +115,9 @@ export default async function (interaction: CommandInteraction | MessageComponen try { i = await m.awaitMessageComponent({ time: 300000, - filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id } + filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id } }); - i.deferUpdate(); + await i.deferUpdate(); } catch { return; } diff --git a/src/reflex/guide.ts b/src/reflex/guide.ts index 3971ad9..e78c0dc 100644 --- a/src/reflex/guide.ts +++ b/src/reflex/guide.ts @@ -273,7 +273,7 @@ export default async (guild: Guild, interaction?: CommandInteraction) => { timedOut = true; continue; } - i.deferUpdate(); + await i.deferUpdate(); if (!("customId" in i.component)) { continue; } else if (i.component.customId === "left") { diff --git a/src/utils/confirmationMessage.ts b/src/utils/confirmationMessage.ts index 613b48c..7d54674 100644 --- a/src/utils/confirmationMessage.ts +++ b/src/utils/confirmationMessage.ts @@ -183,7 +183,7 @@ class confirmationMessage { let component; try { component = await m.awaitMessageComponent({ - filter: (m) => m.user.id === this.interaction.user.id && m.channel!.id === this.interaction.channel!.id, + filter: (i) => i.user.id === this.interaction.user.id && i.channel!.id === this.interaction.channel!.id && i.id === m.id, time: 300000 }); } catch (e) { @@ -287,7 +287,7 @@ class confirmationMessage { await this.interaction.editReply({ embeds: [new EmojiEmbed() .setTitle(this.title) - .setDescription(this.failedMessage ?? "") + .setDescription(this.failedMessage ?? "*Message timed out*") .setStatus(this.failedStatus ?? "Danger") .setEmoji(this.failedEmoji ?? this.redEmoji ?? this.emoji) ], components: [] diff --git a/src/utils/database.ts b/src/utils/database.ts index 1e8e990..3d4ca78 100644 --- a/src/utils/database.ts +++ b/src/utils/database.ts @@ -67,7 +67,6 @@ export class Guilds { value: any, innerKey?: string | null ) { - console.log(Array.isArray(value)); if (innerKey) { await this.guilds.updateOne( { id: guild }, @@ -191,6 +190,10 @@ export class ModNotes { const entry = await this.modNotes.findOne({ guild: guild, user: user }); return entry?.note ?? null; } + + async delete(guild: string) { + await this.modNotes.deleteMany({ guild: guild }); + } } export class Premium { @@ -204,7 +207,18 @@ export class Premium { const entry = await this.premium.findOne({ appliesTo: { $in: [guild] } }); - return entry !== null; + if (!entry) return false; + return entry.expires.valueOf() > Date.now(); + } + + async fetchTotal(user: string): Promise { + const entry = await this.premium.findOne({ user: user }); + if (!entry) return 0; + return entry.appliesTo.length; + } + + setPremium(user: string, guild: string) { + return this.premium.updateOne({ user: user }, { $addToSet: { appliesTo: guild } }, { upsert: true }); } } diff --git a/src/utils/dualCollector.ts b/src/utils/dualCollector.ts index 64e87b8..f55716e 100644 --- a/src/utils/dualCollector.ts +++ b/src/utils/dualCollector.ts @@ -60,15 +60,17 @@ export async function modalInteractionCollector( }) .on("collect", async (i: ButtonInteraction) => { mod.stop(); - if (!i.deferred) await i.deferUpdate(); + int.stop(); + await i.deferUpdate(); resolve(i); }); const mod = new InteractionCollector(client as Client, { - filter: (i: Interaction) => modalFilter(i), + filter: (i: Interaction) => modalFilter(i) && i.isModalSubmit(), time: 300000 }).on("collect", async (i: ModalSubmitInteraction) => { int.stop(); - if (!i.deferred) await i.deferUpdate(); + mod.stop(); + await i.deferUpdate(); resolve(i); }); });