Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into not-ok
Browse files Browse the repository at this point in the history
  • Loading branch information
afeld committed May 7, 2015
2 parents 45c7fcf + 2bb55dd commit b9eb90b
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 49 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ RUN make

EXPOSE 3000

CMD ./bin/slackin --channel $SLACK_CHANNEL --port $PORT $SLACK_SUBDOMAIN $SLACK_API_TOKEN
CMD ./bin/slackin --channels $SLACK_CHANNELS --port $PORT $SLACK_SUBDOMAIN $SLACK_API_TOKEN
2 changes: 1 addition & 1 deletion Procfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
web: make && bin/slackin --channel "$SLACK_CHANNEL" --port $PORT $SLACK_SUBDOMAIN $SLACK_API_TOKEN
web: make && bin/slackin --channels "$SLACK_CHANNELS" --port $PORT $SLACK_SUBDOMAIN $SLACK_API_TOKEN
26 changes: 15 additions & 11 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Read more about the [motivations and history](http://rauchg.com/slackin) behind

### Server

[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/rauchg/slackin/tree/0.4.0)
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/rauchg/slackin/tree/d36c365)

Or install it and launch it on your sever:

Expand All @@ -28,7 +28,7 @@ $ npm install -g slackin
$ slackin "your-slack-subdomain" "your-slack-token"
```

You can find your API token at [api.slack.com/web](https://api.slack.com/web).
You can find your API token at [api.slack.com/web](https://api.slack.com/web) – note that the user you use to generate the token must be an admin. You may want to create a dedicated `@slackin-inviter` user (or similar) for this.

The available options are:

Expand All @@ -37,15 +37,19 @@ Usage: slackin [options] <slack-subdomain> <api-token>
Options:
-h, --help output usage information
-V, --version output the version number
-p, --port <port> Port to listen on [$PORT or 3000]
-c, --channel <chan> Single channel guest invite [$SLACK_CHANNEL]
-i, --interval <int> How frequently (ms) to poll Slack [$SLACK_INTERVAL or 1000]
-s, --silent Do not print out warns or errors
-h, --help output usage information
-V, --version output the version number
-p, --port <port> Port to listen on [$PORT or 3000]
-c, --channels [<chan>] One or more comma-separated channel names to allow single-channel guests [$SLACK_CHANNELS]
-i, --interval <int> How frequently (ms) to poll Slack [$SLACK_INTERVAL or 1000]
-s, --silent Do not print out warns or errors
```

**Important: if you use Slackin in single-channel mode, you'll only be able to invite as many external accounts as paying members you have times 5. If you are not getting invite emails, this might be the reason. Workaround: sign up for a free org, and set up Slackin to point to it (all channels will be visible).**
**Important: if you use Slackin in single-channel mode, you'll only be
able to invite as many external accounts as paying members you have
times 5. If you are not getting invite emails, this might be the reason.
Workaround: sign up for a free org, and set up Slackin to point to it
(all channels will be visible).**

### Realtime Badge

Expand Down Expand Up @@ -90,7 +94,7 @@ require('slackin')({
token: 'yourtoken', // required
interval: 1000,
org: 'your-slack-subdomain', // required
channel: 'channel' // for single channel mode,
channels: 'channel,channel,...' // for single channel mode
silent: false // suppresses warnings
}).listen(3000);
```
Expand All @@ -104,7 +108,7 @@ By default logging is enabled.

- The SVG badge generation was taken from the
excellent [shields](https://github.com/badges/shields) project.
- The button CSS is based on
- The button CSS is based on
[github-buttons](https://github.com/mdo/github-buttons).

## License
Expand Down
2 changes: 1 addition & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"required": true
},
"SLACK_CHANNEL": {
"description": "Name of a single guest channel to invite them to (leave blank for a normal, all-channel invite)",
"description": "Name of a single guest channel to invite them to (leave blank for a normal, all-channel invite). In order to make this work, you have to have a paid account. You'll only be able to invite as many people as your number of paying members times 5.",
"required": false
}
}
Expand Down
8 changes: 7 additions & 1 deletion bin/slackin
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ program
.version(pkg.version)
.usage('[options] <slack-subdomain> <api-token>')
.option('-p, --port <port>', 'Port to listen on [$PORT or 3000]', process.env.PORT || 3000)
.option('-c, --channel <chan>', 'Single channel guest invite [$SLACK_CHANNEL]', process.env.SLACK_CHANNEL)
.option('-c, --channels [<chan>]', 'One or more comma-separated channel names to allow single-channel guests [$SLACK_CHANNELS]', process.env.SLACK_CHANNELS)
.option('-c, --channel <chan>', 'Single channel guest invite (deprecated) [$SLACK_CHANNEL]', process.env.SLACK_CHANNEL)
.option('-i, --interval <int>', 'How frequently (ms) to poll Slack [$SLACK_INTERVAL or 1000]', process.env.SLACK_INTERVAL || 1000)
.option('-s, --silent', 'Do not print out warns or errors')
.option('-c, --css <file>', 'Full URL to a custom CSS file to use on the main page')
Expand All @@ -21,6 +22,11 @@ if (program.args.length != 2) {
program.token = program.args[1];
}

// support deprecated option
if (!program.channels && program.channel) {
program.channels = program.channel;
}

var port = program.port;
slackin(program).listen(port, function(err){
if (err) throw err;
Expand Down
11 changes: 8 additions & 3 deletions lib/assets/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var body = document.body;
var request = superagent;

// elements
var select = body.querySelector('select');
var input = body.querySelector('input');
var button = body.querySelector('button');

Expand All @@ -16,7 +17,8 @@ body.addEventListener('submit', function(ev){
button.disabled = true;
button.className = '';
button.innerHTML = 'Please Wait';
invite(input.value, function(err){
var channel = select ? select.value : null;
invite(channel, input.value, function(err){
if (err) {
button.removeAttribute('disabled');
button.className = 'error';
Expand All @@ -29,10 +31,13 @@ body.addEventListener('submit', function(ev){
});


function invite(email, fn){
function invite(channel, email, fn){
request
.post('/invite')
.send({ email: email })
.send({
channel: channel,
email: email
})
.end(function(res){
if (res.error) {
var err = new Error(res.body.msg || 'Server error');
Expand Down
37 changes: 26 additions & 11 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,29 @@ export default function slackin({
interval = 1000, // jshint ignore:line
org,
css,
channel,
channels,
silent = false // jshint ignore:line
}){
// must haves
if (!token) throw new Error('Must provide a `token`.');
if (!org) throw new Error('Must provide an `org`.');

// sanitize channel name
if (channel && '#' == channel[0]) channel = channel.substr(1);
if (channels) {
// convert to an array
channels = channels.split(',').map((channel) => {
// sanitize channel name
if ('#' == channel[0]) return channel.substr(1);
return channel;
});
}

// setup app
let app = express();
let srv = http(app);
let assets = __dirname + '/assets';

// fetch data
let slack = new Slack({ token, interval, org, channel });
let slack = new Slack({ token, interval, org });

// capture stats
log(slack, silent);
Expand All @@ -61,7 +67,7 @@ export default function slackin({
dom('meta name=viewport content="width=device-width,initial-scale=1.0,minimum-scale=1.0,user-scalable=no"'),
css && dom('link rel=stylesheet', { href: css })
),
splash({ css, name, logo, channel, active, total })
splash({ css, name, logo, channels, active, total })
);
res.type('html');
res.send(page.toHTML());
Expand All @@ -72,10 +78,20 @@ export default function slackin({

// invite endpoint
app.post('/invite', json(), (req, res, next) => {
if (channel && !slack.channel) {
return res
.status(500)
.json({ msg: `Channel not found "${channel}"` });
let chanId;
if (channels) {
let channel = req.body.channel;
if (!channels.includes(channel)) {
return res
.status(400)
.json({ msg: 'Not a permitted channel' });
}
chanId = slack.getChannelId(channel);
if (!chanId) {
return res
.status(400)
.json({ msg: `Channel not found "${channel}"` });
}
}

let email = req.body.email;
Expand All @@ -92,7 +108,6 @@ export default function slackin({
.json({ msg: 'Invalid email' });
}

let chanId = slack.channel ? slack.channel.id : null;
invite({ token, org, email, channel: chanId }, function(err){
if (err) {
return res
Expand All @@ -118,7 +133,7 @@ export default function slackin({
let { name } = slack.org;
let { active, total } = slack.users;
if (!name) return res.send(404);
let dom = splash({ name, channel, active, total, iframe: true });
let dom = splash({ name, channels, active, total, iframe: true });
res.type('html');
res.send(dom.toHTML());
});
Expand Down
26 changes: 12 additions & 14 deletions lib/slack.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { EventEmitter } from 'events';

export default class SlackData extends EventEmitter {

constructor({ token, interval, org: host, channel }){
constructor({ token, interval, org: host }){
this.host = host;
this.token = token;
this.interval = interval;
this.ready = false;
this.org = {};
this.users = {};
this.channelName = channel;
this.channelsByName = {};
this.fetch();
}

Expand All @@ -25,6 +25,11 @@ export default class SlackData extends EventEmitter {
this.emit('fetch');
}

getChannelId(name){
let channel = this.channelsByName[name];
return channel ? channel.id: null;
}

retry(){
let interval = this.interval * 2;
setTimeout(this.fetch.bind(this), interval);
Expand All @@ -37,18 +42,11 @@ export default class SlackData extends EventEmitter {
return this.retry();
}

if (this.channelName && !this.channel) {
let name = this.channelName;
this.channel = res.body.channels.filter(chan => {
return name == chan.name;
})[0];

if (!this.channel) {
let err = new Error(`Channel not found: "${name}"`);
this.emit('error', err);
return;
}
}
// reset the list of channels
this.channelsByName = {};
res.body.channels.forEach(channel => {
this.channelsByName[channel.name] = channel;
});

let users = res.body.users;

Expand Down
23 changes: 17 additions & 6 deletions lib/splash.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@

import dom from 'vd';

export default function splash({ name, logo, active, total, channel, iframe }){
export default function splash({ name, logo, active, total, channels, iframe }){
let div = dom('.splash',
!iframe && dom('.logos',
logo && dom('.logo.org'),
dom('.logo.slack')
),
dom('p',
dom('p',
'Join ', dom('b', name),
channel && dom('span', ' #', channel),
// mention single single-channel inline
channels && channels.length === 1 && dom('span', ' #', channels[0]),
' on Slack.'
),
dom('p.status',
Expand All @@ -21,7 +22,13 @@ export default function splash({ name, logo, active, total, channel, iframe }){
: [dom('b.total', total), ' users are registered so far.']
),
dom('form',
dom('input type=email [email protected] '
// channel selection when there are multiple
channels && channels.length > 1 && dom('select.form-item name=channel',
channels.map(channel => {
return dom('option', { value: channel, text: channel });
})
),
dom('input.form-item type=email [email protected] '
+ (!iframe ? 'autofocus' : '')),
dom('button.loading', 'Get my Invite')
),
Expand Down Expand Up @@ -127,10 +134,15 @@ function style({ logo, active, iframe } = {}){
});
}

css.add('button, input', {
css.add('select', {
'background': 'none'
});

css.add('button, .form-item', {
'font-size': '12px',
'height': '32px',
'line-height': '32px',
'margin-top': iframe ? '5px' : '10px',
'vertical-align': 'middle',
'display': 'block',
'text-align': 'center',
Expand All @@ -140,7 +152,6 @@ function style({ logo, active, iframe } = {}){

css.add('button', {
'color': '#fff',
'margin-top': iframe ? '5px' : '10px',
'font-weight': 'bold',
'border-width': 0,
'background': pink,
Expand Down
1 change: 1 addition & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('slackin', () => {
nock(`https://${org}.slack.com`)
.get('/api/rtm.start?token=mytoken')
.reply(200, {
channels: [{}],
team: {
name: 'myteam',
icon: {}
Expand Down

0 comments on commit b9eb90b

Please sign in to comment.