UNPKG

psyduck-plugin-quotes

Version:
205 lines (195 loc) 9.36 kB
import 'reflect-metadata'; import commandLineArgs, { CommandLineOptions } from 'command-line-args'; import * as Discord from 'discord.js'; import _ from 'lodash'; import moment from 'moment'; import { BotPlugin } from 'psyduck-contracts'; import { PluginQuoteUser, UserQuote, GuildUser, Guild } from 'psyduck-models'; import { ConnectionOptions, createConnection, Repository } from 'typeorm'; export const commandOptions = [ { name: 'pluck', alias: 'p', type: Number }, { name: 'help', alias: 'h', type: Boolean }, { name: 'user', alias: 'u', type: String, defaultOption: true } ]; export const userFormatRegex = new RegExp(/^(<@.+>)|(<!.+>)$/); export enum CommandType { Quote, Random } export default class PsyduckQuotes implements BotPlugin { public users!: Repository<PluginQuoteUser>; public quotes!: Repository<UserQuote>; public connectionOptions: ConnectionOptions; constructor(options: any) { this.connectionOptions = options; } connect() { createConnection({ ...this.connectionOptions, synchronize: true, logging: false, entities: [ PluginQuoteUser, UserQuote ] }).then(async connection => { this.users = connection.getRepository(PluginQuoteUser); this.quotes = connection.getRepository(UserQuote); }).catch(error => console.log(error)); } onMessage(message: Discord.Message) { if (message.author.bot) { return; } if (message.content.length <= 1) { return; } const dupe = RegExp(/^(.)\1*$/gm); if (dupe.test(message.content)) { return; } if (message.content.startsWith('!')) { const commandCode = message.content.slice(1, message.content.indexOf(' ')); if (_.includes(['quote', 'q', 'grab', 'g'], commandCode)) { this.prepareHandler(message, CommandType.Quote); } else if (_.includes(['random', 'r'], commandCode)) { this.prepareHandler(message, CommandType.Random); } } } parseParameters(messageContent: string): string[] { const params = messageContent.match(/ (?=\S)[^'\s]*(?:'[^\\']*(?:\\[\s\S][^\\']*)*'[^'\s]*)*/g) || []; return params.map(p => p.trim()); } hydrateOptions(parameters: string[]): CommandLineOptions { return commandLineArgs(commandOptions, { argv: parameters, partial: true }); } extractUserId(userId: string): string | undefined { const matches = userId.match(/(?<=@|!)(.*)(?=>)/gm); if (matches && matches.length === 1) { return matches[0].replace('!', ''); } return undefined; } prepareHandler(message: Discord.Message, commandType: CommandType) { const parameters = this.parseParameters(message.content); if (parameters.length > 0) { const options = this.hydrateOptions(parameters); if (options.help === true) { this.sendHelp(message); } else { if (!options.user || !userFormatRegex.test(options.user)) { if (commandType === CommandType.Quote) { message.channel.send(`Unable to quote. User missing or wrong format.`); } else if (commandType === CommandType.Random) { message.channel.send(`Unable to recall. User missing or wrong format.`); } } else { const userId = this.extractUserId(options.user); if (!userId) { message.channel.send('Unable to parse user id from supplied parameters.'); } if (userId === message.author.id) { if (commandType === CommandType.Quote) { message.channel.send('It looks like you are trying to quote yourself! Don\'t take all the fun out of it!'); } else if (commandType === CommandType.Random) { message.channel.send('It looks like you are trying to recall yourself! Don\'t take all the fun out of it!'); } } else { if (commandType === CommandType.Quote) { this.saveQuote(message, userId!, options.pluck); } else if (commandType === CommandType.Random) { this.recallQuote(message, userId!); } } } } } } sendHelp(message: Discord.Message) { const embed = { 'title': 'Psyduck Quote Plugin Help', 'description': 'Use this plugin to quote users and recall random quotes from the past.', 'url': 'https://github.com/galactic0wl/psyduck-plugin-quotes', 'color': 3201505, 'author': { 'name': 'Marky Mark', 'url': 'https://github.com/galactic0wl/psyduck-plugin-quotes', 'icon_url': 'https://cdn.discordapp.com/avatars/341668692133806080/a_252e33ff6363f93849e75a5decf9f10a.gif' }, 'fields': [ { 'name': 'Commands', 'value': 'The following commands are available to standard users.\n\n' }, { 'name': '[q]uote & [g]rab', 'value': 'To save a quote from a user run `!q @MentionUser` to grab the last message. If you would like to target a specific message within reason you can run `!quote @MentionUser -p 3` to save the second to the last message of the user, or, 3 messages up.\n\n**Parameters** ```--pluck <count> or -p <count>```' }, { 'name': '[r]andom', 'value': 'To recall a quote from a user run `!r @MentionUser` to grab a random message from the past.' } ] }; message.channel.send({ embed }); } async getUser(userId: string) { return await this.users.findOne({ user: { id: userId } }, { relations: ['quotes'] }); } createUser(guildId: string, serverName: string, guildAvatarUrl: string, userId: string, userName: string, avatarUrl: string) { const user = new PluginQuoteUser(); const guildUser = new GuildUser(); guildUser.id = userId; guildUser.userName = userName; guildUser.avatarUrl = avatarUrl; const guild = new Guild(); guild.id = guildId; guild.serverName = serverName; guild.avatarUrl = guildAvatarUrl; guildUser.guild = guild; user.user = guildUser; user.quotes = []; return user; } async recallQuote(message: Discord.Message, userId: string) { const user = await this.getUser(userId); if (!user || user.quotes.length === 0) { message.channel.send(`Our records indicated that the user has zero quotes. While this is unfortunate, it may be resolved.`); } else { const quote = _.sample(user.quotes)!; message.channel.send(`Remember this one <@${userId}>? '${quote.content}' - Snagged by <@${quote.capturerId}> at ${quote.captureTime}`); } } buildQuote(capturerId: string, content: string): UserQuote { const quote = new UserQuote(); quote.capturerId = capturerId; quote.content = content; quote.captureTime = moment().format('ddd MMM DD YYYY h:mm A'); return quote; } async saveQuote(message: Discord.Message, userId: string, pluck = 1) { const messageMap = await message.channel.fetchMessages({ limit: 100 }); const messages = [...messageMap.values()].filter(m => m.author.id === userId); if (messages.length > 0) { if (messages.length < pluck) { message.channel.send('You attempted to pluck a message out of my range. Please try again.'); } else { let user = await this.getUser(userId); if (!user) { user = this.createUser(message.guild.id, message.guild.name, message.guild.iconURL, message.author.id, message.author.username, message.author.avatarURL); user.quotes.push(this.buildQuote(message.author.id, messages[pluck - 1].content)); } else { if (user.quotes.filter(u => u.content === messages[pluck - 1].content).length <= 0) { user.quotes.push(this.buildQuote(message.author.id, messages[pluck - 1].content)); } else { message.channel.send('It looks like I already have a record of this quote.'); return; } } await this.users.save(user); message.channel.send(`Plucked: ${messages[pluck - 1]}`); } } } }