import { client } from "../client"; import { getRepository } from "typeorm"; import { MessageReaction } from "@shared/db/entity/MessageReaction"; import { KnownUser } from "@shared/db/entity/KnownUser"; import { ReactionType, ReactionEmote } from "@shared/db/entity/ReactionEmote"; import { isAuthorisedAsync } from "../util"; import { CommandSet, Command, Action, ActionType } from "src/model/command"; import { Message } from "discord.js"; const pattern = /^react to\s+"([^"]+)"\s+with\s+<:[^:]+:([^>]+)>$/i; async function getRandomEmotes(allowedTypes: ReactionType[], limit: number) { const reactionEmotesRepo = getRepository(ReactionEmote); const a = await reactionEmotesRepo.query(` select distinct on (type) type, "reactionId" from ( select * from reaction_emote where type in (${allowedTypes.map((s, i) => `$${i + 1}`).join(",")}) order by random(), random() limit ${limit} ) as sub`, allowedTypes) as ReactionEmote[]; return a; } @CommandSet export class ReactCommands { @Command({ pattern: "react to", auth: true, documentation: {description: "React to with .", example: "react to \"\" with "} }) async addReaction(msg: Message, s: string): Promise { if (!await isAuthorisedAsync(msg.member)) return; const contents = pattern.exec(s); if (contents != null) { const reactable = contents[1].trim().toLowerCase(); const reactionEmoji = contents[2]; if (!client.bot.emojis.cache.has(reactionEmoji)) { msg.channel.send(`${msg.author.toString()} I cannot react with this emoji :(`); return; } const repo = getRepository(MessageReaction); const message = repo.create({ message: reactable, reactionEmoteId: reactionEmoji }); await repo.save(message); msg.channel.send(`${msg.author.toString()} Added reaction!`); } } @Command({ pattern: "remove reaction to", auth: true, documentation: {description: "Stops reacting to .", example: "remove reaction to "} }) async removeReaction(msg: Message, s: string): Promise { if (!await isAuthorisedAsync(msg.member)) return; const content = s.substring("remove reaction to ".length).trim().toLowerCase(); const repo = getRepository(MessageReaction); const result = await repo.delete({ message: content }); if (result.affected == 0) { msg.channel.send(`${msg.author.toString()} No such reaction available!`); return; } msg.channel.send(`${msg.author.toString()} Removed reaction!`); } @Command({ pattern: "reactions", documentation: {description: "Lists all known messages this bot can react to.", example: "reactions"} }) async listReactions(msg: Message): Promise { const reactionsRepo = getRepository(MessageReaction); const messages = await reactionsRepo.find({ select: ["message"] }); const reactions = messages.reduce((p, c) => `${p}\n${c.message}`, ""); msg.channel.send(`I'll react to the following messages:\n\`\`\`${reactions}\n\`\`\``); } @Action(ActionType.MESSAGE) async reactToMentions(actionsDone: boolean, msg: Message, content: string): Promise { if (actionsDone) return false; const lowerContent = content.toLowerCase(); const reactionRepo = getRepository(MessageReaction); const usersRepo = getRepository(KnownUser); const message = await reactionRepo.findOne({ message: lowerContent }); if (message) { const emoji = client.bot.emojis.resolve(message.reactionEmoteId); if (emoji) msg.react(emoji); return true; } if (msg.mentions.users.size == 0) return false; const knownUsers = await usersRepo.find({ select: ["mentionReactionType"], where: [...msg.mentions.users.map(u => ({ userID: u.id }))] }); if (knownUsers.length == 0) return false; const reactionEmoteTypes = new Set(); for (const user of knownUsers) { if (user.mentionReactionType == ReactionType.NONE) continue; reactionEmoteTypes.add(user.mentionReactionType); } if(reactionEmoteTypes.size == 0) return false; const randomEmotes = await getRandomEmotes([...reactionEmoteTypes], 5); if (randomEmotes.length == 0) return false; for (const emote of randomEmotes) { const emoji = client.bot.emojis.resolve(emote.reactionId); if(emoji) await msg.react(emoji); } return true; } @Action(ActionType.INDIRECT_MENTION) async reactToPing(actionsDone: boolean, msg: Message): Promise { if (actionsDone) return false; let emoteType = ReactionType.ANGERY; const repo = getRepository(KnownUser); const knownUser = await repo.findOne({ select: ["replyReactionType"], where: [{ userID: msg.author.id }] }); if (knownUser) { if (knownUser.replyReactionType == ReactionType.NONE) return false; emoteType = knownUser.replyReactionType; } const emotes = await getRandomEmotes([emoteType], 1); if (emotes.length != 1) return false; const emote = client.bot.emojis.resolve(emotes[0].reactionId); if (!emote) { console.log(`WARNING: Emote ${emotes[0]} no longer is valid. Deleting invalid emojis from the list...`); const emotesRepo = getRepository(ReactionEmote); await emotesRepo.delete({ reactionId: emotes[0].reactionId }); return false; } msg.channel.send(emote.toString()); return true; } }