Use GuildSavedMessages events in logs. Fix code blocks in edit logs.

This commit is contained in:
Dragory 2018-11-24 17:59:05 +02:00
parent 1a6e680d81
commit 2c8603ca70
4 changed files with 95 additions and 37 deletions

View file

@ -11,6 +11,8 @@ const RETENTION_PERIOD = 7 * 24 * 60 * 60 * 1000; // 1 week
export class GuildSavedMessages extends BaseRepository { export class GuildSavedMessages extends BaseRepository {
private messages: Repository<SavedMessage>; private messages: Repository<SavedMessage>;
protected toBePermanent: Set<string>;
public events: QueuedEventEmitter; public events: QueuedEventEmitter;
constructor(guildId) { constructor(guildId) {
@ -18,6 +20,8 @@ export class GuildSavedMessages extends BaseRepository {
this.messages = getRepository(SavedMessage); this.messages = getRepository(SavedMessage);
this.events = new QueuedEventEmitter(); this.events = new QueuedEventEmitter();
this.toBePermanent = new Set();
this.cleanup(); this.cleanup();
setInterval(() => this.cleanup(), CLEANUP_INTERVAL); setInterval(() => this.cleanup(), CLEANUP_INTERVAL);
} }
@ -84,6 +88,12 @@ export class GuildSavedMessages extends BaseRepository {
} }
async create(data) { async create(data) {
const isPermanent = this.toBePermanent.has(data.id);
if (isPermanent) {
data.is_permanent = true;
this.toBePermanent.delete(data.id);
}
try { try {
await this.messages.insert(data); await this.messages.insert(data);
} catch (e) { } catch (e) {
@ -145,4 +155,18 @@ export class GuildSavedMessages extends BaseRepository {
const newData = this.msgToSavedMessageData(msg); const newData = this.msgToSavedMessageData(msg);
return this.saveEdit(msg.id, newData); return this.saveEdit(msg.id, newData);
} }
async setPermanent(id: string) {
const savedMsg = await this.find(id);
if (savedMsg) {
await this.messages.update(
{ id },
{
is_permanent: true
}
);
} else {
this.toBePermanent.add(id);
}
}
} }

View file

@ -2,12 +2,20 @@ import { decorators as d, Plugin } from "knub";
import { GuildLogs } from "../data/GuildLogs"; import { GuildLogs } from "../data/GuildLogs";
import { LogType } from "../data/LogType"; import { LogType } from "../data/LogType";
import { Channel, Constants as ErisConstants, Member, Message, TextChannel, User } from "eris"; import { Channel, Constants as ErisConstants, Member, Message, TextChannel, User } from "eris";
import { findRelevantAuditLogEntry, formatTemplateString, stripObjectToScalars } from "../utils"; import {
deactivateMentions,
disableCodeBlocks,
findRelevantAuditLogEntry,
formatTemplateString,
stripObjectToScalars
} from "../utils";
import DefaultLogMessages from "../data/DefaultLogMessages.json"; import DefaultLogMessages from "../data/DefaultLogMessages.json";
import moment from "moment-timezone"; import moment from "moment-timezone";
import humanizeDuration from "humanize-duration"; import humanizeDuration from "humanize-duration";
import isEqual from "lodash.isequal"; import isEqual from "lodash.isequal";
import diff from "lodash.difference"; import diff from "lodash.difference";
import { GuildSavedMessages } from "../data/GuildSavedMessages";
import { SavedMessage } from "../data/entities/SavedMessage";
interface ILogChannel { interface ILogChannel {
include?: string[]; include?: string[];
@ -26,8 +34,14 @@ const unknownUser = {
export class LogsPlugin extends Plugin { export class LogsPlugin extends Plugin {
protected serverLogs: GuildLogs; protected serverLogs: GuildLogs;
protected savedMessages: GuildSavedMessages;
protected logListener; protected logListener;
private onMessageDeleteFn;
private onMessageDeleteBulkFn;
private onMessageUpdateFn;
getDefaultOptions() { getDefaultOptions() {
return { return {
config: { config: {
@ -42,13 +56,22 @@ export class LogsPlugin extends Plugin {
onLoad() { onLoad() {
this.serverLogs = new GuildLogs(this.guildId); this.serverLogs = new GuildLogs(this.guildId);
this.savedMessages = GuildSavedMessages.getInstance(this.guildId);
this.logListener = ({ type, data }) => this.log(type, data); this.logListener = ({ type, data }) => this.log(type, data);
this.serverLogs.on("log", this.logListener); this.serverLogs.on("log", this.logListener);
this.savedMessages.events.on("delete", this.onMessageDelete.bind(this));
this.savedMessages.events.on("deleteBulk", this.onMessageDeleteBulk.bind(this));
this.savedMessages.events.on("update", this.onMessageUpdate.bind(this));
} }
onUnload() { onUnload() {
this.serverLogs.removeListener("log", this.logListener); this.serverLogs.removeListener("log", this.logListener);
this.savedMessages.events.off("delete", this.onMessageDelete.bind(this));
this.savedMessages.events.off("deleteBulk", this.onMessageDeleteBulk.bind(this));
this.savedMessages.events.off("update", this.onMessageUpdate.bind(this));
} }
async log(type, data) { async log(type, data) {
@ -59,10 +82,7 @@ export class LogsPlugin extends Plugin {
const channel = this.guild.channels.get(channelId); const channel = this.guild.channels.get(channelId);
if (!channel || !(channel instanceof TextChannel)) continue; if (!channel || !(channel instanceof TextChannel)) continue;
if ( if ((opts.include && opts.include.includes(typeStr)) || (opts.exclude && !opts.exclude.includes(typeStr))) {
(opts.include && opts.include.includes(typeStr)) ||
(opts.exclude && !opts.exclude.includes(typeStr))
) {
const message = this.getLogMessage(type, data); const message = this.getLogMessage(type, data);
// TODO: Split log messages that are too long // TODO: Split log messages that are too long
if (message) await channel.createMessage(message).catch(() => {}); if (message) await channel.createMessage(message).catch(() => {});
@ -234,55 +254,64 @@ export class LogsPlugin extends Plugin {
}); });
} }
@d.event("messageUpdate") // Uses events from savesMessages
onMessageUpdate(msg: Message, oldMsg: Message) { onMessageUpdate(savedMessage: SavedMessage, oldSavedMessage: SavedMessage) {
if (!msg.author) return; if (oldSavedMessage && JSON.stringify(savedMessage.data) === JSON.stringify(oldSavedMessage.data)) return;
if (oldMsg && msg.content === oldMsg.content) return;
if (msg.type !== 0) return; const member = this.guild.members.get(savedMessage.user_id);
const channel = this.guild.channels.get(savedMessage.channel_id);
const before = oldSavedMessage
? disableCodeBlocks(deactivateMentions(oldSavedMessage.data.content || ""))
: "Unknown pre-edit content";
const after = disableCodeBlocks(deactivateMentions(savedMessage.data.content || ""));
this.serverLogs.log(LogType.MESSAGE_EDIT, { this.serverLogs.log(LogType.MESSAGE_EDIT, {
member: stripObjectToScalars(msg.member, ["user"]), member: stripObjectToScalars(member, ["user"]),
channel: stripObjectToScalars(msg.channel), channel: stripObjectToScalars(channel),
before: oldMsg ? oldMsg.cleanContent || oldMsg.content || "" : "Unavailable due to restart", before,
after: msg.cleanContent || msg.content || "" after
}); });
} }
@d.event("messageDelete") // Uses events from savesMessages
onMessageDelete(msg: Message) { onMessageDelete(savedMessage: SavedMessage) {
if (msg.type != null && msg.type !== 0) return; const member = this.guild.members.get(savedMessage.user_id);
const channel = this.guild.channels.get(savedMessage.channel_id);
if (msg.member) { if (member) {
this.serverLogs.log( this.serverLogs.log(
LogType.MESSAGE_DELETE, LogType.MESSAGE_DELETE,
{ {
member: stripObjectToScalars(msg.member, ["user"]), member: stripObjectToScalars(member, ["user"]),
channel: stripObjectToScalars(msg.channel), channel: stripObjectToScalars(channel),
messageText: msg.cleanContent || msg.content || "" messageText: disableCodeBlocks(deactivateMentions(savedMessage.data.content || ""))
}, },
msg.id savedMessage.id
); );
} else { } else {
this.serverLogs.log( this.serverLogs.log(
LogType.MESSAGE_DELETE_BARE, LogType.MESSAGE_DELETE_BARE,
{ {
messageId: msg.id, messageId: savedMessage.id,
channel: stripObjectToScalars(msg.channel) channel: stripObjectToScalars(channel)
}, },
msg.id savedMessage.id
); );
} }
} }
@d.event("messageDeleteBulk") // Uses events from savesMessages
onMessageDeleteBulk(messages: Message[]) { onMessageDeleteBulk(savedMessages: SavedMessage[]) {
const channel = this.guild.channels.get(savedMessages[0].channel_id);
this.serverLogs.log( this.serverLogs.log(
LogType.MESSAGE_DELETE_BULK, LogType.MESSAGE_DELETE_BULK,
{ {
count: messages.length, count: savedMessages.length,
channel: messages[0] ? messages[0].channel : null channel
}, },
messages[0] && messages[0].id savedMessages[0].id
); );
} }

View file

@ -42,7 +42,7 @@ export class PostPlugin extends Plugin {
} }
const createdMsg = await args.channel.createMessage(args.content); const createdMsg = await args.channel.createMessage(args.content);
await this.savedMessages.createFromMsg(createdMsg, { is_permanent: true }); await this.savedMessages.setPermanent(createdMsg.id);
} }
/** /**
@ -64,6 +64,5 @@ export class PostPlugin extends Plugin {
} }
const edited = await this.bot.editMessage(savedMessage.channel_id, savedMessage.id, args.content); const edited = await this.bot.editMessage(savedMessage.channel_id, savedMessage.id, args.content);
await this.savedMessages.saveEditFromMsg(edited);
} }
} }

View file

@ -1,8 +1,9 @@
import at = require("lodash.at"); import at = require("lodash.at");
import { Client, Guild, GuildAuditLogEntry, Message, TextChannel } from "eris"; import { Client, Guild, GuildAuditLogEntry, GuildChannel, Message, TextChannel } from "eris";
import url from "url"; import url from "url";
import tlds from "tlds"; import tlds from "tlds";
import emojiRegex from "emoji-regex"; import emojiRegex from "emoji-regex";
import { GuildSavedMessages } from "./data/GuildSavedMessages";
/** /**
* Turns a "delay string" such as "1h30m" to milliseconds * Turns a "delay string" such as "1h30m" to milliseconds
@ -166,10 +167,7 @@ export function getInviteCodesInString(str: string): string[] {
export const unicodeEmojiRegex = emojiRegex(); export const unicodeEmojiRegex = emojiRegex();
export const customEmojiRegex = /<:(?:.*?):(\d+)>/g; export const customEmojiRegex = /<:(?:.*?):(\d+)>/g;
export const anyEmojiRegex = new RegExp( export const anyEmojiRegex = new RegExp(`(?:(?:${unicodeEmojiRegex.source})|(?:${customEmojiRegex.source}))`, "g");
`(?:(?:${unicodeEmojiRegex.source})|(?:${customEmojiRegex.source}))`,
"g"
);
export function getEmojiInString(str: string): string[] { export function getEmojiInString(str: string): string[] {
return str.match(anyEmojiRegex) || []; return str.match(anyEmojiRegex) || [];
@ -275,4 +273,12 @@ export function disableLinkPreviews(str: string): string {
return str.replace(/(?<!\<)(https?:\/\/\S+)/gi, "<$1>"); return str.replace(/(?<!\<)(https?:\/\/\S+)/gi, "<$1>");
} }
export function deactivateMentions(content: string): string {
return content.replace(/@/g, "@\u200b");
}
export function disableCodeBlocks(content: string): string {
return content.replace(/`/g, "`\u200b");
}
export const DBDateFormat = "YYYY-MM-DD HH:mm:ss"; export const DBDateFormat = "YYYY-MM-DD HH:mm:ss";