diff --git a/src/events.js b/src/events.js index 1611268..6f31095 100644 --- a/src/events.js +++ b/src/events.js @@ -50,6 +50,25 @@ const handlePlusMinus = async( item, operation, channel ) => { return slack.sendMessage( message, channel ); }; +/** + * Handles a = against a user, and then notifies the channel of the new score. + * + * @param {string} item The Slack user ID (if user) or name (if thing) of the item being + * operated on. + * @param {string} operation The mathematical operation performed on the item's score. + * @param {object} channel The ID of the channel (Cxxxxxxxx for public channels or Gxxxxxxxx for + * private channels - aka groups) that the message was sent from. + * @return {Promise} A Promise to send a Slack message back to the requesting channel after the + * points have been updated. + */ +const handlePlusEqual = async( item, operation, channel ) => { + const score = await points.getScore( item, operation ), + operationName = operations.getOperationName( operation ), + message = messages.getRandomMessage( operationName, item, score ); + + return slack.sendMessage( message, channel ); +}; + /** * Sends a random thank you message to the requesting channel. * @@ -94,6 +113,7 @@ const sendHelp = ( event ) => { 'Sure, here\'s what I can do:\n\n' + '• `@Someone++`: Add points to a user or a thing\n' + '• `@Someone--`: Subtract points from a user or a thing\n' + + '• `@Someone==`: Gets current points from a user or a thing\n' + '• `<@' + botUserID + '> leaderboard`: Display the leaderboard\n' + '• `<@' + botUserID + '> help`: Display this message\n\n' + 'You\'ll need to invite me to a channel before I can recognise ' + @@ -134,9 +154,12 @@ const handlers = { return false; } + if ( '=' === operation ) { + return handlePlusEqual( item, operation, event.channel ); + } + // Otherwise, let's go! return handlePlusMinus( item, operation, event.channel ); - }, // Message event. /** @@ -158,7 +181,10 @@ const handlers = { help: sendHelp, thx: sayThankyou, thanks: sayThankyou, - thankyou: sayThankyou + thankyou: sayThankyou, + '++': handlePlusMinus, + '--': handlePlusMinus, + '==': handlePlusEqual }; const validCommands = Object.keys( appCommandHandlers ), diff --git a/src/helpers.js b/src/helpers.js index b5dfeed..b638eaf 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -61,7 +61,8 @@ const extractCommand = ( message, commands ) => { * (i.e. + or -). */ const extractPlusMinusEventData = ( text ) => { - const data = text.match( /@([A-Za-z0-9]+?)>?\s*(\+{2}|-{2}|—{1})/ ); + + const data = text.match( /@([A-Za-z0-9:-_]+?)>?\s*(\+{2}|-{2}|—{1}|={2})/ ); if ( ! data ) { return false; diff --git a/src/messages.js b/src/messages.js index c0245ff..d96f500 100644 --- a/src/messages.js +++ b/src/messages.js @@ -62,6 +62,20 @@ messages[ operations.MINUS ] = [ } ]; +messages[ operations.EQUAL ] = [ + { + probability: 100, + set: [ + 'How is', + 'Why is' + ] + }, + { + probability: 1, + set: [ ':shifty:' ] + } +]; + messages[ operations.SELF ] = [ { probability: 100, @@ -96,13 +110,17 @@ const getRandomMessage = ( operation, item, score = 0 ) => { switch ( operation ) { case operations.MINUS: case operations.PLUS: - format = ' ** is now on point.'; + format = ' ** has point.'; break; case operations.SELF: format = ' '; break; + case operations.EQUAL: + format = ' ** currently at point.'; + break; + default: throw Error ( 'Invalid operation: ' + operation ); } diff --git a/src/operations.js b/src/operations.js index 6805aa1..3abcf2d 100644 --- a/src/operations.js +++ b/src/operations.js @@ -7,7 +7,8 @@ const operations = { PLUS: 'plus', MINUS: 'minus', - SELF: 'selfPlus' + SELF: 'selfPlus', + EQUAL: 'equal' }; /** @@ -23,6 +24,7 @@ const getOperationName = ( operation ) => { switch ( operation ) { case '+': operationName = operations.PLUS; break; case '-': operationName = operations.MINUS; break; + case '=': operationName = operations.EQUAL; break; } /* eslint-enable max-statements-per-line */ diff --git a/src/points.js b/src/points.js index abc201b..a76f820 100644 --- a/src/points.js +++ b/src/points.js @@ -93,7 +93,44 @@ const updateScore = async( item, operation ) => { }; // UpdateScore. +/** + * Gets score + * into the database with an assumed initial score of 0. + * + * This function also sets up the database if it is not already ready, including creating the + * scores table and activating the Postgres case-insensitive extension. + * + * @param {string} item The Slack user ID (if user) or name (if thing) of the item being + * operated on. + * @param {string} operation The mathematical operation performed on the item's score. + * @return {int} The item's new score after the update has been applied. + */ +const getScore = async( item ) => { + + // Connect to the DB, and create a table if it's not yet there. + // We also set up the citext extension, so that we can easily be case insensitive. + const dbClient = await postgres.connect(); + await dbClient.query( '\ + CREATE EXTENSION IF NOT EXISTS citext; \ + CREATE TABLE IF NOT EXISTS ' + scoresTableName + ' (item CITEXT PRIMARY KEY, score INTEGER); \ + ' ); + + // Get the new value. + // TODO: Fix potential SQL injection issues here, even though we know the input should be safe. + const dbSelect = await dbClient.query( '\ + SELECT score FROM ' + scoresTableName + ' WHERE item = \'' + item + '\'; \ + ' ); + + await dbClient.release(); + const score = dbSelect.rows[0].score; + + console.log( item + ' now on ' + score ); + return score; + +}; // UpdateScore. + module.exports = { retrieveTopScores, - updateScore + updateScore, + getScore };