BotKitからSlackの指定チャンネルにポストする


これ、Hubotみたいにうまくいかなったのでメモです。

BotKitだと`bot.say()`コマンドで特定チャンネルのIDとメッセージを指定することでBOTに喋らせることができます。

>単純な返信なら`bot.reply()`です。

[bot.say does not work with # prefixed channel name #7](https://github.com/howdyai/botkit/issues/7)にあるみたいに

```
bot.say({
    text: "Hello World!",
    channel: "#random"
});
```

という感じでSlackのチャンネル名を指定したいんですけど、実際は以下のように

```
bot.say({
    text: "Hello World!",
    channel: 'C0XXXXXXX'
});
```

という見慣れない`C0XXXXXXX`みたいな形式で指定する必要があります。これはHubotだといい感じに変換してくれてるっぽいんですけど、BotKitはまだ対応してない疑惑?でした。

そもそもこの`C0XXXXXXX`みたいな形式がBotKit側の仕様なのかと思ってたらSlackの仕様みたいですね。

## SlackのChannel.list APIでうまいことできそう

Channel.list APIを使えば チャンネル名 -> IDを変換できそうです。

###　Slackのトークン発行

まずはAPIを使うためのトークン発行です。

https://api.slack.com/web から発行します。

![](https://i.gyazo.com/d2ac4cd6874d571edc89f250a9201792.png)
__Generate test tokens__を選択します。

![](https://i.gyazo.com/52208ac63089f22b46f1a67852612405.png)
トークン発行するチームの __Create token__を選択します。

Slackのパスワードを入力すると、
![](https://i.gyazo.com/ed18499c357a6bb1374f78aea68620ae.png)
__Confirm__ボタンが表示されるので選択します。

無事トークンが発行されました。
![](https://i.gyazo.com/9aca395e5be1941857119ce349843f59.png)

> ↑このトークンはすでに無効化してるので悪いことはできないですよ! (とか書いてないと会社の人に刺されそう。)

### channel.list APIを試す

https://api.slack.com/methods/channels.list/test にアクセスしましょう。

![](https://i.gyazo.com/e1e1cb75276e19278824815f0711e4be.png)
__Test Method__ を押すと


```
{
    "ok": true,
    "channels": [
        {
            "id": "C02SRLD8E",
            "name": "circle",
            "is_channel": true,
           ・
           ・
           ・
           (省略)
```

みたいなJSONが表示されます。これでIDをチャンネル名の変換ができそうです。

### channel.list APIをNode.jsから叩く

```channel.js
'use strict'

const request = require('request');
const token = 'トークンを指定';
const URL = `https://slack.com/api/channels.list?token=${token}&pretty=1`;

let target_channel_name = 'general';

request(URL, (error, response, body) => {
  if (!error && response.statusCode == 200) {
    let channels = JSON.parse(body).channels;
    for (let channel of channels) {
      if(channel.name === target_channel_name){
        console.log(`${channel.name}のチャンネルIDは${channel.id}です。`);
      }
    }
  }
});

```

実行

```bash
$ node channel.js
generalのチャンネルIDはC0ATTJVTQです。
```

これでチャンネル名 -> IDの指定ができました。

### BotKitに組み込んでみる

request周りは共通化したいですがとりあえず。

```mybotcommand.js
'use strict';

const request = require('request');
const token = 'トークンを指定';
const URL = `https://slack.com/api/channels.list?token=${token}&pretty=1`;

let target_channel_name = 'renraku';
let channel_id = '';

request(URL, (error, response, body) => {
  if (!error && response.statusCode == 200) {
    let channels = JSON.parse(body).channels;
    for (let channel of channels) {
      if(channel.name === target_channel_name){
        channel_id = channel.id;
        console.log(`${channel.name}のチャンネルIDは${channel.id}です。`);
      }
    }
  }
});

module.exports = (controller) => {
  controller.hears([''],'direct_message,direct_mention,mention', (bot, message) => {
    bot.say({
      text: 'my message text',
      channel: channel_id // a valid slack channel, group, mpim, or im ID
    });
  });
};
```

通常BotKitだとbot.jsの`controller.hears()`ごとにコマンドが記述してあると思うのですが、コマンドごとにファイル分けしたかったので僕のBotKitだとメインのbot.js側で各コマンドを読み込む感じにしてあるので、`module.exports`してます。

```bot.js
require('mybotcommand.js')(controller);
```

みたいな感じで読み込んでます。

## まとめ

BotKit側がすでに対応してたりするのか調べる前に記事書いちゃった (2016年4月)感じですけど、対応してくれるまではこのやり方がいいのかな。