guild logging
This commit is contained in:
parent
88e0ef6825
commit
492de3ede8
657
src/structure/components/observers/GuildLogging.js
Normal file
657
src/structure/components/observers/GuildLogging.js
Normal file
@ -0,0 +1,657 @@
|
||||
/* eslint-disable no-labels */
|
||||
const { MessageAttachment, WebhookClient } = require('discord.js');
|
||||
|
||||
const { Observer } = require('../../interfaces/');
|
||||
const Util = require('../../../Util');
|
||||
const { Constants: { EmbedLimits } } = require('../../../constants');
|
||||
const { stripIndents } = require('common-tags');
|
||||
const moment = require('moment');
|
||||
const { GuildWrapper } = require('../../client/wrappers');
|
||||
|
||||
const CONSTANTS = {
|
||||
COLORS: {
|
||||
RED: 16711680, // message delete
|
||||
YELLOW: 15120384, // message edit
|
||||
LIGHT_BLUE: 11337726, // message pin
|
||||
BLUE: 479397
|
||||
},
|
||||
IMAGES: {
|
||||
PREMIUM_LIMIT: 2,
|
||||
UPLOAD_LIMIT: {
|
||||
'0': 8,
|
||||
'1': 8,
|
||||
'2': 50,
|
||||
'3': 100
|
||||
},
|
||||
MB_DIVIDER: 1024 * 1024
|
||||
},
|
||||
WEEK: 7 * 24 * 60 * 60
|
||||
};
|
||||
|
||||
class GuildLogger extends Observer {
|
||||
|
||||
constructor(client) {
|
||||
|
||||
super(client, {
|
||||
name: 'guildLogger',
|
||||
priority: 3,
|
||||
disabled: false
|
||||
});
|
||||
|
||||
this.hooks = [
|
||||
['messageDelete', this.messageDelete.bind(this)],
|
||||
['messageDeleteBulk', this.messageDeleteBulk.bind(this)],
|
||||
['messageUpdate', this.messageEdit.bind(this)],
|
||||
['voiceStateUpdate', this.voiceState.bind(this)],
|
||||
//['guildBanAdd', this.ban.bind(this)],
|
||||
//['guildBanRemove', this.unban.bind(this)],
|
||||
['guildMemberAdd', this.memberJoin.bind(this)],
|
||||
['guildMemberRemove', this.memberLeave.bind(this)],
|
||||
['guildMemberUpdate', this.memberUpdate.bind(this)]
|
||||
];
|
||||
|
||||
this.attachmentWebhook = new WebhookClient(
|
||||
{
|
||||
id: this.client._options.discord.moderation.attachments.webhook.id,
|
||||
token: this.client._options.discord.moderation.attachments.webhook.token
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
//TODO: Figure this thing out, this should be called from messageDelete and rawMessageDelete if any attachments are present
|
||||
//data should be an object containing the necessary information to query for the attachment from the db, and the relevant information to log it
|
||||
//Will figure this out once I get to that point
|
||||
// async logAttachment(data) {
|
||||
|
||||
// }
|
||||
|
||||
async messageDelete(message) {
|
||||
|
||||
if (!this.client._built
|
||||
|| message.webhookID
|
||||
|| message.author.bot
|
||||
|| !message.guildWrapper
|
||||
|| !message.guild.available) return;
|
||||
|
||||
const wrapper = message.guildWrapper;
|
||||
const settings = await wrapper.settings();
|
||||
|
||||
if (!message.member) try {
|
||||
message.member = await message.guild.members.fetch(message.author.id);
|
||||
} catch (_) {
|
||||
// Member not found, do nothing
|
||||
}
|
||||
|
||||
const { messages: messageLog } = settings;
|
||||
if (!messageLog.channel) return undefined;
|
||||
|
||||
const { bypass, ignore } = messageLog;
|
||||
const logChannel = await wrapper.resolveChannel(messageLog.channel);
|
||||
if (!logChannel) return undefined;
|
||||
|
||||
const perms = logChannel.permissionsFor(message.guild.me);
|
||||
if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return undefined;
|
||||
|
||||
if (bypass.length && message.member.roles.cache.size) {
|
||||
const roles = message.member.roles.cache.map((r) => r.id);
|
||||
for (const role of bypass) {
|
||||
if (roles.includes(role)) return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignore && ignore.includes(message.channel.id)) return undefined;
|
||||
|
||||
const hook = await wrapper.getWebhook('messages');
|
||||
if (!hook) {
|
||||
this.client.logger.debug(`Missing messageLog hook in ${message.guild.name} (${message.guild.id})`);
|
||||
return;
|
||||
}
|
||||
|
||||
const { reference, channel, author, content, id } = message;
|
||||
|
||||
const embed = {
|
||||
title: wrapper.format('MSGLOG_DELETE_TITLE', { channel: channel.name, author: Util.escapeMarkdown(author.tag) }),
|
||||
description: Util.escapeMarkdown(content)?.replace(/\\n/gu, ' ') || wrapper.format('MSGLOG_NOCONTENT'),
|
||||
color: CONSTANTS.COLORS.RED,
|
||||
footer: {
|
||||
text: wrapper.format('MSGLOG_DELETE_FOOTER', { msgID: id, userID: author.id })
|
||||
},
|
||||
timestamp: message.createdAt,
|
||||
fields: []
|
||||
};
|
||||
|
||||
if (reference && reference.channelID === channel.id) {
|
||||
const referenced = await channel.messages.fetch(reference.messageID);
|
||||
embed.fields.push({
|
||||
name: wrapper.format('MSGLOG_REPLY', { tag: referenced.author.tag, id: referenced.author.id }),
|
||||
value: wrapper.format('MSGLOG_REPLY_VALUE', {
|
||||
content: referenced.content.length > 900 ? referenced.content.substring(0, 900) + '...' : referenced.content,
|
||||
link: referenced.url
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (message.filtered) {
|
||||
embed.fields.push({
|
||||
name: wrapper.format('MSGLOG_FILTERED'),
|
||||
value: stripIndents`
|
||||
${wrapper.format(message.filtered.preset ? 'MSGLOG_FILTERED_PRESET' : 'MSGLOG_FILTERED_VALUE',
|
||||
{ ...message.filtered })}
|
||||
${message.filtered.sanctioned ? wrapper.format('MSGLOG_FILTERED_SANCTIONED') : ''}
|
||||
`// + ()
|
||||
});
|
||||
}
|
||||
|
||||
const uploadedFiles = [];
|
||||
if (message.attachments.size > 0 && messageLog.attachments && logChannel.nsfw) {
|
||||
const imageExtensions = ['.png', '.webp', '.jpg', '.jpeg', '.gif'];
|
||||
const data = await this.client.storageManager.mongodb.messages.findOne({
|
||||
id: message.id
|
||||
});
|
||||
|
||||
if (data) {
|
||||
const attachments = await this.client.storageManager.mongodb.attachments.find({
|
||||
_id: { $in: data.attachments.filter((a) => a.index).map((a) => a.index) }
|
||||
});
|
||||
const sortedAttachments = data.attachments.sort((a, b) => b.size - a.size);
|
||||
|
||||
const files = [];
|
||||
for (const attachment of sortedAttachments) {
|
||||
|
||||
const attachmentData = attachments.find((a) => a.attachmentId === attachment.id);
|
||||
|
||||
if (attachmentData) {
|
||||
// Mongo does some weird serialisation of buffer data, so to access the actual buffer, you have to go 1 level deeper
|
||||
attachmentData.buffer = attachmentData.buffer.buffer; //Buffer.from(attachmentData.buffer, 'base64');
|
||||
const messageAttachment = new MessageAttachment(attachmentData.buffer, attachment.name, { size: attachment.size });
|
||||
|
||||
if (messageAttachment.size <
|
||||
CONSTANTS.IMAGES.UPLOAD_LIMIT[message.guild.premiumTier] * CONSTANTS.IMAGES.MB_DIVIDER) {
|
||||
|
||||
if (imageExtensions.includes(attachment.extension) && uploadedFiles.length === 0) {
|
||||
|
||||
uploadedFiles.push(messageAttachment);
|
||||
embed.image = {
|
||||
url: `attachment://${attachment.name}`
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
if (messageAttachment.size > 8 * CONSTANTS.IMAGES.MB_DIVIDER) {
|
||||
|
||||
const combined = uploadedFiles.length > 0 ?
|
||||
uploadedFiles.map((f) => f.size).reduce((p, v) => p + v) : 0;
|
||||
if ((combined + messageAttachment.size) / CONSTANTS.IMAGES.MB_DIVIDER <
|
||||
CONSTANTS.IMAGES.UPLOAD_LIMIT[message.guild.premiumTier]) {
|
||||
uploadedFiles.push(messageAttachment);
|
||||
}
|
||||
|
||||
} else {
|
||||
files.push(messageAttachment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let currentFiles = [];
|
||||
const uploaded = [];
|
||||
|
||||
const upload = async (files) => {
|
||||
const attachmentMessage = await this.attachmentWebhook.send(null, files)
|
||||
.catch((error) => this.client.logger.error(error));
|
||||
attachmentMessage.attachments.map(
|
||||
(a) => uploaded.push(`[${a.filename} (${(a.size / CONSTANTS.IMAGES.MB_DIVIDER).toFixed(2)}mb)](${a.url})`)
|
||||
);
|
||||
};
|
||||
|
||||
for (const file of files) {
|
||||
const currentMb = currentFiles.length > 0 ? currentFiles.map((f) => f.size).reduce((p, v) => p + v) : 0;
|
||||
if (currentMb + file.size > 8 * CONSTANTS.IMAGES.MB_DIVIDER) {
|
||||
await upload(currentFiles);
|
||||
currentFiles = [file];
|
||||
} else {
|
||||
currentFiles.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentFiles.length > 0) {
|
||||
await upload(currentFiles);
|
||||
}
|
||||
|
||||
if (uploaded.length > 0) {
|
||||
embed.description += `\n\n**${uploadedFiles.length > 0 ?
|
||||
'Additional ' : ''}Attachment${uploaded.length > 1 ? 's' : ''}:** ${uploaded.join(', ')}`;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
await hook.send({ embeds: [embed], files: uploadedFiles }).catch((err) => {
|
||||
this.client.logger.error('Error in message delete:\n' + err.stack);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async messageDeleteBulk(messages) {
|
||||
|
||||
//Status: Should be complete, though additional testing might be necessary
|
||||
|
||||
const { guild, channel } = messages.first();
|
||||
if (!guild) return;
|
||||
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const settings = await wrapper.settings();
|
||||
const chatlogs = settings.messages;
|
||||
if (!chatlogs.channel) return;
|
||||
const logChannel = await wrapper.resolveChannel(chatlogs.channel);
|
||||
if (!logChannel) return undefined;
|
||||
|
||||
const { ignore, bypass } = chatlogs;
|
||||
if (ignore.includes(channel.id)) return;
|
||||
|
||||
const hook = await wrapper.getWebhook('messages');
|
||||
if (!hook) return;
|
||||
|
||||
const cutOff = EmbedLimits.fieldValue;// - 3;
|
||||
const fields = [];
|
||||
|
||||
messages = messages.filter((msg) => !msg.author.bot);
|
||||
|
||||
//Compile messages into fields that can be compiled into embeds
|
||||
messageLoop: //Oldest messages first
|
||||
for (const message of messages.sort((a, b) => b.createdTimestamp - a.createdTimestamp).values()) {
|
||||
|
||||
let { member, content } = message;
|
||||
const { author, id } = message;
|
||||
content = Util.escapeMarkdown(content);
|
||||
|
||||
if (author.bot) continue;
|
||||
if (!member || member.partial) member = await guild.members.fetch(message.author.id).catch(() => {
|
||||
return false;
|
||||
});
|
||||
if (member && member.roles.cache.size) {
|
||||
const roles = member.roles.cache.map((role) => role.id);
|
||||
for (const role of roles) {
|
||||
if (bypass.includes(role)) continue messageLoop;
|
||||
}
|
||||
}
|
||||
|
||||
const uploaded = [];
|
||||
if (message.attachments.size > 0 && chatlogs.attachments && logChannel.nsfw) {
|
||||
|
||||
const data = await this.client.storageManager.mongodb.messages.findOne({
|
||||
id: message.id
|
||||
});
|
||||
|
||||
if (data) {
|
||||
|
||||
const attachments = await this.client.storageManager.mongodb.attachments.find({
|
||||
_id: { $in: data.attachments.filter((a) => a.index).map((a) => a.index) }
|
||||
});
|
||||
const sortedAttachments = data.attachments.sort((a, b) => b.size - a.size);
|
||||
|
||||
const files = [];
|
||||
for (const attachment of sortedAttachments) {
|
||||
|
||||
const attachmentData = attachments.find((a) => a.attachmentId === attachment.id);
|
||||
|
||||
if (!attachmentData) continue;
|
||||
// TODO: Implement a webhook on the logging server to upload the images instead
|
||||
if (attachment.size > 8 * CONSTANTS.IMAGES.MB_DIVIDER) continue; //(attachment.size > CONSTANTS.IMAGES.UPLOAD_LIMIT[message.guild.premiumTier] * CONSTANTS.IMAGES.MB_DIVIDER)
|
||||
|
||||
attachmentData.buffer = attachmentData.buffer.buffer;
|
||||
const messageAttachment = new MessageAttachment(attachmentData.buffer, attachment.name, { size: attachment.size });
|
||||
files.push(messageAttachment);
|
||||
|
||||
}
|
||||
|
||||
let currentFiles = [];
|
||||
|
||||
const upload = async (files) => {
|
||||
const attachmentMessage = await this.attachmentWebhook.send(null, files)
|
||||
.catch((error) => this.client.logger.error(error));
|
||||
attachmentMessage.attachments.map(
|
||||
(a) => uploaded.push(`[${a.filename} (${(a.size / CONSTANTS.IMAGES.MB_DIVIDER).toFixed(2)}mb)](${a.url})`)
|
||||
);
|
||||
};
|
||||
|
||||
for (const file of files) {
|
||||
const currentMb = currentFiles.length > 0 ? currentFiles.map((f) => f.size).reduce((p, v) => p + v) : 0;
|
||||
if (currentMb + file.size > 8 * CONSTANTS.IMAGES.MB_DIVIDER) {
|
||||
await upload(currentFiles);
|
||||
currentFiles = [file];
|
||||
} else {
|
||||
currentFiles.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentFiles.length > 0) {
|
||||
await upload(currentFiles);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//const attStr = message.attachments.map((att) => `${att.name} (${att.id})`).join(', ');
|
||||
const value = stripIndents`${content ? content.substring(0, cutOff) : wrapper.format('BULK_DELETE_NO_CONTENT')}`;
|
||||
//${message.attachments.size > 0 ? `__(Attachments: ${attStr})__` : '' }
|
||||
fields.push({
|
||||
name: `${Util.escapeMarkdown(author.tag)} @ ${moment.utc(message.createdAt).format('D/M/YYYY H:m:s')} UTC (MSG ID: ${id})`,
|
||||
value
|
||||
});
|
||||
|
||||
if (content && content.length > cutOff) fields.push({
|
||||
name: '\u200b',
|
||||
value: content.substring(cutOff)
|
||||
});
|
||||
|
||||
if (uploaded.length) fields.push({
|
||||
name: wrapper.format('BULK_DELETE_ATTACHMENTS'),
|
||||
value: uploaded.join('\n'),
|
||||
_attachment: true
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//Compile embeds
|
||||
const embedCutoff = EmbedLimits.embed - 100;
|
||||
const embeds = [];
|
||||
const embed = { // title gets set later
|
||||
fields: [],
|
||||
color: CONSTANTS.COLORS.RED
|
||||
};
|
||||
let length = 0; // Embed total length
|
||||
fields.reduce((_embed, field) => {
|
||||
//Make sure the total character count doesn't exceed the limit
|
||||
const fieldLength = field.name.length + field.value.length;
|
||||
if (_embed.fields.length < EmbedLimits.fieldObjects && length + fieldLength < embedCutoff) {
|
||||
_embed.fields.push(field);
|
||||
} else {
|
||||
//"clone" the embed into the array
|
||||
embeds.push({ ..._embed });
|
||||
_embed.fields = [field];
|
||||
length = 0;
|
||||
}
|
||||
length += fieldLength;
|
||||
return _embed;
|
||||
}, embed);
|
||||
embeds.push(embed);
|
||||
|
||||
//Post messages
|
||||
let showed = 0;
|
||||
for (let i = 0; i < embeds.length; i++) {
|
||||
const embed = embeds[i];
|
||||
//Amount of messages showing
|
||||
const x = embed.fields.filter((field) => field.name !== '\u200b' && !field._attachment).length;
|
||||
embed.title = wrapper.format('BULK_DELETE_TITLE', { embedNr: i + 1, channel: channel.name });
|
||||
embed.footer = {
|
||||
text: wrapper.format('BULK_DELETE_FOOTER',
|
||||
{ rangeStart: showed + 1, rangeEnd: showed += x, total: messages.size })
|
||||
};
|
||||
const result = await hook.send({ embeds: [embed] }).catch((err) => {
|
||||
//Unknown webhook -> webhook was deleted, remove it from db so it doesn't make any more unnecessary calls
|
||||
if (err.code === 10015) {
|
||||
wrapper.updateWebhook('messages');
|
||||
} else this.client.logger.error(err.stack);
|
||||
return { error: true };
|
||||
});
|
||||
if (result.error) break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async messageEdit(oldMessage, newMessage) {
|
||||
|
||||
//Status: Uses webhook, complete
|
||||
|
||||
// embeds loading in (ex. when a link is posted) would cause a message edit event
|
||||
if (oldMessage.embeds.length !== newMessage.embeds.length && oldMessage.content === newMessage.content) return;
|
||||
if (oldMessage.author.bot) return;
|
||||
|
||||
const { guild } = oldMessage;
|
||||
if (!guild) return;
|
||||
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
if (!oldMessage.member) oldMessage.member = await guild.members.fetch(oldMessage.author);
|
||||
const { member, channel, author, reference } = oldMessage;
|
||||
|
||||
const settings = await wrapper.settings();
|
||||
const chatlogs = settings.messages;
|
||||
if (!chatlogs.channel) return;
|
||||
|
||||
const { ignore, bypass } = chatlogs;
|
||||
const hook = await wrapper.getWebhook('messages');
|
||||
if (!hook) return;
|
||||
|
||||
if (bypass && member.roles.cache.size) {
|
||||
const roles = member.roles.cache.map((r) => r.id);
|
||||
for (const role of bypass) {
|
||||
if (roles.includes(role)) return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignore && ignore.includes(channel.id)) return;
|
||||
|
||||
if (oldMessage.content === newMessage.content && oldMessage.pinned !== newMessage.pinned) {
|
||||
|
||||
const embed = {
|
||||
title: wrapper.format('MSGLOG_PINNED_TITLE',
|
||||
{
|
||||
author: Util.escapeMarkdown(author.tag),
|
||||
channel: channel.name,
|
||||
pinned: wrapper.format('PIN_TOGGLE', { toggle: newMessage.pinned }, true)
|
||||
}),
|
||||
description: wrapper.format('MSGLOG_EDIT_JUMP', { guild: guild.id, channel: channel.id, message: oldMessage.id }),
|
||||
color: CONSTANTS.COLORS.LIGHT_BLUE
|
||||
};
|
||||
|
||||
if (oldMessage.content.length) embed.description += '\n' + oldMessage.content.substring(0, 1900);
|
||||
if (oldMessage.attachments.size) {
|
||||
const img = oldMessage.attachments.first();
|
||||
if (img.height && img.width) embed.image = { url: img.url };
|
||||
}
|
||||
|
||||
await hook.send({ embeds: [embed] }).catch(this.client.logger.error);
|
||||
|
||||
} else {
|
||||
|
||||
const embed = {
|
||||
// author: {
|
||||
// name: oldMessage.format('MSGLOG_EDIT_TITLE', { author: Util.escapeMarkdown(author.tag), channel: channel.name }),
|
||||
// icon_url: oldMessage.author.displayAvatarURL({ size: 32 }) // eslint-disable-line camelcase
|
||||
// },
|
||||
title: wrapper.format('MSGLOG_EDIT_TITLE', { author: Util.escapeMarkdown(author.tag), channel: channel.name }),
|
||||
footer: {
|
||||
text: wrapper.format('MSGLOG_EDIT_FOOTER', { msgID: oldMessage.id, userID: author.id })
|
||||
},
|
||||
description: wrapper.format('MSGLOG_EDIT_JUMP', { guild: guild.id, channel: channel.id, message: oldMessage.id }),
|
||||
color: CONSTANTS.COLORS.YELLOW,
|
||||
timestamp: oldMessage.createdAt,
|
||||
fields: []
|
||||
};
|
||||
|
||||
const oldCon = oldMessage.content,
|
||||
newCon = newMessage.content;
|
||||
//Original content
|
||||
embed.fields.push({
|
||||
name: wrapper.format('MSGLOG_EDIT_OLD'),
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
value: oldCon.length > 1024 ? oldCon.substring(0, 1021) + '...' : oldCon.length ? oldCon : '\u200b'
|
||||
});
|
||||
if (oldCon.length > 1024) embed.fields.push({
|
||||
name: '\u200b',
|
||||
value: '...' + oldCon.substring(1021)
|
||||
});
|
||||
//Edited content
|
||||
embed.fields.push({
|
||||
name: wrapper.format('MSGLOG_EDIT_NEW'),
|
||||
value: newCon.length > 1024 ? newCon.substring(0, 1021) + '...' : newCon
|
||||
});
|
||||
if (newCon.length > 1024) embed.fields.push({
|
||||
name: '\u200b',
|
||||
value: '...' + newCon.substring(1021)
|
||||
});
|
||||
|
||||
if (reference && reference.channelID === channel.id) {
|
||||
const referenced = await channel.messages.fetch(reference.messageID);
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
const content = referenced.content ?
|
||||
referenced.content.length > 900 ?
|
||||
referenced.content.substring(0, 900) + '...' :
|
||||
referenced.content :
|
||||
wrapper.format('MSGLOG_REPLY_NOCONTENT');
|
||||
|
||||
embed.fields.push({
|
||||
name: wrapper.format('MSGLOG_REPLY', { tag: referenced.author.tag, id: referenced.author.id }),
|
||||
value: wrapper.format('MSGLOG_REPLY_VALUE', {
|
||||
content,
|
||||
link: referenced.url
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
//if(oldMessage.content.length > 1024) embed.description += '\n' + oldMessage.format('MSGLOG_EDIT_OLD_CUTOFF');
|
||||
//if(newMessage.content.length > 1024) embed.description += '\n' + oldMessage.format('MSGLOG_EDIT_NEW_CUTOFF');
|
||||
|
||||
await hook.send({ embeds: [embed] }).catch((err) => {
|
||||
this.client.logger.error('Error in message edit:\n' + err.stack);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async voiceState(oldState, newState) {
|
||||
|
||||
if (oldState.channel && newState.channel && oldState.channel === newState.channel) return;
|
||||
const { guild, member } = oldState;
|
||||
|
||||
//TODO: add checks for disconnecting bot from vc when left alone in one (music player)
|
||||
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const settings = await wrapper.settings();
|
||||
const setting = settings.voice;
|
||||
if (!setting || !setting.channel) return;
|
||||
|
||||
const logChannel = await wrapper.resolveChannel(setting.channel);
|
||||
if (!logChannel) return;
|
||||
|
||||
const perms = logChannel.permissionsFor(guild.me);
|
||||
if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return;
|
||||
|
||||
let index = null;
|
||||
const langParams = {
|
||||
nickname: member.nickname ? `\`(${member.nickname})\`` : '',
|
||||
tag: Util.escapeMarkdown(member.user.tag),
|
||||
id: member.id,
|
||||
oldChannel: oldState.channel?.name,
|
||||
newChannel: newState.channel?.name
|
||||
};
|
||||
|
||||
if (!oldState.channel && newState.channel) index = 'VCLOG_JOIN';
|
||||
else if (oldState.channel && newState.channel) index = 'VCLOG_SWITCH';
|
||||
else index = 'VCLOG_LEAVE';
|
||||
|
||||
this.client.rateLimiter.queueSend(logChannel, wrapper.format(index, langParams).trim());
|
||||
|
||||
}
|
||||
|
||||
// async ban(guild, user) {
|
||||
|
||||
// }
|
||||
|
||||
// async unban(guild, user) {
|
||||
|
||||
// }
|
||||
|
||||
_replaceTags(text, member) {
|
||||
const { user, guild } = member;
|
||||
return text
|
||||
.replace(/\{mention\}/gu, `<@${member.id}>`)
|
||||
.replace(/\{tag\}/gu, Util.escapeMarkdown(user.tag))
|
||||
.replace(/\{user\}/gu, Util.escapeMarkdown(user.username))
|
||||
.replace(/\{serversize\}/gu, guild.memberCount)
|
||||
.replace(/\{servername\}/gu, guild.name)
|
||||
.replace(/\{accage\}/gu, this.client.resolver.timeAgo(Date.now() / 1000 - user.createdTimestamp / 1000)) //.replace(/a/, '1')
|
||||
.replace(/\{id\}/gu, user.id)
|
||||
.trim();
|
||||
}
|
||||
|
||||
async memberJoin(member) {
|
||||
|
||||
const { guild } = member;
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const settings = await wrapper.settings();
|
||||
const setting = settings.members;
|
||||
if (!setting.channel) return;
|
||||
|
||||
const logChannel = await wrapper.resolveChannel(setting.channel);
|
||||
if (!logChannel) return;
|
||||
|
||||
const perms = logChannel.permissionsFor(guild.me);
|
||||
if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return;
|
||||
|
||||
let { joinMessage } = setting;
|
||||
joinMessage = this._replaceTags(joinMessage, member);
|
||||
this.client.rateLimiter.queueSend(logChannel, joinMessage);
|
||||
|
||||
}
|
||||
|
||||
async memberLeave(member) {
|
||||
|
||||
const { guild } = member;
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const settings = await wrapper.settings();
|
||||
const setting = settings.members;
|
||||
if (!setting.channel) return;
|
||||
|
||||
const logChannel = await wrapper.resolveChannel(setting.channel);
|
||||
if (!logChannel) return;
|
||||
|
||||
const perms = logChannel.permissionsFor(guild.me);
|
||||
if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return;
|
||||
|
||||
let { leaveMessage } = setting;
|
||||
leaveMessage = this._replaceTags(leaveMessage, member);
|
||||
this.client.rateLimiter.queueSend(logChannel, leaveMessage);
|
||||
|
||||
}
|
||||
|
||||
async memberUpdate(oldMember, newMember) {
|
||||
|
||||
if (oldMember.nickname === newMember.nickname) return;
|
||||
|
||||
const { guild, user } = oldMember;
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const settings = await wrapper.settings();
|
||||
const setting = settings.nicknames;
|
||||
if (!setting.channel) return;
|
||||
|
||||
const logChannel = await wrapper.resolveChannel(setting.channel);
|
||||
if (!logChannel) return;
|
||||
|
||||
const perms = logChannel.permissionsFor(guild.me);
|
||||
if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return;
|
||||
|
||||
const oldNick = oldMember.nickname || oldMember.user.username;
|
||||
const newNick = newMember.nickname || newMember.user.username;
|
||||
|
||||
const embed = {
|
||||
title: wrapper.format('NICKLOG_TITLE', { user: Util.escapeMarkdown(user.tag) }),
|
||||
description: wrapper.format('NICKLOG_DESCRIPTION', { oldNick, newNick }),
|
||||
footer: {
|
||||
text: wrapper.format('NICKLOG_FOOTER', { id: user.id })
|
||||
},
|
||||
color: CONSTANTS.COLORS.BLUE
|
||||
};
|
||||
|
||||
logChannel.send({ embed });
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildLogger;
|
Loading…
Reference in New Issue
Block a user