react.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import { client } from "../client";
  2. import { ICommand } from "./command";
  3. import { getRepository } from "typeorm";
  4. import { MessageReaction } from "../entity/MessageReaction";
  5. import { KnownUser } from "../entity/KnownUser";
  6. import { ReactionType, ReactionEmote } from "../entity/ReactionEmote";
  7. import { isAuthorisedAsync } from "../util";
  8. const pattern = /^react to\s+"([^"]+)"\s+with\s+\<:[^:]+:([^\>]+)\>$/i;
  9. async function getRandomEmotes(allowedTypes: ReactionType[], limit: number) {
  10. let reactionEmotesRepo = getRepository(ReactionEmote);
  11. let a = await reactionEmotesRepo.query(`
  12. select reactionId
  13. from ( select type, reactionId
  14. from reaction_emote
  15. where type in (${allowedTypes.map(s => "?").join(",")})
  16. order by type, random() )
  17. group by type
  18. limit ${limit}`, allowedTypes) as ReactionEmote[];
  19. return a;
  20. }
  21. export default {
  22. commands: [
  23. {
  24. pattern: "react to",
  25. action: async (msg, s) => {
  26. if (!await isAuthorisedAsync(msg.member))
  27. return;
  28. let contents = pattern.exec(s);
  29. if (contents != null) {
  30. let reactable = contents[1].trim().toLowerCase();
  31. let reactionEmoji = contents[2];
  32. if (!client.emojis.has(reactionEmoji)) {
  33. msg.channel.send(`${msg.author.toString()} I cannot react with this emoji :(`);
  34. return;
  35. }
  36. let repo = getRepository(MessageReaction);
  37. let message = repo.create({
  38. message: reactable,
  39. reactionEmoteId: reactionEmoji
  40. });
  41. await repo.save(message);
  42. msg.channel.send(`${msg.author.toString()} Added reaction!`);
  43. }
  44. }
  45. },
  46. {
  47. pattern: "remove reaction to",
  48. action: async (msg, s) => {
  49. if (!await isAuthorisedAsync(msg.member))
  50. return;
  51. let content = s.substring("remove reaction to ".length).trim().toLowerCase();
  52. let repo = getRepository(MessageReaction);
  53. let result = await repo.delete({ message: content });
  54. if (result.affected == 0) {
  55. msg.channel.send(`${msg.author.toString()} No such reaction available!`);
  56. return;
  57. }
  58. msg.channel.send(`${msg.author.toString()} Removed reaction!`);
  59. }
  60. },
  61. {
  62. pattern: "reactions",
  63. action: async msg => {
  64. let reactionsRepo = getRepository(MessageReaction);
  65. let messages = await reactionsRepo.find({
  66. select: [ "message" ]
  67. });
  68. let reactions = messages.reduce((p, c) => `${p}\n${c.message}`, "");
  69. msg.channel.send(`I'll react to the following messages:\n\`\`\`${reactions}\n\`\`\``);
  70. }
  71. }
  72. ],
  73. documentation: {
  74. "react to \"<message>\" with <emote>": {
  75. auth: true,
  76. description: "React to <message> with <emote>."
  77. },
  78. "remove reaction to <message>": {
  79. auth: true,
  80. description: "Stops reacting to <message>."
  81. },
  82. "reactions": {
  83. auth: false,
  84. description: "Lists all known messages this bot can react to."
  85. }
  86. },
  87. onMessage: async (actionsDone, msg, content) => {
  88. if (actionsDone)
  89. return false;
  90. let lowerContent = content.toLowerCase();
  91. let reactionRepo = getRepository(MessageReaction);
  92. let usersRepo = getRepository(KnownUser);
  93. let message = await reactionRepo.findOne({ message: lowerContent });
  94. if(message) {
  95. msg.react(client.emojis.get(message.reactionEmoteId));
  96. return true;
  97. }
  98. if (msg.mentions.users.size == 0)
  99. return false;
  100. let knownUsers = await usersRepo.find({
  101. select: [ "mentionReactionType" ],
  102. where: [...msg.mentions.users.map(u => ({ userID: u.id }))]
  103. });
  104. if(knownUsers.length == 0)
  105. return false;
  106. let reactionEmoteTypes = new Set<ReactionType>();
  107. for(let user of knownUsers) {
  108. if(user.mentionReactionType == ReactionType.NONE)
  109. continue;
  110. reactionEmoteTypes.add(user.mentionReactionType);
  111. }
  112. let randomEmotes = await getRandomEmotes([...reactionEmoteTypes], 5);
  113. if(randomEmotes.length == 0)
  114. return false;
  115. for(let emote of randomEmotes)
  116. await msg.react(client.emojis.find(e => e.id == emote.reactionId));
  117. return true;
  118. },
  119. onIndirectMention: async (actionsDone, msg) => {
  120. if (actionsDone)
  121. return false;
  122. let emoteType = ReactionType.ANGERY;
  123. let repo = getRepository(KnownUser);
  124. let knownUser = await repo.findOne({
  125. select: [ "mentionReactionType" ],
  126. where: [{userID: msg.id}]
  127. });
  128. if(knownUser){
  129. if(knownUser.mentionReactionType == ReactionType.NONE)
  130. return false;
  131. emoteType = knownUser.mentionReactionType;
  132. }
  133. let emotes = await getRandomEmotes([ emoteType ], 1);
  134. if(emotes.length != 1)
  135. return false;
  136. let emote = client.emojis.find(e => e.id == emotes[0].reactionId);
  137. if (!emote) {
  138. console.log(`WARNING: Emote ${emotes[0]} no longer is valid. Deleting invalid emojis from the list...`);
  139. let emotesRepo = getRepository(ReactionEmote);
  140. await emotesRepo.delete({ reactionId: emotes[0].reactionId });
  141. return false;
  142. }
  143. msg.channel.send(emote.toString());
  144. return true;
  145. }
  146. } as ICommand;