diff --git a/bin/pairingBot.js b/bin/pairingBot.js new file mode 100755 index 0000000..dcd1dd1 --- /dev/null +++ b/bin/pairingBot.js @@ -0,0 +1,4 @@ +#!/usr/bin/env node +const PairingBot = require('../src/pairingBot'); +const pairingBot = new PairingBot(); +pairingBot.start(); \ No newline at end of file diff --git a/package.json b/package.json index 787b9e6..e280231 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,13 @@ "name": "pairing-bot", "version": "1.0.1", "description": "A bot to track pairing from git commit, post stats and do suggestions.", - "main": "index.js", + "main": "pairingBot.js", + "bin": { + "pairing-bot": "bin/pairingBot.js" + }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "node src/index.js" + "start": "node bin/pairingBot.js" }, "repository": { "type": "git", @@ -22,7 +25,7 @@ "programming", "slack" ], - "author": "Shaffi", + "author": "Mohammed Shaffi", "license": "MIT", "dependencies": { "botkit": "^0.4.9", diff --git a/src/index.js b/src/index.js deleted file mode 100644 index c31d271..0000000 --- a/src/index.js +++ /dev/null @@ -1,262 +0,0 @@ -if (!process.env.token) { - console.log('Error: Specify token in environment'); - process.exit(1); -} - -const Botkit = require('Botkit'); -const os = require('os'); -const PairingService = require('./service/pairingService'); -const NotificationService = require('./service/notificationService'); -const CommonUtils = require('./utils/commonUtils'); -const PairingStore = require('./store/pairingStore'); -const PeopleStore = require('./store/peopleStore') -const NotificationStore = require('./store/notificationStore') -const Time = require('time-js'); - -const controller = Botkit.slackbot({ - debug: false -}); - -const bot = controller.spawn({ - token: process.env.token, - retry: 5 -}).startRTM(); - -const sendMessage = (message) => { - bot.say(message); -} - -const peopleStore = new PeopleStore(); -const pairingStore = new PairingStore(); -const notificationStore = new NotificationStore(); -const pairingService = new PairingService(peopleStore, pairingStore); -const notificationService = new NotificationService(notificationStore, pairingService, sendMessage); - -controller.on('rtm_open',function(bot) { - console.log('** The RTM api just connected! **'); -}); - -controller.on('rtm_close',function(bot) { - console.log('** The RTM api just closed **'); -}); - -controller.hears([/\bhello\b/i, /\bhi\b/i], 'direct_message,direct_mention', function (bot, message) { - bot.reply(message, 'hello'); -}); - -controller.on('bot_channel_join', function(bot, message) { - bot.reply(message, 'Hurray! Here I am! :robot_face:'); - isTeamConfigured(bot, message); -}); - -controller.hears([/list members/i], 'direct_message,direct_mention', function (bot, message) { - if(peopleStore.getMemberList().length === 0) { - bot.reply(message, 'No members added yet! :neutral_face:'); - return; - } - - let members = peopleStore.getMemberList().map((member) => `:small_red_triangle: ${member}`).join('\n'); - let memberCountStatus = `Members in team: (*${peopleStore.getMemberList().length}/${peopleStore.getExpectedMemberCount()}*)\n` - bot.reply(message, memberCountStatus + members); -}); - -controller.hears([/set member count ([0-9]*)/i], 'direct_message,direct_mention', function (bot, message) { - let count = message.match[1]; - let response = peopleStore.setExpectedMemberCount(count) ? - `Cool! I have set the member count to ${count} :thumbsup:` : 'You are not allowed to set invalid count.' - bot.reply(message, response); -}); - -controller.hears([/add member ([a-zA-Z]*)/i], 'direct_message,direct_mention', function (bot, message) { - let personName = message.match[1]; - if(peopleStore.addMember(personName)) { - bot.reply(message, `Added ${personName.toLowerCase().trim()} to list! :thumbsup:`); - return; - } - bot.reply(message, 'Member already exist! :confused:'); -}); - -controller.hears([/remove member ([a-zA-Z]*)/i], 'direct_message,direct_mention', function (bot, message) { - let personName = message.match[1]; - if (!peopleStore.removeMember(personName)) { - bot.reply(message, 'Member doesn\'t exist! :confused:'); - return; - } - - bot.startConversation(message, function(err, convo) { - convo.ask(`Removed ${personName.toLowerCase().trim()} from list! :thumbsup:\nYour team had ${peopleStore.getExpectedMemberCount()} members before. Would you like to reduce it by 1?`, - [{ - pattern: bot.utterances.yes, - callback: function(response, convo) { - peopleStore.setExpectedMemberCount(peopleStore.getExpectedMemberCount() - 1); - convo.next(); - } - }, { - pattern: bot.utterances.no, - callback: function(response, convo) { - convo.stop(); - } - }, { - default: true, - callback: function(response, convo) { - convo.repeat(); - convo.next(); - } - } - ]); - - convo.on('end', function(convo) { - if (convo.status == 'completed') { - bot.reply(message, 'OK! I will update my dossier! :thumbsup:'); - } else { - bot.reply(message, 'I cannot track pairing untill the team list is complete!' - + ' You can `add member` or `set team count` to resume tracking anytime.'); - } - }); - }); -}); - -controller.hears([/add solo ([a-zA-Z]*)/i], 'direct_message,direct_mention', function (bot, message) { - if(isTeamConfigured(bot, message)) { - let pairName = message.match[1]; - if(pairingService.addPair([pairName])) { - bot.reply(message, `Oh! we have a lone wolf today!\nHave updated ${pairName} to the stats :thumbsup:`); - return; - } - bot.reply(message, `Unable to identify \`${pairName}\` in the team :white_frowning_face:`); - } -}); - -controller.hears([/add pair ([a-zA-Z]*)(?:,\s?)([a-zA-Z]*)/i], 'direct_message,direct_mention', function (bot, message) { - if(isTeamConfigured(bot, message)){ - let pair = [message.match[1], message.match[2]]; - if(pairingService.addPair(pair)) { - bot.reply(message, `Added ${pair[0]} and ${pair[1]} to today's stats :thumbsup:`); - return; - } - bot.reply(message, `Unable to identify \`${pair.join(' / ')}\` in the team :white_frowning_face:`); - } -}); - -controller.hears(['uptime', 'identify yourself', 'who are you', 'what is your name'], - 'direct_message,direct_mention', function (bot, message) { - - const hostname = os.hostname(); - const uptime = CommonUtils.formatTime(process.uptime()); - - bot.reply(message, - ':robot_face: I am a bot named <@' + bot.identity.name + - '>. I have been running for ' + uptime + ' on ' + hostname + '.'); - - }); - -controller.hears([/^notify ([a-zA-Z\s]*) at (.*)/i], 'direct_message,direct_mention', function (bot, message) { - const notificationName = message.match[1].trim().toLowerCase(); - if(!notificationService.isValidNotification(notificationName)){ - bot.reply(message, 'Sorry, the notification type specified is invalid.\nReply with \`help\` to see list of supported messages.'); - return; - } - - const time = Time(message.match[2].trim()); - if(!time.isValid()){ - bot.reply(message, 'Sorry, the time specified is invalid.\nReply with \`help\` to see list of supported messages.'); - return; - } - if(!notificationService.subscribe(notificationName, time, message.channel)){ - bot.reply(message, 'You have already subscribed for the notification.\nIf you intend to update, deactivate existing notification and try again.'); - return; - } - - bot.reply(message, `Cool! You will be notified with \`${notificationName}\` at ${time.toString()} everyday.\ - \nYou can deactivate it anytime with the message \`deactivate ${notificationName} notification\`.`); -}); - -controller.hears([/^deactivate ([a-zA-Z\s]*) notification/i], 'direct_message,direct_mention', function (bot, message) { - const notificationName = message.match[1].trim().toLowerCase(); - if(!notificationService.isValidNotification(notificationName)){ - bot.reply(message, 'Sorry, the notification type specified is invalid.\nReply with \`help\` to see list of supported messages.'); - return; - } - - if(!notificationService.unSubscribe(notificationName)){ - bot.reply(message, `You do not have \`${notificationName}\` in your existing subscription.`); - return; - } - - bot.reply(message, `You have been unsubscribed from \`${notificationName}\` notification.`); -}); - -controller.hears([/^pairing stats/i], 'direct_message,direct_mention', function (bot, message) { - bot.reply(message, pairingService.getPairingStatsMessage()); -}); - -controller.hears([/^missing stats/i], 'direct_message,direct_mention', function (bot, message) { - if (isTeamConfigured(bot, message)) { - bot.reply(message, pairingService.getMissingStatsMessage()); - } -}); - -controller.hears([/^(bye|see you later|tata|ciao|adieu)/i], ['direct_message,direct_mention'], function (bot, message) { - bot.reply(message, 'Thanks. Have a good time! :wave:'); -}); - -controller.hears([/^help/i], ['direct_message,direct_mention'], function (bot, message) { - response = "Once you invite me to the commit channel, I start listening to git webhook.\n \ - Acceptable commit message samples\n\ - • `[StoryCardNumber] [Person1/Person2] commit message description`\n\ - • `[StoryCardNumber] [Person1|Person2] commit message description`\n\ - • `[StoryCardNumber] [Person1] commit message description`\n\ - • `[Person1/Person2] commit message description`\n\ - • `Person1/Person2: commit message description`\n\ - • `Person1/Person2 - commit message description`\n\ - Below are the few messages to which I can respond: \n\ - • `hello, hi` \n\ - • `list members` \n\ - • `set member count ` \n\ - • `add member ` \n\ - • `remove member ` \n\ - • `add solo ` \n\ - • `add pair ` \n\ - • `pairing stats` \n\ - • `missing stats` \n\ - • `notify pairing stats at