Performance testing
diff --git a/src/actions/roleMenu.ts b/src/actions/roleMenu.ts
index 48ca49c..1c493bb 100644
--- a/src/actions/roleMenu.ts
+++ b/src/actions/roleMenu.ts
@@ -1,11 +1,10 @@
-import { Interaction, ButtonBuilder, CommandInteraction, Role, ButtonStyle } from "discord.js";
+import { Interaction, ButtonBuilder, CommandInteraction, Role, ButtonStyle, ButtonInteraction } from "discord.js";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";
import { ActionRowBuilder, SelectMenuBuilder } from "discord.js";
import getEmojiByName from "../utils/getEmojiByName.js";
import client from "../utils/client.js";
import { LoadingEmbed } from "../utils/defaultEmbeds.js";
import type { GuildConfig } from "../utils/database.js";
-import type { ButtonComponent } from "@discordjs/builders";
export interface RoleMenuSchema {
guild: string;
@@ -17,7 +16,7 @@
interaction: Interaction;
}
-export async function callback(interaction: CommandInteraction) {
+export async function callback(interaction: CommandInteraction | ButtonInteraction) {
if(!interaction.guild) return interaction.reply({ content: "This command can only be used in a server.", ephemeral: true });
if(!interaction.member) return interaction.reply({ content: "You must be in a server to use this command.", ephemeral: true });
const config = await client.database.guilds.read(interaction.guild.id);
diff --git a/src/actions/tickets/create.ts b/src/actions/tickets/create.ts
index e1821ef..595a5b3 100644
--- a/src/actions/tickets/create.ts
+++ b/src/actions/tickets/create.ts
@@ -1,4 +1,4 @@
-import Discord, { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction } from "discord.js";
+import Discord, { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, ButtonInteraction } from "discord.js";
import { tickets, toHexArray } from "../../utils/calculate.js";
import client from "../../utils/client.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
@@ -9,7 +9,7 @@
return s.length < 3 ? s.toUpperCase() : s[0].toUpperCase() + s.slice(1).toLowerCase();
}
-export default async function (interaction: CommandInteraction) {
+export default async function (interaction: CommandInteraction | ButtonInteraction) {
if (!interaction.guild) return;
const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
diff --git a/src/actions/tickets/delete.ts b/src/actions/tickets/delete.ts
index 33860b7..cab38ec 100644
--- a/src/actions/tickets/delete.ts
+++ b/src/actions/tickets/delete.ts
@@ -1,9 +1,9 @@
-import Discord, { ButtonBuilder, ActionRowBuilder, ButtonStyle } from "discord.js";
+import Discord, { ButtonBuilder, ActionRowBuilder, ButtonStyle, ButtonInteraction } from "discord.js";
import client from "../../utils/client.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
-export default async function (interaction: Discord.CommandInteraction) {
+export default async function (interaction: Discord.CommandInteraction | ButtonInteraction) {
if (!interaction.guild) return;
const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
diff --git a/src/commands/help.ts b/src/commands/help.ts
index e85cf6b..c9bba7d 100644
--- a/src/commands/help.ts
+++ b/src/commands/help.ts
@@ -1,4 +1,4 @@
-import type { CommandInteraction } from "discord.js";
+import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction } from "discord.js";
import { SlashCommandBuilder } from "@discordjs/builders";
const command = new SlashCommandBuilder()
@@ -6,7 +6,12 @@
.setDescription("Shows help for commands");
const callback = async (interaction: CommandInteraction): Promise<void> => {
- interaction.reply("hel p D:"); // TODO: FINISH THIS FOR RELEASE
+ interaction.reply({components: [new ActionRowBuilder<ButtonBuilder>().addComponents(
+ new ButtonBuilder()
+ .setLabel("Verify")
+ .setStyle(ButtonStyle.Primary)
+ .setCustomId("verifybutton")
+ )]}); // TODO: FINISH THIS FOR RELEASE
};
const check = (_interaction: CommandInteraction) => {
diff --git a/src/commands/mod/_meta.ts b/src/commands/mod/_meta.ts
index 987a1c1..af8006c 100644
--- a/src/commands/mod/_meta.ts
+++ b/src/commands/mod/_meta.ts
@@ -3,6 +3,6 @@
const name = "mod";
const description = "Perform moderator actions";
-const subcommand = await command(name, description, `mod`)
+const subcommand = await command(name, description, `mod`);
export { name, description, subcommand as command };
diff --git a/src/commands/mod/ban.ts b/src/commands/mod/ban.ts
index 7346bcc..ba60d1e 100644
--- a/src/commands/mod/ban.ts
+++ b/src/commands/mod/ban.ts
@@ -74,6 +74,7 @@
const config = await client.database.guilds.read(interaction.guild.id);
try {
if (notify) {
+ if (reason) { reason = reason.split("\n").map((line) => "> " + line).join("\n") }
const messageData: {
embeds: EmojiEmbed[];
components: ActionRowBuilder<ButtonBuilder>[];
@@ -83,7 +84,8 @@
.setEmoji("PUNISH.BAN.RED")
.setTitle("Banned")
.setDescription(
- `You have been banned in ${interaction.guild.name}` + (reason ? ` for:\n> ${reason}` : ".")
+ `You have been banned in ${interaction.guild.name}` +
+ (reason ? ` for:\n${reason}` : ".\n*No reason was provided.*")
)
.setStatus("Danger")
],
diff --git a/src/commands/mod/info.ts b/src/commands/mod/info.ts
index 6b5c81e..fac87a0 100644
--- a/src/commands/mod/info.ts
+++ b/src/commands/mod/info.ts
@@ -23,6 +23,7 @@
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("info")
+ // .setNameLocalizations({"ru": "about", "zh-CN": "history", "zh-TW": "notes", "pt-BR": "flags"})
.setDescription("Shows moderator information about a user")
.addUserOption((option) =>
option.setName("user").setDescription("The user to get information about").setRequired(true)
diff --git a/src/commands/mod/kick.ts b/src/commands/mod/kick.ts
index dd71892..88b6e14 100644
--- a/src/commands/mod/kick.ts
+++ b/src/commands/mod/kick.ts
@@ -75,6 +75,7 @@
const config = await client.database.guilds.read(interaction.guild.id);
try {
if (notify) {
+ if (reason) { reason = reason.split("\n").map((line) => "> " + line).join("\n") }
const messageData: {
embeds: EmojiEmbed[];
components: ActionRowBuilder<ButtonBuilder>[];
@@ -85,7 +86,7 @@
.setTitle("Kicked")
.setDescription(
`You have been kicked from ${interaction.guild.name}` +
- (reason ? ` for:\n> ${reason}` : ".\n*No reason was provided.*")
+ (reason ? ` for:\n${reason}` : ".\n*No reason was provided.*")
)
.setStatus("Danger")
],
diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts
index 05a9ec2..d68272b 100644
--- a/src/commands/mod/mute.ts
+++ b/src/commands/mod/mute.ts
@@ -13,6 +13,7 @@
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("mute")
+ // .setNameLocalizations({"ru": "silence"})
.setDescription("Mutes a member, stopping them from talking in the server")
.addUserOption((option) => option.setName("user").setDescription("The user to mute").setRequired(true))
.addIntegerOption((option) =>
@@ -234,6 +235,7 @@
let dmMessage;
try {
if (notify) {
+ if (reason) { reason = reason.split("\n").map((line) => "> " + line).join("\n") }
const messageData: {
embeds: EmojiEmbed[];
components: ActionRowBuilder<ButtonBuilder>[];
@@ -244,7 +246,7 @@
.setTitle("Muted")
.setDescription(
`You have been muted in ${interaction.guild.name}` +
- (reason ? ` for:\n> ${reason}` : ".\n*No reason was provided*") + "\n\n" +
+ (reason ? ` for:\n${reason}` : ".\n*No reason was provided*") + "\n\n" +
`You will be unmuted at: <t:${Math.round(new Date().getTime() / 1000) + muteTime}:D> at ` +
`<t:${Math.round(new Date().getTime() / 1000) + muteTime}:T> (<t:${Math.round(new Date().getTime() / 1000) + muteTime
}:R>)` + "\n\n" +
diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts
index 0975375..81935a2 100644
--- a/src/commands/mod/nick.ts
+++ b/src/commands/mod/nick.ts
@@ -1,4 +1,4 @@
-import { CommandInteraction, GuildMember } from "discord.js";
+import type { CommandInteraction, GuildMember } from "discord.js";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import confirmationMessage from "../../utils/confirmationMessage.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
@@ -8,6 +8,7 @@
const command = (builder: SlashCommandSubcommandBuilder) => builder
.setName("nick")
+ // .setNameLocalizations({"ru": "name", "zh-CN": "nickname"})
.setDescription("Changes a users nickname")
.addUserOption((option) => option.setName("user").setDescription("The user to change").setRequired(true))
.addStringOption((option) =>
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index 6087890..3020eb8 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -29,11 +29,7 @@
if (!interaction.guild) return;
const user = (interaction.options.getMember("user") as GuildMember | null);
const channel = interaction.channel as GuildChannel;
- if (
- !["GUILD_TEXT", "GUILD_NEWS", "GUILD_NEWS_THREAD", "GUILD_PUBLIC_THREAD", "GUILD_PRIVATE_THREAD"].includes(
- channel.type.toString()
- )
- ) {
+ if (channel.isTextBased()) {
return await interaction.reply({
embeds: [
new EmojiEmbed()
diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts
index 390baa5..d920bb0 100644
--- a/src/commands/mod/warn.ts
+++ b/src/commands/mod/warn.ts
@@ -84,6 +84,7 @@
const config = await client.database.guilds.read(interaction.guild.id);
try {
if (notify) {
+ if (reason) { reason = reason.split("\n").map((line) => "> " + line).join("\n") }
const messageData: {
embeds: EmojiEmbed[];
components: ActionRowBuilder<ButtonBuilder>[];
@@ -94,7 +95,7 @@
.setTitle("Warned")
.setDescription(
`You have been warned in ${interaction.guild.name}` +
- (reason ? ` for:\n> ${reason}` : ".\n*No reason was provided*") +
+ (reason ? ` for:\n${reason}` : ".\n*No reason was provided*") +
"\n\n" +
(createAppealTicket
? `You can appeal this in the ticket created in <#${confirmation.components!["appeal"]!.response}>`
diff --git a/src/commands/nucleus/_meta.ts b/src/commands/nucleus/_meta.ts
index d66b5d2..521b338 100644
--- a/src/commands/nucleus/_meta.ts
+++ b/src/commands/nucleus/_meta.ts
@@ -5,4 +5,6 @@
const subcommand = await command(name, description, `nucleus`)
-export { name, description, subcommand as command };
+const allowedInDMs = true;
+
+export { name, description, subcommand as command, allowedInDMs };
diff --git a/src/commands/nucleus/guide.ts b/src/commands/nucleus/guide.ts
index ffc441a..d3370ba 100644
--- a/src/commands/nucleus/guide.ts
+++ b/src/commands/nucleus/guide.ts
@@ -1,11 +1,12 @@
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import type { CommandInteraction } from 'discord.js';
+import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import guide from "../../reflex/guide.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder.setName("guide").setDescription("Shows the welcome guide for the bot");
-const callback = async (interaction) => {
- guide(interaction.guild, interaction);
+const callback = async (interaction: CommandInteraction) => {
+ guide(interaction.guild!, interaction);
};
const check = () => {
diff --git a/src/commands/nucleus/invite.ts b/src/commands/nucleus/invite.ts
index 7c36d62..fd65e51 100644
--- a/src/commands/nucleus/invite.ts
+++ b/src/commands/nucleus/invite.ts
@@ -1,5 +1,5 @@
import { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import client from "../../utils/client.js";
@@ -16,12 +16,12 @@
.setStatus("Danger")
],
components: [
- new ActionRowBuilder().addComponents([
+ new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setLabel("Invite")
.setStyle(ButtonStyle.Link)
.setURL(
- `https://discord.com/api/oauth2/authorize?client_id=${client.user.id}&permissions=295157886134&scope=bot%20applications.commands`
+ `https://discord.com/api/oauth2/authorize?client_id=${client.user!.id}&permissions=295157886134&scope=bot%20applications.commands`
)
])
],
diff --git a/src/commands/nucleus/ping.ts b/src/commands/nucleus/ping.ts
index 59b6393..3cbd049 100644
--- a/src/commands/nucleus/ping.ts
+++ b/src/commands/nucleus/ping.ts
@@ -1,6 +1,6 @@
import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import type { CommandInteraction } from "discord.js";
+import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import client from "../../utils/client.js";
@@ -19,8 +19,8 @@
.setTitle("Ping")
.setDescription(
`**Ping:** \`${ping}ms\`\n` +
- `**To Discord:** \`${client.ws.ping}ms\`\n` +
- `**From Expected:** \`±${Math.abs(ping / 2 - client.ws.ping)}ms\``
+ `**To Discord:** \`${client.ws.ping}ms\`\n` +
+ `**From Expected:** \`±${Math.abs(ping / 2 - client.ws.ping)}ms\``
)
.setEmoji("CHANNEL.SLOWMODE.OFF")
.setStatus("Danger")
diff --git a/src/commands/nucleus/stats.ts b/src/commands/nucleus/stats.ts
index a67cd36..d8b2807 100644
--- a/src/commands/nucleus/stats.ts
+++ b/src/commands/nucleus/stats.ts
@@ -1,5 +1,5 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import type { CommandInteraction } from "discord.js";
+import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import client from "../../utils/client.js";
diff --git a/src/commands/nucleus/suggest.ts b/src/commands/nucleus/suggest.ts
index 49c80fb..a75e8a0 100644
--- a/src/commands/nucleus/suggest.ts
+++ b/src/commands/nucleus/suggest.ts
@@ -1,4 +1,5 @@
-import Discord, { CommandInteraction } from "discord.js";
+import type { CommandInteraction } from "discord.js";
+import type Discord from "discord.js";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import confirmationMessage from "../../utils/confirmationMessage.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
@@ -13,8 +14,9 @@
);
const callback = async (interaction: CommandInteraction): Promise<void> => {
+ await interaction.guild?.members.fetch(interaction.member!.user.id)
const { renderUser } = client.logger;
- const suggestion = interaction.options.getString("suggestion");
+ const suggestion = interaction.options.get("suggestion")?.value as string;
const confirmation = await new confirmationMessage(interaction)
.setEmoji("ICONS.OPP.ADD")
.setTitle("Suggest")
@@ -32,7 +34,7 @@
new EmojiEmbed()
.setTitle("Suggestion")
.setDescription(
- `**From:** ${renderUser(interaction.member.user)}\n**Suggestion:**\n> ${suggestion}`
+ `**From:** ${renderUser(interaction.member!.user as Discord.User)}\n**Suggestion:**\n> ${suggestion}`
)
.setStatus("Danger")
.setEmoji("NUCLEUS.LOGO")
diff --git a/src/commands/server/about.ts b/src/commands/server/about.ts
index b895768..e5bea60 100644
--- a/src/commands/server/about.ts
+++ b/src/commands/server/about.ts
@@ -1,4 +1,4 @@
-import type { CommandInteraction } from "discord.js";
+import { CommandInteraction, GuildMFALevel } from "discord.js";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
@@ -8,6 +8,28 @@
const command = (builder: SlashCommandSubcommandBuilder) =>
builder.setName("about").setDescription("Shows info about the server");
+
+const verificationTypes = {
+ 0: "None - Unrestricted",
+ 1: "Low - Must have a verified email",
+ 2: "Medium - Must be registered for 5 minutes",
+ 3: "High - Must be a member for 10 minutes",
+ 4: "Highest - Must have a verified phone"
+}
+
+const premiumTiers = {
+ 0: "None",
+ 1: "Tier 1",
+ 2: "Tier 2",
+ 3: "Tier 3"
+}
+
+const filterLevels = {
+ 0: "Disabled",
+ 1: "Members without roles",
+ 2: "All members"
+}
+
const callback = async (interaction: CommandInteraction): Promise<void> => {
const guild = interaction.guild!;
const { renderUser, renderDelta } = client.logger;
@@ -27,28 +49,26 @@
`${guild.emojis.cache.size}` +
(guild.emojis.cache.size > 1
? `\n> ${guild.emojis.cache
- .first(10)
- .map((emoji) => `<${emoji.animated ? "a" : ""}:${emoji.name}:${emoji.id}>`)
- .join(" ")}` +
- (guild.emojis.cache.size > 10 ? ` and ${guild.emojis.cache.size - 10} more` : "")
+ .first(10)
+ .map((emoji) => `<${emoji.animated ? "a" : ""}:${emoji.name}:${emoji.id}>`)
+ .join(" ")}` +
+ (guild.emojis.cache.size > 10 ? ` and ${guild.emojis.cache.size - 10} more` : "")
: ""),
icon: `[Discord](${guild.iconURL()})`,
"2 factor authentication": `${
- guild.mfaLevel === "NONE"
+ guild.mfaLevel === GuildMFALevel.None
? `${getEmojiByName("CONTROL.CROSS")} No`
: `${getEmojiByName("CONTROL.TICK")} Yes`
}`,
- "verification level": `${toCapitals(guild.verificationLevel)}`,
- "explicit content filter": `${toCapitals(
- guild.explicitContentFilter.toString().replace(/_/, " ")
- )}`,
- "nitro boost level": `${guild.premiumTier !== "NONE" ? guild.premiumTier.toString()[-1] : "0"}`,
+ "verification level": `${toCapitals(verificationTypes[guild.verificationLevel])}`,
+ "explicit content filter": `${filterLevels[guild.explicitContentFilter]}`,
+ "nitro boost level": `${premiumTiers[guild.premiumTier]}`,
channels: `${guild.channels.cache.size}`,
roles: `${guild.roles.cache.size}`,
members: `${guild.memberCount}`
})
)
- .setThumbnail(guild.iconURL({ dynamic: true }))
+ .setThumbnail(guild.iconURL())
],
ephemeral: true
});
diff --git a/src/commands/settings/_meta.ts b/src/commands/settings/_meta.ts
index 76e570d..666dbf4 100644
--- a/src/commands/settings/_meta.ts
+++ b/src/commands/settings/_meta.ts
@@ -4,6 +4,8 @@
const description = "Change bot settings";
-const subcommand = await command(name, description, "settings")
+const subcommand = await command(name, description, "settings", undefined, undefined, undefined, [
+ "ManageGuild"
+])
export { name, description, subcommand as command};
diff --git a/src/commands/settings/stats.ts b/src/commands/settings/stats.ts
index f19998a..a768cb8 100644
--- a/src/commands/settings/stats.ts
+++ b/src/commands/settings/stats.ts
@@ -224,6 +224,16 @@
return true;
};
+const autocomplete = async (interaction: AutocompleteInteraction): Promise<string[]> => {
+ if (!interaction.guild) return [];
+ const prompt = interaction.options.getString("tag");
+ // generateStatsChannelAutocomplete(int.options.getString("name") ?? "")
+ const results = generateStatsChannelAutocomplete(prompt ?? "");
+ return results;
+};
+
+
+
export { command };
export { callback };
export { check };
diff --git a/src/commands/settings/welcome.ts b/src/commands/settings/welcome.ts
index 5284f8a..7f02cd7 100644
--- a/src/commands/settings/welcome.ts
+++ b/src/commands/settings/welcome.ts
@@ -7,7 +7,8 @@
ButtonBuilder,
MessageComponentInteraction,
Role,
- ButtonStyle
+ ButtonStyle,
+ AutocompleteInteraction
} from "discord.js";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
@@ -204,7 +205,7 @@
.setEmoji("CHANNEL.TEXT.CREATE")
],
components: [
- new ActionRowBuilder().addComponents([
+ new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setLabel(lastClicked == "clear-message" ? "Click again to confirm" : "Clear Message")
.setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
@@ -296,11 +297,42 @@
const check = (interaction: CommandInteraction) => {
const member = interaction.member as Discord.GuildMember;
- if (!member.permissions.has("MANAGE_GUILD"))
+ if (!member.permissions.has("ManageGuild"))
throw new Error("You must have the *Manage Server* permission to use this command");
return true;
};
-export { command };
-export { callback };
-export { check };
+const autocomplete = async (interaction: AutocompleteInteraction): Promise<string[]> => {
+ const validReplacements = ["serverName", "memberCount", "memberCount:bots", "memberCount:humans"]
+ if (!interaction.guild) return [];
+ const prompt = interaction.options.getString("message");
+ const autocompletions = [];
+ if ( prompt === null ) {
+ for (const replacement of validReplacements) {
+ autocompletions.push(`{${replacement}}`);
+ };
+ return autocompletions;
+ };
+ const beforeLastOpenBracket = prompt.match(/(.*){[^{}]{0,15}$/);
+ const afterLastOpenBracket = prompt.match(/{[^{}]{0,15}$/);
+ if (beforeLastOpenBracket !== null) {
+ if (afterLastOpenBracket !== null) {
+ for (const replacement of validReplacements) {
+ if (replacement.startsWith(afterLastOpenBracket[0].slice(1))) {
+ autocompletions.push(`${beforeLastOpenBracket[1]}{${replacement}}`);
+ }
+ }
+ } else {
+ for (const replacement of validReplacements) {
+ autocompletions.push(`${beforeLastOpenBracket[1]}{${replacement}}`);
+ }
+ }
+ } else {
+ for (const replacement of validReplacements) {
+ autocompletions.push(`${prompt} {${replacement}}`);
+ }
+ }
+ return autocompletions;
+};
+
+export { command, callback, check, autocomplete };
diff --git a/src/commands/tag.ts b/src/commands/tag.ts
index 859b7fc..a65947c 100644
--- a/src/commands/tag.ts
+++ b/src/commands/tag.ts
@@ -58,10 +58,8 @@
const autocomplete = async (interaction: AutocompleteInteraction): Promise<string[]> => {
if (!interaction.guild) return [];
const prompt = interaction.options.getString("tag");
- console.log(prompt)
const possible = Object.keys((await client.memory.readGuildInfo(interaction.guild.id)).tags);
const results = getResults(prompt ?? "", possible);
- console.log(results)
return results;
};
diff --git a/src/commands/user/about.ts b/src/commands/user/about.ts
index 72ad1eb..aa45690 100644
--- a/src/commands/user/about.ts
+++ b/src/commands/user/about.ts
@@ -79,7 +79,7 @@
Staff: "Discord Staff",
VerifiedDeveloper: "Verified Bot Developer",
ActiveDeveloper: "Active Developer",
- Quarantined: "Quarantined [What does this mean?](https://support.discord.com/hc/en-us/articles/6461420677527)",
+ Quarantined: "Quarantined [[What does this mean?]](https://support.discord.com/hc/en-us/articles/6461420677527)",
Spammer: "Likely Spammer"
// CertifiedModerator
// VerifiedBot
diff --git a/src/config/default.json b/src/config/default.json
index 824f12c..8e4197c 100644
--- a/src/config/default.json
+++ b/src/config/default.json
@@ -19,7 +19,11 @@
},
"invite": {
"enabled": false,
- "channels": []
+ "allowed": {
+ "users": [],
+ "roles": [],
+ "channels": []
+ }
},
"pings": {
"mass": 5,
diff --git a/src/config/emojis.json b/src/config/emojis.json
index 168d84b..cbf3dc3 100644
--- a/src/config/emojis.json
+++ b/src/config/emojis.json
@@ -41,7 +41,8 @@
"GUILD_STAGE_VOICE": "853668786842763294",
"THREAD_CHANNEL": "990210005108158514",
"THREAD_PIPE": "990213168183779348",
- "RULES": "990213153080115250"
+ "RULES": "990213153080115250",
+ "FORUM": "1061706437526552716"
}
},
"CONTROL": {
diff --git a/src/events/channelCreate.ts b/src/events/channelCreate.ts
index b3cba33..dda37af 100644
--- a/src/events/channelCreate.ts
+++ b/src/events/channelCreate.ts
@@ -1,47 +1,54 @@
-import type { GuildAuditLogsEntry } from "discord.js";
+import { AuditLogEvent, ChannelType, GuildAuditLogsEntry } from "discord.js";
import type { GuildBasedChannel } from "discord.js";
import type { NucleusClient } from "../utils/client.js";
export const event = "channelCreate";
export async function callback(client: NucleusClient, channel: GuildBasedChannel) {
const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta, renderChannel } = client.logger;
- const auditLog = await getAuditLog(channel.guild, "CHANNEL_CREATE");
- const audit = auditLog.entries.filter((entry: GuildAuditLogsEntry) => entry.target!.id === channel.id).first();
- if (audit.executor.id === client.user.id) return;
+ const auditLog = (await getAuditLog(channel.guild, AuditLogEvent.ChannelCreate))
+ .filter((entry: GuildAuditLogsEntry) => (entry.target as GuildBasedChannel)!.id === channel.id)[0];
+ if (!auditLog) return;
+ if (auditLog.executor!.id === client.user!.id) return;
let emoji;
let readableType;
let displayName;
switch (channel.type) {
- case "GUILD_TEXT": {
+ case ChannelType.GuildText: {
emoji = "CHANNEL.TEXT.CREATE";
readableType = "Text";
displayName = "Text Channel";
break;
}
- case "GUILD_NEWS": {
+ case ChannelType.GuildAnnouncement: {
emoji = "CHANNEL.TEXT.CREATE";
readableType = "Announcement";
displayName = "Announcement Channel";
break;
}
- case "GUILD_VOICE": {
+ case ChannelType.GuildVoice: {
emoji = "CHANNEL.VOICE.CREATE";
readableType = "Voice";
displayName = "Voice Channel";
break;
}
- case "GUILD_STAGE_VOICE": {
+ case ChannelType.GuildStageVoice: {
emoji = "CHANNEL.VOICE.CREATE";
readableType = "Stage";
displayName = "Stage Channel";
break;
}
- case "GUILD_CATEGORY": {
+ case ChannelType.GuildCategory: {
emoji = "CHANNEL.CATEGORY.CREATE";
readableType = "Category";
displayName = "Category";
break;
}
+ case ChannelType.GuildForum: {
+ emoji = "CHANNEL.TEXT.CREATE";
+ readableType = "Forum";
+ displayName = "Forum Channel";
+ break;
+ }
default: {
emoji = "CHANNEL.TEXT.CREATE";
readableType = "Channel";
@@ -65,12 +72,12 @@
channel.parent ? channel.parent.id : null,
channel.parent ? channel.parent.name : "Uncategorised"
),
- createdBy: entry(audit.executor.id, renderUser(audit.executor)),
- created: entry(channel.createdTimestamp, renderDelta(channel.createdTimestamp))
+ createdBy: entry(auditLog.executor!.id, renderUser(auditLog.executor!)),
+ created: entry(channel.createdTimestamp, renderDelta(channel.createdTimestamp!))
},
hidden: {
guild: channel.guild.id
}
};
log(data);
-}
+};
diff --git a/src/events/channelUpdate.ts b/src/events/channelUpdate.ts
index a7af453..df212a2 100644
--- a/src/events/channelUpdate.ts
+++ b/src/events/channelUpdate.ts
@@ -5,6 +5,7 @@
export async function callback(client, oc, nc) {
const config = await client.memory.readGuildInfo(nc.guild.id);
+ return;
const { getAuditLog, log, NucleusColors, entry, renderDelta, renderUser, renderChannel } = client.logger;
if (nc.parent && nc.parent.id === config.tickets.category) return;
diff --git a/src/events/guildUpdate.ts b/src/events/guildUpdate.ts
index e463007..eefab4b 100644
--- a/src/events/guildUpdate.ts
+++ b/src/events/guildUpdate.ts
@@ -78,7 +78,7 @@
const data = {
meta: {
type: "guildUpdate",
- displayName: "Guild Edited",
+ displayName: "Server Edited",
calculateType: "guildUpdate",
color: NucleusColors.yellow,
emoji: "GUILD.YELLOW",
diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts
index 1796146..62e9609 100644
--- a/src/events/interactionCreate.ts
+++ b/src/events/interactionCreate.ts
@@ -4,7 +4,7 @@
import close from "../actions/tickets/delete.js";
import createTranscript from "../premium/createTranscript.js";
-import type { Interaction, MessageComponentInteraction } from "discord.js";
+import type { Interaction } from "discord.js";
import type { NucleusClient } from "../utils/client.js";
export const event = "interactionCreate";
@@ -12,30 +12,16 @@
async function interactionCreate(interaction: Interaction) {
if (interaction.isButton()) {
- const int = interaction as MessageComponentInteraction;
- switch (int.customId) {
- case "rolemenu": {
- return await roleMenu(interaction);
- }
- case "verifybutton": {
- return verify(int);
- }
- case "createticket": {
- return create(interaction);
- }
- case "closeticket": {
- return close(interaction);
- }
- case "createtranscript": {
- return createTranscript(int);
- }
+ switch (interaction.customId) {
+ case "rolemenu": { return await roleMenu(interaction); }
+ case "verifybutton": { return await verify(interaction); }
+ case "createticket": { return await create(interaction); }
+ case "closeticket": { return await close(interaction); }
+ case "createtranscript": { return await createTranscript(interaction); }
}
// } else if (interaction.type === "APPLICATION_COMMAND_AUTOCOMPLETE") {
// const int = interaction as AutocompleteInteraction;
// switch (`${int.commandName} ${int.options.getSubcommandGroup(false)} ${int.options.getSubcommand(false)}`) {
- // case "tag null null": {
- // return int.respond(getAutocomplete(int.options.getString("tag") ?? "", await tagAutocomplete(int)));
- // }
// case "settings null stats": {
// return int.respond(generateStatsChannelAutocomplete(int.options.getString("name") ?? ""));
// }
diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts
index 3f85de6..2f3a077 100644
--- a/src/events/messageCreate.ts
+++ b/src/events/messageCreate.ts
@@ -12,7 +12,7 @@
export async function callback(_client: NucleusClient, message: Message) {
if (!message.guild) return;
if (message.author.bot) return;
- if (message.channel.type === "DM") return;
+ if (message.channel.isDMBased()) return;
try {
await statsChannelUpdate(client, await message.guild.members.fetch(message.author.id));
} catch (e) {
@@ -38,7 +38,7 @@
mentions: message.mentions.users.size,
attachments: entry(message.attachments.size, message.attachments.size + attachmentJump),
repliedTo: entry(
- message.reference ? message.reference.messageId : null,
+ (message.reference ? message.reference.messageId : null) ?? null,
message.reference
? `[[Jump to message]](https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.reference.messageId})`
: "None"
diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts
index ddeff96..f8433fc 100644
--- a/src/events/messageDelete.ts
+++ b/src/events/messageDelete.ts
@@ -1,27 +1,24 @@
import type { NucleusClient } from "../utils/client.js";
-import type { GuildAuditLogsEntry, Message } from "discord.js";
+import Discord, { AuditLogEvent, GuildAuditLogsEntry, Message, User } from "discord.js";
export const event = "messageDelete";
export async function callback(client: NucleusClient, message: Message) {
try {
- if (message.author.id === client.user.id) return;
+ if (message.author.id === client.user!.id) return;
if (client.noLog.includes(`${message.id}/${message.channel.id}/${message.id}`)) return;
const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta, renderChannel } = client.logger;
- const auditLog = await getAuditLog(message.guild, "MEMBER_BAN_ADD");
- const audit = auditLog.entries
- .filter((entry: GuildAuditLogsEntry) => entry.target!.id === message.author.id)
- .first();
- if (audit) {
- if (audit.createdAt - 100 < new Date().getTime()) return;
+ const auditLog = (await getAuditLog(message.guild!, AuditLogEvent.MemberBanAdd))
+ .filter((entry: GuildAuditLogsEntry) => (entry.target! as User).id === message.author.id)[0];
+ if (auditLog) {
+ if (auditLog.createdTimestamp - 1000 < new Date().getTime()) return;
}
const replyTo = message.reference;
let content = message.cleanContent;
content.replace("`", "\\`");
if (content.length > 256) content = content.substring(0, 253) + "...";
const attachments =
- message.attachments.size +
- (
+ message.attachments.size + (
message.content.match(
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/gi
) ?? []
@@ -30,9 +27,7 @@
const config = (await client.database.guilds.read(message.guild!.id)).logging.attachments.saved[
message.channel.id + message.id
];
- if (config) {
- attachmentJump = ` [[View attachments]](${config})`;
- }
+ if (config) { attachmentJump = ` [[View attachments]](${config})`; }
const data = {
meta: {
type: "messageDelete",
@@ -48,17 +43,14 @@
list: {
messageId: entry(message.id, `\`${message.id}\``),
sentBy: entry(message.author.id, renderUser(message.author)),
- sentIn: entry(message.channel.id, renderChannel(message.channel)),
+ sentIn: entry(message.channel.id, renderChannel(message.channel as Discord.GuildChannel | Discord.ThreadChannel)),
deleted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
mentions: message.mentions.users.size,
attachments: entry(attachments, attachments + attachmentJump),
repliedTo: entry(
- replyTo,
- replyTo
- ? `[[Jump to message]](https://discord.com/channels/${message.guild!.id}/${
- message.channel.id
- }/${replyTo.messageId})`
- : "None"
+ replyTo ? replyTo.messageId! : null,
+ replyTo ? `[[Jump to message]](https://discord.com/channels/${message.guild!.id}/${message.channel.id}/${replyTo.messageId})`
+ : "None"
)
},
hidden: {
diff --git a/src/events/messageEdit.ts b/src/events/messageEdit.ts
index 37178a7..20624fe 100644
--- a/src/events/messageEdit.ts
+++ b/src/events/messageEdit.ts
@@ -1,10 +1,11 @@
import type { NucleusClient } from "../utils/client.js";
import type { Message, MessageReference } from "discord.js";
+import type Discord from "discord.js";
export const event = "messageUpdate";
export async function callback(client: NucleusClient, oldMessage: Message, newMessage: Message) {
- if (newMessage.author.id === client.user.id) return;
+ if (newMessage.author.id === client.user!.id) return;
if (!newMessage.guild) return;
const { log, NucleusColors, entry, renderUser, renderDelta, renderNumberDelta, renderChannel } = client.logger;
const replyTo: MessageReference | null = newMessage.reference;
@@ -17,8 +18,8 @@
if (config) {
attachmentJump = ` [[View attachments]](${config})`;
}
- if (newContent === oldContent) {
- if (!oldMessage.flags.has("CROSSPOSTED") && newMessage.flags.has("CROSSPOSTED")) {
+ if (newContent === oldContent && newMessage.attachments.size === oldMessage.attachments.size) {
+ if (!replyTo) {
const data = {
meta: {
type: "messageAnnounce",
@@ -34,14 +35,14 @@
list: {
messageId: entry(newMessage.id, `\`${newMessage.id}\``),
sentBy: entry(newMessage.author.id, renderUser(newMessage.author)),
- sentIn: entry(newMessage.channel.id, renderChannel(newMessage.channel)),
+ sentIn: entry(newMessage.channel.id, renderChannel(newMessage.channel as Discord.GuildBasedChannel)),
sent: entry(
- new Date(newMessage.createdTimestamp),
- renderDelta(new Date(newMessage.createdTimestamp))
+ newMessage.createdTimestamp,
+ renderDelta(newMessage.createdTimestamp)
),
published: entry(
- new Date(newMessage.editedTimestamp!),
- renderDelta(new Date(newMessage.editedTimestamp!))
+ newMessage.editedTimestamp!,
+ renderDelta(newMessage.editedTimestamp!)
),
mentions: renderNumberDelta(oldMessage.mentions.users.size, newMessage.mentions.users.size),
attachments: entry(
@@ -81,16 +82,16 @@
list: {
messageId: entry(newMessage.id, `\`${newMessage.id}\``),
sentBy: entry(newMessage.author.id, renderUser(newMessage.author)),
- sentIn: entry(newMessage.channel.id, renderChannel(newMessage.channel)),
- sent: entry(new Date(newMessage.createdTimestamp), renderDelta(new Date(newMessage.createdTimestamp))),
- edited: entry(new Date(newMessage.editedTimestamp), renderDelta(new Date(newMessage.editedTimestamp))),
+ sentIn: entry(newMessage.channel.id, renderChannel(newMessage.channel as Discord.GuildBasedChannel)),
+ sent: entry(newMessage.createdTimestamp, renderDelta(newMessage.createdTimestamp)),
+ edited: entry(newMessage.editedTimestamp, renderDelta(newMessage.editedTimestamp)),
mentions: renderNumberDelta(oldMessage.mentions.users.size, newMessage.mentions.users.size),
attachments: entry(
renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size),
renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size) + attachmentJump
),
repliedTo: entry(
- replyTo,
+ replyTo ? replyTo.messageId! : null,
replyTo
? `[[Jump to message]](https://discord.com/channels/${newMessage.guild.id}/${newMessage.channel.id}/${replyTo.messageId})`
: "None"
diff --git a/src/index.ts b/src/index.ts
index f7fdde5..aff1b2b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,8 +1,8 @@
import runServer from "./api/index.js";
import client from "./utils/client.js";
-// @ts-expect-error
import config from "./config/main.json" assert { type: "json" };
import register from "./utils/commandRegistration/register.js";
+import { record as recordPerformance } from "./utils/performanceTesting/record.js";
client.on("ready", () => {
console.log(`Logged in as ${client.user!.tag}!`);
@@ -18,3 +18,5 @@
if (config.enableDevelopment) { await client.login(config.developmentToken); }
else { await client.login(config.token); }
+
+await recordPerformance();
\ No newline at end of file
diff --git a/src/premium/attachmentLogs.ts b/src/premium/attachmentLogs.ts
index 0c491b7..abda27d 100644
--- a/src/premium/attachmentLogs.ts
+++ b/src/premium/attachmentLogs.ts
@@ -4,7 +4,7 @@
import { saveAttachment } from "../reflex/scanners.js";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";
import addPlural from "../utils/plurals.js";
-import type { Message } from "discord.js";
+import type { GuildTextBasedChannel, Message } from "discord.js";
export default async function logAttachment(message: Message): Promise<AttachmentLogSchema> {
if (!message.guild) throw new Error("Tried to log an attachment in a non-guild message");
@@ -31,7 +31,7 @@
}
}
if (attachments.length === 0) return { files: [] };
- if (client.database.premium.hasPremium(message.guild.id)) {
+ if (await client.database.premium.hasPremium(message.guild.id)) {
const channel = (await client.database.guilds.read(message.guild.id)).logging.attachments.channel;
if (!channel) {
singleNotify(
@@ -52,7 +52,7 @@
);
return { files: attachments };
}
- const m = await channelObj.send({
+ const m = await (channelObj as GuildTextBasedChannel).send({
embeds: [
new EmojiEmbed()
.setTitle(`${addPlural(attachments.length, "Attachment")} Sent`)
@@ -60,8 +60,8 @@
keyValueList({
messageId: `\`${message.id}\``,
sentBy: renderUser(message.author),
- sentIn: renderChannel(message.channel),
- sent: renderDelta(new Date(message.createdTimestamp))
+ sentIn: renderChannel(message.channel as GuildTextBasedChannel),
+ sent: renderDelta((new Date(message.createdTimestamp)).getTime())
}) + `\n[[Jump to message]](${message.url})`
)
.setEmoji("ICONS.ATTACHMENT")
diff --git a/src/premium/createTranscript.ts b/src/premium/createTranscript.ts
index 6805017..e755b83 100644
--- a/src/premium/createTranscript.ts
+++ b/src/premium/createTranscript.ts
@@ -6,7 +6,8 @@
ButtonBuilder,
MessageComponentInteraction,
TextChannel,
- ButtonStyle
+ ButtonStyle,
+ User
} from "discord.js";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";
import getEmojiByName from "../utils/getEmojiByName.js";
@@ -76,7 +77,7 @@
.setEmoji("CONTROL.DOWNLOAD")
],
components: [
- new ActionRowBuilder().addComponents([
+ new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(url),
new ButtonBuilder()
.setLabel("Delete")
@@ -99,7 +100,7 @@
.setEmoji("CONTROL.DOWNLOAD")
],
components: [
- new ActionRowBuilder().addComponents([
+ new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setLabel("Delete")
.setStyle(ButtonStyle.Danger)
@@ -128,8 +129,8 @@
},
list: {
ticketFor: member ? entry(member.id, renderUser(member.user)) : entry(null, "*Unknown*"),
- deletedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user)),
- deleted: entry(new Date().getTime(), renderDelta(new Date().getTime()))
+ deletedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user as User)),
+ deleted: entry(new Date().getTime().toString(), renderDelta(new Date().getTime()))
},
hidden: {
guild: interaction.guild!.id
diff --git a/src/reflex/verify.ts b/src/reflex/verify.ts
index 6458439..2372130 100644
--- a/src/reflex/verify.ts
+++ b/src/reflex/verify.ts
@@ -5,7 +5,8 @@
MessageComponentInteraction,
Role,
ButtonStyle,
- PermissionsBitField
+ PermissionsBitField,
+ ButtonInteraction
} from "discord.js";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";
import fetch from "node-fetch";
@@ -28,7 +29,7 @@
return "\n\n" + createPageIndicator(5, i);
}
-export default async function (interaction: CommandInteraction | MessageComponentInteraction) {
+export default async function (interaction: CommandInteraction | ButtonInteraction) {
const verify = client.verify;
await interaction.reply({
embeds: LoadingEmbed,
diff --git a/src/utils/client.ts b/src/utils/client.ts
index a57c639..43cbe11 100644
--- a/src/utils/client.ts
+++ b/src/utils/client.ts
@@ -1,8 +1,8 @@
-import Discord, { Client, Interaction, AutocompleteInteraction } from 'discord.js';
+import Discord, { Client, Interaction, AutocompleteInteraction, GatewayIntentBits } from 'discord.js';
import { Logger } from "../utils/log.js";
import Memory from "../utils/memory.js";
import type { VerifySchema } from "../reflex/verify.js";
-import { Guilds, History, ModNotes, Premium } from "../utils/database.js";
+import { Guilds, History, ModNotes, Premium, PerformanceTest } from "../utils/database.js";
import EventScheduler from "../utils/eventScheduler.js";
import type { RoleMenuSchema } from "../actions/roleMenu.js";
import config from "../config/main.json" assert { type: "json" };
@@ -21,6 +21,7 @@
notes: ModNotes;
premium: Premium;
eventScheduler: EventScheduler;
+ performanceTest: PerformanceTest;
};
commands: Record<string, {
command: Discord.SlashCommandBuilder |
@@ -32,7 +33,13 @@
}> = {};
constructor(database: typeof NucleusClient.prototype.database) {
- super({ intents: 32767 });
+ super({ intents: [
+ GatewayIntentBits.Guilds,
+ GatewayIntentBits.GuildMessages,
+ GatewayIntentBits.MessageContent,
+ GatewayIntentBits.GuildPresences,
+ GatewayIntentBits.GuildMembers
+ ]});
this.database = database;
}
}
@@ -42,7 +49,8 @@
history: new History(),
notes: new ModNotes(),
premium: new Premium(),
- eventScheduler: new EventScheduler()
+ eventScheduler: new EventScheduler(),
+ performanceTest: new PerformanceTest()
});
export default client;
diff --git a/src/utils/commandRegistration/register.ts b/src/utils/commandRegistration/register.ts
index a4c57c4..d96ca90 100644
--- a/src/utils/commandRegistration/register.ts
+++ b/src/utils/commandRegistration/register.ts
@@ -16,7 +16,7 @@
async function registerCommands() {
const commands = [];
- const files = fs.readdirSync(config.commandsFolder, { withFileTypes: true }).filter(
+ const files: fs.Dirent[] = fs.readdirSync(config.commandsFolder, { withFileTypes: true }).filter(
file => !file.name.endsWith(".ts") && !file.name.endsWith(".map")
);
console.log(`Registering ${files.length} commands`)
@@ -25,10 +25,15 @@
const last = i === files.length - 1 ? "└" : "├";
if (file.isDirectory()) {
console.log(`${last}─ ${colours.yellow}Loading subcommands of ${file.name}${colours.none}`)
- commands.push((await import(`../../../${config.commandsFolder}/${file.name}/_meta.js`)).command);
+ const fetched = (await import(`../../../${config.commandsFolder}/${file.name}/_meta.js`)).command;
+ commands.push(fetched);
} else if (file.name.endsWith(".js")) {
console.log(`${last}─ ${colours.yellow}Loading command ${file.name}${colours.none}`)
const fetched = (await import(`../../../${config.commandsFolder}/${file.name}`));
+ fetched.command.setDMPermission(fetched.allowedInDMs ?? false)
+ fetched.command.setNameLocalizations(fetched.nameLocalizations ?? {})
+ fetched.command.setDescriptionLocalizations(fetched.descriptionLocalizations ?? {})
+ if (fetched.nameLocalizations || fetched.descriptionLocalizations) console.log("AAAAA")
commands.push(fetched.command);
client.commands["commands/" + fetched.command.name] = fetched;
}
@@ -97,6 +102,8 @@
console.log(`${last}─ ${colours.yellow}Loading message context menu ${file.name}${colours.none}`)
const context = (await import(`../../../${config.messageContextFolder}/${file.name}`));
context.command.setType(ApplicationCommandType.Message);
+ context.command.setDMPermission(context.allowedInDMs ?? false)
+ context.command.setNameLocalizations(context.nameLocalizations ?? {})
commands.push(context.command);
client.commands["contextCommands/message/" + context.command.name] = context;
@@ -182,6 +189,7 @@
callback(data);
}
+
export default async function register() {
let commandList: ( Discord.SlashCommandBuilder | Discord.ContextMenuCommandBuilder )[] = [];
commandList = commandList.concat(await registerCommands());
diff --git a/src/utils/commandRegistration/slashCommandBuilder.ts b/src/utils/commandRegistration/slashCommandBuilder.ts
index 76ecabe..b2927d6 100644
--- a/src/utils/commandRegistration/slashCommandBuilder.ts
+++ b/src/utils/commandRegistration/slashCommandBuilder.ts
@@ -13,7 +13,13 @@
}
-export async function group(name: string, description: string, path: string) {
+export async function group(
+ name: string,
+ description: string,
+ path: string,
+ nameLocalizations?: Record<string, string>,
+ descriptionLocalizations?: Record<string, string>
+) {
// If the name of the command does not match the path (e.g. attachment.ts has /attachments), use commandString
console.log(`│ ├─ Loading group ${name}`)
const fetched = await getSubcommandsInFolder(config.commandsFolder + "/" + path, "│ ")
@@ -22,6 +28,8 @@
subcommandGroup
.setName(name)
.setDescription(description)
+ if (nameLocalizations) { subcommandGroup.setNameLocalizations(nameLocalizations) }
+ if (descriptionLocalizations) { subcommandGroup.setDescriptionLocalizations(descriptionLocalizations) }
for (const subcommand of fetched.subcommands) {
subcommandGroup.addSubcommand(subcommand.command);
@@ -31,7 +39,16 @@
};
}
-export async function command(name: string, description: string, path: string, commandString: string | undefined = undefined) {
+export async function command(
+ name: string,
+ description: string,
+ path: string,
+ commandString: string | undefined = undefined,
+ nameLocalizations?: Record<string, string>,
+ descriptionLocalizations?: Record<string, string>,
+ userPermissions?: Discord.PermissionsString[],
+ allowedInDMs?: boolean
+) {
// If the name of the command does not match the path (e.g. attachment.ts has /attachments), use commandString
commandString = "commands/" + (commandString ?? path);
const fetched = await getSubcommandsInFolder(config.commandsFolder + "/" + path);
@@ -39,6 +56,14 @@
return (command: SlashCommandBuilder) => {
command.setName(name)
command.setDescription(description)
+ command.setNameLocalizations(nameLocalizations ?? {})
+ command.setDescriptionLocalizations(descriptionLocalizations ?? {})
+ command.setDMPermission(allowedInDMs ?? false)
+ if (userPermissions) {
+ const bitfield = new Discord.PermissionsBitField()
+ bitfield.add(userPermissions)
+ command.setDefaultMemberPermissions(bitfield.bitfield)
+ }
for (const subcommand of fetched.subcommands) {
let fetchedCommand;
diff --git a/src/utils/database.ts b/src/utils/database.ts
index b14c5c4..ba1d89d 100644
--- a/src/utils/database.ts
+++ b/src/utils/database.ts
@@ -149,6 +149,33 @@
}
}
+export class PerformanceTest {
+ performanceData: Collection<PerformanceDataSchema>;
+
+ constructor() {
+ this.performanceData = database.collection<PerformanceDataSchema>("performance");
+ }
+
+ async record(data: PerformanceDataSchema) {
+ data.timestamp = new Date();
+ await this.performanceData.insertOne(data);
+ }
+ async read() {
+ return await this.performanceData.find({}).toArray();
+ }
+}
+
+export interface PerformanceDataSchema {
+ timestamp?: Date;
+ discord: number;
+ databaseRead: number;
+ resources: {
+ cpu: number;
+ memory: number;
+ temperature: number;
+ }
+}
+
export class ModNotes {
modNotes: Collection<ModNoteSchema>;
@@ -205,7 +232,11 @@
};
invite: {
enabled: boolean;
- channels: string[];
+ allowed: {
+ channels: string[];
+ roles: string[];
+ users: string[];
+ };
};
pings: {
mass: number;
diff --git a/src/utils/log.ts b/src/utils/log.ts
index b097798..7ab7903 100644
--- a/src/utils/log.ts
+++ b/src/utils/log.ts
@@ -25,7 +25,7 @@
const delta = num2 - num1;
return `${num1} -> ${num2} (${delta > 0 ? "+" : ""}${delta})`;
},
- entry(value: string | null, displayValue: string): { value: string | null; displayValue: string } {
+ entry(value: string | number | null, displayValue: string): { value: string | null; displayValue: string } {
return { value: value, displayValue: displayValue };
},
renderChannel(channel: Discord.GuildChannel | Discord.ThreadChannel) {
@@ -44,16 +44,15 @@
},
async getAuditLog(guild: Discord.Guild, event: Discord.GuildAuditLogsResolvable): Promise<Discord.GuildAuditLogsEntry[]> {
await wait(250);
- const auditLog = await guild.fetchAuditLogs({ type: event });
- return auditLog as unknown as Discord.GuildAuditLogsEntry[];
+ const auditLog = (await guild.fetchAuditLogs({ type: event })).entries.map(m => m)
+ return auditLog as Discord.GuildAuditLogsEntry[];
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async log(log: any): Promise<void> {
const config = await client.database.guilds.read(log.hidden.guild);
if (!config.logging.logs.enabled) return;
- if (!(log.meta.calculateType === true)) {
- if (!toHexArray(config.logging.logs.toLog).includes(log.meta.calculateType))
- console.log("Not logging this type of event");
+ if (!toHexArray(config.logging.logs.toLog).includes(log.meta.calculateType)) {
+ console.log("Not logging this type of event");
return;
}
if (config.logging.logs.channel) {
diff --git a/src/utils/logTranscripts.ts b/src/utils/logTranscripts.ts
new file mode 100644
index 0000000..d5ab0b2
--- /dev/null
+++ b/src/utils/logTranscripts.ts
@@ -0,0 +1,3 @@
+function JSONTranscriptFromMessageArray(messages: Discord.Message[]) {
+
+}
\ No newline at end of file
diff --git a/src/utils/performanceTesting/record.ts b/src/utils/performanceTesting/record.ts
new file mode 100644
index 0000000..2d9524b
--- /dev/null
+++ b/src/utils/performanceTesting/record.ts
@@ -0,0 +1,47 @@
+import client from "../client.js";
+import { resourceUsage } from "process";
+import { spawn } from "child_process";
+import config from "../../config/main.json" assert { type: "json" };
+
+
+const discordPing = () => {
+ return client.ws.ping;
+}
+
+const databaseReadTime = async () => {
+ const guild = await client.guilds.fetch(config.managementGuildID);
+ const user = guild.ownerId;
+ const currentYear = new Date().getFullYear();
+ const start = Date.now();
+ client.database.history.read(guild.id, user, currentYear - 1);
+ const end = Date.now();
+ return end - start;
+}
+
+const resources = () => {
+ const current = resourceUsage();
+ const temperatureRaw = spawn("acpi", ["-t"])
+ let temperatureData: number = 0;
+ temperatureRaw.stdout.on("data", (data) => {
+ return temperatureData = data.toString().split(", ")[1].split(" ")[0]; // °C
+ })
+ return {
+ memory: current.sharedMemorySize,
+ cpu: current.userCPUTime + current.systemCPUTime,
+ temperature: temperatureData
+ }
+}
+
+const record = async () => {
+ const results = {
+ discord: discordPing(),
+ databaseRead: await databaseReadTime(),
+ resources: resources()
+ }
+ client.database.performanceTest.record(results)
+ setInterval(async () => {
+ record();
+ }, 10 * 1000);
+}
+
+export { record };
\ No newline at end of file