From 5e860175a42626254432d361f2c0c44faaeebc5e Mon Sep 17 00:00:00 2001 From: Michael Stahnke Date: Fri, 14 Jun 2024 10:13:43 -0500 Subject: [PATCH] feat(hubot-wisdom): Add a wisdom hubot module Adds a new hubot modules to enable quotes. This follows the format "a quote I would like to remember" -- author When that happens, hubot will respond with a :quote: emoji and that is the indicator that the quote is now in the brain. To recall a random quote (ala fortune), you simply run `hubot wisdom` and it will provide a random one. The more quotes, the better! --- hubot-modules/hubot-wisdom/.jsbeautifyrc | 25 +++++++ hubot-modules/hubot-wisdom/.npmignore | 2 + hubot-modules/hubot-wisdom/LICENSE | 19 ++++++ hubot-modules/hubot-wisdom/README.md | 23 +++++++ hubot-modules/hubot-wisdom/index.js | 8 +++ hubot-modules/hubot-wisdom/package.json | 28 ++++++++ hubot-modules/hubot-wisdom/src/wisdom.js | 85 ++++++++++++++++++++++++ hubot-modules/hubot-wisdom/wisdom.js | 85 ++++++++++++++++++++++++ 8 files changed, 275 insertions(+) create mode 100644 hubot-modules/hubot-wisdom/.jsbeautifyrc create mode 100644 hubot-modules/hubot-wisdom/.npmignore create mode 100644 hubot-modules/hubot-wisdom/LICENSE create mode 100644 hubot-modules/hubot-wisdom/README.md create mode 100644 hubot-modules/hubot-wisdom/index.js create mode 100644 hubot-modules/hubot-wisdom/package.json create mode 100644 hubot-modules/hubot-wisdom/src/wisdom.js create mode 100644 hubot-modules/hubot-wisdom/wisdom.js diff --git a/hubot-modules/hubot-wisdom/.jsbeautifyrc b/hubot-modules/hubot-wisdom/.jsbeautifyrc new file mode 100644 index 0000000..5579b00 --- /dev/null +++ b/hubot-modules/hubot-wisdom/.jsbeautifyrc @@ -0,0 +1,25 @@ +{ + "js": { + "allowed_file_extensions": ["js", "json", "jshintrc", "jsbeautifyrc"], + "brace_style": "collapse", + "break_chained_methods": false, + "e4x": true, + "eval_code": false, + "end_with_newline": true, + "indent_char": " ", + "indent_level": 0, + "indent_size": 2, + "indent_with_tabs": false, + "jslint_happy": true, + "jslint_happy_align_switch_case": true, + "space_after_anon_function": false, + "keep_array_indentation": false, + "keep_function_indentation": false, + "max_preserve_newlines": 2, + "preserve_newlines": true, + "space_before_conditional": false, + "space_in_paren": false, + "unescape_strings": false, + "wrap_line_length": 0 + } +} diff --git a/hubot-modules/hubot-wisdom/.npmignore b/hubot-modules/hubot-wisdom/.npmignore new file mode 100644 index 0000000..fa0af3c --- /dev/null +++ b/hubot-modules/hubot-wisdom/.npmignore @@ -0,0 +1,2 @@ +.flox +node_modules diff --git a/hubot-modules/hubot-wisdom/LICENSE b/hubot-modules/hubot-wisdom/LICENSE new file mode 100644 index 0000000..046860f --- /dev/null +++ b/hubot-modules/hubot-wisdom/LICENSE @@ -0,0 +1,19 @@ +Copyright 2024 Michael Stahnke + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/hubot-modules/hubot-wisdom/README.md b/hubot-modules/hubot-wisdom/README.md new file mode 100644 index 0000000..dcaba63 --- /dev/null +++ b/hubot-modules/hubot-wisdom/README.md @@ -0,0 +1,23 @@ +# hubot-wisdom + +Store and retrieve quotes of "wisdom" from the members of your chat. + +# Installation + + npm i --save hubot-wisdom + +Edit your `external-scripts.json` file in your hubot applicaiton directory and add `hubot-wisdom` to it. + +# Usage + + > "Let It Be" -- Paul + + > hubot wisdom + "A random quote is returned" -- how fun + + +# Configuration +N/A + +# License +MIT diff --git a/hubot-modules/hubot-wisdom/index.js b/hubot-modules/hubot-wisdom/index.js new file mode 100644 index 0000000..d18cd82 --- /dev/null +++ b/hubot-modules/hubot-wisdom/index.js @@ -0,0 +1,8 @@ +'use strict' + +const path = require('path') + +module.exports = (robot) => { + const scriptsPath = path.resolve(__dirname, 'src') + robot.loadFile(scriptsPath, 'wisdom.js') +} diff --git a/hubot-modules/hubot-wisdom/package.json b/hubot-modules/hubot-wisdom/package.json new file mode 100644 index 0000000..7f86483 --- /dev/null +++ b/hubot-modules/hubot-wisdom/package.json @@ -0,0 +1,28 @@ +{ + "name": "hubot-wisdom", + "version": "0.0.1", + "description": "Store and retrieve quotes of 'wisdom' from the members of your chat.", + "main": "index.js", + "scripts": { + "test": "EXPRESS_PORT=9012 mocha --extension mjs --verbose --exit \"test/**/*.*\" --reporter spec", + "lint": "jshint src/*.js test/*.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/stahnma/mandatoryFun/hubot-modules/hubot-wisdom" + }, + "keywords": [ + "hubot", + "quotes", + "wisdom" + ], + "author": "stahnma", + "license": "MIT", + "devDependencies": { + "chai": "^5.1.0", + "hubot-mock-adapter": "^2.3.0", + "hubot-test-helper": "^1.9.0", + "mocha": "^10.4.0", + "sinon": "^17.0.1" + } +} diff --git a/hubot-modules/hubot-wisdom/src/wisdom.js b/hubot-modules/hubot-wisdom/src/wisdom.js new file mode 100644 index 0000000..897e933 --- /dev/null +++ b/hubot-modules/hubot-wisdom/src/wisdom.js @@ -0,0 +1,85 @@ +// Description: +// Store and retrieve quotes along with the author, submitter, and timestamp. +// +// Commands: +// hubot "" -- - Store a new quote along with your username and the current time. +// hubot wisdom - Responds with a random quote from the memory. + +// Author: stahnma + +// Category: social + +const { + WebClient +} = require('@slack/web-api'); + +module.exports = (robot) => { + + // Listening for quotes and storing them + robot.hear(/^\s*(\"|“)(.+?)(\"|”)\s+(--|—)\s*(.+?)$/, async (msg) => { + // Extract quote and author from the message + const quote = msg.match[2]; + const author = msg.match[5]; + const user = msg.message.user.name; // Capturing the user who added the quote + const timestamp = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, ''); // ISO format to YYYY-MM-DD HH:MM:SS + + // Initialize the quotes array in the brain if it doesn't exist + if(!robot.brain.data.quotes) { + robot.brain.data.quotes = []; + } + + // Store the new quote with user and timestamp + robot.brain.data.quotes.push({ + quote: `"${quote}"`, + author, + user, + timestamp + }); + + // Check if the bot is running in Slack + if(robot.adapterName === 'slack') { + const slackMessage = msg.message.rawMessage; + + if(slackMessage && slackMessage.ts && slackMessage.channel) { + try { + // Create a new instance of WebClient using the bot's token + const token = process.env.HUBOT_SLACK_TOKEN || process.env.SLACK_BOT_TOKEN; // Ensure the token is set in environment variables + const web = new WebClient(token); + + // Add a reaction to the message + await web.reactions.add({ + name: 'quote', + channel: slackMessage.channel, + timestamp: slackMessage.ts + }); + + robot.logger.info('Reaction added successfully'); + } catch (err) { + robot.logger.error('Failed to add reaction:', err); + } + } else { + robot.logger.error('Missing Slack message data: ts or channel'); + } + } else { + // Fallback if not running in Slack + msg.send(`Quote added.`); + } + }); + + // Responding with a random quote + robot.respond(/wisdom$/i, (msg) => { + const quotes = robot.brain.data.quotes; + + // Check if there are any quotes stored + if(quotes && quotes.length > 0) { + const randomIndex = Math.floor(Math.random() * quotes.length); + const { + quote, + author + } = quotes[randomIndex]; + msg.send(`${quote} -- ${author}`); + } else { + msg.send("I have no wisdom to share yet. Please teach me."); + } + }); +}; diff --git a/hubot-modules/hubot-wisdom/wisdom.js b/hubot-modules/hubot-wisdom/wisdom.js new file mode 100644 index 0000000..cca4d9d --- /dev/null +++ b/hubot-modules/hubot-wisdom/wisdom.js @@ -0,0 +1,85 @@ +// Description: +// Store and retrieve quotes along with the author, submitter, and timestamp. +// +// Commands: +// hubot "" -- - Store a new quote along with your username. +// hubot wisdom - Responds with a random quote from the wisdom bank.. +// +// Author: stahnma +// +// Category: social + +const { + WebClient +} = require('@slack/web-api'); + +module.exports = (robot) => { + + // Listening for quotes and storing them + robot.hear(/^\s*(\"|“)(.+?)(\"|”)\s+(--|—)\s*(.+?)$/, async (msg) => { + // Extract quote and author from the message + const quote = msg.match[2]; + const author = msg.match[5]; + const user = msg.message.user.name; // Capturing the user who added the quote + const timestamp = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, ''); // ISO format to YYYY-MM-DD HH:MM:SS + + // Initialize the quotes array in the brain if it doesn't exist + if(!robot.brain.data.quotes) { + robot.brain.data.quotes = []; + } + + // Store the new quote with user and timestamp + robot.brain.data.quotes.push({ + quote: `"${quote}"`, + author, + user, + timestamp + }); + + // Check if the bot is running in Slack + if(robot.adapterName === 'slack') { + const slackMessage = msg.message.rawMessage; + + if(slackMessage && slackMessage.ts && slackMessage.channel) { + try { + // Create a new instance of WebClient using the bot's token + const token = process.env.HUBOT_SLACK_TOKEN || process.env.SLACK_BOT_TOKEN; // Ensure the token is set in environment variables + const web = new WebClient(token); + + // Add a reaction to the message + await web.reactions.add({ + name: 'quote', + channel: slackMessage.channel, + timestamp: slackMessage.ts + }); + + robot.logger.info('Reaction added successfully'); + } catch (err) { + robot.logger.error('Failed to add reaction:', err); + } + } else { + robot.logger.error('Missing Slack message data: ts or channel'); + } + } else { + // Fallback if not running in Slack + msg.send(`Quote added.`); + } + }); + + // Responding with a random quote + robot.respond(/wisdom$/i, (msg) => { + const quotes = robot.brain.data.quotes; + + // Check if there are any quotes stored + if(quotes && quotes.length > 0) { + const randomIndex = Math.floor(Math.random() * quotes.length); + const { + quote, + author + } = quotes[randomIndex]; + msg.send(`${quote} -- ${author}`); + } else { + msg.send("I have no wisdom to share yet. Please teach me."); + } + }); +};