Working on viewas

pull/17/head
PineaFan 3 years ago
parent 538d375729
commit 1dee28f37e
No known key found for this signature in database
GPG Key ID: D404018735F488C9

@ -23,6 +23,7 @@
"node-tesseract-ocr": "^2.2.1",
"pastebin-api": "^5.1.1",
"structured-clone": "^0.2.2",
"systeminformation": "^5.17.3",
"typescript": "^5.0.0-dev.20230102",
"uuid": "^8.3.2"
},

@ -1,4 +1,4 @@
import { LoadingEmbed } from './../../utils/defaultEmbeds.js';
import { LoadingEmbed } from '../../utils/defaultEmbeds.js';
import type { HistorySchema } from "../../utils/database.js";
import Discord, {
CommandInteraction,
@ -22,8 +22,8 @@ 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"})
.setName("about")
// .setNameLocalizations({"ru": "info", "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)

@ -59,6 +59,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
)
.setColor("Danger")
.addReasonButton(reason ?? "")
.setFailedMessage("No changes were made", "Success", "PUNISH.BAN.GREEN")
.send(reason !== null);
reason = reason ?? "";
if (confirmation.cancelled) timedOut = true;
@ -66,116 +67,103 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
else if (confirmation.newReason) reason = confirmation.newReason;
else if (confirmation.components) notify = confirmation.components["notify"]!.active;
} while (!timedOut && !chosen)
if (timedOut) return;
if (confirmation.success) {
reason = reason.length ? reason : null
let dmSent = false;
let dmMessage;
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>[];
} = {
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.BAN.RED")
.setTitle("Banned")
.setDescription(
`You have been banned in ${interaction.guild.name}` +
(reason ? ` for:\n${reason}` : ".\n*No reason was provided.*")
)
.setStatus("Danger")
],
components: []
};
if (config.moderation.ban.text && config.moderation.ban.link) {
messageData.embeds[0]!.setFooter(LinkWarningFooter)
messageData.components.push(new ActionRowBuilder<Discord.ButtonBuilder>()
.addComponents(new ButtonBuilder()
.setStyle(ButtonStyle.Link)
.setLabel(config.moderation.ban.text)
.setURL(config.moderation.ban.link)
)
)
}
dmMessage = await (interaction.options.getMember("user") as GuildMember).send(messageData);
dmSent = true;
}
} catch {
dmSent = false;
}
try {
const member = interaction.options.getMember("user") as GuildMember;
const days: number = interaction.options.get("delete")?.value as number | null ?? 0;
member.ban({
deleteMessageSeconds: days * 24 * 60 * 60,
reason: reason ?? "*No reason provided*"
});
await client.database.history.create("ban", interaction.guild.id, member.user, interaction.user, reason);
const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger;
const data = {
meta: {
type: "memberBan",
displayName: "Member Banned",
calculateType: "guildMemberPunish",
color: NucleusColors.red,
emoji: "PUNISH.BAN.RED",
timestamp: new Date().getTime()
},
list: {
memberId: entry(member.user.id, `\`${member.user.id}\``),
name: entry(member.user.id, renderUser(member.user)),
banned: entry(new Date().getTime().toString(), renderDelta(new Date().getTime())),
bannedBy: entry(interaction.user.id, renderUser(interaction.user)),
reason: entry(reason, reason ? `\n> ${reason}` : "*No reason provided.*"),
accountCreated: entry(member.user.createdAt.toString(), renderDelta(member.user.createdAt.getTime())),
serverMemberCount: interaction.guild.memberCount
},
hidden: {
guild: interaction.guild.id
}
};
log(data);
} catch {
await interaction.editReply({
if (timedOut || !confirmation.success) return;
reason = reason.length ? reason : null
let dmSent = false;
let dmMessage;
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>[];
} = {
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.BAN.RED")
.setTitle("Ban")
.setDescription("Something went wrong and the user was not banned")
.setTitle("Banned")
.setDescription(
`You have been banned in ${interaction.guild.name}` +
(reason ? ` for:\n${reason}` : ".\n*No reason was provided.*")
)
.setStatus("Danger")
],
components: []
});
if (dmSent && dmMessage) await dmMessage.delete();
return;
};
if (config.moderation.ban.text && config.moderation.ban.link) {
messageData.embeds[0]!.setFooter(LinkWarningFooter)
messageData.components.push(new ActionRowBuilder<Discord.ButtonBuilder>()
.addComponents(new ButtonBuilder()
.setStyle(ButtonStyle.Link)
.setLabel(config.moderation.ban.text)
.setURL(config.moderation.ban.link)
)
)
}
dmMessage = await (interaction.options.getMember("user") as GuildMember).send(messageData);
dmSent = true;
}
const failed = !dmSent && notify;
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji(`PUNISH.BAN.${failed ? "YELLOW" : "GREEN"}`)
.setTitle("Ban")
.setDescription("The member was banned" + (failed ? ", but could not be notified" : ""))
.setStatus(failed ? "Warning" : "Success")
],
components: []
} catch {
dmSent = false;
}
try {
const member = interaction.options.getMember("user") as GuildMember;
const days: number = interaction.options.get("delete")?.value as number | null ?? 0;
member.ban({
deleteMessageSeconds: days * 24 * 60 * 60,
reason: reason ?? "*No reason provided*"
});
} else {
await client.database.history.create("ban", interaction.guild.id, member.user, interaction.user, reason);
const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger;
const data = {
meta: {
type: "memberBan",
displayName: "Member Banned",
calculateType: "guildMemberPunish",
color: NucleusColors.red,
emoji: "PUNISH.BAN.RED",
timestamp: new Date().getTime()
},
list: {
memberId: entry(member.user.id, `\`${member.user.id}\``),
name: entry(member.user.id, renderUser(member.user)),
banned: entry(new Date().getTime().toString(), renderDelta(new Date().getTime())),
bannedBy: entry(interaction.user.id, renderUser(interaction.user)),
reason: entry(reason, reason ? `\n> ${reason}` : "*No reason provided.*"),
accountCreated: entry(member.user.createdAt.toString(), renderDelta(member.user.createdAt.getTime())),
serverMemberCount: interaction.guild.memberCount
},
hidden: {
guild: interaction.guild.id
}
};
log(data);
} catch {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.BAN.GREEN")
.setEmoji("PUNISH.BAN.RED")
.setTitle("Ban")
.setDescription("No changes were made")
.setStatus("Success")
.setDescription("Something went wrong and the user was not banned")
.setStatus("Danger")
],
components: []
});
if (dmSent && dmMessage) await dmMessage.delete();
return;
}
const failed = !dmSent && notify;
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji(`PUNISH.BAN.${failed ? "YELLOW" : "GREEN"}`)
.setTitle("Ban")
.setDescription("The member was banned" + (failed ? ", but could not be notified" : ""))
.setStatus(failed ? "Warning" : "Success")
],
components: []
});
};
const check = async (interaction: CommandInteraction) => {

@ -47,6 +47,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
notify
)
.addReasonButton(reason ?? "")
.setFailedMessage("No changes were made", "Success", "PUNISH.KICK.GREEN")
.send(reason !== null);
reason = reason ?? "";
if (confirmation.cancelled) timedOut = true;
@ -56,20 +57,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
notify = confirmation.components["notify"]!.active;
}
} while (!timedOut && !success)
if (timedOut) return;
if (!confirmation.success) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.KICK.GREEN")
.setTitle("Kick")
.setDescription("No changes were made")
.setStatus("Success")
],
components: []
});
return;
}
if (timedOut || !confirmation.success) return;
let dmSent = false;
let dmMessage;
const config = await client.database.guilds.read(interaction.guild.id);

@ -207,6 +207,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
notify
)
.addReasonButton(reason ?? "")
.setFailedMessage("No changes were made", "Success", "PUNISH.MUTE.GREEN")
.send(true);
reason = reason ?? "";
if (confirmation.cancelled) timedOut = true;
@ -217,20 +218,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
createAppealTicket = confirmation.components["appeal"]!.active;
}
} while (!timedOut && !success)
if (timedOut) return;
if (!confirmation.success) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.BAN.GREEN")
.setTitle("Softban")
.setDescription("No changes were made")
.setStatus("Success")
],
components: []
});
return;
}
if (timedOut || !confirmation.success) return;
const status: {timeout: boolean | null, role: boolean | null, dm: boolean | null} = {timeout: null, role: null, dm: null};
let dmMessage;
try {

@ -169,22 +169,22 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
const check = (interaction: CommandInteraction) => {
const member = interaction.member as GuildMember;
const me = interaction.guild.me!;
const me = interaction.guild!.members.me!;
const apply = interaction.options.getMember("user") as GuildMember;
if (member === null || me === null || apply === null) throw new Error("That member is not in the server");
const memberPos = member.roles.cache.size ? member.roles.highest.position : 0;
const mePos = me.roles.cache.size ? me.roles.highest.position : 0;
const applyPos = apply.roles.cache.size ? apply.roles.highest.position : 0;
if (!interaction.guild) return false;
// Do not allow any changing of the owner
if (member.id === interaction.guild.ownerId) throw new Error("You cannot change the owner's nickname");
// Check if Nucleus can change the nickname
if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
// Check if Nucleus has permission to change the nickname
if (!me.permissions.has("MANAGE_NICKNAMES")) throw new Error("I do not have the *Manage Nicknames* permission");
if (!me.permissions.has("ManageNicknames")) throw new Error("I do not have the *Manage Nicknames* permission");
// Allow the owner to change anyone's nickname
if (member.id === interaction.guild.ownerId) return true;
// Check if the user has manage_nicknames permission
if (!member.permissions.has("MANAGE_NICKNAMES"))
if (!member.permissions.has("ManageNicknames"))
throw new Error("You do not have the *Manage Nicknames* permission");
// Allow changing your own nickname
if (member === apply) return true;

@ -240,170 +240,158 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
})
)
.setColor("Danger")
.setFailedMessage("No changes were made", "Success", "CHANNEL.PURGE.GREEN")
.send();
if (confirmation.cancelled) return;
if (confirmation.success) {
let messages;
try {
if (!user) {
const toDelete = await (interaction.channel as TextChannel).messages.fetch({
limit: interaction.options.get("amount")?.value as number
});
messages = await (channel as TextChannel).bulkDelete(toDelete, true);
} else {
const toDelete = (
await (
await (interaction.channel as TextChannel).messages.fetch({
limit: 100
})
).filter((m) => m.author.id === user.id)
).first(interaction.options.get("amount")?.value as number);
messages = await (channel as TextChannel).bulkDelete(toDelete, true);
}
} catch (e) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.PURGE.RED")
.setTitle("Purge")
.setDescription("Something went wrong and no messages were deleted")
.setStatus("Danger")
],
components: []
});
}
if (!messages) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.PURGE.RED")
.setTitle("Purge")
.setDescription("No messages could be deleted")
.setStatus("Danger")
],
components: []
if (confirmation.cancelled || !confirmation.success) return;
let messages;
try {
if (!user) {
const toDelete = await (interaction.channel as TextChannel).messages.fetch({
limit: interaction.options.get("amount")?.value as number
});
return;
messages = await (channel as TextChannel).bulkDelete(toDelete, true);
} else {
const toDelete = (
await (
await (interaction.channel as TextChannel).messages.fetch({
limit: 100
})
).filter((m) => m.author.id === user.id)
).first(interaction.options.get("amount")?.value as number);
messages = await (channel as TextChannel).bulkDelete(toDelete, true);
}
if (user) {
await client.database.history.create(
"purge",
interaction.guild.id,
user.user,
interaction.user,
(interaction.options.get("reason")?.value as (string | null)) ?? "*No reason provided*",
null,
null,
messages.size.toString()
);
} catch (e) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.PURGE.RED")
.setTitle("Purge")
.setDescription("Something went wrong and no messages were deleted")
.setStatus("Danger")
],
components: []
});
}
if (!messages) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.PURGE.RED")
.setTitle("Purge")
.setDescription("No messages could be deleted")
.setStatus("Danger")
],
components: []
});
return;
}
if (user) {
await client.database.history.create(
"purge",
interaction.guild.id,
user.user,
interaction.user,
(interaction.options.get("reason")?.value as (string | null)) ?? "*No reason provided*",
null,
null,
messages.size.toString()
);
}
const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
const data = {
meta: {
type: "channelPurge",
displayName: "Channel Purged",
calculateType: "messageDelete",
color: NucleusColors.red,
emoji: "PUNISH.BAN.RED",
timestamp: new Date().getTime()
},
list: {
memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
purgedBy: entry(interaction.user.id, renderUser(interaction.user)),
channel: entry(interaction.channel!.id, renderChannel(interaction.channel! as GuildChannel)),
messagesCleared: entry(messages.size.toString(), messages.size.toString())
},
hidden: {
guild: interaction.guild.id
}
const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
const data = {
meta: {
type: "channelPurge",
displayName: "Channel Purged",
calculateType: "messageDelete",
color: NucleusColors.red,
emoji: "PUNISH.BAN.RED",
timestamp: new Date().getTime()
},
list: {
memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
purgedBy: entry(interaction.user.id, renderUser(interaction.user)),
channel: entry(interaction.channel!.id, renderChannel(interaction.channel! as GuildChannel)),
messagesCleared: entry(messages.size.toString(), messages.size.toString())
},
hidden: {
guild: interaction.guild.id
};
log(data);
let out = "";
messages.reverse().forEach((message) => {
if (!message) {
out += "Unknown message\n\n"
} else {
const author = message.author ?? { username: "Unknown", discriminator: "0000", id: "Unknown" };
out += `${author.username}#${author.discriminator} (${author.id}) [${new Date(
message.createdTimestamp
).toISOString()}]\n`;
if (message.content) {
const lines = message.content.split("\n");
lines.forEach((line) => {
out += `> ${line}\n`;
});
}
};
log(data);
let out = "";
messages.reverse().forEach((message) => {
if (!message) {
out += "Unknown message\n\n"
} else {
const author = message.author ?? { username: "Unknown", discriminator: "0000", id: "Unknown" };
out += `${author.username}#${author.discriminator} (${author.id}) [${new Date(
message.createdTimestamp
).toISOString()}]\n`;
if (message.content) {
const lines = message.content.split("\n");
lines.forEach((line) => {
out += `> ${line}\n`;
});
}
if (message.attachments.size > 0) {
message.attachments.forEach((attachment) => {
out += `Attachment > ${attachment.url}\n`;
});
}
out += "\n\n";
if (message.attachments.size > 0) {
message.attachments.forEach((attachment) => {
out += `Attachment > ${attachment.url}\n`;
});
}
out += "\n\n";
}
});
const attachmentObject = {
attachment: Buffer.from(out),
name: `purge-${channel.id}-${Date.now()}.txt`,
description: "Purge log"
};
const m = (await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.PURGE.GREEN")
.setTitle("Purge")
.setDescription("Messages cleared")
.setStatus("Success")
],
components: [
new Discord.ActionRowBuilder<ButtonBuilder>().addComponents([
new Discord.ButtonBuilder()
.setCustomId("download")
.setLabel("Download transcript")
.setStyle(ButtonStyle.Success)
.setEmoji(getEmojiByName("CONTROL.DOWNLOAD", "id"))
])
]
})) as Discord.Message;
let component;
try {
component = await m.awaitMessageComponent({
filter: (m) => m.user.id === interaction.user.id,
time: 300000
});
const attachmentObject = {
attachment: Buffer.from(out),
name: `purge-${channel.id}-${Date.now()}.txt`,
description: "Purge log"
};
const m = (await interaction.editReply({
} catch {
return;
}
if (component.customId === "download") {
interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.PURGE.GREEN")
.setTitle("Purge")
.setDescription("Messages cleared")
.setDescription("Transcript uploaded above")
.setStatus("Success")
],
components: [
new Discord.ActionRowBuilder<ButtonBuilder>().addComponents([
new Discord.ButtonBuilder()
.setCustomId("download")
.setLabel("Download transcript")
.setStyle(ButtonStyle.Success)
.setEmoji(getEmojiByName("CONTROL.DOWNLOAD", "id"))
])
]
})) as Discord.Message;
let component;
try {
component = await m.awaitMessageComponent({
filter: (m) => m.user.id === interaction.user.id,
time: 300000
});
} catch {
return;
}
if (component.customId === "download") {
interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.PURGE.GREEN")
.setTitle("Purge")
.setDescription("Transcript uploaded above")
.setStatus("Success")
],
components: [],
files: [attachmentObject]
});
} else {
interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.PURGE.GREEN")
.setTitle("Purge")
.setDescription("Messages cleared")
.setStatus("Success")
],
components: []
});
}
components: [],
files: [attachmentObject]
});
} else {
await interaction.editReply({
interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.PURGE.GREEN")
.setTitle("Purge")
.setDescription("No changes were made")
.setDescription("Messages cleared")
.setStatus("Success")
],
components: []

@ -47,45 +47,33 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
}) + "Are you sure you want to set the slowmode in this channel?"
)
.setColor("Danger")
.setFailedMessage("No changes were made", "Danger", "CHANNEL.SLOWMODE.ON")
.send();
if (confirmation.cancelled) return;
if (confirmation.success) {
try {
(interaction.channel as TextChannel).setRateLimitPerUser(time);
} catch (e) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.SLOWMODE.OFF")
.setTitle("Slowmode")
.setDescription("Something went wrong while setting the slowmode")
.setStatus("Danger")
],
components: []
});
}
if (confirmation.cancelled || !confirmation.success) return;
try {
(interaction.channel as TextChannel).setRateLimitPerUser(time);
} catch (e) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.SLOWMODE.ON")
.setEmoji("CHANNEL.SLOWMODE.OFF")
.setTitle("Slowmode")
.setDescription("The channel slowmode was set successfully")
.setStatus("Success")
],
components: []
});
} else {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.SLOWMODE.ON")
.setTitle("Slowmode")
.setDescription("No changes were made")
.setStatus("Success")
.setDescription("Something went wrong while setting the slowmode")
.setStatus("Danger")
],
components: []
});
}
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("CHANNEL.SLOWMODE.ON")
.setTitle("Slowmode")
.setDescription("The channel slowmode was set successfully")
.setStatus("Success")
],
components: []
});
};
const check = (interaction: CommandInteraction) => {

@ -1,13 +1,13 @@
import Discord, {
CategoryChannel,
CommandInteraction,
GuildMember,
ActionRowBuilder,
ButtonBuilder,
SelectMenuBuilder,
ButtonStyle
ButtonStyle,
NonThreadGuildBasedChannel
} from "discord.js";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import type { GuildBasedChannel } from "discord.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
import pageIndicator from "../../utils/createPageIndicator.js";
@ -19,145 +19,185 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
.addUserOption((option) => option.setName("member").setDescription("The member to view as").setRequired(true));
const callback = async (interaction: CommandInteraction): Promise<void> => {
let channels = [];
let m;
interaction.guild.channels.cache.forEach((channel) => {
if (!channel.parent && channel.type !== "GUILD_CATEGORY") channels.push(channel);
/*
* {
categoryObject: channel[],
categoryObject: channel[],
"null": channel[]
}
*/
const channels: Record<string, GuildBasedChannel[]> = {"": [] as GuildBasedChannel[]};
interaction.guild!.channels.fetch().then(channelCollection => {
channelCollection.forEach(channel => {
if (!channel) return; // if no channel
if (channel.type === Discord.ChannelType.GuildCategory) {
if(!channels[channel!.id]) channels[channel!.id] = [channel];
} else if (channel.parent) {
if (!channels[channel.parent.id]) channels[channel.parent.id] = [channel];
else (channels[channel.parent.id as string])!.push(channel);
} else {
channels[""]!.push(channel);
}
});
});
channels = [channels];
channels = channels.concat(
interaction.guild.channels.cache
.filter((c) => c.type === "GUILD_CATEGORY")
.map((c) => (c as CategoryChannel).children.map((c) => c))
);
const autoSortBelow = ["GUILD_VOICE", "GUILD_STAGE_VOICE"];
channels = channels.map((c) =>
c.sort((a, b) => {
if (autoSortBelow.includes(a.type) && autoSortBelow.includes(b.type)) return a.position - b.position;
const member = interaction.options.getMember("member") as Discord.GuildMember;
const autoSortBelow = [Discord.ChannelType.GuildVoice, Discord.ChannelType.GuildStageVoice];
// for each category, sort its channels. This should be based on the order of the channels, with voice and stage channels sorted below text
channels = Object.values(channels).map((c) => {
return c.sort((a: GuildBasedChannel, b: GuildBasedChannel) => {
if (a.type === Discord.ChannelType.PrivateThread || b.type === Discord.ChannelType.PrivateThread)
if (autoSortBelow.includes(a.type) && autoSortBelow.includes(b.type)) return a.position ?? 0 - b.position ;
if (autoSortBelow.includes(a.type)) return 1;
if (autoSortBelow.includes(b.type)) return -1;
return a.position - b.position;
})
);
// Sort all arrays by the position of the first channels parent position
channels = channels.sort((a, b) => {
if (!a[0].parent) return -1;
if (!b[0].parent) return 1;
return a[0].parent.position - b[0].parent.position;
});
const member = interaction.options.getMember("member") as Discord.GuildMember;
m = await interaction.reply({
embeds: [
new EmojiEmbed()
.setEmoji("MEMBER.JOIN")
.setTitle("Viewing as " + member.displayName)
.setStatus("Success")
],
ephemeral: true,
fetchReply: true
});
let page = 0;
let timedOut = false;
while (!timedOut) {
m = await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("MEMBER.JOIN")
.setTitle("Viewing as " + member.displayName)
.setStatus("Success")
.setDescription(
`**${channels[page][0].parent ? channels[page][0].parent.name : "Uncategorised"}**` +
"\n" +
channels[page]
.map((c) => {
let channelType = c.type;
if (interaction.guild.rulesChannelId === c.id) channelType = "RULES";
else if ("nsfw" in c && c.nsfw) channelType += "_NSFW";
return c.permissionsFor(member).has("VIEW_CHANNEL")
? `${getEmojiByName("ICONS.CHANNEL." + channelType)} ${c.name}\n` +
(() => {
if ("threads" in c && c.threads.cache.size > 0) {
return (
c.threads.cache
.map(
(t) =>
` ${
getEmojiByName("ICONS.CHANNEL.THREAD_PIPE") +
" " +
getEmojiByName("ICONS.CHANNEL.THREAD_CHANNEL")
} ${t.name}`
)
.join("\n") + "\n"
);
}
return "";
})()
: "";
})
.join("") +
"\n" +
pageIndicator(channels.length, page)
)
],
components: [
new ActionRowBuilder().addComponents([
new SelectMenuBuilder()
.setOptions(
channels.map((c, index) => ({
label: c[0].parent ? c[0].parent.name : "Uncategorised",
value: index.toString(),
default: page === index
}))
)
.setCustomId("select")
.setMaxValues(1)
.setMinValues(1)
.setPlaceholder("Select a category")
]),
new ActionRowBuilder().addComponents([
new ButtonBuilder()
.setLabel(
page === 0
? ""
: channels[page - 1][0].parent
? channels[page - 1][0].parent.name
: "Uncategorised"
)
.setDisabled(page === 0)
.setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
.setStyle(ButtonStyle.Primary)
.setCustomId("previous"),
new ButtonBuilder()
.setLabel(
page === channels.length - 1
? ""
: channels[page + 1][0].parent
? channels[page + 1][0].parent.name
: "Uncategorised"
)
.setDisabled(page === channels.length - 1)
.setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
.setStyle(ButtonStyle.Primary)
.setCustomId("next")
])
]
return a - b;
});
let i;
try {
i = await m.awaitMessageComponent({ time: 300000 });
} catch (e) {
timedOut = true;
continue;
}
i.deferUpdate();
if (i.customId === "next") {
page++;
} else if (i.customId === "previous") {
page--;
} else if (i.customId === "select") {
page = parseInt(i.values[0]);
}
}
//OLD CODE START
// const unprocessedChannels: GuildBasedChannel[] = [];
// let m;
// interaction.guild!.channels.cache.forEach((channel) => {
// if (!channel.parent && channel.type !== Discord.ChannelType.GuildCategory) unprocessedChannels.push(channel);
// });
// let channels: GuildBasedChannel[][] = [unprocessedChannels];
// channels = channels.concat(
// interaction.guild!.channels.cache
// .filter((c) => c.type === Discord.ChannelType.GuildCategory)
// .map((c) => (c as CategoryChannel).children.map((c) => c))
// );
// const autoSortBelow = ["GUILD_VOICE", "GUILD_STAGE_VOICE"];
// channels = channels.map((c) =>
// c.sort((a, b) => {
// if (autoSortBelow.includes(a.type) && autoSortBelow.includes(b.type)) return a.position - b.position;
// if (autoSortBelow.includes(a.type)) return 1;
// if (autoSortBelow.includes(b.type)) return -1;
// return a.position - b.position;
// })
// );
// // Sort all arrays by the position of the first channels parent position
// channels = channels.sort((a, b) => {
// if (!a[0].parent) return -1;
// if (!b[0].parent) return 1;
// return a[0].parent.position - b[0].parent.position;
// });
// const member = interaction.options.getMember("member") as Discord.GuildMember;
// m = await interaction.reply({
// embeds: [
// new EmojiEmbed()
// .setEmoji("MEMBER.JOIN")
// .setTitle("Viewing as " + member.displayName)
// .setStatus("Success")
// ],
// ephemeral: true,
// fetchReply: true
// });
// let page = 0;
// let timedOut = false;
// while (!timedOut) {
// m = await interaction.editReply({
// embeds: [
// new EmojiEmbed()
// .setEmoji("MEMBER.JOIN")
// .setTitle("Viewing as " + member.displayName)
// .setStatus("Success")
// .setDescription(
// `**${channels[page][0].parent ? channels[page][0].parent.name : "Uncategorised"}**` +
// "\n" +
// channels[page]
// .map((c) => {
// let channelType = c.type;
// if (interaction.guild.rulesChannelId === c.id) channelType = "RULES";
// else if ("nsfw" in c && c.nsfw) channelType += "_NSFW";
// return c.permissionsFor(member).has("VIEW_CHANNEL")
// ? `${getEmojiByName("ICONS.CHANNEL." + channelType)} ${c.name}\n` +
// (() => {
// if ("threads" in c && c.threads.cache.size > 0) {
// return (
// c.threads.cache
// .map(
// (t) =>
// ` ${
// getEmojiByName("ICONS.CHANNEL.THREAD_PIPE") +
// " " +
// getEmojiByName("ICONS.CHANNEL.THREAD_CHANNEL")
// } ${t.name}`
// )
// .join("\n") + "\n"
// );
// }
// return "";
// })()
// : "";
// })
// .join("") +
// "\n" +
// pageIndicator(channels.length, page)
// )
// ],
// components: [
// new ActionRowBuilder().addComponents([
// new SelectMenuBuilder()
// .setOptions(
// channels.map((c, index) => ({
// label: c[0].parent ? c[0].parent.name : "Uncategorised",
// value: index.toString(),
// default: page === index
// }))
// )
// .setCustomId("select")
// .setMaxValues(1)
// .setMinValues(1)
// .setPlaceholder("Select a category")
// ]),
// new ActionRowBuilder().addComponents([
// new ButtonBuilder()
// .setLabel(
// page === 0
// ? ""
// : channels[page - 1][0].parent
// ? channels[page - 1][0].parent.name
// : "Uncategorised"
// )
// .setDisabled(page === 0)
// .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
// .setStyle(ButtonStyle.Primary)
// .setCustomId("previous"),
// new ButtonBuilder()
// .setLabel(
// page === channels.length - 1
// ? ""
// : channels[page + 1][0].parent
// ? channels[page + 1][0].parent.name
// : "Uncategorised"
// )
// .setDisabled(page === channels.length - 1)
// .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
// .setStyle(ButtonStyle.Primary)
// .setCustomId("next")
// ])
// ]
// });
// let i;
// try {
// i = await m.awaitMessageComponent({ time: 300000 });
// } catch (e) {
// timedOut = true;
// continue;
// }
// i.deferUpdate();
// if (i.customId === "next") {
// page++;
// } else if (i.customId === "previous") {
// page--;
// } else if (i.customId === "select") {
// page = parseInt(i.values[0]);
// }
// }
};
const check = (interaction: CommandInteraction) => {

@ -56,6 +56,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
notify
)
.addReasonButton(reason ?? "")
.setFailedMessage("No changes were made", "Success", "PUNISH.WARN.GREEN")
.send(reason !== null);
reason = reason ?? "";
if (confirmation.cancelled) timedOut = true;
@ -66,20 +67,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
createAppealTicket = confirmation.components["appeal"]!.active;
}
} while (!timedOut && !success)
if (timedOut) return;
if (!confirmation.success) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.WARN.GREEN")
.setTitle("Warn")
.setDescription("No changes were made")
.setStatus("Success")
],
components: []
});
return;
}
if (timedOut || !confirmation.success) return;
let dmSent = false;
const config = await client.database.guilds.read(interaction.guild.id);
try {

@ -1,9 +1,11 @@
import type { CommandInteraction } from "discord.js";
import type Discord from "discord.js";
import { LoadingEmbed } from './../../utils/defaultEmbeds.js';
import { ButtonStyle, CommandInteraction } from "discord.js";
import Discord from "discord.js";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import confirmationMessage from "../../utils/confirmationMessage.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import client from "../../utils/client.js";
import getEmojiByName from '../../utils/getEmojiByName.js';
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
@ -17,6 +19,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
await interaction.guild?.members.fetch(interaction.member!.user.id)
const { renderUser } = client.logger;
const suggestion = interaction.options.get("suggestion")?.value as string;
await interaction.reply({embeds: LoadingEmbed, ephemeral: true})
const confirmation = await new confirmationMessage(interaction)
.setEmoji("ICONS.OPP.ADD")
.setTitle("Suggest")
@ -26,7 +29,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
)
.setColor("Danger")
.setInverted(true)
.send();
.send(true);
if (confirmation.cancelled) return;
if (confirmation.success) {
await (client.channels.cache.get("955161206459600976") as Discord.TextChannel).send({
@ -34,11 +37,22 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
new EmojiEmbed()
.setTitle("Suggestion")
.setDescription(
`**From:** ${renderUser(interaction.member!.user as Discord.User)}\n**Suggestion:**\n> ${suggestion}`
`**From:** ${renderUser(interaction.member!.user as Discord.User)}\n**Suggestion:**\n> ${suggestion}\n\n` +
`**Server:** ${interaction.guild!.name} (${interaction.guild!.id})\n`,
)
.setStatus("Danger")
.setEmoji("NUCLEUS.LOGO")
]
.setStatus("Warning")
], components: [new Discord.ActionRowBuilder<Discord.ButtonBuilder>().addComponents(
new Discord.ButtonBuilder()
.setCustomId("suggestionAccept")
.setLabel("Accept")
.setStyle(ButtonStyle.Secondary)
.setEmoji(getEmojiByName("ICONS.ADD", "id")),
new Discord.ButtonBuilder()
.setCustomId("suggestionDeny")
.setLabel("Delete")
.setStyle(ButtonStyle.Secondary)
.setEmoji(getEmojiByName("ICONS.REMOVE", "id"))
)]
});
await interaction.editReply({
embeds: [

@ -5,7 +5,9 @@ import close from "../actions/tickets/delete.js";
import createTranscript from "../premium/createTranscript.js";
import type { Interaction } from "discord.js";
import type Discord from "discord.js";
import type { NucleusClient } from "../utils/client.js";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";
export const event = "interactionCreate";
@ -18,20 +20,29 @@ async function interactionCreate(interaction: Interaction) {
case "createticket": { return await create(interaction); }
case "closeticket": { return await close(interaction); }
case "createtranscript": { return await createTranscript(interaction); }
case "suggestionAccept": { return await modifySuggestion(interaction, true); }
case "suggestionDeny": { return await modifySuggestion(interaction, false); }
}
// } else if (interaction.type === "APPLICATION_COMMAND_AUTOCOMPLETE") {
// const int = interaction as AutocompleteInteraction;
// switch (`${int.commandName} ${int.options.getSubcommandGroup(false)} ${int.options.getSubcommand(false)}`) {
// case "settings null stats": {
// return int.respond(generateStatsChannelAutocomplete(int.options.getString("name") ?? ""));
// }
// case "settings null welcome": {
// return int.respond(generateWelcomeMessageAutocomplete(int.options.getString("message") ?? ""));
// }
// }
}
}
async function modifySuggestion(interaction: Discord.MessageComponentInteraction, accept: boolean) {
const message = await interaction.message;
await message.fetch();
if (message.embeds.length === 0) return;
const embed = message.embeds[0];
const newColour = accept ? "Success" : "Danger";
const footer = {text: `Suggestion ${accept ? "accepted" : "denied"} by ${interaction.user.tag}`, iconURL: interaction.user.displayAvatarURL()};
const newEmbed = new EmojiEmbed()
.setTitle(embed!.title!)
.setDescription(embed!.description!)
.setFooter(footer)
.setStatus(newColour);
await interaction.update({embeds: [newEmbed], components: []});
}
export async function callback(_client: NucleusClient, interaction: Interaction) {
await interactionCreate(interaction);
}

@ -30,7 +30,9 @@ class confirmationMessage {
title = "";
emoji = "";
redEmoji: string | null = null;
timeoutText: string | null = null;
failedMessage: string | null = null;
failedEmoji: string | null = null;
failedStatus: "Success" | "Danger" | "Warning" | null = null;
description = "";
color: "Danger" | "Warning" | "Success" = "Success";
customButtons: Record<string, CustomBoolean<unknown>> = {};
@ -45,14 +47,13 @@ class confirmationMessage {
this.title = title;
return this;
}
setEmoji(emoji: string, redEmoji?: string) {
setEmoji(emoji: string) {
this.emoji = emoji;
if (redEmoji) this.redEmoji = redEmoji; // TODO: go through all confirmation messages and change them to use this, and not do their own edits
return this;
}
setDescription(description: string, timedOut?: string) {
this.description = description;
if (timedOut) this.timeoutText = timedOut; // TODO also this
if (timedOut) this.failedMessage = timedOut;
return this;
}
setColor(color: "Danger" | "Warning" | "Success") {
@ -63,6 +64,12 @@ class confirmationMessage {
this.inverted = inverted;
return this;
}
setFailedMessage(text: string, failedStatus: "Success" | "Danger" | "Warning" | null, failedEmoji: string | null = null) {
this.failedMessage = text;
this.failedStatus = failedStatus;
this.failedEmoji = failedEmoji;
return this;
}
addCustomBoolean(
customId: string,
title: string,
@ -243,8 +250,7 @@ class confirmationMessage {
out = await modalInteractionCollector(
m,
(m: Interaction) =>
(m as MessageComponentInteraction | ModalSubmitInteraction).channelId ===
this.interaction.channelId,
(m as MessageComponentInteraction | ModalSubmitInteraction).channelId === this.interaction.channelId,
(m) => m.customId === "reason"
);
} catch (e) {
@ -277,6 +283,17 @@ class confirmationMessage {
await this.timeoutError()
returnValue.cancelled = true;
}
if (success == false) {
await this.interaction.editReply({
embeds: [new EmojiEmbed()
.setTitle(this.title)
.setDescription(this.failedMessage ?? "")
.setStatus(this.failedStatus ?? "Danger")
.setEmoji(this.failedEmoji ?? this.redEmoji ?? this.emoji)
], components: []
});
return {success: false}
}
if (newReason) returnValue.newReason = newReason;
const typedReturnValue = returnValue as {cancelled: true} |
@ -294,10 +311,10 @@ class confirmationMessage {
.setTitle(this.title)
.setDescription("We closed this message because it was not used for a while.")
.setStatus("Danger")
.setEmoji(this.redEmoji ?? this.emoji)
.setEmoji("CONTROL.BLOCKCROSS")
],
components: []
})
})
}
}

@ -1,7 +1,9 @@
import client from "../client.js";
import { resourceUsage } from "process";
import { spawn } from "child_process";
import * as CP from 'child_process';
import * as process from 'process';
import systeminformation from "systeminformation";
import config from "../../config/main.json" assert { type: "json" };
import singleNotify from "../singleNotify.js";
const discordPing = () => {
@ -18,17 +20,11 @@ const databaseReadTime = async () => {
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
})
const resources = async () => {
return {
memory: current.sharedMemorySize,
cpu: current.userCPUTime + current.systemCPUTime,
temperature: temperatureData
memory: process.memoryUsage().rss / 1024 / 1024,
cpu: parseFloat(CP.execSync(`ps -p ${process.pid} -o %cpu=`).toString().trim()),
temperature: (await systeminformation.cpuTemperature()).main
}
}
@ -36,12 +32,24 @@ const record = async () => {
const results = {
discord: discordPing(),
databaseRead: await databaseReadTime(),
resources: resources()
resources: await resources()
};
if (results.discord > 1000 || results.databaseRead > 500 || results.resources.cpu > 100) {
singleNotify(
"performanceTest",
config.developmentGuildID,
`Discord ping time: \`${results.discord}ms\`\nDatabase read time: \`${results.databaseRead}ms\`\nCPU usage: \`${results.resources.cpu}%\`\nMemory usage: \`${results.resources.memory}MB\`\nCPU temperature: \`${results.resources.temperature}°C\``,
"Critical",
config.owners
)
} else {
singleNotify("performanceTest", config.developmentGuildID, true)
}
client.database.performanceTest.record(results)
setInterval(async () => {
record();
}, 10 * 1000);
setTimeout(async () => {
await record();
}, 60 * 1000);
}
export { record };

@ -13,7 +13,8 @@ export default async function (
type: string,
guild: string,
message: string | true,
severity: "Critical" | "Warning" | "Info" = "Info"
severity: "Critical" | "Warning" | "Info" = "Info",
pings?: string[]
) {
const data = await client.database.guilds.read(guild);
if (data.logging.staff.channel === null) return;
@ -30,6 +31,11 @@ export default async function (
const channel = await client.channels.fetch(data.logging.staff.channel);
if (!channel) return;
if (!channel.isTextBased()) return;
if (pings) {
await channel.send({
content: pings.map((ping) => `<@${ping}>`).join(" ")
});
}
await channel.send({
embeds: [
new EmojiEmbed()

Loading…
Cancel
Save