Chatwork から Slackへの Webhook通知


前置き

社内は Slackを多用していて参加チャンネルも多かったのですが、
最近案件の都合でChatWorkのチャンネルにも入ったことで
通知のチェックが大変になってきました。

そこで、ChatWorkの通知をSlackでも受け取りたいと思い
アプリを検索してみたのですが...

以外とないので、Lambdaで適当に作ってみることに。

連携イメージ

こんな流れにで、Webhookの フォーマット形式を良い感じ変換できれば
以外と簡単に実現できそう! (と、思ってました)。

作成

データのフローとは逆の形で、エンドポイント側(Slack側)から
対応していく必要があります。

1. Slack - IncomingWebhook

IncomingWebhook のインストールをし、新規WebhookURLを発行します。

アプリURL:
 https://slack.com/apps/A0F7XDUAZ--incoming-webhook-

2. Lambda

1. 実装

今回は Nodejsにて実装。
-> index.js に以下のように作成

index.js
const https = require('https');

// Slack の IncomingWebhook のURLを設定
const slack_host = "hooks.slack.com";
const slack_path = "/services/*********/*********/*****************";

exports.handler = async (event) => {

  if(!event["webhook_event"]){
    return "no event data.";
  }

  let chatevent = event["webhook_event"];

  let postData = {
    username : "chatwork-bot / " + (chatevent["from_account_id"] || chatevent["account_id"]),
    text : chatevent["body"] + (event["webhook_event_type"] == "message_updated" ? " (edited)": ""),
    icon_emoji : ":ghost:"
  };

  let data = "payload="+JSON.stringify(postData)+"";
  let options = {
    host : slack_host,
    path : slack_path,
    method : "post",
    headers: {
     "Content-type": "application/x-www-form-urlencoded",
     "Content-Length" : Buffer.byteLength(data),
    }
  };

  return new Promise((resolve, reject) => {
    let buff = [];
    let req = https.request(options, (res)=> {
      res.on('data', (chunk) => {
        buff.push(chunk);
      });
      res.on('end', () => {
        if (res.statusCode == 200) {
          resolve(Buffer.concat(buff).toString());
        } else {
          reject("request failed: " + res.statusCode + " - " + res.statusMessage + " " + Buffer.concat(buff).toString());
        }
      });
    });
    req.on('error', (e) => {
      console.error(`request error: ${e.message}`);
    });
    req.write(data);
    req.end();
  });


};
2. テスト

この段階で IncomingWebhookとLambdaの実装が正しくできていれば
Slackへのテスト通知が可能です。

テストは、Chatworkの仕様に従い2種用意します。
- test1: 通常メッセージ
- test2: 自分へのメンションメッセージ

※ webhook_event_type は message_created, message_updated, mention_to_me の3種あり、
 message_created と message_updatedはフォーマット形式が同じ。
 (公式のサンプルだと、message_idが被ってるので、微調整)

テスト1 (webhook_event_type...message_created,message_updated)
{
  "webhook_setting_id": "12345",
  "webhook_event_type": "message_created",
  "webhook_event_time": 1498028152,
  "webhook_event": {
    "message_id": "789012345",
    "room_id": 567890123,
    "account_id": 1484814,
    "body": "お客様とのランチミーティング用のお弁当、発注完了しました。",
    "send_time": 1498028120,
    "update_time": 0
  }
}
テスト2 (webhook_event_type...mention_to_me)
{
  "webhook_setting_id": "12345",
  "webhook_event_type": "mention_to_me",
  "webhook_event_time": 1498028130,
  "webhook_event": {
    "from_account_id": 123456,
    "to_account_id": 1484814,
    "room_id": 567890123,
    "message_id": "789012346",
    "body": "[To:1484814]おかずはなんですか?",
    "send_time": 1498028125,
    "update_time": 0
  }
}

     ⬇︎ テスト1 実行例

     ⬇︎ テスト2 実行例

といった具合にslackへ通知が飛べばここまで成功です。

※ この段階で気づいたのですが、
 通知された情報に投稿者名がなく、アカウントIDしかなかったんですよね。
 -> 取り急ぎ連携することを優先するので、ここでは見ないことにします。

3. APIGateway

API-Gateway にて上で定義したLambda関数の呼び出すエンドポイントを作成します。

  1. リソース作成(任意)
  2. メソッド作成 -> 上で作成したLambda を指定
  3. ステージの作成 -> 公開URLの発行

※ リソースを追加した際は、リソースのパスの追加を忘れずに

4. Chatwork - Webhook

  1. API設定画面の起動
     画面右上の API設定 を選択
     https://www.chatwork.com/service/packages/chatwork/subpackages/webhook/list.php

  2. 新規作成にて 3.で作ったAPIGatewayのURLをWebhookURLへ登録

 
上記で設定完了です。
 
 

5. 実装結果

Chatwork

      ⬇︎
Slack

ご覧の通り、良い感じに連携できました。 (※投稿者以外は)
 

も、目的の、通知が使えれば良いんじゃないかな。
一応他も試して見る。

Chatwork

      ⬇︎
Slack

と少々残念なことに。

他、引用や返信を試してみたところ

Chatwork

      ⬇︎
Slack

 
ぱっと見、よくわからない。

※ 引用元の発言者の名前が載ってるので誤認しそう

 
他:
- リアクションは、何も通知されませんでした。
- 投稿済の記事の編集は、編集後の内容でSlackへ通知されました。
(IncomingWebhookの特性上記事の更新は難しいので、今回は末尾に (edited) を直接付与して誤魔化し)

6 最後に

適当に作ってみたのですが、課題が山積みでした。
Webhookの対応のみでは、完全な通知の連携とまでいかないので、
何らかの通知があったことを知ることに使おうかなと思います。
 

改善に向けた課題:

  • 投稿者の accout_id を名前へ変換
  • メンションの変換
  • 発言者のサムネイル表示
  • 発言内容の絵文字も変換
  • 引用元がわかるように
  • 添付ファイルも直リンクできるように
  • Webhookの接続元の検証の実施 (X-ChatWorkWebhookSignature)
  • 記事の編集通知

 
APIの仕様上、どこまで対応できるかわかりませんが、 
今後時間を見てブラッシュアップしていきたいと思います。
 

 
 
参考:
- http://developer.chatwork.com/ja/webhook.html
- https://api.slack.com/messaging/webhooks