UNPKG

hubot-randomquote

Version:
271 lines (227 loc) 10.7 kB
// Description: // Leave a quote, take a quote. // // Adds quotes to hubot that can be retrieved later. Store inspirational // quotes, out of context quotes, funny quotes, thought-provoking quotes, // you decide! If you later change your mind, you can delete them, too. // // Configuration: // HUBOT_RANDOMQUOTE_LENGTH - how long the quotes can be. Default is 140. // // Commands: // hubot addquote "{quote}" [by {user}] - adds the given quote to hubot, crediting the user, or anonymously if no user is given. // !qadd "{quote}" [by {user}] - shorthand for the above // hubot removequote {number} - quotes are labeled with a number. If you later decide to remove a quote, you can do so from that number. // !qremove {number} - shorthand for the above // hubot quote {number, author, or nothing} - get a random quote! If a number was supplied, get that specific quote. If an author was supplied, get a random quote by that author. // !quote {number, author, or nothing} - shorthand for the above // hubot quotesearch {term} - searches the quotes for the specified term. // !qsearch {term} - shorthand for the above // hubot quotestats - show some nifty stats about the stored quotes! // hubot fixauthor "oldAuthor" "newAuthor" - changes all quotes submitted for oldAuthor to be credited to newAuthor instead. // hubot revertfixes - undo all edits made by "fixauthor" and return quotes to their original credits. // // Author: // Perry Goy https://github.com/perrygoy const QuotesMod = require('./quotekeeper') const QUOTE_MAXLENGTH = process.env.HUBOT_RANDOMQUOTE_LENGTH || 140; module.exports = function(robot) { const QuoteKeeper = new QuotesMod(robot); this.getUsername = response => { const user = response.message.user; if (user.profile) { return user.profile.display_name || user.name; } else { return user.name; } }; this.stripTag = name => { if (typeof name !== "string") { return name; } return (name[0] === '@' ? name.slice(1) : name); }; this.addQuote = (quote, author, submitter) => { return QuoteKeeper.addQuote(quote, author, submitter); }; this.removeQuote = index => { return QuoteKeeper.removeQuote(index); }; this.searchQuotes = searchTerm => { return QuoteKeeper.searchQuotes(searchTerm); }; this.truncateQuote = (quote, fulcrum) => { const startOfFulcrum = quote.toLowerCase().indexOf(fulcrum.toLowerCase()); const endOfFulcrum = startOfFulcrum + fulcrum.length; const padding = Math.max(25 - fulcrum.length, 0); return `${startOfFulcrum > padding ? '...' : ''}${quote.slice(Math.max(0, startOfFulcrum - padding), Math.min(endOfFulcrum + padding, quote.length))}${endOfFulcrum < quote.length - padding ? '...' : ''}`; }; this.fixAuthor = (oldAuthor, newAuthor) => { return QuoteKeeper.fixAuthor(oldAuthor, newAuthor); }; this.revertFixes = () => { return QuoteKeeper.revertFixes(); }; this.retrieveQuote = (lookup = false) => { robot.logger.info(`Retrieving a quote with lookup: ${lookup}`); if (/^\d+$/.test(lookup)) { return QuoteKeeper.getQuoteByIndex(lookup); } else if (lookup) { if (/ \d+$/.test(lookup)) { const [_, author, quotenum] = lookup.match(/^(.*?) (\d+)$/); let quote = QuoteKeeper.getQuoteByAuthor(author, quotenum - 1); if (quote) { return quote; } } return QuoteKeeper.getQuoteByAuthor(lookup); } else { return QuoteKeeper.getRandomQuote(); } }; this.retrieveQuoteStats = () => { return QuoteKeeper.getQuoteStats(); }; this.retrieveQuoteStatsForAuthor = author => { return QuoteKeeper.getQuoteStatsFor(author); } this.stringifyQuote = quote => { const date = quote.timestamp ? `, ${new Date(quote.timestamp).toDateString()}` : ''; return `*Quote #${quote.index}*:\n>"${quote.quote}"\n —${QuoteKeeper.getAuthor(quote)} (${quote.indexByAuthor} of ${quote.totalByAuthor})${date}`; }; // handlers this.handleAddQuote = (response, quote, author = "_anonymous_") => { author = this.stripTag(author); const submitter = this.getUsername(response); if (quote.length > 140) { response.send(`Sorry friend, that quote is too long at ${quote.length} characters. I can only remember ${QUOTE_MAXLENGTH} characters maximum.`); return; } const numQuotes = this.addQuote(quote, author, submitter); response.send(`OK, added! Total quotes stored: ${numQuotes}`); }; this.handleRemoveQuote = (response, index) => { if (index <= 0) { response.send("That number is too low. Nice try!"); return; } const quote = this.removeQuote(index); const numQuotes = this.getNumQuotes(); robot.messageRoom(response.message.user.id, `Quote #${index}, "${quote.quote}" by ${QuoteKeeper.getAuthor(quote)}, is gone.`); response.send(`OK, stricken! Total quotes remaining: ${numQuotes}`) }; this.handleGetQuote = (response, lookup = false) => { lookup = this.stripTag(response.match[1]); const quote = this.retrieveQuote(lookup); if (quote === null) { if (/^\d+$/.test(lookup)) { const numQuotes = this.getNumQuotes(); response.send(`Sorry, I can't map that index to a quote. I currently know ${numQuotes} quotes.`); } else if (/\d+$/.test(lookup)) { const author = lookup.match(/^(.*?) (\d+)$/)[1]; response.send(`Sorry, ${author} doesn't have that many quotes.`); } else { response.send(`Sorry, I don't know any quotes by ${lookup}.`); } } else { response.send(this.stringifyQuote(quote)); } }; this.handleQuoteSearch = (response, searchTerm) => { if (searchTerm.length < 3) { response.send(`Sorry, I can't search using a term less than 3 characters long.`); return; } const quotes = this.searchQuotes(searchTerm); if (quotes.length == 0) { response.send(`Sorry, I don't know any quotes containing "${searchTerm}".`); } else { let message = `I know ${quotes.length} quote${quotes.length != 1? 's' : ''} about "${searchTerm}":\n`; for (const quote of quotes) { message += `• *${quote.index}*: "${this.truncateQuote(quote.quote, searchTerm)}" by ${QuoteKeeper.getAuthor(quote)}\n`; } response.send(message); } }; this.handleFixAuthor = (response, oldAuthor, newAuthor) => { const numQuotes = this.fixAuthor(oldAuthor, newAuthor); if (numQuotes == 0) { response.send(`Sorry, I don't know any quotes by ${oldAuthor}.`); } else { response.send(`OK! Number of quotes updated: ${numQuotes}`); } }; this.handleRevertFixes = (response) => { this.revertFixes(); response.send(`OK! All fixed authors reverted to their originally submitted names.`); }; this.handleQuoteStats = (response) => { const stats = this.retrieveQuoteStats(); let message = '_Quote Repository Stats_:\n'; message += `>*Total Quotes*: ${stats.totalQuotes}\n`; message += `>*Authors*: \n> * ${stats.authors.join("\n> * ")}\n`; message += `> - *Most Quoted*: ${stats.mostQuotes.name}, ${stats.mostQuotes.number} quotes!\n`; message += `>*Submitters*: ${stats.submitters.join(", ")}\n`; message += `> - *Most Submitted*: ${stats.mostSubmissions.name}, ${stats.mostSubmissions.number} quotes!\n`; if (stats.mostEuphoric.name) { message += `> - *Most Euphoric*: ${stats.mostEuphoric.name} :face_with_rolling_eyes: \n`; } message += 'To retrieve stats on a particular author, use `quotestats authorname`!'; response.send(message); }; this.handleQuoteStatsForAuthor = (response, author) => { const stats = this.retrieveQuoteStatsForAuthor(author) if (!stats) { response.send(`Sorry, I don't have any quotes by ${author}!`); return; } let message = `_Quote Stats for ${author}_:\n`; message += `>*Total Quotes*: ${stats.totalQuotes}\n`; message += `>*Latest Quote*: ${stats.latest}\n`; message += `>*Fixauthor Settings*: \n> * ${stats.fixAuthors.join("\n> * ")}\n` response.send(message) } // responses robot.respond(/addquote ["“”](.+?)["“”](?: by (.+))/i, response => { this.handleAddQuote(response, response.match[1], response.match[2]); }); robot.hear(/^!(qadd|addquote) ["“”](.+?)["“”](?: by (.+))/i, response => { this.handleAddQuote(response, response.match[2], response.match[3]); }); robot.respond(/removequote (\d+)/i, response => { this.handleRemoveQuote(response, Number(response.match[1])); }); robot.hear(/^!(qremove|removequote) (\d+)/i, response => { this.handleRemoveQuote(response, Number(response.match[2])); }); robot.respond(/quote(?: ?me)?(?: (.+))?$/i, response => { this.handleGetQuote(response, response.match[1]) }); robot.hear(/^!quote(?: ?me)?(?: (.+))?$/i, response => { this.handleGetQuote(response, response.match[1]) }); robot.respond(/quotesearch\s+(.+)/i, response => { this.handleQuoteSearch(response, response.match[1]); }); robot.hear(/^!(qsearch|quotesearch|searchquotes?)\s+(.+)/i, response => { this.handleQuoteSearch(response, response.match[2]); }); robot.respond(/fixauthor ["“”]?([^"]+)["“”]?\s+["“”]?([^"]+)["“”]?$/i, response => { this.handleFixAuthor(response, response.match[1], response.match[2]); }); robot.respond(/revertfixes$/i, response => { this.handleRevertFixes(response); }); robot.respond(/quotestats$/i, response => { this.handleQuoteStats(response); }); robot.hear(/^!(qstats|quotestats)$/i, response => { this.handleQuoteStats(response); }); robot.respond(/quotestats (.+)$/i, response => { this.handleQuoteStatsForAuthor(response, response.match[1]); }); robot.hear(/^!(qstats|quotestats) (.+)$/i, response => { this.handleQuoteStatsForAuthor(response, response.match[2]); }); };