Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b405000
Removes config.json from repo
Ustice Dec 17, 2014
50a8e9c
Fixes setup functions not running.
Ustice Dec 18, 2014
ac483fa
Minor style changes
Ustice Dec 18, 2014
f01d931
Pass arguments on to node
Ustice Dec 18, 2014
5014162
Updates help action
Ustice Dec 18, 2014
f9918ee
Trims unnecessary code.
Ustice Dec 18, 2014
fd5faf7
Improves format of multi-line help.
Ustice Dec 18, 2014
086da19
Removes unnecessary code and adds helpText.
Ustice Dec 18, 2014
0c41c84
Improves help formatting.
Ustice Dec 18, 2014
843ffcd
Adds help text for gif action.
Ustice Dec 18, 2014
a28db5f
Tweaks output format.
Ustice Dec 18, 2014
87aedbd
Title for help text is now included in the action.
Ustice Dec 18, 2014
f18386d
Add support for Heroku
Ustice Dec 18, 2014
45c1f58
Remove dead code.
Ustice Dec 18, 2014
6503c56
Rename config.token elements to be more clear.
Ustice Dec 18, 2014
ead1c9a
Removes the need for keys, adds sample config
Ustice Dec 18, 2014
1599fd4
Updates documentation.
Ustice Dec 18, 2014
ada7685
Updates documentation with user not bot
Ustice Dec 18, 2014
40a0bd7
Allows users to end commands with >
Ustice Dec 18, 2014
f560db5
Fixes youtube
Ustice Dec 18, 2014
d738d6d
Remove console log
Ustice Dec 18, 2014
539e84e
Adds npm start script
Ustice Dec 19, 2014
3f9ab58
Adds default confirmation response.
Ustice Dec 19, 2014
1a4fe03
Sets node to start directly for Heroku
Ustice Dec 19, 2014
6a49f60
Adds Heroku Procfile
Ustice Dec 19, 2014
c6ba803
Update Procfile
Ustice Dec 19, 2014
2896fd3
Adds install script
Ustice Dec 19, 2014
7f35e02
Oops, that was a bad idea...
Ustice Dec 19, 2014
5a7f1b5
Adds Heroku-compatible configuration
Ustice Dec 19, 2014
4b87113
Logs errors to the console for better debugging
Ustice Dec 20, 2014
16a7357
No double stringifying
Ustice Dec 20, 2014
71e0bd2
BTC action was failing. fixed.
Ustice Dec 20, 2014
e8e3cd3
Log redirects.
Ustice Dec 20, 2014
db5bd61
Debugging
Ustice Dec 20, 2014
b23d356
Debugging
Ustice Dec 20, 2014
7c67cdb
Debugging
Ustice Dec 20, 2014
962e8f5
Debugging
Ustice Dec 20, 2014
92d2fff
Debugging
Ustice Dec 20, 2014
06ae65b
Debugging
Ustice Dec 20, 2014
06a5b8a
Debugging
Ustice Dec 20, 2014
4d81e64
Config was missing user token for Heroku.
Ustice Dec 20, 2014
6620857
Adds github contacts to contributors.
Ustice Dec 22, 2014
6bd9aa4
Ignore OS X .DS_Store files
Ustice Dec 22, 2014
1a30491
Fix: Slacker not parsing `-` correctly.
Ustice Dec 22, 2014
95cf8b0
new action commitmsg
Jan 12, 2015
15fa43e
Remove trigger, add helptext
Jan 12, 2015
25117e8
Merge pull request #1 from firoze/master
Ustice Jan 12, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ logs/
config.json
node_modules/
config.json
.DS_Store
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: node master.js
141 changes: 110 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
.d8888b. 888 888
d88P Y88b 888 888
Y88b. 888 888
"Y888b. 888 d888b. .d8888b 888 .888 .d88b. 888d88b
"Y888b. 888 d888b. .d8888b 888 .888 .d88b. 888d88b
"Y88b. 888 "88b d88P" 888 .88P d8P Y8b 888P"
"888 888 .d888888 888 888888K 88888888 888
"888 888 .d888888 888 888888K 88888888 888
Y88b d88P 888 888 888 Y88b. 888 "88b Y8b. 888
"Y8888P" 888 "Y888888 "Y8888P 888 .888 "Y888P 888
````

### Slacker is a bot for [Slack](https://slack.com) built on the Node.js platform.

Slacker processes Slack WebHook requests and executes pre-defined actions before responding to Slack. It deals with the networking aspects of your bot so you can focus on functionality.
Slacker processes Slack Slash Command requests and executes pre-defined actions before responding to Slack. It deals with the networking aspects of your bot so you can focus on functionality.

## Setup

Expand All @@ -25,25 +25,92 @@

3. Set Slack Integrations.

* Create a Outgoing WebHook in Slack and point it to your instance of Slacker.
* Create a Slash Command integration in Slack and point it to your instance of Slacker.

* Slacker expects to receive requests directly to the server's root URL.

* Be sure to include a valid `key` URL parameter on your outgoing-webhook URL when you set it in Slack.
* Be sure to note the token for this Slash Command, as you will need it for the configuration file.

* Create an Incoming WebHook in Slack.
* Get your admin user token. The easiest way is to use the (API explorer)[https://api.slack.com/methods/emoji.list/test], and grab it off the url.

* Be sure to update `hostname` and `path` in `config.json` in match your incoming-webhook.
4. Create a `config.json` file. Note that a `sample-config.json` is included in this package. You can simply copy this, and replace the two token values with the tokens that you noted above.

4. Start Slacker.
````json
{
"port": 80,
"logs": "logs",
"token": {
"slashCommand": "[Enter your Slash Command token here.]",
"user": "[Enter your User token here.]"
},
"timeout": 8000
}
````

5. Start Slacker.

````
➜ ~ sh Slacker
````
## Using Slacker

Slacker uses a command-line-like syntax. To interact with Slacker, use the Slash Command that you previously set up. For demonstration purposes, we'll assume that you named it `/slacker`.

One of the most basic uses of Slacker is to get a list of commands. To do this, on an empty input line in Slack, type

````
➜ /slacker list
````

Assuming that everything is set up correctly, you should now see a list of commands. Note that these are returned to you through Slackbot, which only you can see.

Another useful action is __help__. If you wanted to learn how to use the `gif` action, for instance, you could use the following command.

````
➜ /slacker help gif
````

This time, we sent 'gif' as an argument for __help__. Beware that different actions may use arguments differently, so pay attention to their help. If you want to send multiple words as single argument, simply wrap them in quotes like so.

````
~ sh Slacker
/slacker gif "Homer Simpson"
````

Alternately, you can escape a space like so.

````
➜ /slacker gif Peter/ Griffin
````

If you want to pass in quotes as part of an argument, you can escape them as well.

````
➜ /slacker echo "The worm looked up at me and said, \"I'd like to poison your mind.\""
````

You can also redirect where the output goes through the use of the `>` character, which is often used to redirect output on a terminal to a file. Valid targets include rooms,

````
➜ /slacker gif daily kitten > #general
````

and users.

````
➜ /slacker btc > @stewie_griffin
````

One of the more powerful features of Slacker is the user of pipes (`|`), where you can pipe the output of one action into the input of the next.

````
➜ /slacker btc | echo
````

(Yes, I know that example is lame, but our actions catalogue is a bit light at the moment.)

## Actions

Actions are script files located in the `actions/` directory. When Slacker receives a request from Slack it will check for and execute the appropriate action. Actions receive a `data` object with relevant information about the request from Slack, process the data and then return a response string. Slacker facilitates the response process.
Actions are script files located in the `actions/` directory. When Slacker receives a request from Slack it will check for and execute the appropriate action. Actions receive a `data` object with relevant information about the request from Slack and the command that triggered it, process the data and then return a response string. Slacker facilitates the response process.

### Creating an Action

Expand All @@ -57,36 +124,38 @@

### A Sample Action

````
var bot = require(__dirname + '/../bot.js')
````javascript
// Loads all of the bot functionality.
var bot = require(__dirname + '/../bot.js');

var action = {
// This is the string that will
name: 'echo',

trigger: /^echo \".*\"$/,

// Used for the `list` action.
description: 'Echo a string to Slack.',

// Used for the `help` action.
helpText: 'Echo a string to Slack.',

setup: function() {
// This method will be run at server start up.
},

execute: function(data, callback) {
callback(data.text.split('\"')[1])
// If piped data is provided, send that, otherwise send any text passed in.
callback( data.pipedResponse || data.command.arguments.join(' ') );
}
}
};

bot.addAction(action)
// Adds this action to the action list.
bot.addAction(action);
````

#### Name

The `name` attribute defines your action. It is used by the __help__ and __list__ actions to inform users about your action. `name` attributes must be unique; Slacker will ignore actions if their `name` has already been defined by another action. This attribute is required on all actions.

#### Trigger

Your action's `trigger` attribute is a regular expression which defines when it will be exectued. If a Slack user activates your bot and his message text matches your action's `trigger` then Slacker will perform your action. `trigger` attributes should be unique; Slacker will ignore actions if their `trigger` attributes have already been defined by another action. This attribute is required on all actions.

#### Description

The `description` attribute is a string used to describe your action when a user triggers the __list__ action. This attribute is required on all actions.
Expand All @@ -101,16 +170,26 @@

##### The `data` Object

````
var data = {
team_id: 'T028JNZFM',
team_domain: 'mobdev',
channel_id: 'C02DCNQRN',
channel_name: 'slacker-testing',
timestamp: '1405215092.000210',
user_id: 'U02A1R3PM',
user_name: 'chris_young',
text: 'echo foo'
````javascript
data === {
"channel_id": "D02DVPT67",
"channel_name": "directmessage",
"team_domain": "ustice",
"team_id": "T02DVPT63",
"text": "echo \"This is a test of the Emergency Broadcast System.\"",
"user_id": "U02DVPT65",
"user_name": "ustice",
"command": {
"name": "echo",
"id": "A230317A-82C7-4FA5-91A8-92DFEFB49C06",
"arguments": [
"This is a test of the Emergency Broadcast System."
],
"switches": [],
"pipe": false,
"redirectTo": []
},
"pipedResponse": null
}
````

Expand Down
2 changes: 1 addition & 1 deletion Slacker
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ rm -rf logs/*.log

clear

node master.js
node master.js $1 $2 $3 $4 $5 $6 $7 $8 $9
4 changes: 1 addition & 3 deletions action_data/help.md
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
*Help*

Try `list` to see available actions, or try `help action` for help with a specific action.
Try `list` to see available actions, or try `help <action>` for help with a specific action.
6 changes: 4 additions & 2 deletions actions/btc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,18 @@ var action = {
});
response.on('end', function() {
try {
callback(JSON.parse(responseText).ask + ' USD');
callback('1 BTC = ' + JSON.parse(responseText).ask + ' USD');
} catch (exception) {
throw exception;
}
});
}).end();
});

request.on('error', function(error) {
throw error;
});

request.end();
}
};

Expand Down
25 changes: 25 additions & 0 deletions actions/commitmsg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
var bot = require(__dirname + '/../bot.js');
var $ = require('jquerygo');

var action = {
name: "commitmsg",

description: "Display a message from http://whatthecommit.com/",

helpText: "Display a random message from http://whatthecommit.com/",

execute: function(data, callback) {
$.visit("http://whatthecommit.com/", function() {
$("#content p:first-child").text(function(text) {
if (text) {
callback(text);
} else {
callback("Sorry. Something went wrong :disappointed:");
}
$.close();
});
});
}
};

bot.addAction(action);
12 changes: 9 additions & 3 deletions actions/echo.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
// Loads all of the bot functionality.
var bot = require(__dirname + '/../bot.js');

var action = {
// This is the string that will
name: 'echo',

trigger: /^echo \".*\"$/,

// Used for the `list` action.
description: 'Echo a string to Slack.',

// Used for the `help` action.
helpText: 'Echo a string to Slack.',

setup: function() {
// This method will be run at server start up.
},

execute: function(data, callback) {
callback( data.pipedResponse || data.command.arguments.join(' ') );
// If piped data is provided, send that, otherwise send any text passed in.
callback( data.pipedResponse || data.command.arguments.join(' ') );
}
};

// Adds this action to the action list.
bot.addAction(action);
10 changes: 8 additions & 2 deletions actions/gif.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@ var https = require('https')
var action = {
name: 'gif',

trigger: /^gif ".*"$/,
description: 'Displays animated GIFs from Giphy.',

description: 'Display a random GIF from Giphy.',
helpText: '' +
'Displays animated GIFs from Giphy.\n' +
'```' +
'/slacker gif [tag] [...]' +
'```\n' +
'If no tag is supplied, then `gif` will return a completely random gif. If one or more tags are provided, `gif` will return a random result from a search for all of the tags on Giphy.'
,

apiKey: 'dc6zaTOxFJmzC',

Expand Down
50 changes: 35 additions & 15 deletions actions/help.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,57 @@
var bot = require(__dirname + '/../bot.js')

var fs = require('fs')
var _ = require('lodash');

var action = {
name: 'help',

trigger: /^help.*/,

description: 'Display information on how to user Slacker.',

helpText: 'help.md has not loaded yet, try again.',

setup: function() {
fs.readFile(__dirname + '/../action_data/help.md', function(error, data) {
if (error)
throw error
if (error) {
throw error;
}

action.helpText = data.toString()
action.helpText = data.toString();
})
},

execute: function(data, callback) {
var components = data.text.split(' ')

if (components.length === 1)
callback(this.helpText)

for (var x = 0; x < bot.actions.length; x++)
if (bot.actions[x].name === components[1])
callback(bot.actions[x].trigger)
var args, action, helpText, helpTitle;

args = data.command.arguments;
helpText = '';
helpTitle = '';

if (args.length === 0) {

helpTitle = this.name;
helpText = this.helpText;
} else if (args.length >= 1) {
action = _.find(bot.actions, {name: data.command.arguments[0]});
helpTitle = args[0];

if (!action) {
console.log('No action.');
helpText = 'Command, `' + args[0] + '`, not found. Did you mistype it?';
} else if (!action.helpText && !action.description) {
helpText = 'No help information found.';
} else if (!action.helpText && action.description) {
helpText = action.description;
} else if (typeof action.helpText === 'string') {
helpText = action.helpText;
} else if (typeof action.helpText === 'function') {
helpText = action.helpText();
}
}

callback('*' + helpTitle.toUpperCase() + '*\n' + '> ' + helpText.replace(/\n/g, '\n> '));

callback('Action "' + components[1] + '" not found.')
}
}

bot.addAction(action)
bot.addAction(action);
Loading