Start of context menus

pull/17/head
PineaFan 3 years ago
parent 100df685e2
commit a00db1b8ba
No known key found for this signature in database
GPG Key ID: 0AEF25BAA0FB1C74

@ -1,4 +1,4 @@
import Discord, { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
import Discord, { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction } from "discord.js";
import { tickets, toHexArray } from "../../utils/calculate.js";
import client from "../../utils/client.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
@ -9,7 +9,8 @@ function capitalize(s: string) {
return s.length < 3 ? s.toUpperCase() : s[0].toUpperCase() + s.slice(1).toLowerCase();
}
export default async function (interaction) {
export default async function (interaction: CommandInteraction) {
if (!interaction.guild) return;
const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
const config = await client.database.guilds.read(interaction.guild.id);

@ -4,9 +4,10 @@ import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
export default async function (interaction: Discord.CommandInteraction) {
if (!interaction.guild) return;
const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
const config = await client.database.guilds.read(interaction.guild!.id);
const config = await client.database.guilds.read(interaction.guild.id);
let thread = false;
if (interaction.channel instanceof Discord.ThreadChannel) thread = true;
const threadChannel = interaction.channel as Discord.ThreadChannel;

@ -24,6 +24,7 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
const callback = async (interaction: CommandInteraction): Promise<void> => {
if (!interaction.guild) return;
const { renderUser } = client.logger;
// TODO:[Modals] Replace this with a modal
let reason = null;
@ -69,7 +70,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
reason = reason.length ? reason : null
let dmSent = false;
let dmMessage;
const config = await client.database.guilds.read(interaction.guild!.id);
const config = await client.database.guilds.read(interaction.guild.id);
try {
if (notify) {
const messageData: {
@ -81,7 +82,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
.setEmoji("PUNISH.BAN.RED")
.setTitle("Banned")
.setDescription(
`You have been banned in ${interaction.guild!.name}` + (reason ? ` for:\n> ${reason}` : ".")
`You have been banned in ${interaction.guild.name}` + (reason ? ` for:\n> ${reason}` : ".")
)
.setStatus("Danger")
],
@ -110,7 +111,7 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
deleteMessageSeconds: days * 24 * 60 * 60,
reason: reason ?? "*No reason provided*"
});
await client.database.history.create("ban", interaction.guild!.id, member.user, interaction.user, reason);
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: {
@ -128,10 +129,10 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
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
serverMemberCount: interaction.guild.memberCount
},
hidden: {
guild: interaction.guild!.id
guild: interaction.guild.id
}
};
log(data);
@ -175,20 +176,21 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
};
const check = async (interaction: CommandInteraction) => {
if (!interaction.guild) return;
const member = interaction.member as GuildMember;
const me = interaction.guild!.members.me!;
const me = interaction.guild.members.me!;
let apply = interaction.options.getUser("user") as User | GuildMember;
const memberPos = member.roles.cache.size > 1 ? member.roles.highest.position : 0;
const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
let applyPos = 0
try {
apply = await interaction.guild!.members.fetch(apply.id) as GuildMember
apply = await interaction.guild.members.fetch(apply.id) as GuildMember
applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
} catch {
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) throw new Error("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");
// Check if Nucleus has permission to ban
@ -196,7 +198,7 @@ const check = async (interaction: CommandInteraction) => {
// Do not allow banning Nucleus
if (member.id === me.id) throw new Error("I cannot ban myself");
// Allow the owner to ban anyone
if (member.id === interaction.guild!.ownerId) return true;
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");
// Check if the user is below on the role list

@ -1,7 +1,9 @@
import { LinkWarningFooter } from './../../utils/defaultEmbeds';
import { CommandInteraction, GuildMember, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
// @ts-expect-error
import humanizeDuration from "humanize-duration";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import type Discord from "discord.js";
import confirmationMessage from "../../utils/confirmationMessage.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import keyValueList from "../../utils/generateKeyValueList.js";
@ -14,77 +16,103 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
.addUserOption((option) => option.setName("user").setDescription("The user to kick").setRequired(true));
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return;
const { renderUser } = client.logger;
// TODO:[Modals] Replace this with a modal
let reason = null;
let reason: string | null = null;
let notify = true;
let confirmation;
let timedOut = false;
let chosen = false;
while (!timedOut && !chosen) {
let success = false;
do {
confirmation = await new confirmationMessage(interaction)
.setEmoji("PUNISH.KICK.RED")
.setTitle("Kick")
.setDescription(
keyValueList({
user: renderUser(interaction.options.getUser("user")),
user: renderUser(interaction.options.getUser("user")!),
reason: reason ? "\n> " + (reason).replaceAll("\n", "\n> ") : "*No reason provided*"
}) +
`The user **will${notify ? "" : " not"}** be notified\n\n` +
`Are you sure you want to kick <@!${(interaction.options.getMember("user") as GuildMember).id}>?`
)
.setColor("Danger")
.addCustomBoolean(
"notify",
"Notify user",
false,
null,
"The user will be sent a DM",
"ICONS.NOTIFY." + (notify ? "ON" : "OFF"),
notify
)
.addReasonButton(reason ?? "")
.send(reason !== null);
reason = reason ?? "";
if (confirmation.cancelled) timedOut = true;
else if (confirmation.success !== undefined) chosen = true;
else if (confirmation.success !== undefined) success = true;
else if (confirmation.newReason) reason = confirmation.newReason;
else if (confirmation.components) {
notify = confirmation.components["notify"]!.active;
}
}
} while (!timedOut && !success)
if (timedOut) return;
let dmd = false;
let dm;
const config = await client.database.guilds.read(interaction.guild!.id);
if (!confirmation.success) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.KICK.GREEN")
.setTitle("Kick")
.setDescription("No changes were made")
.setStatus("Success")
],
components: []
});
return;
}
let dmSent = false;
let dmMessage;
const config = await client.database.guilds.read(interaction.guild.id);
try {
if (notify) {
dm = await (interaction.options.getMember("user") as GuildMember).send({
const messageData: {
embeds: EmojiEmbed[];
components: ActionRowBuilder<ButtonBuilder>[];
} = {
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.KICK.RED")
.setTitle("Kicked")
.setDescription(
`You have been kicked in ${interaction.guild!.name}` + (reason ? ` for:\n> ${reason}` : ".")
`You have been kicked from ${interaction.guild.name}` +
(reason ? ` for:\n> ${reason}` : ".\n*No reason was provided.*")
)
.setStatus("Danger")
],
components: [
new ActionRowBuilder().addComponents(
config.moderation.kick.text
? [
new ButtonBuilder()
components: []
};
if (config.moderation.kick.text && config.moderation.kick.link) {
messageData.embeds[0]!.setFooter(LinkWarningFooter)
messageData.components.push(new ActionRowBuilder<Discord.ButtonBuilder>()
.addComponents(new ButtonBuilder()
.setStyle(ButtonStyle.Link)
.setLabel(config.moderation.kick.text)
.setURL(config.moderation.kick.link)
]
: []
)
]
});
dmd = true;
)
}
dmMessage = await (interaction.options.getMember("user") as GuildMember).send(messageData);
dmSent = true;
}
} catch {
dmd = false;
dmSent = false;
}
try {
(interaction.options.getMember("user") as GuildMember).kick(reason ?? "No reason provided.");
(interaction.options.getMember("user") as GuildMember).kick(reason || "No reason provided");
const member = interaction.options.getMember("user") as GuildMember;
await client.database.history.create("kick", interaction.guild!.id, member.user, interaction.user, reason);
await client.database.history.create("kick", interaction.guild.id, member.user, interaction.user, reason);
const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger;
const timeInServer = member.joinedTimestamp ? entry(
new Date().getTime() - member.joinedTimestamp,
(new Date().getTime() - member.joinedTimestamp).toString(),
humanizeDuration(new Date().getTime() - member.joinedTimestamp, {
round: true
})
@ -101,18 +129,27 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
list: {
memberId: entry(member.id, `\`${member.id}\``),
name: entry(member.id, renderUser(member.user)),
joined: entry(member.joinedAt, renderDelta(member.joinedAt)),
kicked: entry(new Date().getTime(), renderDelta(new Date().getTime())),
joined: undefined as (unknown | typeof entry),
kicked: entry(new Date().getTime().toString(), renderDelta(new Date().getTime())),
kickedBy: entry(interaction.user.id, renderUser(interaction.user)),
reason: entry(reason, reason ? `\n> ${reason}` : "*No reason provided.*"),
timeInServer: timeInServer,
accountCreated: entry(member.user.createdAt, renderDelta(member.user.createdAt)),
serverMemberCount: member.guild.memberCount
},
hidden: {
guild: member.guild.id
}
};
if (member.joinedTimestamp) {
data.list.joined = entry(member.joinedTimestamp.toString(), renderDelta(member.joinedTimestamp))
}
await client.database.history.create(
"kick",
interaction.guild.id,
member.user,
interaction.user,
reason
)
log(data);
} catch {
await interaction.editReply({
@ -125,10 +162,10 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
],
components: []
});
if (dmd && dm) await dm.delete();
if (dmSent && dmMessage) await dmMessage.delete();
return;
}
const failed = !dmd && notify;
const failed = !dmSent && notify;
await interaction.editReply({
embeds: [
new EmojiEmbed()
@ -142,24 +179,25 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
};
const check = (interaction: CommandInteraction) => {
if (!interaction.guild) return;
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;
const memberPos = member.roles.cache.size > 1 ? member.roles.highest.position : 0;
const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
const applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
// Do not allow kicking the owner
if (member.id === interaction.guild!.ownerId) throw new Error("You cannot kick the owner of the server");
if (member.id === interaction.guild.ownerId) throw new Error("You cannot kick the owner of the server");
// Check if Nucleus can kick the member
if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
// Check if Nucleus has permission to kick
if (!me.permissions.has("KICK_MEMBERS")) throw new Error("I do not have the *Kick Members* permission");
if (!me.permissions.has("KickMembers")) throw new Error("I do not have the *Kick Members* permission");
// Do not allow kicking Nucleus
if (member.id === interaction.guild!.me!.id) throw new Error("I cannot kick myself");
if (member.id === interaction.guild.members.me!.id) throw new Error("I cannot kick myself");
// Allow the owner to kick anyone
if (member.id === interaction.guild!.ownerId) return true;
if (member.id === interaction.guild.ownerId) return true;
// Check if the user has kick_members permission
if (!member.permissions.has("KICK_MEMBERS")) throw new Error("You do not have the *Kick Members* permission");
if (!member.permissions.has("KickMembers")) throw new Error("You do not have the *Kick 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");
// Allow kick

@ -49,6 +49,7 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return;
const { log, NucleusColors, renderUser, entry, renderDelta } = client.logger;
const user = interaction.options.getMember("user") as GuildMember;
const time = {
@ -57,7 +58,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
minutes: interaction.options.getInteger("minutes") ?? 0,
seconds: interaction.options.getInteger("seconds") ?? 0
};
const config = await client.database.guilds.read(interaction.guild!.id);
const config = await client.database.guilds.read(interaction.guild.id);
let serverSettingsDescription = config.moderation.mute.timeout ? "given a timeout" : "";
if (config.moderation.mute.role)
serverSettingsDescription +=
@ -187,9 +188,9 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.addCustomBoolean(
"appeal",
"Create appeal ticket",
!(await areTicketsEnabled(interaction.guild!.id)),
!(await areTicketsEnabled(interaction.guild.id)),
async () =>
await create(interaction.guild!, interaction.options.getUser("user")!, interaction.user, reason),
await create(interaction.guild, interaction.options.getUser("user")!, interaction.user, reason),
"An appeal ticket will be created when Confirm is clicked",
"CONTROL.TICKET",
createAppealTicket
@ -226,7 +227,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.setEmoji("PUNISH.MUTE.RED")
.setTitle("Muted")
.setDescription(
`You have been muted in ${interaction.guild!.name}` +
`You have been muted in ${interaction.guild.name}` +
(reason
? ` for:\n> ${reason}`
: ".\n\n" +
@ -267,7 +268,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (config.moderation.mute.role !== null) {
await member.roles.add(config.moderation.mute.role);
await client.database.eventScheduler.schedule("naturalUnmute", new Date().getTime() + muteTime * 1000, {
guild: interaction.guild!.id,
guild: interaction.guild.id,
user: user.id,
expires: new Date().getTime() + muteTime * 1000
});
@ -280,7 +281,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (config.moderation.mute.role !== null) {
await member.roles.add(config.moderation.mute.role);
await client.database.eventScheduler.schedule("unmuteRole", new Date().getTime() + muteTime * 1000, {
guild: interaction.guild!.id,
guild: interaction.guild.id,
user: user.id,
role: config.moderation.mute.role
});
@ -303,7 +304,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (dmd && dm) await dm.delete();
return;
}
await client.database.history.create("mute", interaction.guild!.id, member.user, interaction.user, reason);
await client.database.history.create("mute", interaction.guild.id, member.user, interaction.user, reason);
const failed = !dmd && notify;
await interaction.editReply({
embeds: [
@ -342,7 +343,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
reason: entry(reason, reason ? reason : "*No reason provided*")
},
hidden: {
guild: interaction.guild!.id
guild: interaction.guild.id
}
};
log(data);
@ -361,14 +362,15 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
};
const check = (interaction: CommandInteraction) => {
if (!interaction.guild) return;
const member = interaction.member as GuildMember;
const me = interaction.guild!.me!;
const me = interaction.guild.me!;
const apply = interaction.options.getMember("user") as GuildMember;
const memberPos = member.roles.cache.size > 1 ? member.roles.highest.position : 0;
const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
const applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
// Do not allow muting the owner
if (member.id === interaction.guild!.ownerId) throw new Error("You cannot mute the owner of the server");
if (member.id === interaction.guild.ownerId) throw new Error("You cannot mute the owner of the server");
// Check if Nucleus can mute the member
if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
// Check if Nucleus has permission to mute
@ -376,7 +378,7 @@ const check = (interaction: CommandInteraction) => {
// Do not allow muting Nucleus
if (member.id === me.id) throw new Error("I cannot mute myself");
// Allow the owner to mute anyone
if (member.id === interaction.guild!.ownerId) return true;
if (member.id === interaction.guild.ownerId) return true;
// Check if the user has moderate_members permission
if (!member.permissions.has("MODERATE_MEMBERS"))
throw new Error("You do not have the *Moderate Members* permission");

@ -26,7 +26,7 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
const user = (interaction.options.getMember("user") as GuildMember) ?? null;
const user = (interaction.options.getMember("user") as GuildMember);
const channel = interaction.channel as GuildChannel;
if (
!["GUILD_TEXT", "GUILD_NEWS", "GUILD_NEWS_THREAD", "GUILD_PUBLIC_THREAD", "GUILD_PRIVATE_THREAD"].includes(

@ -34,7 +34,7 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
);
const callback = async (interaction: CommandInteraction): Promise<void> => {
let time = parseInt(interaction.options.getString("time") ?? "0");
let time = parseInt(interaction.options.get("time")?.value as string || "0");
if (time === 0 && (interaction.channel as TextChannel).rateLimitPerUser === 0) {
time = 10;
}
@ -91,10 +91,9 @@ const callback = async (interaction: CommandInteraction): Promise<void> => {
const check = (interaction: CommandInteraction) => {
const member = interaction.member as GuildMember;
// Check if Nucleus can set the slowmode
if (!interaction.guild.me.permissions.has("MANAGE_CHANNELS"))
throw new Error("I do not have the *Manage Channels* permission");
if (!interaction.guild!.members.me!.permissions.has("ManageChannels")) throw new Error("I do not have the *Manage Channels* permission");
// Check if the user has manage_channel permission
if (!member.permissions.has("MANAGE_CHANNELS")) throw new Error("You do not have the *Manage Channels* permission");
if (!member.permissions.has("ManageChannels")) throw new Error("You do not have the *Manage Channels* permission");
// Allow slowmode
return true;
};

@ -1,5 +1,5 @@
import { CommandInteraction, GuildMember, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import confirmationMessage from "../../utils/confirmationMessage.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import keyValueList from "../../utils/generateKeyValueList.js";

@ -14,6 +14,7 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return;
const bans = await interaction.guild.bans.fetch();
const user = interaction.options.getString("user");
let resolved = bans.find((ban) => ban.user.id === user);
@ -107,6 +108,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
};
const check = (interaction: CommandInteraction) => {
if (!interaction.guild) return;
const member = interaction.member as GuildMember;
const me = interaction.guild.me!;
// Check if Nucleus can unban members

@ -1,5 +1,5 @@
import { CommandInteraction, GuildMember } from "discord.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import type { CommandInteraction, GuildMember } from "discord.js";
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import confirmationMessage from "../../utils/confirmationMessage.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import keyValueList from "../../utils/generateKeyValueList.js";
@ -12,40 +12,51 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
.addUserOption((option) => option.setName("user").setDescription("The user to unmute").setRequired(true));
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return;
const { log, NucleusColors, renderUser, entry, renderDelta } = client.logger;
// TODO:[Modals] Replace this with a modal
let reason = null;
let reason: string | null = null;
let notify = false;
let confirmation;
let timedOut = false;
let success = false;
while (!success) {
do {
confirmation = await new confirmationMessage(interaction)
.setEmoji("PUNISH.MUTE.RED")
.setTitle("Unmute")
.setDescription(
keyValueList({
user: renderUser(interaction.options.getUser("user")),
user: renderUser(interaction.options.getUser("user")!),
reason: `\n> ${reason ? reason : "*No reason provided*"}`
}) +
`The user **will${notify ? "" : " not"}** be notified\n\n` +
`Are you sure you want to unmute <@!${(interaction.options.getMember("user") as GuildMember).id}>?`
)
.setColor("Danger")
.addCustomBoolean(
"notify",
"Notify user",
false,
null,
"The user will be sent a DM",
"ICONS.NOTIFY." + (notify ? "ON" : "OFF"),
notify
)
.addReasonButton(reason ?? "")
.send(reason !== null);
if (confirmation.success) success = true;
if (confirmation.cancelled) timedOut = true;
else if (confirmation.success !== undefined) success = true;
else if (confirmation.newReason) reason = confirmation.newReason;
else if (confirmation.components) {
notify = confirmation.components.notify.active;
}
notify = confirmation.components!["notify"]!.active;
}
} while (!timedOut && !success);
if (confirmation.cancelled) return;
if (confirmation.success) {
let dmd = false;
let dm;
let dmSent = false;
let dmMessage;
try {
if (notify) {
dm = await (interaction.options.getMember("user") as GuildMember).send({
dmMessage = await (interaction.options.getMember("user") as GuildMember).send({
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.MUTE.GREEN")
@ -57,10 +68,10 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.setStatus("Success")
]
});
dmd = true;
dmSent = true;
}
} catch {
dmd = false;
dmSent = false;
}
const member = interaction.options.getMember("user") as GuildMember;
try {
@ -76,7 +87,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
],
components: []
});
if (dmd) await dm.delete();
if (dmSent && dmMessage) await dmMessage.delete();
return;
}
await client.database.history.create(
@ -98,7 +109,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
list: {
memberId: entry(member.user.id, `\`${member.user.id}\``),
name: entry(member.user.id, renderUser(member.user)),
unmuted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
unmuted: entry(new Date().getTime().toString(), renderDelta(new Date().getTime())),
unmutedBy: entry(interaction.user.id, renderUser(interaction.user))
},
hidden: {
@ -106,7 +117,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
}
};
log(data);
const failed = !dmd && notify;
const failed = !dmSent && notify;
await interaction.editReply({
embeds: [
new EmojiEmbed()
@ -132,10 +143,10 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
};
const check = (interaction: CommandInteraction) => {
if (!interaction.guild) return;
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 > 1 ? member.roles.highest.position : 0;
const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
const applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
@ -144,11 +155,11 @@ const check = (interaction: CommandInteraction) => {
// Check if Nucleus can unmute the member
if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
// Check if Nucleus has permission to unmute
if (!me.permissions.has("MODERATE_MEMBERS")) throw new Error("I do not have the *Moderate Members* permission");
if (!me.permissions.has("ModerateMembers")) throw new Error("I do not have the *Moderate Members* permission");
// Allow the owner to unmute anyone
if (member.id === interaction.guild.ownerId) return true;
// Check if the user has moderate_members permission
if (!member.permissions.has("MODERATE_MEMBERS"))
if (!member.permissions.has("ModerateMembers"))
throw new Error("You do not have the *Moderate 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");

@ -14,6 +14,7 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
.addUserOption((option) => option.setName("user").setDescription("The user to warn").setRequired(true));
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (interaction.guild === null) return;
const { log, NucleusColors, renderUser, entry } = client.logger;
// TODO:[Modals] Replace this with a modal
let reason: string | null = null;
@ -37,7 +38,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.addCustomBoolean(
"appeal",
"Create appeal ticket",
!(await areTicketsEnabled(interaction.guild!.id)),
!(await areTicketsEnabled(interaction.guild.id)),
async () => await create(interaction.guild!, interaction.options.getUser("user")!, interaction.user, reason),
"An appeal ticket will be created",
"CONTROL.TICKET",
@ -64,9 +65,21 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
}
} while (!timedOut && !success)
if (timedOut) return;
if (confirmation.success) {
if (!confirmation.success) {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.WARN.GREEN")
.setTitle("Warn")
.setDescription("No changes were made")
.setStatus("Success")
],
components: []
});
return;
}
let dmSent = false;
const config = await client.database.guilds.read(interaction.guild!.id);
const config = await client.database.guilds.read(interaction.guild.id);
try {
if (notify) {
const messageData: {
@ -78,7 +91,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.setEmoji("PUNISH.WARN.RED")
.setTitle("Warned")
.setDescription(
`You have been warned in ${interaction.guild!.name}` +
`You have been warned in ${interaction.guild.name}` +
(reason ? ` for:\n> ${reason}` : ".\n*No reason was provided*") +
"\n\n" +
(createAppealTicket
@ -123,12 +136,12 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
reason: reason ? `\n> ${reason}` : "*No reason provided*"
},
hidden: {
guild: interaction.guild!.id
guild: interaction.guild.id
}
};
await client.database.history.create(
"warn",
interaction.guild!.id,
interaction.guild.id,
(interaction.options.getMember("user") as GuildMember).user,
interaction.user,
reason
@ -239,7 +252,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
});
} else if (component.customId === "ticket") {
const ticketChannel = await create(
interaction.guild!,
interaction.guild,
interaction.options.getUser("user")!,
interaction.user,
reason,
@ -269,21 +282,10 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
});
}
}
} else {
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("PUNISH.WARN.GREEN")
.setTitle("Warn")
.setDescription("No changes were made")
.setStatus("Success")
],
components: []
});
}
};
const check = (interaction: CommandInteraction) => {
if (!interaction.guild) return;
const member = interaction.member as GuildMember;
const apply = interaction.options.getMember("user") as GuildMember | null;
if (apply === null) throw new Error("That member is not in the server");
@ -292,7 +294,7 @@ const check = (interaction: CommandInteraction) => {
// Do not allow warning bots
if (member.user.bot) throw new Error("I cannot warn bots");
// Allow the owner to warn anyone
if (member.id === interaction.guild!.ownerId) return true;
if (member.id === interaction.guild.ownerId) return true;
// Check if the user has moderate_members permission
if (!member.permissions.has("ModerateMembers"))
throw new Error("You do not have the *Moderate Members* permission");

@ -62,6 +62,7 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return;
let m = (await interaction.reply({
embeds: LoadingEmbed,
ephemeral: true,
@ -77,7 +78,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (options.category) {
let channel: GuildChannel | null;
try {
channel = await interaction.guild!.channels.fetch(options.category.id);
channel = await interaction.guild.channels.fetch(options.category.id);
} catch {
return await interaction.editReply({
embeds: [
@ -91,7 +92,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
}
if (!channel) return;
channel = channel as Discord.CategoryChannel;
if (channel.guild.id !== interaction.guild!.id)
if (channel.guild.id !== interaction.guild.id)
return interaction.editReply({
embeds: [
new EmojiEmbed()
@ -117,7 +118,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
let role: Role | null;
if (options.supportping) {
try {
role = await interaction.guild!.roles.fetch(options.supportping.id);
role = await interaction.guild.roles.fetch(options.supportping.id);
} catch {
return await interaction.editReply({
embeds: [
@ -131,7 +132,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
}
if (!role) return;
role = role as Discord.Role;
if (role.guild.id !== interaction.guild!.id)
if (role.guild.id !== interaction.guild.id)
return interaction.editReply({
embeds: [
new EmojiEmbed()
@ -170,7 +171,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (options.maxtickets) toUpdate["tickets.maxTickets"] = options.maxtickets;
if (options.supportping) toUpdate["tickets.supportRole"] = options.supportping.id;
try {
await client.database.guilds.write(interaction.guild!.id, toUpdate);
await client.database.guilds.write(interaction.guild.id, toUpdate);
} catch (e) {
return interaction.editReply({
embeds: [
@ -196,7 +197,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
});
}
}
let data = await client.database.guilds.read(interaction.guild!.id);
let data = await client.database.guilds.read(interaction.guild.id);
data.tickets.customTypes = (data.tickets.customTypes || []).filter(
(value: string, index: number, array: string[]) => array.indexOf(value) === index
);
@ -284,19 +285,19 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if ((i.component as Component).customId === "clearCategory") {
if (lastClicked === "cat") {
lastClicked = "";
await client.database.guilds.write(interaction.guild!.id, null, ["tickets.category"]);
await client.database.guilds.write(interaction.guild.id, null, ["tickets.category"]);
data.category = undefined;
} else lastClicked = "cat";
} else if ((i.component as Component).customId === "clearMaxTickets") {
if (lastClicked === "max") {
lastClicked = "";
await client.database.guilds.write(interaction.guild!.id, null, ["tickets.maxTickets"]);
await client.database.guilds.write(interaction.guild.id, null, ["tickets.maxTickets"]);
data.maxTickets = 5;
} else lastClicked = "max";
} else if ((i.component as Component).customId === "clearSupportPing") {
if (lastClicked === "sup") {
lastClicked = "";
await client.database.guilds.write(interaction.guild!.id, null, ["tickets.supportRole"]);
await client.database.guilds.write(interaction.guild.id, null, ["tickets.supportRole"]);
data.supportRole = undefined;
} else lastClicked = "sup";
} else if ((i.component as Component).customId === "send") {
@ -732,7 +733,7 @@ async function manageTypes(interaction: CommandInteraction, data: GuildConfig["t
const check = (interaction: CommandInteraction) => {
const member = interaction.member as Discord.GuildMember;
if (!member.permissions.has("MANAGE_GUILD"))
if (!member.permissions.has("ManageGuild"))
throw new Error("You must have the *Manage Server* permission to use this command");
return true;
};

@ -30,6 +30,7 @@ const command = (builder: SlashCommandSubcommandBuilder) =>
);
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (!interaction.guild) return;
const m = (await interaction.reply({
embeds: LoadingEmbed,
ephemeral: true,
@ -51,7 +52,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
});
}
role = role as Discord.Role;
if (role.guild.id !== interaction.guild!.id) {
if (role.guild.id !== interaction.guild.id) {
return interaction.editReply({
embeds: [
new EmojiEmbed()
@ -72,7 +73,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
if (confirmation.cancelled) return;
if (confirmation.success) {
try {
await client.database.guilds.write(interaction.guild!.id, {
await client.database.guilds.write(interaction.guild.id, {
"verify.role": role.id,
"verify.enabled": true
});
@ -92,7 +93,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
role: entry(role.id, renderRole(role))
},
hidden: {
guild: interaction.guild!.id
guild: interaction.guild.id
}
};
log(data);
@ -123,7 +124,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
}
}
let clicks = 0;
const data = await client.database.guilds.read(interaction.guild!.id);
const data = await client.database.guilds.read(interaction.guild.id);
let role = data.verify.role;
let timedOut = false;
@ -166,7 +167,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
clicks += 1;
if (clicks === 2) {
clicks = 0;
await client.database.guilds.write(interaction.guild!.id, null, ["verify.role", "verify.enabled"]);
await client.database.guilds.write(interaction.guild.id, null, ["verify.role", "verify.enabled"]);
role = undefined;
}
} else if ((i.component as Component).customId === "send") {
@ -379,7 +380,7 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
const check = (interaction: CommandInteraction) => {
const member = interaction.member as Discord.GuildMember;
if (!member.permissions.has("MANAGE_GUILD"))
if (!member.permissions.has("ManageGuild"))
throw new Error("You must have the *Manage Server* permission to use this command");
return true;
};

@ -11,6 +11,8 @@ const defaultDict: Record<string, string | string[] | boolean> = {
owners: [],
commandsFolder: "Your built commands folder (usually dist/commands)",
eventsFolder: "Your built events folder (usually dist/events)",
messageContextFolder: "Your built message context folder (usually dist/context/messages)",
userContextFolder: "Your built user context folder (usually dist/context/users)",
verifySecret:
"If using verify, enter a code here which matches the secret sent back by your website. You can use a random code if you do not have one already. (Optional)",
mongoUrl: "Your Mongo connection string, e.g. mongodb://127.0.0.1:27017",

@ -1,4 +1,5 @@
import { Interaction, SlashCommandBuilder } from 'discord.js';
import { typeSlashCommandSubcommandBuilder } from '@discordjs/builders';
import { Interaction, SlashCommandBuilder, ApplicationCommandType } from 'discord.js';
// @ts-expect-error
import config from "../../config/main.json" assert { type: "json" };
import client from "../client.js";
@ -88,8 +89,64 @@ async function registerEvents() {
console.log(`Loaded ${files.length - errors} events (${errors} failed)`)
};
async function registerContextMenus() {
console.log("Reading context menus")
const messageFiles = fs.readdirSync(config.messageContextFolder, { withFileTypes: true }).filter(
file => !file.name.endsWith(".ts") && !file.name.endsWith(".map")
);
const userFiles = fs.readdirSync(config.userContextFolder, { withFileTypes: true }).filter(
file => !file.name.endsWith(".ts") && !file.name.endsWith(".map")
);
console.log(`Registering ${messageFiles.length} message context menus and ${userFiles.length} user context menus`)
let i = 0;
let errors = 0;
for (const file of messageFiles) {
const last = i === messageFiles.length - 1 ? "└" : "├";
i++;
try {
console.log(`${last}${colours.yellow}Loading message context menu ${file.name}${colours.none}`)
const context = (await import(`../../../${config.messageContextFolder}/${file.name}`));
context.command.setType(ApplicationCommandType.Message);
client.commands["contextCommands/message/" + file.name.replace(".js", "")] = context;
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.green}Loaded ${file.name} [${i} / ${messageFiles.length}]${colours.none}`)
} catch (e) {
errors++;
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.red}Failed to load ${file.name} [${i} / ${messageFiles.length}]${colours.none}`)
}
}
for (const file of userFiles) {
const last = i === userFiles.length - 1 ? "└" : "├";
i++;
try {
console.log(`${last}${colours.yellow}Loading user context menu ${file.name}${colours.none}`)
const context = (await import(`../../../${config.userContextFolder}/${file.name}`));
context.command.setType(ApplicationCommandType.User);
client.commands["contextCommands/user/" + file.name.replace(".js", "")] = context;
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.green}Loaded ${file.name} [${i} / ${userFiles.length}]${colours.none}`)
} catch (e) {
errors++;
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.red}Failed to load ${file.name} [${i} / ${userFiles.length}]${colours.none}`)
}
}
console.log(`Loaded ${messageFiles.length + userFiles.length - errors} context menus (${errors} failed)`)
};
async function registerCommandHandler() {
client.on("interactionCreate", async (interaction: Interaction) => {
if (interaction.isUserContextMenuCommand()) {;
const commandName = interaction.commandName;
console.log(commandName);
return;
} else if (interaction.isMessageContextMenuCommand()) {
const commandName = interaction.commandName;
console.log(commandName);
return;
}
if (!interaction.isChatInputCommand()) return;
const commandName = interaction.commandName;
@ -118,7 +175,8 @@ async function registerCommandHandler() {
}
export default async function register() {
await registerCommands();
let commandList: (SlashCommandBuilder | SlashCommandSubcommandBuilder)[] = []
commandList.concat(await registerCommands());
await registerCommandHandler();
await registerEvents();
console.log(`${colours.green}Registered commands and events${colours.none}`)

Loading…
Cancel
Save