From b2dccae805388bc9beb4aed360420909c868c843 Mon Sep 17 00:00:00 2001 From: Vermium Sifell Date: Sun, 17 Apr 2022 19:27:57 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20basic=20audit=20logs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/events/guildMemberAdd/audits.ts | 43 ++++++++++ src/events/guildMemberAdd/index.ts | 2 + src/events/guildMemberRemove/audits.ts | 40 +++++++++ src/events/guildMemberRemove/index.ts | 2 + src/events/interactionCreate/audits.ts | 48 +++++++++++ src/events/interactionCreate/index.ts | 2 + src/events/messageDelete/audits.ts | 51 ++++++++++++ src/events/messageDelete/index.ts | 9 +++ src/events/messageUpdate/audits.ts | 53 ++++++++++++ src/events/messageUpdate/index.ts | 6 +- src/plugins/settings/guild/index.ts | 22 ++++- src/plugins/settings/guild/modules/audits.ts | 85 ++++++++++++++++++++ 12 files changed, 358 insertions(+), 5 deletions(-) create mode 100644 src/events/guildMemberAdd/audits.ts create mode 100644 src/events/guildMemberRemove/audits.ts create mode 100644 src/events/interactionCreate/audits.ts create mode 100644 src/events/messageDelete/audits.ts create mode 100644 src/events/messageDelete/index.ts create mode 100644 src/events/messageUpdate/audits.ts create mode 100644 src/plugins/settings/guild/modules/audits.ts diff --git a/src/events/guildMemberAdd/audits.ts b/src/events/guildMemberAdd/audits.ts new file mode 100644 index 0000000..6d76893 --- /dev/null +++ b/src/events/guildMemberAdd/audits.ts @@ -0,0 +1,43 @@ +import logger from "@logger"; +import { GuildMember, MessageEmbed, TextChannel } from "discord.js"; + +import guildSchema from "@schemas/guild"; + +import { footerText, footerIcon, successColor } from "@config/embed"; + +export default { + execute: async (member: GuildMember) => { + const guildData = await guildSchema.findOne({ guildId: member.guild.id }); + + const { client } = member; + + if (guildData === null) return; + + if (guildData.audits.status !== true) return; + if (!guildData.audits.channelId) return; + + const channel = client.channels.cache.get(`${guildData.audits.channelId}`); + + if (channel === null) return; + + (channel as TextChannel).send({ + embeds: [ + new MessageEmbed() + .setColor(successColor) + .setAuthor({ + name: "Member Joined", + iconURL: member.user.displayAvatarURL(), + }) + .setDescription(`${member.user} ${member.user.tag}`) + .addFields([ + { name: "Account Age", value: `${member.user.createdAt}` }, + ]) + .setTimestamp() + .setFooter({ + text: footerText, + iconURL: footerIcon, + }), + ], + }); + }, +}; diff --git a/src/events/guildMemberAdd/index.ts b/src/events/guildMemberAdd/index.ts index bd15935..4b2cbe0 100644 --- a/src/events/guildMemberAdd/index.ts +++ b/src/events/guildMemberAdd/index.ts @@ -6,6 +6,7 @@ import updatePresence from "@helpers/updatePresence"; import fetchUser from "@helpers/fetchUser"; import logger from "@logger"; import joinMessage from "../guildMemberAdd/joinMessage"; +import audits from "../guildMemberAdd/audits"; export default { name: "guildMemberAdd", @@ -16,6 +17,7 @@ export default { `New member: ${user.tag} (${user.id}) added to guild: ${guild.name} (${guild.id})` ); + await audits.execute(member); await joinMessage.execute(member); await fetchUser(user, guild); await updatePresence(client); diff --git a/src/events/guildMemberRemove/audits.ts b/src/events/guildMemberRemove/audits.ts new file mode 100644 index 0000000..e096814 --- /dev/null +++ b/src/events/guildMemberRemove/audits.ts @@ -0,0 +1,40 @@ +import logger from "@logger"; +import { GuildMember, MessageEmbed, TextChannel } from "discord.js"; + +import guildSchema from "@schemas/guild"; + +import { footerText, footerIcon, errorColor } from "@config/embed"; + +export default { + execute: async (member: GuildMember) => { + const guildData = await guildSchema.findOne({ guildId: member.guild.id }); + + const { client } = member; + + if (guildData === null) return; + + if (guildData.audits.status !== true) return; + if (!guildData.audits.channelId) return; + + const channel = client.channels.cache.get(`${guildData.audits.channelId}`); + + if (channel === null) return; + + (channel as TextChannel).send({ + embeds: [ + new MessageEmbed() + .setColor(errorColor) + .setAuthor({ + name: "Member Left", + iconURL: member.user.displayAvatarURL(), + }) + .setDescription(`${member.user} ${member.user.tag}`) + .setTimestamp() + .setFooter({ + text: footerText, + iconURL: footerIcon, + }), + ], + }); + }, +}; diff --git a/src/events/guildMemberRemove/index.ts b/src/events/guildMemberRemove/index.ts index f813870..e2fe667 100644 --- a/src/events/guildMemberRemove/index.ts +++ b/src/events/guildMemberRemove/index.ts @@ -6,6 +6,7 @@ import updatePresence from "@helpers/updatePresence"; import dropUser from "@helpers/dropUser"; import logger from "@logger"; import leaveMessage from "./leaveMessage"; +import audits from "./audits"; export default { name: "guildMemberRemove", @@ -16,6 +17,7 @@ export default { `Removed member: ${user.tag} (${user.id}) from guild: ${guild.name} (${guild.id})` ); + await audits.execute(member); await leaveMessage.execute(member); await dropUser(user, guild); await updatePresence(client); diff --git a/src/events/interactionCreate/audits.ts b/src/events/interactionCreate/audits.ts new file mode 100644 index 0000000..5fe29e6 --- /dev/null +++ b/src/events/interactionCreate/audits.ts @@ -0,0 +1,48 @@ +import logger from "@logger"; +import { Interaction, MessageEmbed, TextChannel } from "discord.js"; + +import guildSchema from "@schemas/guild"; + +import { footerText, footerIcon, successColor } from "@config/embed"; + +export default { + execute: async (interaction: Interaction) => { + if (interaction === null) return; + + if (interaction.guild === null) return; + + const guildData = await guildSchema.findOne({ + guildId: interaction.guild.id, + }); + + const { client } = interaction; + + if (guildData === null) return; + + if (guildData.audits.status !== true) return; + if (!guildData.audits.channelId) return; + + const channel = client.channels.cache.get(`${guildData.audits.channelId}`); + + if (channel === null) return; + + (channel as TextChannel).send({ + embeds: [ + new MessageEmbed() + .setColor(successColor) + .setDescription( + ` + **Interaction created by** ${interaction.user.username} **in** ${interaction.channel} + ` + ) + .setThumbnail(interaction.user.displayAvatarURL()) + .addFields([{ name: "Event", value: "interactionCreate" }]) + .setTimestamp() + .setFooter({ + text: footerText, + iconURL: footerIcon, + }), + ], + }); + }, +}; diff --git a/src/events/interactionCreate/index.ts b/src/events/interactionCreate/index.ts index e93d10a..fb35bc9 100644 --- a/src/events/interactionCreate/index.ts +++ b/src/events/interactionCreate/index.ts @@ -4,6 +4,7 @@ import { CommandInteraction } from "discord.js"; // Dependencies import isCommand from "@root/events/interactionCreate/components/isCommand"; import logger from "@logger"; +import audits from "./audits"; export default { name: "interactionCreate", @@ -14,6 +15,7 @@ export default { `New interaction: ${id} in guild: ${guild?.name} (${guild?.id})` ); + await audits.execute(interaction); await isCommand(interaction); }, }; diff --git a/src/events/messageDelete/audits.ts b/src/events/messageDelete/audits.ts new file mode 100644 index 0000000..f7f0ed1 --- /dev/null +++ b/src/events/messageDelete/audits.ts @@ -0,0 +1,51 @@ +import logger from "@logger"; +import { Message, MessageEmbed, TextChannel } from "discord.js"; + +import guildSchema from "@schemas/guild"; + +import { footerText, footerIcon, successColor } from "@config/embed"; + +export default { + execute: async (message: Message) => { + if (message === null) return; + + if (message.guild === null) return; + + const guildData = await guildSchema.findOne({ + guildId: message.guild.id, + }); + + const { client } = message; + + if (guildData === null) return; + + if (guildData.audits.status !== true) return; + if (!guildData.audits.channelId) return; + + const channel = client.channels.cache.get(`${guildData.audits.channelId}`); + + if (channel === null) return; + + (channel as TextChannel).send({ + embeds: [ + new MessageEmbed() + .setColor(successColor) + .setAuthor({ + name: message.author.username, + iconURL: message.author.displayAvatarURL(), + }) + .setDescription( + ` + **Message sent by** ${message.author} **deleted in** ${message.channel} + ${message.content} + ` + ) + .setTimestamp() + .setFooter({ + text: footerText, + iconURL: footerIcon, + }), + ], + }); + }, +}; diff --git a/src/events/messageDelete/index.ts b/src/events/messageDelete/index.ts new file mode 100644 index 0000000..97fcfde --- /dev/null +++ b/src/events/messageDelete/index.ts @@ -0,0 +1,9 @@ +import { Message } from "discord.js"; +import audits from "@events/messageDelete/audits"; + +export default { + name: "messageDelete", + async execute(message: Message) { + await audits.execute(message); + }, +}; diff --git a/src/events/messageUpdate/audits.ts b/src/events/messageUpdate/audits.ts new file mode 100644 index 0000000..50c76b5 --- /dev/null +++ b/src/events/messageUpdate/audits.ts @@ -0,0 +1,53 @@ +/* eslint-disable no-loops/no-loops */ +import logger from "@logger"; +import { Message, MessageEmbed, TextChannel } from "discord.js"; + +import guildSchema from "@schemas/guild"; + +import { footerText, footerIcon, successColor } from "@config/embed"; + +export default { + execute: async (oldMessage: Message, newMessage: Message) => { + if (oldMessage === null) return; + if (newMessage === null) return; + + if (oldMessage.guild === null) return; + if (newMessage.guild === null) return; + + const guildData = await guildSchema.findOne({ + guildId: oldMessage.guild.id, + }); + + const { client } = oldMessage; + + if (guildData === null) return; + + if (guildData.audits.status !== true) return; + if (!guildData.audits.channelId) return; + + const channel = client.channels.cache.get(`${guildData.audits.channelId}`); + + if (channel === null) return; + + (channel as TextChannel).send({ + embeds: [ + new MessageEmbed() + .setColor(successColor) + .setAuthor({ + name: newMessage.author.username, + iconURL: newMessage.author.displayAvatarURL(), + }) + .setDescription( + ` + **Message edited in** ${newMessage.channel} [jump to message](https://discord.com/channels/${newMessage.guild.id}/${newMessage.channel.id}/${newMessage.id}) + ` + ) + .setTimestamp() + .setFooter({ + text: footerText, + iconURL: footerIcon, + }), + ], + }); + }, +}; diff --git a/src/events/messageUpdate/index.ts b/src/events/messageUpdate/index.ts index 52547b5..2ea1e42 100644 --- a/src/events/messageUpdate/index.ts +++ b/src/events/messageUpdate/index.ts @@ -5,11 +5,15 @@ import logger from "@logger"; // Modules import counter from "./modules/counter"; +import audits from "./audits"; + export default { name: "messageUpdate", - async execute(_oldMessage: Message, newMessage: Message) { + async execute(oldMessage: Message, newMessage: Message) { const { author, guild } = newMessage; + await audits.execute(oldMessage, newMessage); + logger?.verbose( `Message update event fired by ${author.tag} (${author.id}) in guild: ${guild?.name} (${guild?.id})` ); diff --git a/src/plugins/settings/guild/index.ts b/src/plugins/settings/guild/index.ts index 3b88f8c..f9e8939 100644 --- a/src/plugins/settings/guild/index.ts +++ b/src/plugins/settings/guild/index.ts @@ -12,6 +12,7 @@ import pterodactyl from "./modules/pterodactyl"; import credits from "./modules/credits"; import points from "./modules/points"; import welcome from "./modules/welcome"; +import audits from "./modules/audits"; import { SlashCommandSubcommandGroupBuilder } from "@discordjs/builders"; // Function @@ -23,7 +24,8 @@ export default { .addSubcommand(pterodactyl.data) .addSubcommand(credits.data) .addSubcommand(points.data) - .addSubcommand(welcome.data); + .addSubcommand(welcome.data) + .addSubcommand(audits.data); }, execute: async (interaction: CommandInteraction) => { // Destructure member @@ -53,20 +55,32 @@ export default { logger?.verbose(`Executing pterodactyl subcommand`); return pterodactyl.execute(interaction); - } else if (options?.getSubcommand() === "credits") { + } + + if (options?.getSubcommand() === "credits") { logger?.verbose(`Executing credits subcommand`); return credits.execute(interaction); - } else if (options?.getSubcommand() === "points") { + } + + if (options?.getSubcommand() === "points") { logger?.verbose(`Executing points subcommand`); return points.execute(interaction); - } else if (options?.getSubcommand() === "welcome") { + } + + if (options?.getSubcommand() === "welcome") { logger?.verbose(`Executing welcome subcommand`); return welcome.execute(interaction); } + if (options?.getSubcommand() === "audits") { + logger?.verbose(`Executing audit subcommand`); + + return audits.execute(interaction); + } + logger?.verbose(`No subcommand found`); }, }; diff --git a/src/plugins/settings/guild/modules/audits.ts b/src/plugins/settings/guild/modules/audits.ts new file mode 100644 index 0000000..f04ff97 --- /dev/null +++ b/src/plugins/settings/guild/modules/audits.ts @@ -0,0 +1,85 @@ +// Dependencies +import { CommandInteraction } from "discord.js"; + +// Configurations +import { successColor, footerText, footerIcon } from "@config/embed"; + +// Handlers +import logger from "@logger"; + +// Models +import guildSchema from "@schemas/guild"; +import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; +import { ChannelType } from "discord-api-types/v10"; + +// Function +export default { + data: (command: SlashCommandSubcommandBuilder) => { + return command + .setName("audits") + .setDescription("Audits") + .addBooleanOption((option) => + option.setName("status").setDescription("Should audits be enabled?") + ) + .addChannelOption((option) => + option + .setName("channel") + .setDescription("Channel for audit messages.") + .addChannelType(ChannelType.GuildText as number) + ); + }, + execute: async (interaction: CommandInteraction) => { + // Destructure member + const { options, guild } = interaction; + + // Get options + const status = options?.getBoolean("status"); + const channel = options?.getChannel("channel"); + + // Get guild object + const guildDB = await guildSchema?.findOne({ + guildId: guild?.id, + }); + + if (guildDB === null) { + return logger?.verbose(`Guild not found in database.`); + } + + // Modify values + guildDB.audits.status = status !== null ? status : guildDB?.audits?.status; + guildDB.audits.channelId = + channel !== null ? channel.id : guildDB?.audits?.channelId; + + // Save guild + await guildDB?.save()?.then(async () => { + logger?.verbose(`Guild audits updated.`); + + return interaction?.editReply({ + embeds: [ + { + title: ":hammer: Settings - Guild [Audits]", + description: `Audits settings updated.`, + color: successColor, + fields: [ + { + name: "🤖 Status", + value: `${guildDB?.audits?.status}`, + inline: true, + }, + { + name: "🌊 Channel", + value: `${guildDB?.audits?.channelId}`, + inline: true, + }, + ], + timestamp: new Date(), + footer: { + iconURL: footerIcon, + text: footerText, + }, + }, + ], + }); + }); + }, +};