12
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SlackのBotkitでbuttonとinteractive messagesを使ってみた

Last updated at Posted at 2016-08-28

#SlackのBotkitでbuttonとinteractive messages
初めてJavaScriptとSlackを触って簡単なボットを作ってみたので、備忘録としての投稿です。
4月にプログラミングを始めたので理解できていない点が多いと思います。Slack関連の日本語の投稿が少ないので、本家の英語の各種説明を読むよりはマシ、という方の参考になれば嬉しいです。

##環境

  • Node.js(6.4.0)
  • Heroku

##初めに

ボタンなどのインタラクティブな機能を実装するにはSlack Appの登録が必要です。
Slackのローカルから動かせるカスタムインテグレーションとしてのUser Botでは使えないので注意してください。
またhttps通信を行うので今回はHerokuを使うことを前提に書いていきます。

基本的には
Welcome to the Slack API
に細かく書いてあることを基に行っていきます。

##Slack App登録
Create App

Create App

  • App Name
  • Team
  • Description
  • Describe what your app does on Slack (3-5 sentences)
    を入力して登録。

次に、移った先の左側の欄にあるApp CredentialsBot UserInteractive Messagesを設定します。


App Credentials

Client IDClient Secretは後で必要です。

Redirect URI(s)は、

https://{your app}.herokuapp.com/oauth
と入力します。


Bot User

ボットを自分のチャンネルへ呼び出すときに使用するボットの名前を設定します。
 


Interactive Messages

Request URLには、

https://{your app}.herokuapp.com/slack/receive
が入ります。

以上でSlackでの設定は終わりです。

##コード
Heroku上で動かすためには、

  • main.js
  • Procfile
  • package.json
    の3つのファイルが必要です。

main.jsに関しては公式のデモもありますが個人的には非常にわかりにくかったため、動かす上で不可欠なもの(だと僕が思ったもの)だけを抜粋して諸々付け加えたコードを載せます。

main.js
/* Uses the slack button feature to offer a real time bot to multiple teams */
const querystring = require("querystring");
const Botkit = require("botkit");
const os = require("os");

// Heroku上で動かすため、port指定の箇所を !process.env.port から !process.env.PORT に変更
if (!process.env.clientId || !process.env.clientSecret || !process.env.PORT) {
  console.log('Error: Specify clientId clientSecret and port in environment');
  process.exit(1);
}

var controller = Botkit.slackbot({
  // interactive_replies: true, // tells botkit to send button clicks into conversations
  json_file_store: './db_slackbutton_bot/',
}).configureSlackApp(
  {
    clientId: process.env.clientId,
    clientSecret: process.env.clientSecret,
    scopes: ['bot'],
  }
);

controller.setupWebserver(process.env.PORT,function(err,webserver) {
  controller.createWebhookEndpoints(controller.webserver);

  controller.createOauthEndpoints(controller.webserver,function(err,req,res) {
    if (err) {
      res.status(500).send('ERROR: ' + err);
    } else {
      res.send('Success!');
    }
  });
});

// just a simple way to make sure we don't
// connect to the RTM twice for the same team
var _bots = {};
function trackBot(bot) {
  _bots[bot.config.token] = bot;
}

controller.on('create_bot',function(bot,config) {

  if (_bots[bot.config.token]) {
    // already online! do nothing.
  } else {
    bot.startRTM(function(err) {

      if (!err) {
        trackBot(bot);
      }

      bot.startPrivateConversation({user: config.createdBy},function(err,convo) {
        if (err) {
          console.log(err);
        } else {
          convo.say('I am a bot that has just joined your team');
          convo.say('You must now /invite me to a channel so that I can be of use!');
        }
      });
    });
  }
});

// Handle events related to the websocket connection to Slack
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');
  // you may want to attempt to re-open
});


// ========================================================================================================================================================================
// 以下 リアクション定義

controller.hears("hi", "direct_message,direct_mention,mention", (bot, message) => {

  bot.reply(message, {
    "text" : "hello"
  });

});


controller.hears("how are you", "direct_message,direct_mention,mention", (bot, message) => {

  bot.reply(message, {
    "text": "Great, you?",
    "attachments": [{
      "fallback": "Couldn't reply.",
      "callback_id": "greeting",
      "attachment_type": 'default',
      "actions": [
        {
          "name": "good",
          "value": "good",
          "text": "Pretty Good",
          "type": "button"
        },{
          "name": "bad",
          "value": "bad",
          "text": "Not so good",
          "type": "button"
        }
      ]
    }]
  });

});


controller.on('interactive_message_callback', function(bot, message) {

  if (message.callback_id == "greeting") {

    const name = message.actions[0].name;
    const value = message.actions[0].value;

    var text = ""

    if (name == "good") {
      text = "That's good."
    } else {
      text = "What's wrong?"
    }

    bot.replyInteractive(message, {
      "text": text
    });
  }

});

Procfile
web: clientId={your slack app ID} clientSecret={your slack app pw} node main.js
package.json
{
  "name": "slack-bot-botkit",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "engines": {
    "node": "6.4.0"
  },
  "author": "",
  "license": "ISC",
  
  "dependencies": {
    "botkit": "^0.2.2",
    "querystring": "^0.2.0"
  }
}

##デプロイ

最低限ではありますが一応この3つのファイルだけで動くので、試しに自分のHerokuへデプロイしてみます。

Herokuへのデプロイについては、Heroku:(Application Errorにならないための)Node.jsアプリのデプロイ入門の記事に詳しくあります。

Herokuへのデプロイ後は、ブラウザから
https://{your app}.herokuapp.com/login

にアクセスして自分のチームで動かすための認証を行います。

作ったボットはチームのチャット画面で生きているので、ダイレクトメッセージで指定のキーワードを送ればボタン付きで反応してくれます。

##メッセージの形式

bot.replybot.replyInteractiveが取る引数のオブジェクトの形式については、

Basic message formatting(基本的な形式)
Making messages more interactive with buttons(ボタン用の形式)

に詳しく載っています。また今度翻訳してみようと思います。

##おわり

備忘録としてではありますが、初めて投稿したので一瞬で疲れてしまい割と大事なところを割愛してしまった気がします。次は(?)もう少し頑張りたいと思います…

12
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?