Performance testing

pull/17/head
PineaFan 3 years ago
parent 5bea7e1286
commit 538d375729
No known key found for this signature in database
GPG Key ID: 0AEF25BAA0FB1C74

@ -48,7 +48,11 @@ for (const file of files) {
},
invite: {
enabled: data.invite ? data.invite.enabled : false,
channels: data.invite ? data.invite.whitelist.channels.map((channel) => channel.toString()) : []
allowed: {
channels: data.invite ? data.invite.whitelist.channels.map((channel) => channel.toString()) : [],
users: [],
roles: []
}
},
pings: {
mass: 5,

@ -0,0 +1,30 @@
-rw-r--r-- 1 pineapplefan pineapplefan 2735 Dec 29 11:03 channelCreate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 3661 Dec 29 11:04 channelDelete.ts
-rw-r--r-- 1 pineapplefan pineapplefan 7430 Nov 15 20:45 channelUpdate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 960 Nov 15 20:39 commandError.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1097 Aug 8 21:15 emojiCreate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1184 Aug 8 21:15 emojiDelete.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1183 Aug 8 21:15 emojiUpdate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1849 Dec 29 11:04 guildBanAdd.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1558 Dec 29 11:04 guildBanRemove.ts
-rw-r--r-- 1 pineapplefan pineapplefan 267 Dec 29 11:04 guildCreate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 5553 Dec 29 11:04 guildMemberUpdate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 3863 Jan 6 17:42 guildUpdate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1710 Jan 6 18:38 interactionCreate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1482 Dec 29 11:04 inviteCreate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1471 Dec 29 11:04 inviteDelete.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1387 Dec 29 11:04 memberJoin.ts
-rw-r--r-- 1 pineapplefan pineapplefan 3260 Jan 2 21:41 memberLeave.ts
-rw-r--r-- 1 pineapplefan pineapplefan 14919 Dec 29 11:04 messageCreate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 4907 Dec 29 11:04 ! messageDelete.ts
-rw-r--r-- 1 pineapplefan pineapplefan 4907 Dec 29 11:04 ? messageEdit.ts: Check message publishing
-rw-r--r-- 1 pineapplefan pineapplefan 1268 Dec 29 11:04 roleCreate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1915 Dec 29 11:04 roleDelete.ts
-rw-r--r-- 1 pineapplefan pineapplefan 2562 Dec 29 11:04 roleUpdate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1262 Dec 29 11:04 stickerCreate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1349 Dec 29 11:04 stickerDelete.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1272 Dec 29 11:04 stickerUpdate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 1967 Dec 29 11:04 threadCreate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 2140 Dec 29 11:04 threadDelete.ts
-rw-r--r-- 1 pineapplefan pineapplefan 2464 Dec 29 11:04 threadUpdate.ts
-rw-r--r-- 1 pineapplefan pineapplefan 6352 Dec 29 11:04 webhookUpdate.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 @@ export interface RoleMenuSchema {
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);

@ -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 @@ function capitalize(s: string) {
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;

@ -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;

@ -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 @@ const command = new SlashCommandBuilder()
.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) => {

@ -3,6 +3,6 @@ import { command } from "../../utils/commandRegistration/slashCommandBuilder.js"
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 };

@ -74,6 +74,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
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 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
.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")
],

@ -23,6 +23,7 @@ import pageIndicator from "../../utils/createPageIndicator.js";
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)

@ -75,6 +75,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
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 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.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")
],

@ -13,6 +13,7 @@ import { areTicketsEnabled, create } from "../../actions/createModActionTicket.j
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 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
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 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.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" +

@ -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 @@ import client from "../../utils/client.js";
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) =>

@ -29,11 +29,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
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()

@ -84,6 +84,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
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 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.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}>`

@ -5,4 +5,6 @@ const description = "Commands relating to Nucleus itself";
const subcommand = await command(name, description, `nucleus`)
export { name, description, subcommand as command };
const allowedInDMs = true;
export { name, description, subcommand as command, allowedInDMs };

@ -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 = () => {

@ -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 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
.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`
)
])
],

@ -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 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
.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")

@ -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";

@ -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 command = (builder: SlashCommandSubcommandBuilder) =>
);
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 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
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")

@ -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 @@ import client from "../../utils/client.js";
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 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
`${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
});

@ -4,6 +4,8 @@ const name = "settings";
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};

@ -224,6 +224,16 @@ const check = (interaction: CommandInteraction) => {
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 };

@ -7,7 +7,8 @@ import Discord, {
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 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.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 callback = async (interaction: CommandInteraction): Promise<unknown> => {
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 };

@ -58,10 +58,8 @@ const check = () => {
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;
};

@ -79,7 +79,7 @@ async function userAbout(guild: Discord.Guild, member: Discord.GuildMember, inte
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

@ -19,7 +19,11 @@
},
"invite": {
"enabled": false,
"channels": []
"allowed": {
"users": [],
"roles": [],
"channels": []
}
},
"pings": {
"mass": 5,

@ -41,7 +41,8 @@
"GUILD_STAGE_VOICE": "853668786842763294",
"THREAD_CHANNEL": "990210005108158514",
"THREAD_PIPE": "990213168183779348",
"RULES": "990213153080115250"
"RULES": "990213153080115250",
"FORUM": "1061706437526552716"
}
},
"CONTROL": {

@ -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 @@ export async function callback(client: NucleusClient, channel: GuildBasedChannel
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);
}
};

@ -5,6 +5,7 @@ export const event = "channelUpdate";
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;

@ -78,7 +78,7 @@ export async function callback(client: NucleusClient, before: Guild, after: Guil
const data = {
meta: {
type: "guildUpdate",
displayName: "Guild Edited",
displayName: "Server Edited",
calculateType: "guildUpdate",
color: NucleusColors.yellow,
emoji: "GUILD.YELLOW",

@ -4,7 +4,7 @@ import create from "../actions/tickets/create.js";
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 @@ export const event = "interactionCreate";
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") ?? ""));
// }

@ -12,7 +12,7 @@ export const event = "messageCreate";
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 @@ export async function callback(_client: NucleusClient, message: Message) {
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"

@ -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 @@ export async function callback(client: NucleusClient, message: Message) {
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 @@ export async function callback(client: NucleusClient, message: Message) {
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: {

@ -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 @@ export async function callback(client: NucleusClient, oldMessage: Message, newMe
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 @@ export async function callback(client: NucleusClient, oldMessage: Message, newMe
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 @@ export async function callback(client: NucleusClient, oldMessage: Message, newMe
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"

@ -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 @@ process.on("uncaughtException", (err) => {
if (config.enableDevelopment) { await client.login(config.developmentToken); }
else { await client.login(config.token); }
await recordPerformance();

@ -4,7 +4,7 @@ import singleNotify from "../utils/singleNotify.js";
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 @@ export default async function logAttachment(message: Message): Promise<Attachmen
}
}
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 @@ export default async function logAttachment(message: Message): Promise<Attachmen
);
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 @@ export default async function logAttachment(message: Message): Promise<Attachmen
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")

@ -6,7 +6,8 @@ import {
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 @@ export default async function (interaction: CommandInteraction | MessageComponen
.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 @@ export default async function (interaction: CommandInteraction | MessageComponen
.setEmoji("CONTROL.DOWNLOAD")
],
components: [
new ActionRowBuilder().addComponents([
new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setLabel("Delete")
.setStyle(ButtonStyle.Danger)
@ -128,8 +129,8 @@ export default async function (interaction: CommandInteraction | MessageComponen
},
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

@ -5,7 +5,8 @@ import Discord, {
MessageComponentInteraction,
Role,
ButtonStyle,
PermissionsBitField
PermissionsBitField,
ButtonInteraction
} from "discord.js";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";
import fetch from "node-fetch";
@ -28,7 +29,7 @@ function step(i: number) {
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,

@ -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 @@ class NucleusClient extends Client {
notes: ModNotes;
premium: Premium;
eventScheduler: EventScheduler;
performanceTest: PerformanceTest;
};
commands: Record<string, {
command: Discord.SlashCommandBuilder |
@ -32,7 +33,13 @@ class NucleusClient extends Client {
}> = {};
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 @@ const client = new NucleusClient({
history: new History(),
notes: new ModNotes(),
premium: new Premium(),
eventScheduler: new EventScheduler()
eventScheduler: new EventScheduler(),
performanceTest: new PerformanceTest()
});
export default client;

@ -16,7 +16,7 @@ const colours = {
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 @@ async function registerCommands() {
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 @@ async function registerContextMenus() {
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 @@ async function execute(check: Function | undefined, callback: Function | undefin
callback(data);
}
export default async function register() {
let commandList: ( Discord.SlashCommandBuilder | Discord.ContextMenuCommandBuilder )[] = [];
commandList = commandList.concat(await registerCommands());

@ -13,7 +13,13 @@ const colours = {
}
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 @@ export async function group(name: string, description: string, path: string) {
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 group(name: string, description: string, path: string) {
};
}
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 @@ export async function command(name: string, description: string, path: string, c
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;

@ -149,6 +149,33 @@ export class History {
}
}
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 @@ export interface GuildConfig {
};
invite: {
enabled: boolean;
channels: string[];
allowed: {
channels: string[];
roles: string[];
users: string[];
};
};
pings: {
mass: number;

@ -25,7 +25,7 @@ export const Logger = {
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 @@ export const Logger = {
},
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) {

@ -0,0 +1,3 @@
function JSONTranscriptFromMessageArray(messages: Discord.Message[]) {
}

@ -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 };
Loading…
Cancel
Save