varks-auditlog
Version:
Simple Discord.js v12 Module that send somne custom audit logs to specifics channel
655 lines (591 loc) • 28.1 kB
JavaScript
/*
Simple Discord.js module to log member-related event
Authors: Flisher et Patrix
Version: 2.2.5
Todo:
Add 2000 character handlings on msg related event
Add kick detection capability when audit permission is available
History:
2.2.5 - Improved README.md format (OwenPotent)
2.2.3 - Added ability to use channel ID instead of channel name (it check name, then id if name isn`t found)
2.2.2 - Initial commit to GitHub
2.1.6 - Fixed typo in documentation
2.1.5 - Fixed Linting and self-reported version
2.1.4 - Bugfix: fixed race condition crash on updateMessage(Delete) when banning someone
2.1.3 - Bugfix: fixed race condition crash on updateMessage(Delete)
2.1.2 - Bugfix: fixed race condition crash on voiceUpdate
2.1.1 - Bugfix: fixed crash when message is modified or deleted in private message
2.1.0 - Bugfix: Should not crash anymore when logging deleted message from banned user
2.0.2 - Added mode debugging capability for future development
2.0.1 - Fixed Readme.md with better description
2.0.0 - Initial DiscordJS V12 Compatibility
1.9.4 - Latest version compatible with DiscordJS V11, use "npm i discord-auditlog@1.9.4" to install
*/
module.exports = function (bot, options) {
const description = {
name: "varks-auditlog",
filename: "varks-auditlog.js",
version: "0.1.4"
}
const eventtype = {
guildMemberAdd: "movement",
guildMemberRemove: "movement",
guildBanAdd: "movement",
guildBanRemove: "movement",
guildMemberUpdate: "auditlog",
usernameChangedMsg: "auditlog",
discriminatorChangedMsg: "auditlog",
avatarChangedMsg: "auditlog",
messageDelete: "auditmsg",
messageUpdate: "auditmsg",
voiceStateUpdate: "voice"
}
console.log(`Module: ${description.name} | Loaded version ${description.version} from ("${description.filename}")`)
let debugmode = false
if (options && options.debugmode === true) debugmode = true
const moment = require("moment");
const DiscordJSversion = require("discord.js").version
if (DiscordJSversion.substring(0, 2) !== "12") console.error("This version of discord-lobby only run on DiscordJS V12 and up, please run \"npm i discord-auditlog@discord.js-v11\" to install an older version")
if (DiscordJSversion.substring(0, 2) !== "12") return
// Event Handlers
/*
COLORS
:join: USER JOINED 65280 https://cdn.discordapp.com/emojis/435119354867220511.png
:leave: USER LEFT 16711680 https://cdn.discordapp.com/emojis/435119363595436042.png
:kick: USER KICKED 16748544 https://cdn.discordapp.com/emojis/435119368989573122.png
:ban: USER BANNED 16711901 https://cdn.discordapp.com/emojis/435119375138422811.png
:unban: USER UNBANNED 16776960 https://cdn.discordapp.com/emojis/435462140900409344.png
:nicknamechange: NICKNAME UPDATE 29372 https://cdn.discordapp.com/emojis/435119397237948427.png
:usernamechange: USERNAME UPDATE 29372 https://cdn.discordapp.com/emojis/435119402279763968.png
:avatarchange: AVATAR UPDATE 29372 https://cdn.discordapp.com/emojis/435119382910337024.png
:discriminatorchange: DISCRIMINATOR UPDATE 29372 https://cdn.discordapp.com/emojis/435119390078271488.png
:channeljoin: CHANNEL JOINED 3381555 https://cdn.discordapp.com/emojis/435184638160404480.png
:channelexit: CHANNEL LEFT 10040115 https://cdn.discordapp.com/emojis/435174900227899393.png
:channelchange: CHANNEL SWITCH 13421568 https://cdn.discordapp.com/emojis/435440286559371265.png
:messageDelete: MESSAGE DELETE 16711680 https://cdn.discordapp.com/emojis/619328827872641024.png
:messageUpdate: MESSAGE UPDATE 16737792 https://cdn.discordapp.com/emojis/619328813381320735.png
*/
// MESSAGE DELETE V12
bot.on("messageDelete", message => {
if (message.author.bot === true) return
if (message.channel.type !== "text") return
if (debugmode) console.log(`Module: ${description.name} | messageDelete triggered`)
var embed = {
description: `
**Message sent by** <@${message.author.id}> **deleted in** <#${message.channel.id}>
**Content : **
${message.content}
`,
image: {
url: message.attachments.map(x => x.proxyURL)[0]
},
color: 16711680,
timestamp: new Date(),
footer: {
text: `
Author: ${message.author.id} | Message ID: ${message.id} `
},
author: {
name: `
MESSAGE DELETED `,
icon_url: "https://cdn.discordapp.com/emojis/619328827872641024.png"
}
}
if (message && message.member && typeof message.member.guild === "object") {
send(bot, message.member.guild, options, embed, "messageDelete")
} else {
console.error(`Module: ${description.name} | messageDelete - ERROR - member guild id couldn't be retrieved`)
console.error("author", message.author)
console.error("member", message.member)
console.error("content", message.content)
}
})
// MESSAGE UPDATE V12
bot.on("messageUpdate", (oldMessage, newMessage) => {
if (oldMessage.author.bot === true) return
if (oldMessage.channel.type !== "text") return
if (newMessage.channel.type !== "text") return
if (oldMessage.content === newMessage.content) return
var embed = {
description:
`
Message sent by <@${newMessage.member.user.id}> edited in <#${newMessage.channel.id}>
**Orignal Message : **
${oldMessage.content.replace(/`/g, "'")}
**Updated Message : **
${newMessage.content.replace(/`/g, "'")}
`,
color: 16737792,
timestamp: new Date(),
footer: {
text: `User ID: ${newMessage.member.user.id}`
},
author: {
name: "MESSAGE EDITED",
icon_url: "https://cdn.discordapp.com/emojis/619328813381320735.png"
}
}
send(bot, newMessage.member.guild, options, embed, "messageDelete")
})
// USER JOINED V12
bot.on("guildMemberAdd", member => {
if (debugmode) console.log(`Module: ${description.name} | guildMemberAdd triggered`)
var embed = {
description: `<@${member.user.id}> joined the server \nAccount creation : ${new Date(member.user.createdTimestamp).toDateString()}`,
url: member.user.displayAvatarURL(),
color: 65280,
timestamp: new Date(),
footer: {
text: `${member.nickname || member.user.username}`
},
thumbnail: {
url: member.user.displayAvatarURL()
},
author: {
name: `USER JOINED : ${member.user.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435119354867220511.png"
}
}
send(bot, member.guild, options, embed, "guildMemberAdd")
})
// USER LEFT V12
bot.on("guildMemberRemove", member => {
if (debugmode) console.log(`Module: ${description.name} | guildMemberRemove triggered`)
var embed = {
description: `<@${member.user.id}> - *${member.user.id}*`,
url: member.user.displayAvatarURL(),
color: 16711680,
timestamp: new Date(),
footer: {
text: `${member.nickname || member.user.username}`
},
thumbnail: {
url: member.user.displayAvatarURL()
},
author: {
name: `USER LEFT : ${member.user.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435119363595436042.png"
},
fields: [{
name: "Nickname",
value: `**${member.nickname || member.user.username}**`,
inline: true
}]
}
send(bot, member.guild, options, embed, "guildMemberRemove")
})
// USER KICKED
// Not very doable
// USER BANNED V12
bot.on("guildBanAdd", (banguild, banuser) => {
if (debugmode) console.log(`Module: ${description.name} | guildBanAdd triggered`)
var embed = {
url: banuser.displayAvatarURL(),
color: 16711901,
timestamp: new Date(),
footer: {
text: `${banuser.username}`
},
thumbnail: {
url: banuser.displayAvatarURL()
},
author: {
name: `USER BANNED : ${banuser.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435119375138422811.png"
}
}
send(bot, banguild, options, embed, "guildBanAdd")
})
// USER UNBANNED V12
bot.on("guildBanRemove", (banguild, banuser) => {
if (debugmode) console.log(`Module: ${description.name} | guildBanRemove triggered`)
var embed = {
url: banuser.displayAvatarURL(),
color: 16776960,
timestamp: new Date(),
footer: {
text: `${banuser.username}`
},
thumbnail: {
url: banuser.displayAvatarURL()
},
author: {
name: `USER UNBANNED : ${banuser.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435462140900409344.png"
}
}
send(bot, banguild, options, embed, "guildBanRemove")
})
// USER NICKNAME UPDATE V12
bot.on("guildMemberUpdate", (oldMember, newMember) => {
if (debugmode) console.log(`Module: ${description.name} | guildMemberUpdate:nickname triggered`)
if (oldMember.nickname !==
newMember.nickname) {
var embed = {
url: newMember.user.displayAvatarURL(),
color: 29372,
timestamp: new Date(),
footer: {
text: `${newMember.nickname || newMember.user.username}`
},
thumbnail: {
url: newMember.user.displayAvatarURL()
},
author: {
name: `NICKNAME CHANGED: ${newMember.user.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435119397237948427.png"
},
fields: [{
name: "Old Nickname",
value: `**${oldMember.nickname || oldMember.user.username}**`,
inline: true
},
{
name: "New Nickname",
value: `**${newMember.nickname || newMember.user.username}**`,
inline: true
}
]
}
send(bot, newMember.guild, options, embed, "guildMemberUpdate")
}
})
// MEMBER ROLE (Groups) UPDATE V12
bot.on("guildMemberUpdate", (oldMember, newMember) => {
if (debugmode) console.log(`Module: ${description.name} | guildMemberUpdate:roles triggered`)
// Initialize option if empty
if (!options) {
options = {}
}
if (options[newMember.guild.id]) {
options = options[newMember.guild.id]
}
// Add default empty list
if (typeof options.excludedroles === "undefined") options.excludedroles = new Array([])
if (typeof options.trackroles === "undefined") options.trackroles = false
if (options.trackroles !== false) {
const oldMemberRoles = oldMember.roles.cache.keyArray()
const newMemberRoles = newMember.roles.cache.keyArray()
// Check inspired by https://medium.com/@alvaro.saburido/set-theory-for-arrays-in-es6-eb2f20a61848
const oldRoles = oldMemberRoles.filter(x => !options.excludedroles.includes(x)).filter(x => !newMemberRoles.includes(x))
const newRoles = newMemberRoles.filter(x => !options.excludedroles.includes(x)).filter(x => !oldMemberRoles.includes(x))
const rolechanged = (newRoles.length || oldRoles.length)
if (rolechanged) {
let roleadded = ""
if (newRoles.length > 0) {
for (let i = 0; i < newRoles.length; i++) {
if (i > 0) roleadded += ", "
roleadded += `<@&${newRoles[i]}>`
}
}
let roleremoved = ""
if (oldRoles.length > 0) {
for (let i = 0; i < oldRoles.length; i++) {
if (i > 0) roleremoved += ", "
roleremoved += `<@&${oldRoles[i]}>`
}
}
var embed = {
url: newMember.user.displayAvatarURL(),
color: 29372,
timestamp: new Date(),
footer: {
text: `${newMember.nickname || newMember.user.username}`
},
thumbnail: {
url: newMember.user.displayAvatarURL()
},
author: {
name: `ROLES CHANGED: ${newMember.user.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435119397237948427.png"
},
fields: [{
name: "ROLES REMOVED",
value: `**${roleremoved} **`,
inline: true
},
{
name: "ROLES ADDED: ",
value: `**${roleadded} **`,
inline: true
}
]
}
send(bot, newMember.guild, options, embed, "guildMemberUpdate")
}
}
})
// USER UPDATE AVATAR, USERNAME, DISCRIMINATOR V12
bot.on("userUpdate", (oldUser, newUser) => {
if (debugmode) console.log(`Module: ${description.name} | userUpdate triggered`)
// Log quand le user change de username (et possiblement discriminator)
var usernameChangedMsg = null
var discriminatorChangedMsg = null
var avatarChangedMsg = null
// search the member from all guilds, since the userUpdate event doesn't provide guild information as it is a global event.
bot.guilds.cache.forEach(function (guild, guildid) {
guild.members.cache.forEach(function (member, memberid) {
if (newUser.id === memberid) {
// var member = bot.guilds.get(guildid).members.get(member.id)
// USERNAME CHANGED V12
if (oldUser.username !== newUser.username) {
if (debugmode) console.log(`Module: ${description.name} | userUpdate:USERNAME triggered`)
usernameChangedMsg = {
url: newUser.displayAvatarURL(),
color: 29372,
timestamp: new Date(),
footer: {
text: `${member.nickname || member.user.username}`
},
thumbnail: {
url: newUser.displayAvatarURL()
},
author: {
name: `USERNAME CHANGED: ${newUser.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435119402279763968.png"
},
fields: [{
name: "Old Username",
value: `**${oldUser.username}**`,
inline: true
},
{
name: "New Username",
value: `**${newUser.username}**`,
inline: true
}
]
}
}
// DISCRIMINATOR CHANGED V12
if (oldUser.discriminator !== newUser.discriminator) {
if (debugmode) console.log(`Module: ${description.name} | userUpdate:DISCRIMINATOR triggered`)
discriminatorChangedMsg = {
url: newUser.displayAvatarURL(),
color: 29372,
timestamp: new Date(),
footer: {
text: `${member.nickname || member.user.username}`
},
thumbnail: {
url: newUser.displayAvatarURL()
},
author: {
name: `DISCRIMINATOR CHANGED: ${newUser.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435119390078271488.png"
},
fields: [{
name: "Old Discriminator",
value: `**${oldUser.discriminator}**`,
inline: true
},
{
name: "New Discriminator",
value: `**${newUser.discriminator}**`,
inline: true
}
]
}
}
// AVATAR CHANGED V12
if (oldUser.avatar !== newUser.avatar) {
if (debugmode) console.log(`Module: ${description.name} | userUpdate:AVATAR triggered`)
avatarChangedMsg = {
url: newUser.displayAvatarURL(),
color: 29372,
timestamp: new Date(),
footer: {
text: `${member.nickname || member.user.username}`
},
thumbnail: {
url: newUser.displayAvatarURL()
},
author: {
name: `AVATAR CHANGED: ${newUser.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435119382910337024.png"
},
image: {
url: oldUser.displayAvatarURL()
},
fields: [{
name: "Old Avatar",
value: ":arrow_down:"
}]
}
}
if (usernameChangedMsg) send(bot, guild, options, usernameChangedMsg, "usernameChangedMsg")
if (discriminatorChangedMsg) send(bot, guild, options, discriminatorChangedMsg, "discriminatorChangedMsg")
if (avatarChangedMsg) send(bot, guild, options, avatarChangedMsg, "avatarChangedMsg")
}
})
})
})
// CHANNEL JOIN LEAVE SWITCH V12
bot.on("voiceStateUpdate", (oldState, newState) => {
if (debugmode) console.log(`Module: ${description.name} | voiceStateUpdate triggered`)
var oldChannelName
var newChannelName
var embed
// SET CHANNEL NAME STRING
let oldparentname = "unknown"
let oldchannelname = "unknown"
let oldchanelid = "unknown"
if (oldState && oldState.channel && oldState.channel.parent && oldState.channel.parent.name) oldparentname = oldState.channel.parent.name
if (oldState && oldState.channel && oldState.channel.name) oldchannelname = oldState.channel.name
if (oldState && oldState.channelID) oldchanelid = oldState.channelID
let newparentname = "unknown"
let newchannelname = "unknown"
let newchanelid = "unknown"
if (newState && newState.channel && newState.channel.parent && newState.channel.parent.name) newparentname = newState.channel.parent.name
if (newState && newState.channel && newState.channel.name) newchannelname = newState.channel.name
if (newState && newState.channelID) newchanelid = newState.channelID
if (oldState.channelID) {
if (typeof oldState.channel.parent !== "undefined") {
oldChannelName = `\n\t${oldchannelname}`
} else {
oldChannelName = `\n\t*${oldchanelid}*`
}
}
if (newState.channelID) {
if (typeof newState.channel.parent !== "undefined") {
newChannelName = `\n\t${newchannelname}`
} else {
newChannelName = `-\n\t*${newchanelid}*`
}
}
// JOINED V12
if (!oldState.channelID && newState.channelID) {
if (debugmode) console.log(`Module: ${description.name} | voiceStateUpdate:JOINED triggered`)
embed = {
url: newState.member.user.displayAvatarURL(),
color: 3381555,
timestamp: new Date(),
footer: {
text: `${newState.member.nickname || newState.member.user.username}`
},
thumbnail: {
url: newState.member.user.displayAvatarURL()
},
author: {
name: `Joined channel : ${newState.member.user.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435184638160404480.png"
},
fields: [{
name: "Joined channel",
value: `${newChannelName}`
}]
}
}
// LEFT V12
if (oldState.channelID && !newState.channelID) {
if (debugmode) console.log(`Module: ${description.name} | voiceStateUpdate:LEFT triggered`)
embed = {
url: newState.member.user.displayAvatarURL(),
color: 10040115,
timestamp: new Date(),
footer: {
text: `${newState.member.nickname || newState.member.user.username}`
},
thumbnail: {
url: newState.member.user.displayAvatarURL()
},
author: {
name: `Left channel : ${newState.member.user.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435174900227899393.png"
},
fields: [{
name: "Left channel",
value: `${oldChannelName}`
}]
}
}
// SWITCH V12
if (oldState.channelID && newState.channelID) {
// False positive check
if (oldState.channelID !== newState.channelID) {
if (debugmode) console.log(`Module: ${description.name} | voiceStateUpdate:SWITCH triggered`)
embed = {
url: newState.member.user.displayAvatarURL(),
color: 13421568,
timestamp: new Date(),
footer: {
text: `${newState.member.nickname || newState.member.user.username}`
},
thumbnail: {
url: newState.member.user.displayAvatarURL()
},
author: {
name: `Switched channel : ${newState.member.user.tag}`,
icon_url: "https://cdn.discordapp.com/emojis/435440286559371265.png"
},
fields: [{
name: "Left channel",
value: `${oldChannelName}`,
inline: true
},
{
name: "Joined channel",
value: `${newChannelName}`,
inline: true
}
]
}
}
}
// SEND
if (embed) {
send(bot, newState.guild, options, embed, "voiceStateUpdate")
}
})
// SEND FUNCTION V12
function send (bot, guild, options, msg, movement) {
let embed = ""
if (debugmode) console.log(`Module: ${description.name} | send - configured options:`, options)
// Initialize option if empty
if (!options) {
options = {}
}
// Initialize if options are multi-server
if (options[guild.id]) {
options = options[guild.id]
}
if (debugmode) console.log(`Module: ${description.name} | send - specifics options:`, options)
// Add default channel
if (typeof options.auditlog === "undefined") options.auditlog = "audit-log"
if (typeof options.auditmsg === "undefined") options.auditmsg = false
if (typeof options.movement === "undefined") options.movement = "in-out"
if (typeof options.voice === "undefined") options.voice = false
if (debugmode) console.log(`Module: ${description.name} | send - computed options:`, options)
const channelname = (options[eventtype[movement]])
if (channelname) {
// define channel object
const channel = guild.channels.cache.find(val => val.name === channelname) || guild.channels.cache.find(val => val.id === channelname)
if (channel) {
if (channel.permissionsFor(bot.user).has("SEND_MESSAGES") && channel.permissionsFor(bot.user).has("SEND_MESSAGES")) {
if (typeof msg === "object") {
// Embed
if (channel.permissionsFor(bot.user).has("EMBED_LINKS")) {
embed = msg
channel.send({
embed
})
.catch(console.error)
} else {
console.log(`${description.name} -> The Bot doesn't have the permission EMBED_LINKS to the configured channel "${channelname}" on server "${guild.name}" (${guild.id})`)
}
} else {
// Send the Message
channel.send(msg)
.catch(console.error)
}
} else {
console.log(`${description.name} -> The Bot doesn't have the permission to send public message to the configured channel "${channelname}" on server "${guild.name}" (${guild.id})`)
}
} else {
console.log(`${description.name} -> The channel "${channelname}" do not exist on server "${guild.name}" (${guild.id})`)
}
} else {
// console.log(`AuditLog: No channel option for event ${movement} on server "${guild.name}" (${guild.id})`);
}
}
}