Working on viewas
diff --git a/src/commands/mod/info.ts b/src/commands/mod/about.ts
similarity index 98%
rename from src/commands/mod/info.ts
rename to src/commands/mod/about.ts
index fac87a0..c69f4a9 100644
--- a/src/commands/mod/info.ts
+++ b/src/commands/mod/about.ts
@@ -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 @@
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)
diff --git a/src/commands/mod/ban.ts b/src/commands/mod/ban.ts
index ba60d1e..330edfd 100644
--- a/src/commands/mod/ban.ts
+++ b/src/commands/mod/ban.ts
@@ -59,6 +59,7 @@
)
.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 @@
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: []
- });
- } else {
- await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("PUNISH.BAN.GREEN")
- .setTitle("Ban")
- .setDescription("No changes were made")
- .setStatus("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*"
+ });
+ 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.RED")
+ .setTitle("Ban")
+ .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) => {
diff --git a/src/commands/mod/kick.ts b/src/commands/mod/kick.ts
index 88b6e14..a4b9774 100644
--- a/src/commands/mod/kick.ts
+++ b/src/commands/mod/kick.ts
@@ -47,6 +47,7 @@
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 @@
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);
diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts
index d68272b..b558e87 100644
--- a/src/commands/mod/mute.ts
+++ b/src/commands/mod/mute.ts
@@ -207,6 +207,7 @@
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 @@
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 {
diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts
index 81935a2..c5e45b6 100644
--- a/src/commands/mod/nick.ts
+++ b/src/commands/mod/nick.ts
@@ -169,22 +169,22 @@
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;
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index 3020eb8..5425714 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -240,113 +240,153 @@
})
)
.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 (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
});
+ 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 (!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
- }
- };
- 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";
- }
+ } 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: []
});
- const attachmentObject = {
- attachment: Buffer.from(out),
- name: `purge-${channel.id}-${Date.now()}.txt`,
- description: "Purge log"
- };
- const m = (await interaction.editReply({
+ }
+ 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
+ }
+ };
+ 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";
+ }
+ });
+ 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
+ });
+ } 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")
@@ -354,58 +394,6 @@
.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
- });
- } 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: []
- });
- }
- } else {
- await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("CHANNEL.PURGE.GREEN")
- .setTitle("Purge")
- .setDescription("No changes were made")
- .setStatus("Success")
- ],
components: []
});
}
diff --git a/src/commands/mod/slowmode.ts b/src/commands/mod/slowmode.ts
index b565deb..9bd994d 100644
--- a/src/commands/mod/slowmode.ts
+++ b/src/commands/mod/slowmode.ts
@@ -47,45 +47,33 @@
}) + "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) => {
diff --git a/src/commands/mod/viewas.ts b/src/commands/mod/viewas.ts
index a713f55..8b2864a 100644
--- a/src/commands/mod/viewas.ts
+++ b/src/commands/mod/viewas.ts
@@ -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 @@
.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) => {
diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts
index d920bb0..c4aa7c3 100644
--- a/src/commands/mod/warn.ts
+++ b/src/commands/mod/warn.ts
@@ -56,6 +56,7 @@
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 @@
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 {
diff --git a/src/commands/nucleus/suggest.ts b/src/commands/nucleus/suggest.ts
index a75e8a0..e31696b 100644
--- a/src/commands/nucleus/suggest.ts
+++ b/src/commands/nucleus/suggest.ts
@@ -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 @@
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 @@
)
.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 @@
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: [
diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts
index 62e9609..a22045b 100644
--- a/src/events/interactionCreate.ts
+++ b/src/events/interactionCreate.ts
@@ -5,7 +5,9 @@
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 @@
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);
}
diff --git a/src/utils/confirmationMessage.ts b/src/utils/confirmationMessage.ts
index 6682be0..b3202e3 100644
--- a/src/utils/confirmationMessage.ts
+++ b/src/utils/confirmationMessage.ts
@@ -30,7 +30,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
.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: []
- })
+ })
}
}
diff --git a/src/utils/performanceTesting/record.ts b/src/utils/performanceTesting/record.ts
index 2d9524b..9f840af 100644
--- a/src/utils/performanceTesting/record.ts
+++ b/src/utils/performanceTesting/record.ts
@@ -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 @@
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 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 };
\ No newline at end of file
+export { record };
diff --git a/src/utils/singleNotify.ts b/src/utils/singleNotify.ts
index e762487..8e3aa60 100644
--- a/src/utils/singleNotify.ts
+++ b/src/utils/singleNotify.ts
@@ -13,7 +13,8 @@
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 @@
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()