Coded wanted to host the liveshare
diff --git a/src/Unfinished/all.ts b/src/Unfinished/all.ts
index 9d9e653..d09ca7b 100644
--- a/src/Unfinished/all.ts
+++ b/src/Unfinished/all.ts
@@ -5,7 +5,9 @@
ActionRowBuilder,
ButtonBuilder,
SelectMenuBuilder,
- ButtonStyle
+ ButtonStyle,
+ StringSelectMenuBuilder,
+ APIMessageComponentEmoji
} from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";
@@ -171,8 +173,8 @@
const all = true;
while (true) {
let count = 0;
- const affected = [];
- const members = interaction.guild.members.cache;
+ const affected: GuildMember[] = [];
+ const members = interaction.guild!.members.cache;
if (all) {
members.forEach((member) => {
let applies = true;
@@ -224,8 +226,8 @@
.setStatus("Success")
],
components: [
- new ActionRowBuilder().addComponents([
- new SelectMenuBuilder()
+ new ActionRowBuilder<StringSelectMenuBuilder>().addComponents([
+ new StringSelectMenuBuilder()
.setOptions(
filters.map((f, index) => ({
label: (f.inverted ? "(Not) " : "") + f.name,
@@ -237,18 +239,18 @@
.setCustomId("select")
.setPlaceholder("Remove a filter")
]),
- new ActionRowBuilder().addComponents([
+ new ActionRowBuilder<ButtonBuilder>().addComponents([
new ButtonBuilder()
.setLabel("Apply")
.setStyle(ButtonStyle.Primary)
.setCustomId("apply")
- .setEmoji(client.emojis.cache.get(getEmojiByName("CONTROL.TICK", "id")))
+ .setEmoji(client.emojis.cache.get(getEmojiByName("CONTROL.TICK", "id"))! as APIMessageComponentEmoji)
.setDisabled(affected.length === 0),
new ButtonBuilder()
.setLabel("Add filter")
.setStyle(ButtonStyle.Primary)
.setCustomId("add")
- .setEmoji(client.emojis.cache.get(getEmojiByName("ICONS.FILTER", "id")))
+ .setEmoji(client.emojis.cache.get(getEmojiByName("ICONS.FILTER", "id"))! as APIMessageComponentEmoji)
.setDisabled(filters.length >= 25)
])
]
@@ -260,12 +262,12 @@
const check = async (interaction: CommandInteraction) => {
const member = interaction.member as GuildMember;
- const me = interaction.guild.me!;
- if (!me.permissions.has("MANAGE_ROLES")) throw new Error("I do not have the *Manage Roles* permission");
+ const me = interaction.guild!.members.me!;
+ if (!me.permissions.has("ManageRoles")) return "I do not have the *Manage Roles* permission";
// Allow the owner to role anyone
- if (member.id === interaction.guild.ownerId) return true;
+ if (member.id === interaction.guild!.ownerId) return true;
// Check if the user has manage_roles permission
- if (!member.permissions.has("MANAGE_ROLES")) throw new Error("You do not have the *Manage Roles* permission");
+ if (!member.permissions.has("ManageRoles")) return "You do not have the *Manage Roles* permission";
// Allow role
return true;
};
diff --git a/src/commands/mod/ban.ts b/src/commands/mod/ban.ts
index 70e904c..ebc44ad 100644
--- a/src/commands/mod/ban.ts
+++ b/src/commands/mod/ban.ts
@@ -181,19 +181,19 @@
apply = apply as User
}
// Do not allow banning the owner
- if (member.id === interaction.guild.ownerId) throw new Error("You cannot ban the owner of the server");
+ if (member.id === interaction.guild.ownerId) return "You cannot ban the owner of the server";
// Check if Nucleus can ban the member
- if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
+ if (!(mePos > applyPos)) return "I do not have a role higher than that member";
// Check if Nucleus has permission to ban
- if (!me.permissions.has("BanMembers")) throw new Error("I do not have the *Ban Members* permission");
+ if (!me.permissions.has("BanMembers")) return "I do not have the *Ban Members* permission";
// Do not allow banning Nucleus
- if (member.id === me.id) throw new Error("I cannot ban myself");
+ if (member.id === me.id) return "I cannot ban myself";
// Allow the owner to ban anyone
if (member.id === interaction.guild.ownerId) return true;
// Check if the user has ban_members permission
- if (!member.permissions.has("BanMembers")) throw new Error("You do not have the *Ban Members* permission");
+ if (!member.permissions.has("BanMembers")) return "You do not have the *Ban Members* permission";
// Check if the user is below on the role list
- if (!(memberPos > applyPos)) throw new Error("You do not have a role higher than that member");
+ if (!(memberPos > applyPos)) return "You do not have a role higher than that member";
// Allow ban
return true;
};
diff --git a/src/commands/mod/softban.ts b/src/commands/mod/softban.ts
index 2787e91..2c87420 100644
--- a/src/commands/mod/softban.ts
+++ b/src/commands/mod/softban.ts
@@ -182,19 +182,19 @@
apply = apply as User
}
// Do not allow banning the owner
- if (member.id === interaction.guild.ownerId) throw new Error("You cannot softban the owner of the server");
+ if (member.id === interaction.guild.ownerId) return "You cannot softban the owner of the server";
// Check if Nucleus can ban the member
- if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
+ if (!(mePos > applyPos)) return "I do not have a role higher than that member";
// Check if Nucleus has permission to ban
- if (!me.permissions.has("BanMembers")) throw new Error("I do not have the *Ban Members* permission");
+ if (!me.permissions.has("BanMembers")) return "I do not have the *Ban Members* permission";
// Do not allow banning Nucleus
- if (member.id === me.id) throw new Error("I cannot softban myself");
+ if (member.id === me.id) return "I cannot softban myself";
// Allow the owner to ban anyone
if (member.id === interaction.guild.ownerId) return true;
// Check if the user has ban_members permission
- if (!member.permissions.has("BanMembers")) throw new Error("You do not have the *Ban Members* permission");
+ if (!member.permissions.has("BanMembers")) return "You do not have the *Ban Members* permission";
// Check if the user is below on the role list
- if (!(memberPos > applyPos)) throw new Error("You do not have a role higher than that member");
+ if (!(memberPos > applyPos)) return "You do not have a role higher than that member";
// Allow ban
return true;
};
diff --git a/src/commands/settings/logs/attachment.ts b/src/commands/settings/logs/attachment.ts
index 2709bee..6fb2461 100644
--- a/src/commands/settings/logs/attachment.ts
+++ b/src/commands/settings/logs/attachment.ts
@@ -60,7 +60,7 @@
`Are you sure you want to set the attachment log channel to <#${channel.id}>?`
)
.setColor("Warning")
- .setFailedMessage("Attachment log channel not set", "Warning", "CHANNEL.TEXT.DELETE")
+ .setFailedMessage("No changes were made", "Success", "CHANNEL.TEXT.CREATE")
.setInverted(true)
.send(true);
if (confirmation.cancelled) return;
diff --git a/src/commands/settings/logs/channel.ts b/src/commands/settings/logs/channel.ts
index 992491a..9b594e8 100644
--- a/src/commands/settings/logs/channel.ts
+++ b/src/commands/settings/logs/channel.ts
@@ -56,7 +56,7 @@
.setTitle("Log Channel")
.setDescription(`Are you sure you want to set the log channel to <#${channel.id}>?`)
.setColor("Warning")
- .setFailedMessage("The log channel was not changed", "Danger", "CHANNEL.TEXT.DELETE")
+ .setFailedMessage("No changes were made", "Success", "CHANNEL.TEXT.CREATE")
.setInverted(true)
.send(true);
if (confirmation.cancelled) return;
diff --git a/src/commands/settings/logs/staff.ts b/src/commands/settings/logs/staff.ts
index 13125ef..3a0f395 100644
--- a/src/commands/settings/logs/staff.ts
+++ b/src/commands/settings/logs/staff.ts
@@ -61,7 +61,7 @@
`Are you sure you want to set the staff notifications channel to <#${channel.id}>?`
)
.setColor("Warning")
- .setFailedMessage("Staff notifications channel not set", "Warning", "CHANNEL.TEXT.DELETE")
+ .setFailedMessage("No changes were made", "Success", "CHANNEL.TEXT.CREATE")
.setInverted(true)
.send(true);
if (confirmation.cancelled) return;
diff --git a/src/commands/settings/stats.ts b/src/commands/settings/stats.ts
index cdd218b..1093bd2 100644
--- a/src/commands/settings/stats.ts
+++ b/src/commands/settings/stats.ts
@@ -1,5 +1,5 @@
import { LoadingEmbed } from "../../utils/defaults.js";
-import Discord, { CommandInteraction, Message, ActionRowBuilder, GuildMember, StringSelectMenuBuilder, StringSelectMenuInteraction, AutocompleteInteraction } from "discord.js";
+import Discord, { CommandInteraction, Message, ActionRowBuilder, GuildMember, StringSelectMenuBuilder, StringSelectMenuInteraction, SelectMenuOptionBuilder } from "discord.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import confirmationMessage from "../../utils/confirmationMessage.js";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
@@ -12,214 +12,34 @@
builder
.setName("stats")
.setDescription("Controls channels which update when someone joins or leaves the server")
- .addChannelOption((option) => option.setName("channel").setDescription("The channel to modify"))
- .addStringOption((option) =>
- option
- .setName("name")
- .setDescription("The new channel name | Enter any text or use the extra variables like {memberCount}")
- .setAutocomplete(true)
- );
-const callback = async (interaction: CommandInteraction): Promise<unknown> => { // TODO: This command feels unintuitive. Clicking a channel in the select menu deletes it
- // instead, it should give a submenu to edit the channel, enable/disable or delete it
- singleNotify("statsChannelDeleted", interaction.guild!.id, true);
- const m = (await interaction.reply({
- embeds: LoadingEmbed,
- ephemeral: true,
- fetchReply: true
- })) as Message;
- let config = await client.database.guilds.read(interaction.guild!.id);
- if (interaction.options.get("name")?.value as string) {
- let channel;
- if (Object.keys(config.stats).length >= 25) {
- return await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("CHANNEL.TEXT.DELETE")
- .setTitle("Stats Channel")
- .setDescription("You can only have 25 stats channels in a server")
- .setStatus("Danger")
- ]
- });
+const callback = async (interaction: CommandInteraction) => {
+ if (!interaction.guild) return;
+ let closed = false;
+ let page = 0;
+ do {
+ const config = await client.database.guilds.read(interaction.guild.id);
+ const stats = config.stats; // stats: Record<string, { name: string; enabled: boolean }>
+ if (!stats) {
+ await interaction.editReply({embeds: [new EmojiEmbed()
+ .setTitle("Stats channels")
+ .setDescription("You don't have ant stats channels yet")
+ .setStatus("Success")
+ .setEmoji("")
+ ]})
}
- try {
- channel = interaction.options.get("channel")?.channel as Discord.Channel;
- } catch {
- return await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setEmoji("CHANNEL.TEXT.DELETE")
- .setTitle("Stats Channel")
- .setDescription("The channel you provided is not a valid channel")
- .setStatus("Danger")
- ]
- });
- }
- channel = channel as Discord.TextChannel;
- if (channel.guild.id !== interaction.guild!.id) {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Stats Channel")
- .setDescription("You must choose a channel in this server")
- .setStatus("Danger")
- .setEmoji("CHANNEL.TEXT.DELETE")
- ]
- });
- }
- let newName = await convertCurlyBracketString(
- interaction.options.get("name")?.value as string,
- "",
- "",
- interaction.guild!.name,
- interaction.guild!.members
- );
- if (interaction.options.get("channel")?.channel!.type === Discord.ChannelType.GuildText) {
- newName = newName.toLowerCase().replace(/[\s]/g, "-");
- }
- const confirmation = await new confirmationMessage(interaction)
- .setEmoji("CHANNEL.TEXT.EDIT")
- .setTitle("Stats Channel")
- .setDescription(
- `Are you sure you want to set <#${channel.id}> to a stats channel?\n\n*Preview: ${newName.replace(
- /^ +| $/g,
- ""
- )}*`
- )
- .setColor("Warning")
- .setInverted(true)
- .setFailedMessage(`Could not convert <#${channel.id}> to a stats chanel.`, "Danger", "CHANNEL.TEXT.DELETE")
- .send(true);
- if (confirmation.cancelled) return;
- if (confirmation.success) {
- try {
- const name = interaction.options.get("name")?.value as string;
- const channel = interaction.options.get("channel")?.channel as Discord.TextChannel;
- await client.database.guilds.write(interaction.guild!.id, {
- [`stats.${channel.id}`]: { name: name, enabled: true }
- });
- const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
- const data = {
- meta: {
- type: "statsChannelUpdate",
- displayName: "Stats Channel Updated",
- calculateType: "nucleusSettingsUpdated",
- color: NucleusColors.yellow,
- emoji: "CHANNEL.TEXT.EDIT",
- timestamp: new Date().getTime()
- },
- list: {
- memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
- changedBy: entry(interaction.user.id, renderUser(interaction.user)),
- channel: entry(channel.id, renderChannel(channel)),
- name: entry(
- interaction.options.get("name")?.value as string,
- `\`${interaction.options.get("name")?.value as string}\``
- )
- },
- hidden: {
- guild: interaction.guild!.id
- }
- };
- log(data);
- } catch (e) {
- console.log(e);
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Stats Channel")
- .setDescription("Something went wrong and the stats channel could not be set")
- .setStatus("Danger")
- .setEmoji("CHANNEL.TEXT.DELETE")
- ],
- components: []
- });
- }
- } else {
- return interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Stats Channel")
- .setDescription("No changes were made")
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: []
- });
- }
- await statsChannelAddCallback(client, interaction.member as GuildMember);
- }
- let timedOut = false;
- while (!timedOut) {
- config = await client.database.guilds.read(interaction.guild!.id);
- const stats = config.stats;
- const selectMenu = new StringSelectMenuBuilder()
- .setCustomId("remove")
+ let pageSelect = new StringSelectMenuBuilder()
+ .setCustomId("page")
+ .setPlaceholder("Select a stats channel to manage")
.setMinValues(1)
- .setMaxValues(Math.max(1, Object.keys(stats).length));
- await interaction.editReply({
- embeds: [
- new EmojiEmbed()
- .setTitle("Stats Channel")
- .setDescription(
- "The following channels update when someone joins or leaves the server. You can select a channel to remove it from the list."
- )
- .setStatus("Success")
- .setEmoji("CHANNEL.TEXT.CREATE")
- ],
- components: [
- new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
- Object.keys(stats).length
- ? [
- selectMenu
- .setPlaceholder("Select a stats channel to remove, stopping it updating")
- .addOptions(
- Object.keys(stats).map((key) => ({
- label: interaction.guild!.channels.cache.get(key)!.name,
- value: key,
- description: `${stats[key]!.name}`
- }))
- )
- ]
- : [
- selectMenu
- .setPlaceholder("The server has no stats channels")
- .setDisabled(true)
- .setOptions([
- {
- label: "*Placeholder*",
- value: "placeholder",
- description: "No stats channels"
- }
- ])
- ]
- )
- ]
- });
- let i: StringSelectMenuInteraction;
- try {
- i = await m.awaitMessageComponent({
- time: 300000,
- filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
- }) as StringSelectMenuInteraction;
- } catch (e) {
- timedOut = true;
- continue;
+ .setMaxValues(1);
+ for (const [id, { name, enabled }] of Object.entries(stats)) {
+ pageSelect.addOption()
}
- i.deferUpdate();
- if (i.customId === "remove") {
- const toRemove = i.values;
- await client.database.guilds.write(
- interaction.guild!.id,
- null,
- toRemove.map((k) => `stats.${k}`)
- );
- }
- }
- await interaction.editReply({
- embeds: [new Discord.EmbedBuilder(m.embeds[0]!.data).setFooter({ text: "Message timed out" })],
- components: []
- });
+ // [ Action... ] -> Edit, delete, reorder
+ // [Back][Next][Add]
+ } while (!closed);
+ closed = true;
};
const check = (interaction: CommandInteraction) => {
@@ -229,21 +49,7 @@
return true;
};
-const generateStatsChannelAutocomplete = (prompt: string): string[] => {
- return [prompt];
-};
-
-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 };
-export { autocomplete };
\ No newline at end of file
+export { check };
\ No newline at end of file
diff --git a/src/commands/settings/tickets.ts b/src/commands/settings/tickets.ts
index 892a420..aa25b69 100644
--- a/src/commands/settings/tickets.ts
+++ b/src/commands/settings/tickets.ts
@@ -163,7 +163,7 @@
"\nAre you sure you want to apply these settings?"
)
.setColor("Warning")
- .setFailedMessage("Cancelled", "Warning", "GUILD.TICKET.CLOSE") // TODO: Set Actual Message
+ .setFailedMessage("No changes were made", "Success", "GUILD.TICKET.OPEN")
.setInverted(true)
.send(true);
if (confirmation.cancelled) return;
diff --git a/src/commands/settings/welcome.ts b/src/commands/settings/welcome.ts
index e7143fb..42376e8 100644
--- a/src/commands/settings/welcome.ts
+++ b/src/commands/settings/welcome.ts
@@ -103,7 +103,7 @@
.setTitle("Welcome Events")
.setDescription(generateKeyValueList(options))
.setColor("Warning")
- .setFailedMessage("Cancelled", "Warning", "GUILD.ROLES.DELETE") //TODO: Actual Message Needed
+ .setFailedMessage("No changes were made", "Success", "GUILD.ROLES.CREATE")
.setInverted(true)
.send(true);
if (confirmation.cancelled) return;
@@ -324,7 +324,7 @@
if (beforeLastOpenBracket !== null) {
if (afterLastOpenBracket !== null) {
for (const replacement of validReplacements) {
- if (replacement.startsWith(afterLastOpenBracket[0].slice(1))) {
+ if (replacement.startsWith(afterLastOpenBracket[0]!.slice(1))) {
autocompletions.push(`${beforeLastOpenBracket[1]}{${replacement}}`);
}
}
diff --git a/src/commands/user/track.ts b/src/commands/user/track.ts
index 0814cfa..b7b239b 100644
--- a/src/commands/user/track.ts
+++ b/src/commands/user/track.ts
@@ -209,7 +209,7 @@
const check = async (interaction: CommandInteraction) => {
const tracks = (await client.database.guilds.read(interaction.guild!.id)).tracks;
- if (tracks.length === 0) throw new Error("This server does not have any tracks");
+ if (tracks.length === 0) return "This server does not have any tracks";
const member = interaction.member as GuildMember;
// Allow the owner to promote anyone
if (member.id === interaction.guild!.ownerId) return true;
@@ -223,8 +223,7 @@
break;
}
// Check if the user has manage_roles permission
- if (!managed && !member.permissions.has("ManageRoles"))
- throw new Error("You do not have the *Manage Roles* permission");
+ if (!managed && !member.permissions.has("ManageRoles")) return "You do not have the *Manage Roles* permission";
// Allow track
return true;
};
diff --git a/src/config/format.ts b/src/config/format.ts
index 713a233..929552f 100644
--- a/src/config/format.ts
+++ b/src/config/format.ts
@@ -61,6 +61,13 @@
out = false;
json = {};
}
+ if (json) {
+ if (json.token === defaultDict["token"] || json.developmentToken === defaultDict["developmentToken"]) {
+ console.log("\x1b[31m⚠ No main.json found, creating one.");
+ console.log(" \x1b[2mYou can edit src/config/main.json directly using template written to the file.\x1b[0m\n");
+ json = {};
+ }
+ }
for (const key in defaultDict) {
if (!json[key]) {
if (walkthrough) {
diff --git a/src/events/channelDelete.ts b/src/events/channelDelete.ts
index 4780700..a93e6c7 100644
--- a/src/events/channelDelete.ts
+++ b/src/events/channelDelete.ts
@@ -15,7 +15,6 @@
export async function callback(client: NucleusClient, channel: GuildBasedChannel) {
const { getAuditLog, log, NucleusColors, entry, renderDelta, renderUser } = client.logger;
- // const audit = auditLog.entries.filter((entry: GuildAuditLogsEntry) => entry.target!.id === channel.id).first();
const auditLog = (await getAuditLog(channel.guild, AuditLogEvent.ChannelDelete))
.filter((entry: GuildAuditLogsEntry) => (entry.target as GuildBasedChannel)!.id === channel.id)[0];
if (!auditLog) return;
diff --git a/src/events/channelUpdate.ts b/src/events/channelUpdate.ts
index 7c80e12..6c8687e 100644
--- a/src/events/channelUpdate.ts
+++ b/src/events/channelUpdate.ts
@@ -174,7 +174,7 @@
if ((oldChannel as StageChannel).rtcRegion !== (newChannel as StageChannel).rtcRegion)
changes.region = entry(
[(oldChannel as StageChannel).rtcRegion ?? "Automatic", (newChannel as StageChannel).rtcRegion ?? "Automatic"],
- `${(oldChannel as StageChannel).rtcRegion?.toUpperCase() ?? "Automatic"} -> ${(newChannel as StageChannel).rtcRegion?.toUpperCase() ?? "Automatic"}`
+ `${capitalize((oldChannel as StageChannel).rtcRegion?.toUpperCase() ?? "automatic")} -> ${capitalize((newChannel as StageChannel).rtcRegion?.toUpperCase() ?? "automatic")}`
);
break;
}
diff --git a/src/utils/commandRegistration/register.ts b/src/utils/commandRegistration/register.ts
index 281be18..4a13807 100644
--- a/src/utils/commandRegistration/register.ts
+++ b/src/utils/commandRegistration/register.ts
@@ -189,11 +189,10 @@
if (typeof result === "string") {
const { NucleusColors } = client.logger
return data.reply({embeds: [new EmojiEmbed()
- .setTitle("")
.setDescription(result)
.setColor(NucleusColors.red)
.setEmoji(getEmojiByName("CONTROL.BLOCKCROSS"))
- ]});
+ ], ephemeral: true});
};
}
callback(data);
diff --git a/src/utils/generateEmojiEmbed.ts b/src/utils/generateEmojiEmbed.ts
index c0f17ae..2978176 100644
--- a/src/utils/generateEmojiEmbed.ts
+++ b/src/utils/generateEmojiEmbed.ts
@@ -13,13 +13,16 @@
description = "";
_generateTitle() {
+ if (this._emoji && !this._title) return getEmojiByName(this._emoji)
if (this._emoji) { return `${getEmojiByName(this._emoji)} ${this._title}`; }
- return this._title;
+ if (this._title) { return this._title };
+ return "";
}
override setTitle(title: string) {
this._title = title;
- super.setTitle(this._generateTitle());
+ const proposedTitle = this._generateTitle();
+ if (proposedTitle) super.setTitle(proposedTitle);
return this;
}
override setDescription(description: string) {
@@ -29,7 +32,8 @@
}
setEmoji(emoji: string) {
this._emoji = emoji;
- super.setTitle(this._generateTitle());
+ const proposedTitle = this._generateTitle();
+ if (proposedTitle) super.setTitle(proposedTitle);
return this;
}
setStatus(color: "Danger" | "Warning" | "Success") {