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) { let reactionEmotesRepo = getRepository(ReactionEmote); let 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) { if (!await isAuthorisedAsync(msg.member)) return; let contents = pattern.exec(s); if (contents != null) { let reactable = contents[1].trim().toLowerCase(); let reactionEmoji = contents[2]; if (!client.emojis.cache.has(reactionEmoji)) { msg.channel.send(`${msg.author.toString()} I cannot react with this emoji :(`); return; } let repo = getRepository(MessageReaction); let 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) { if (!await isAuthorisedAsync(msg.member)) return; let content = s.substring("remove reaction to ".length).trim().toLowerCase(); let repo = getRepository(MessageReaction); let 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) { let reactionsRepo = getRepository(MessageReaction); let messages = await reactionsRepo.find({ select: ["message"] }); let 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) { if (actionsDone) return false; let lowerContent = content.toLowerCase(); let reactionRepo = getRepository(MessageReaction); let usersRepo = getRepository(KnownUser); let message = await reactionRepo.findOne({ message: lowerContent }); if (message) { msg.react(client.emojis.resolve(message.reactionEmoteId)); return true; } if (msg.mentions.users.size == 0) return false; let knownUsers = await usersRepo.find({ select: ["mentionReactionType"], where: [...msg.mentions.users.map(u => ({ userID: u.id }))] }); if (knownUsers.length == 0) return false; let reactionEmoteTypes = new Set(); for (let user of knownUsers) { if (user.mentionReactionType == ReactionType.NONE) continue; reactionEmoteTypes.add(user.mentionReactionType); } if(reactionEmoteTypes.size == 0) return false; let randomEmotes = await getRandomEmotes([...reactionEmoteTypes], 5); if (randomEmotes.length == 0) return false; for (let emote of randomEmotes) await msg.react(client.emojis.cache.find(e => e.id == emote.reactionId)); return true; } @Action(ActionType.INDIRECT_MENTION) async reactToPing(actionsDone: boolean, msg: Message) { if (actionsDone) return false; let emoteType = ReactionType.ANGERY; let repo = getRepository(KnownUser); let knownUser = await repo.findOne({ select: ["replyReactionType"], where: [{ userID: msg.author.id }] }); if (knownUser) { if (knownUser.replyReactionType == ReactionType.NONE) return false; emoteType = knownUser.replyReactionType; } let emotes = await getRandomEmotes([emoteType], 1); if (emotes.length != 1) return false; let emote = client.emojis.cache.find(e => e.id == emotes[0].reactionId); if (!emote) { console.log(`WARNING: Emote ${emotes[0]} no longer is valid. Deleting invalid emojis from the list...`); let emotesRepo = getRepository(ReactionEmote); await emotesRepo.delete({ reactionId: emotes[0].reactionId }); return false; } msg.channel.send(emote.toString()); return true; } };