From 52db74005b9091d25d60d2bb0ab84fef6544fe43 Mon Sep 17 00:00:00 2001 From: Dragory Date: Sat, 9 Feb 2019 14:36:03 +0200 Subject: [PATCH] ReactionRoles: only require message id; allow use of emojis from other (shared) servers; add !reaction_roles clear command --- src/plugins/ReactionRoles.ts | 102 +++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/src/plugins/ReactionRoles.ts b/src/plugins/ReactionRoles.ts index 41a0ab6b..c49511c0 100644 --- a/src/plugins/ReactionRoles.ts +++ b/src/plugins/ReactionRoles.ts @@ -1,77 +1,85 @@ -import { Plugin, decorators as d } from "knub"; -import { CustomEmoji, errorMessage, isSnowflake } from "../utils"; +import { decorators as d } from "knub"; +import { CustomEmoji, errorMessage, isSnowflake, successMessage } from "../utils"; import { GuildReactionRoles } from "../data/GuildReactionRoles"; import { Channel, Message, TextChannel } from "eris"; +import { ZeppelinPlugin } from "./ZeppelinPlugin"; +import { GuildSavedMessages } from "../data/GuildSavedMessages"; type ReactionRolePair = [string, string, string?]; -export class ReactionRolesPlugin extends Plugin { +export class ReactionRolesPlugin extends ZeppelinPlugin { public static pluginName = "reaction_roles"; protected reactionRoles: GuildReactionRoles; + protected savedMessages: GuildSavedMessages; getDefaultOptions() { return { permissions: { - manage: false + manage: false, }, overrides: [ { level: ">=100", permissions: { - manage: true - } - } - ] + manage: true, + }, + }, + ], }; } async onLoad() { this.reactionRoles = GuildReactionRoles.getInstance(this.guildId); - return; - - // Pre-fetch all messages with reaction roles so we get their events - const reactionRoles = await this.reactionRoles.all(); - - const channelMessages: Map> = reactionRoles.reduce((map: Map>, row) => { - if (!map.has(row.channel_id)) map.set(row.channel_id, new Set()); - map.get(row.channel_id).add(row.message_id); - return map; - }, new Map()); - - const msgLoadPromises = []; - - for (const [channelId, messageIdSet] of channelMessages.entries()) { - const messageIds = Array.from(messageIdSet.values()); - const channel = (await this.guild.channels.get(channelId)) as TextChannel; - if (!channel) continue; - - for (const messageId of messageIds) { - msgLoadPromises.push(channel.getMessage(messageId)); - } - } - - await Promise.all(msgLoadPromises); + this.savedMessages = GuildSavedMessages.getInstance(this.guildId); } - @d.command("reaction_roles", " ") + @d.command("reaction_roles clear", "") @d.permission("manage") - async reactionRolesCmd(msg: Message, args: { channel: Channel; messageId: string; reactionRolePairs: string }) { - if (!(args.channel instanceof TextChannel)) { - msg.channel.createMessage(errorMessage("Channel must be a text channel!")); + async clearReactionRolesCmd(msg: Message, args: { messageId: string }) { + const savedMessage = await this.savedMessages.find(args.messageId); + if (!savedMessage) { + msg.channel.createMessage(errorMessage("Unknown message")); return; } - const targetMessage = await args.channel.getMessage(args.messageId); + const existingReactionRoles = this.reactionRoles.getForMessage(args.messageId); + if (!existingReactionRoles) { + msg.channel.createMessage(errorMessage("Message doesn't have reaction roles on it")); + return; + } + + this.reactionRoles.removeFromMessage(args.messageId); + + const channel = this.guild.channels.get(savedMessage.channel_id) as TextChannel; + const targetMessage = await channel.getMessage(savedMessage.id); + await targetMessage.removeReactions(); + + msg.channel.createMessage(successMessage("Reaction roles cleared")); + } + + @d.command("reaction_roles", " ") + @d.permission("manage") + async reactionRolesCmd(msg: Message, args: { messageId: string; reactionRolePairs: string }) { + const savedMessage = await this.savedMessages.find(args.messageId); + if (!savedMessage) { + msg.channel.createMessage(errorMessage("Unknown message")); + return; + } + + const channel = await this.guild.channels.get(savedMessage.channel_id); + if (!channel || !(channel instanceof TextChannel)) { + msg.channel.createMessage(errorMessage("Channel no longer exists")); + return; + } + + const targetMessage = await channel.getMessage(args.messageId); if (!targetMessage) { - args.channel.createMessage(errorMessage("Unknown message!")); + msg.channel.createMessage(errorMessage("Unknown message (2)")); return; } - const guildEmojis = this.guild.emojis as CustomEmoji[]; - const guildEmojiIds = guildEmojis.map(e => e.id); - // Turn "emoji = role" pairs into an array of tuples of the form [emoji, roleId] // Emoji is either a unicode emoji or the snowflake of a custom emoji const newRolePairs: ReactionRolePair[] = args.reactionRolePairs @@ -86,13 +94,13 @@ export class ReactionRolesPlugin extends Plugin { } else { return pair as ReactionRolePair; } - } + }, ); // Verify the specified emojis and roles are valid for (const pair of newRolePairs) { - if (isSnowflake(pair[0]) && !guildEmojiIds.includes(pair[0])) { - msg.channel.createMessage(errorMessage("I can only use regular emojis and custom emojis from this server")); + if (!this.canUseEmoji(pair[0])) { + msg.channel.createMessage(errorMessage("I can only use regular emojis and custom emojis from servers I'm on")); return; } @@ -107,7 +115,7 @@ export class ReactionRolesPlugin extends Plugin { // Remove old reaction/role pairs that weren't included in the new pairs or were changed in some way const toRemove = oldRolePairs.filter( - pair => !newRolePairs.find(oldPair => oldPair[0] === pair[0] && oldPair[1] === pair[1]) + pair => !newRolePairs.find(oldPair => oldPair[0] === pair[0] && oldPair[1] === pair[1]), ); for (const rolePair of toRemove) { await this.reactionRoles.removeFromMessage(targetMessage.id, rolePair[0]); @@ -123,7 +131,7 @@ export class ReactionRolesPlugin extends Plugin { // Add new/changed reaction/role pairs const toAdd = newRolePairs.filter( - pair => !oldRolePairs.find(oldPair => oldPair[0] === pair[0] && oldPair[1] === pair[1]) + pair => !oldRolePairs.find(oldPair => oldPair[0] === pair[0] && oldPair[1] === pair[1]), ); for (const rolePair of toAdd) { let emoji; @@ -137,7 +145,7 @@ export class ReactionRolesPlugin extends Plugin { } await targetMessage.addReaction(emoji); - await this.reactionRoles.add(args.channel.id, targetMessage.id, rolePair[0], rolePair[1]); + await this.reactionRoles.add(channel.id, targetMessage.id, rolePair[0], rolePair[1]); } }