Development (#85)

- updated versioning
- added myself to contributors list :(
- I'm not sure if this works yet. DO NOT PR UNTIL TESTED
- Squashed Bugs
- Fixed User Context Menus
- added flags and fixed user context menus
- fixed server buttons
- added permission
- nothing notable
- fixed lowercase messageCreate logs
pull/89/head
Skyler 3 years ago committed by GitHub
commit 70c2b11d9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,3 +1,4 @@
ClicksMigratingProblems/**/*
src/reflex/nsfwjs/**/*
ecosystem.config.cjs
ecosystem.config.cjs
test.ts

@ -34,7 +34,7 @@
"discord-api-types": "0.37.23"
},
"name": "nucleus",
"version": "0.0.1",
"version": "1.1.0",
"description": "Nucleus: The core of your server",
"main": "dist/index.js",
"scripts": {
@ -61,7 +61,8 @@
"author": "Clicks",
"contributors": [
"Minion3665",
"PineappleFan"
"PineappleFan",
"TheCodedProf"
],
"license": "SEE LICENSE IN LICENSE",
"bugs": {

@ -1,5 +1,5 @@
import { LoadingEmbed } from "../../utils/defaults.js";
import type { HistorySchema } from "../../utils/database.js";
import type { HistorySchema, FlagColors } from "../../utils/database.js";
import Discord, {
CommandInteraction,
GuildMember,
@ -7,11 +7,13 @@ import Discord, {
ActionRowBuilder,
ButtonBuilder,
MessageComponentInteraction,
ModalSubmitInteraction,
ButtonStyle,
TextInputStyle,
APIMessageComponentEmoji,
SlashCommandSubcommandBuilder
SlashCommandSubcommandBuilder,
StringSelectMenuBuilder,
StringSelectMenuOptionBuilder,
ContextMenuCommandInteraction
} from "discord.js";
import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
@ -327,35 +329,41 @@ async function showHistory(member: Discord.GuildMember, interaction: CommandInte
return timedOut ? 0 : 1;
}
const callback = async (interaction: CommandInteraction): Promise<unknown> => {
export const noteMenu = async (
member: GuildMember,
interaction: CommandInteraction | ContextMenuCommandInteraction
): Promise<unknown> => {
let m: Message;
const member = interaction.options.getMember("user") as Discord.GuildMember;
await interaction.reply({
embeds: LoadingEmbed,
ephemeral: true,
fetchReply: true
});
let note;
let firstLoad = true;
let timedOut = false;
while (!timedOut) {
note = await client.database.notes.read(member.guild.id, member.id);
if (firstLoad && !note) {
await showHistory(member, interaction);
}
firstLoad = false;
const colors: Record<string, Discord.ColorResolvable> = {
none: "#424242",
red: "#F27878",
yellow: "#EDC575",
green: "#68D49E",
blue: "#6576CC",
purple: "#D46899",
gray: "#C4C4C4"
};
m = (await interaction.editReply({
embeds: [
new EmojiEmbed()
.setEmoji("MEMBER.JOIN")
.setEmoji(`ICONS.FLAGS.${(note?.flag ?? "none").toUpperCase()}`)
.setTitle("Mod notes for " + member.user.username)
.setDescription(note ? note : "*No note set*")
.setStatus("Success")
.setDescription(note?.note ? note.note : "*No note set*")
.setColor(colors[note?.flag ?? "none"]!)
],
components: [
new ActionRowBuilder<Discord.ButtonBuilder>().addComponents([
new ButtonBuilder()
.setLabel(`${note ? "Modify" : "Create"} note`)
.setLabel(`${note?.note ? "Modify" : "Create"} note`)
.setStyle(ButtonStyle.Primary)
.setCustomId("modify")
.setEmoji(getEmojiByName("ICONS.EDIT", "id")),
@ -364,6 +372,49 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
.setStyle(ButtonStyle.Primary)
.setCustomId("history")
.setEmoji(getEmojiByName("ICONS.HISTORY", "id"))
]),
new ActionRowBuilder<Discord.StringSelectMenuBuilder>().addComponents([
new StringSelectMenuBuilder()
.setCustomId("flag")
.setPlaceholder("Select a flag")
.addOptions(
new StringSelectMenuOptionBuilder()
.setLabel("None")
.setDefault(!note?.flag)
.setValue("none")
.setDescription("Clear")
.setEmoji(getEmojiByName("ICONS.FLAGS.NONE", "id")),
new StringSelectMenuOptionBuilder()
.setLabel("Red")
.setDefault(note?.flag === "red")
.setValue("red")
.setEmoji(getEmojiByName("ICONS.FLAGS.RED", "id")),
new StringSelectMenuOptionBuilder()
.setLabel("Yellow")
.setDefault(note?.flag === "yellow")
.setValue("yellow")
.setEmoji(getEmojiByName("ICONS.FLAGS.YELLOW", "id")),
new StringSelectMenuOptionBuilder()
.setLabel("Green")
.setDefault(note?.flag === "green")
.setValue("green")
.setEmoji(getEmojiByName("ICONS.FLAGS.GREEN", "id")),
new StringSelectMenuOptionBuilder()
.setLabel("Blue")
.setDefault(note?.flag === "blue")
.setValue("blue")
.setEmoji(getEmojiByName("ICONS.FLAGS.BLUE", "id")),
new StringSelectMenuOptionBuilder()
.setLabel("Purple")
.setDefault(note?.flag === "purple")
.setValue("purple")
.setEmoji(getEmojiByName("ICONS.FLAGS.PURPLE", "id")),
new StringSelectMenuOptionBuilder()
.setLabel("Gray")
.setDefault(note?.flag === "gray")
.setValue("gray")
.setEmoji(getEmojiByName("ICONS.FLAGS.GRAY", "id"))
)
])
]
})) as Message;
@ -383,65 +434,74 @@ const callback = async (interaction: CommandInteraction): Promise<unknown> => {
timedOut = true;
continue;
}
if (i.customId === "modify") {
await i.showModal(
new Discord.ModalBuilder()
.setCustomId("modal")
.setTitle("Editing moderator note")
.addComponents(
new ActionRowBuilder<Discord.TextInputBuilder>().addComponents(
new Discord.TextInputBuilder()
.setCustomId("note")
.setLabel("Note")
.setMaxLength(4000)
.setRequired(false)
.setStyle(TextInputStyle.Paragraph)
.setValue(note ? note : " ")
if (i.isButton()) {
if (i.customId === "modify") {
await i.showModal(
new Discord.ModalBuilder()
.setCustomId("modal")
.setTitle("Editing moderator note")
.addComponents(
new ActionRowBuilder<Discord.TextInputBuilder>().addComponents(
new Discord.TextInputBuilder()
.setCustomId("note")
.setLabel("Note")
.setMaxLength(4000)
.setRequired(false)
.setStyle(TextInputStyle.Paragraph)
.setValue(note?.note ? note.note : " ")
)
)
)
);
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Mod notes for " + member.user.username)
.setDescription("Modal opened. If you can't see it, click back and try again.")
.setStatus("Success")
.setEmoji("GUILD.TICKET.OPEN")
],
components: [
new ActionRowBuilder<Discord.ButtonBuilder>().addComponents([
new ButtonBuilder()
.setLabel("Back")
.setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
.setStyle(ButtonStyle.Primary)
.setCustomId("back")
])
]
});
let out;
try {
out = await modalInteractionCollector(m, interaction.user);
} catch (e) {
timedOut = true;
continue;
}
if (out === null || out.isButton()) {
continue;
} else if (out instanceof ModalSubmitInteraction) {
let toAdd = out.fields.getTextInputValue("note") || null;
if (toAdd === " ") toAdd = null;
if (toAdd) toAdd = toAdd.trim();
await client.database.notes.create(member.guild.id, member.id, toAdd);
} else {
continue;
);
await interaction.editReply({
embeds: [
new EmojiEmbed()
.setTitle("Mod notes for " + member.user.username)
.setDescription("Modal opened. If you can't see it, click back and try again.")
.setStatus("Success")
.setEmoji("GUILD.TICKET.OPEN")
],
components: [
new ActionRowBuilder<Discord.ButtonBuilder>().addComponents([
new ButtonBuilder()
.setLabel("Back")
.setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
.setStyle(ButtonStyle.Primary)
.setCustomId("back")
])
]
});
let out;
try {
out = await modalInteractionCollector(m, interaction.user);
} catch (e) {
timedOut = true;
continue;
}
if (out === null || out.isButton()) {
continue;
} else {
let toAdd = out.fields.getTextInputValue("note").trim() || null;
if (toAdd === "") toAdd = null;
await client.database.notes.create(member.guild.id, member.id, toAdd);
}
} else if (i.customId === "history") {
await i.deferUpdate();
if (!(await showHistory(member, interaction))) return;
}
} else if (i.customId === "history") {
} else if (i.isStringSelectMenu()) {
await i.deferUpdate();
if (!(await showHistory(member, interaction))) return;
let flag: string | null = i.values[0]!;
if (flag === "none") flag = null;
await client.database.notes.flag(member.guild.id, member.id, flag as FlagColors | null);
}
}
};
const callback = async (interaction: CommandInteraction): Promise<void> => {
const member = interaction.options.getMember("user") as Discord.GuildMember;
await noteMenu(member, interaction);
};
const check = (interaction: CommandInteraction) => {
const member = interaction.member as GuildMember;
if (!member.permissions.has("ManageMessages")) return "You do not have the *Manage Messages* permission";

@ -6,7 +6,6 @@ import {
ChannelSelectMenuBuilder,
ChannelType,
CommandInteraction,
MessageCreateOptions,
ModalBuilder,
SlashCommandSubcommandBuilder,
StringSelectMenuBuilder,
@ -98,7 +97,7 @@ export const callback = async (interaction: CommandInteraction): Promise<void> =
.setCustomId("send")
.setLabel("Send")
.setStyle(ButtonStyle.Primary)
.setDisabled(!data.channel)
.setDisabled(!(data.channel && (data.title ?? data.description ?? data.buttons.length)))
);
const colorSelect = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
@ -137,7 +136,7 @@ export const callback = async (interaction: CommandInteraction): Promise<void> =
new StringSelectMenuBuilder()
.setCustomId("button")
.setPlaceholder("Select buttons to add")
.setMinValues(1)
.setMinValues(0)
.setMaxValues(3)
.addOptions(
new StringSelectMenuOptionBuilder()
@ -175,7 +174,7 @@ export const callback = async (interaction: CommandInteraction): Promise<void> =
.setTitle(data.title ?? "No title set")
.setDescription(data.description ?? "*No description set*")
.setColor(data.color)
.setFooter({ text: `Click the button below to edit the embed | The embed will be sent in ${channelName}` });
.setFooter({ text: `The embed will be sent in ${channelName} | Click the button below to edit the embed` });
await interaction.editReply({
embeds: [embed],
@ -266,9 +265,10 @@ export const callback = async (interaction: CommandInteraction): Promise<void> =
case "send": {
await i.deferUpdate();
const channel = interaction.guild!.channels.cache.get(data.channel!) as Discord.TextChannel;
const messageData: MessageCreateOptions = {};
let components: ActionRowBuilder<ButtonBuilder>[] = [];
let embeds: EmojiEmbed[] = [];
for (const button of data.buttons) {
messageData.components = [
components = [
new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId(button)
@ -277,14 +277,14 @@ export const callback = async (interaction: CommandInteraction): Promise<void> =
)
];
}
if (data.title || data.description || data.color) {
if (data.title || data.description) {
const e = new EmojiEmbed();
if (data.title) e.setTitle(data.title);
if (data.description) e.setDescription(data.description);
if (data.color) e.setColor(data.color);
messageData.embeds = [e];
embeds = [e];
}
await channel.send(messageData);
await channel.send({ embeds, components });
break;
}
}

@ -757,8 +757,9 @@ const mentionMenu = async (
.addComponents(
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
.setLabel("Amount")
.setCustomId("mass")
.setPlaceholder("Amount")
.setPlaceholder(current.mass === 5 ? "Amount" : current.mass.toString())
.setMinLength(1)
.setMaxLength(3)
.setStyle(TextInputStyle.Short)

@ -51,6 +51,7 @@ export default {
CATEGORY: "1064943289708597348"
},
FLAGS: {
NONE: "1099782406417940520",
RED: "1082719687219101800",
YELLOW: "1082719684060794890",
GREEN: "1082719681326108763",

@ -9,12 +9,15 @@ import Discord, {
GuildMember,
GuildTextBasedChannel,
Message,
MessageContextMenuCommandInteraction
MessageContextMenuCommandInteraction,
PermissionFlagsBits
} from "discord.js";
import client from "../../utils/client.js";
import { messageException } from "../../utils/createTemporaryStorage.js";
const command = new ContextMenuCommandBuilder().setName("Purge up to here");
const command = new ContextMenuCommandBuilder()
.setName("Purge up to Here")
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages);
async function waitForButton(m: Discord.Message, member: Discord.GuildMember): Promise<boolean> {
let component;
@ -38,9 +41,6 @@ const callback = async (interaction: MessageContextMenuCommandInteraction) => {
const channel = interaction.channel;
if (!channel) return;
await interaction.reply({ embeds: LoadingEmbed, ephemeral: true, fetchReply: true });
// Option for "include this message"?
// Option for "Only selected user"?
const history: Discord.Collection<string, Discord.Message> = await channel.messages.fetch({ limit: 100 });
if (Date.now() - targetMessage.createdTimestamp > 2 * 7 * 24 * 60 * 60 * 1000) {
const m = await interaction.editReply({

@ -0,0 +1,24 @@
import {
ContextMenuCommandBuilder,
GuildMember,
PermissionFlagsBits,
UserContextMenuCommandInteraction
} from "discord.js";
import { noteMenu } from "../../commands/mod/about.js";
const command = new ContextMenuCommandBuilder()
.setName("Flag User")
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages);
const callback = async (interaction: UserContextMenuCommandInteraction) => {
const guild = interaction.guild!;
let member = interaction.targetMember as GuildMember | null;
if (!member) member = await guild.members.fetch(interaction.targetId);
await noteMenu(member, interaction);
};
const check = async (_interaction: UserContextMenuCommandInteraction) => {
return true;
};
export { command, callback, check };

@ -5,12 +5,14 @@ const command = new ContextMenuCommandBuilder().setName("User info");
const callback = async (interaction: UserContextMenuCommandInteraction) => {
const guild = interaction.guild!;
let member = interaction.targetMember;
let member = interaction.targetMember as GuildMember | null;
if (!member) member = await guild.members.fetch(interaction.targetId);
await userAbout(guild, member as GuildMember, interaction);
};
const check = async (_interaction: UserContextMenuCommandInteraction) => {
const check = async (interaction: UserContextMenuCommandInteraction) => {
if (!interaction.inGuild()) return "You must be in a server to use this command.";
return true;
};

@ -8,12 +8,50 @@ import {
ThreadChannel,
VoiceChannel
} from "discord.js";
import type { NucleusClient } from "../utils/client.js";
import _client, { NucleusClient } from "../utils/client.js";
import getEmojiByName from "../utils/getEmojiByName.js";
export const event = "channelDelete";
// function getPropFromObject(splitProp: string[], object: Record<string, unknown>) {
// if (splitProp.length === 0) return null
// if (splitProp.length === 1) {
// return object[splitProp[0]!]
// }
// const property: string = splitProp[0]!
// if (! Object.keys(object).includes(property)) return null;
// splitProp = splitProp.splice(1)
// return getPropFromObject(splitProp, object[property] as Record<string, unknown>)
// }
// async function deleteFromGuildConfig(channel: GuildBasedChannel) {
// const guildConfig = await client.database.guilds.read(channel.guild.id);
// const lists = [
// "filters.wordFilter.allowed.channels",
// "filters.invite.allowed.channels",
// "filters.pings.allowed.channels",
// "filters.clean.allowed.channels",
// "filters.autoPublish.allowed.channels"
// ]
// const single = [
// "welcome.channel",
// "logging.logs.channel",
// "logging.staff.channel",
// "logging.attachments.channel",
// "tickets.category"
// ]
// console.log(guildConfig, lists, single)
// // for (const list of lists) {
// // const index = guildConfig[list].indexOf(channel.id);
// // if (index !== -1) guildConfig[list].splice(index, 1);
// // }
// };
export async function callback(client: NucleusClient, channel: GuildBasedChannel) {
// In future, please avoid using client from the outer scope. If you import client separately this
// parameter should shadow it.
// await deleteFromGuildConfig(channel)
const { getAuditLog, log, isLogging, NucleusColors, entry, renderDelta, renderUser } = client.logger;
if (!(await isLogging(channel.guild.id, "channelUpdate"))) return;
const auditLog = (await getAuditLog(channel.guild, AuditLogEvent.ChannelDelete)).filter(

@ -5,11 +5,19 @@ import { messageException } from "../utils/createTemporaryStorage.js";
import getEmojiByName from "../utils/getEmojiByName.js";
import client from "../utils/client.js";
import { callback as statsChannelUpdate } from "../reflex/statsChannelUpdate.js";
import { ChannelType, Message, ThreadChannel } from "discord.js";
import { ChannelType, GuildMember, Message, ThreadChannel } from "discord.js";
import singleNotify from "../utils/singleNotify.js";
export const event = "messageCreate";
function checkUserForExceptions(user: GuildMember, exceptions: { roles: string[]; users: string[] }) {
if (exceptions.users.includes(user.id)) return true;
for (const role of user.roles.cache.values()) {
if (exceptions.roles.includes(role.id)) return true;
}
return false;
}
export async function callback(_client: NucleusClient, message: Message) {
if (!message.guild) return;
const config = await client.memory.readGuildInfo(message.guild.id);
@ -42,17 +50,14 @@ export async function callback(_client: NucleusClient, message: Message) {
const { log, isLogging, NucleusColors, entry, renderUser, renderDelta, renderChannel } = client.logger;
const fileNames = await logAttachment(message);
const content = message.content.toLowerCase() || "";
const lowerCaseContent = message.content.toLowerCase() || "";
if (config.filters.clean.channels.includes(message.channel.id)) {
const memberRoles = message.member!.roles.cache.map((role) => role.id);
const roleAllow = config.filters.clean.allowed.roles.some((role) => memberRoles.includes(role));
const userAllow = config.filters.clean.allowed.users.includes(message.author.id);
if (!roleAllow && !userAllow) return await message.delete();
if (!checkUserForExceptions(message.member!, config.filters.clean.allowed)) return await message.delete();
}
const filter = getEmojiByName("ICONS.FILTER");
let attachmentJump = "";
console.log(config.logging.attachments.saved);
if (config.logging.attachments.saved[message.channel.id + message.id]) {
attachmentJump = ` [[View attachments]](${config.logging.attachments.saved[message.channel.id + message.id]})`;
}
@ -72,32 +77,38 @@ export async function callback(_client: NucleusClient, message: Message) {
};
if (config.filters.invite.enabled) {
if (!config.filters.invite.allowed.channels.includes(message.channel.id)) {
if (/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/.test(content)) {
messageException(message.guild.id, message.channel.id, message.id);
await message.delete();
const data = {
meta: {
type: "messageDelete",
displayName: "Message Deleted",
calculateType: "autoModeratorDeleted",
color: NucleusColors.red,
emoji: "MESSAGE.DELETE",
timestamp: Date.now()
},
separate: {
start:
filter +
" Contained invite\n\n" +
(content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
},
list: list,
hidden: {
guild: message.channel.guild.id
}
};
return log(data);
}
if (
!(
config.filters.invite.allowed.channels.includes(message.channel.id) ||
checkUserForExceptions(message.member!, config.filters.invite.allowed)
) &&
/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/.test(lowerCaseContent)
) {
messageException(message.guild.id, message.channel.id, message.id);
await message.delete();
const data = {
meta: {
type: "messageDelete",
displayName: "Message Deleted",
calculateType: "autoModeratorDeleted",
color: NucleusColors.red,
emoji: "MESSAGE.DELETE",
timestamp: Date.now()
},
separate: {
start:
filter +
" Contained invite\n\n" +
(lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*")
},
list: list,
hidden: {
guild: message.channel.guild.id
}
};
return log(data);
}
}
@ -131,8 +142,8 @@ export async function callback(_client: NucleusClient, message: Message) {
start:
filter +
" Image detected as NSFW\n\n" +
(content
? `**Message:**\n\`\`\`${content}\`\`\``
(lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*")
},
list: list,
@ -149,7 +160,11 @@ export async function callback(_client: NucleusClient, message: Message) {
config.filters.wordFilter.words.loose,
config.filters.wordFilter.words.strict
);
if (check !== null) {
if (
check !== null &&
(!checkUserForExceptions(message.member!, config.filters.wordFilter.allowed) ||
!config.filters.wordFilter.allowed.channels.includes(message.channel.id))
) {
messageException(message.guild.id, message.channel.id, message.id);
await message.delete();
const data = {
@ -165,8 +180,8 @@ export async function callback(_client: NucleusClient, message: Message) {
start:
filter +
" Image contained filtered word\n\n" +
(content
? `**Message:**\n\`\`\`${content}\`\`\``
(lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*")
},
list: list,
@ -195,8 +210,8 @@ export async function callback(_client: NucleusClient, message: Message) {
start:
filter +
" Image was too small\n\n" +
(content
? `**Message:**\n\`\`\`${content}\`\`\``
(lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*")
},
list: list,
@ -225,7 +240,9 @@ export async function callback(_client: NucleusClient, message: Message) {
start:
filter +
" File detected as malware\n\n" +
(content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
(lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*")
},
list: list,
hidden: {
@ -254,7 +271,9 @@ export async function callback(_client: NucleusClient, message: Message) {
start:
filter +
` Link filtered as ${linkDetectionTypes[0]?.toLowerCase()}\n\n` +
(content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
(lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*")
},
list: list,
hidden: {
@ -264,9 +283,15 @@ export async function callback(_client: NucleusClient, message: Message) {
return log(data);
}
if (config.filters.wordFilter.enabled) {
if (
config.filters.wordFilter.enabled &&
!(
checkUserForExceptions(message.member!, config.filters.wordFilter.allowed) ||
config.filters.wordFilter.allowed.channels.includes(message.channel.id)
)
) {
const check = TestString(
content,
lowerCaseContent,
config.filters.wordFilter.words.loose,
config.filters.wordFilter.words.strict
);
@ -286,7 +311,9 @@ export async function callback(_client: NucleusClient, message: Message) {
start:
filter +
" Message contained filtered word\n\n" +
(content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
(lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*")
},
list: list,
hidden: {
@ -297,7 +324,11 @@ export async function callback(_client: NucleusClient, message: Message) {
}
}
if (config.filters.pings.everyone && message.mentions.everyone) {
if (
config.filters.pings.everyone &&
message.mentions.everyone &&
!checkUserForExceptions(message.member!, config.filters.pings.allowed)
) {
if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
const data = {
meta: {
@ -309,7 +340,9 @@ export async function callback(_client: NucleusClient, message: Message) {
timestamp: Date.now()
},
separate: {
start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
start: lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*"
},
list: list,
hidden: {
@ -318,7 +351,7 @@ export async function callback(_client: NucleusClient, message: Message) {
};
return log(data);
}
if (config.filters.pings.roles) {
if (config.filters.pings.roles && !checkUserForExceptions(message.member!, config.filters.pings.allowed)) {
for (const roleId in message.mentions.roles) {
if (!config.filters.pings.allowed.roles.includes(roleId)) {
messageException(message.guild.id, message.channel.id, message.id);
@ -334,8 +367,8 @@ export async function callback(_client: NucleusClient, message: Message) {
timestamp: Date.now()
},
separate: {
start: content
? `**Message:**\n\`\`\`${content}\`\`\``
start: lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*"
},
list: list,
@ -347,7 +380,11 @@ export async function callback(_client: NucleusClient, message: Message) {
}
}
}
if (message.mentions.users.size >= config.filters.pings.mass && config.filters.pings.mass) {
if (
message.mentions.users.size >= config.filters.pings.mass &&
config.filters.pings.mass &&
!checkUserForExceptions(message.member!, config.filters.pings.allowed)
) {
messageException(message.guild.id, message.channel.id, message.id);
await message.delete();
if (!(await isLogging(message.guild.id, "messageMassPing"))) return;
@ -361,7 +398,9 @@ export async function callback(_client: NucleusClient, message: Message) {
timestamp: Date.now()
},
separate: {
start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
start: lowerCaseContent
? `**Message:**\n\`\`\`${message.content}\`\`\``
: "**Message:** *Message had no content*"
},
list: list,
hidden: {

@ -156,7 +156,13 @@ async function registerContextMenus() {
context.command.setType(ApplicationCommandType.User);
commands.push(context.command);
client.commands["contextCommands/user/" + context.command.name] = context;
client.commands["contextCommands/user/" + context.command.name] = [
context,
{
name: context.name ?? context.command.name,
description: context.description ?? context.command.description
}
];
console.log(
`${last.replace("└", " ").replace("├", "│")} └─ ${colors.green}Loaded ${

@ -696,15 +696,25 @@ export class ModNotes {
this.modNotes = database.collection<ModNoteSchema>("modNotes");
}
async flag(guild: string, user: string, flag: FlagColors | null) {
const modNote = await this.modNotes.findOne({ guild: guild, user: user });
modNote
? await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { flag: flag } }, collectionOptions)
: await this.modNotes.insertOne({ guild: guild, user: user, note: null, flag: flag }, collectionOptions);
}
async create(guild: string, user: string, note: string | null) {
// console.log("ModNotes create");
await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note } }, { upsert: true });
const modNote = await this.modNotes.findOne({ guild: guild, user: user });
modNote
? await this.modNotes.updateOne({ guild: guild, user: user }, { $set: { note: note } }, collectionOptions)
: await this.modNotes.insertOne({ guild: guild, user: user, note: note, flag: null }, collectionOptions);
}
async read(guild: string, user: string) {
// console.log("ModNotes read");
const entry = await this.modNotes.findOne({ guild: guild, user: user });
return entry?.note ?? null;
return entry ?? null;
}
async delete(guild: string) {
@ -1033,10 +1043,13 @@ export interface HistorySchema {
amount: string | null;
}
export type FlagColors = "red" | "yellow" | "green" | "blue" | "purple" | "gray";
export interface ModNoteSchema {
guild: string;
user: string;
note: string | null;
flag: FlagColors | null;
}
export interface PremiumSchema {

Loading…
Cancel
Save