commit b08773f233f94cff86797135fd5dd1d5d9d9f766 Author: Kegan Myers Date: Fri Aug 8 20:13:24 2014 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a4a918 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +slack-command-router +==================== +This is a simple library that exposes both a way to add event handlers for slack commands, and connect middleware to +facilitate the simple addition of a slack command handler to any project. + +This project is written as a standalone library, but primarily designed for use in `slack-command-server` \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..c97ad11 --- /dev/null +++ b/index.js @@ -0,0 +1,99 @@ +var _ = require('lodash'), + Formidable = require('formidable'), + EventEmitter = require('events').EventEmitter; + +function Slacker() { +} +_.assign(Slacker.prototype, EventEmitter.prototype); + +function SlashCommand(body, res) { + //Things from the server + this.token = body.token; + this.teamId = body.team_id; + this.channelId = body.channel_id; + this.channelName = body.channel_name; + this.userId = body.user_id; + this.userName = body.user_name; + this.command = body.command; + this.text = body.text; + this.res = res; + + //State variables + this._hasReplied = false; +} +_.assign(SlashCommand.prototype, { + _generalReply: function() { + if (this.hasReplied) { + throw { + message: "Only one handler can respond to a command" + } + } + this.hasReplied = true; + }, + replyUser: function (message) { + this._generalReply(); + this.res.end(message); + }, + replyChannel: function () { + this._generalReply(); + this.res.end(); + }, + error: function (message) { + this._generalReply(); + this.res.writeHead(400); + this.res.end(message); + } +}); + +function SlackIncoming(commands) { + this.router = new Slacker(); + + if (typeof commands === "object") { + for (var handlerName in commands) { + if (commands.hasOwnProperty(handlerName)) { + this.registerHandler(commands[handlerName]); + } + } + } +} + +(function () { + var checkedFields = ["token", "team_id", "channel_id", "channel_name", "user_id", "user_name", "command", "text"]; + + function checkCommand(fields) { + return _.xor(_.keys(fields), checkedFields).length === 0; + } + + _.assign(SlackIncoming.prototype, { + registerHandler: function (handler) { + handler(this.router); + }, + getMiddleware: function () { + var self = this; + return function (req, res, next) { + var form = new Formidable.IncomingForm(); + form.encoding = 'utf-8'; + form.type = 'urlencoded'; + form.maxFieldsSize = 8192; + form.maxFields = 15; + form.parse(req, function (err, fields, files) { + if (err || !checkCommand(fields) + //Actually run the handlers + || !self.router.emit(fields.command.slice(1), new SlashCommand(fields, res))) { + + //This will only happen if there were no handlers for our event + next(); + } + }); + form.on('error', function(){ + next(); + }); + form.on('aborted', function(){ + next(); + }); + } + } + }); +})(); + +module.exports = SlackIncoming; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..2e30a8b --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "slack-command-router", + "version": "0.0.0", + "description": "A slack slash command handler routing framework", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "slack", + "slash", + "command", + "webhooks" + ], + "author": "Kegan Myers ", + "license": "BSD-2-Clause", + "dependencies": { + "formidable": "~1.0.15", + "lodash": "~2.4.1" + } +}