3
2

More than 3 years have passed since last update.

Chatwork から Slackへの Webhook通知

Last updated at Posted at 2019-12-14

前置き

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

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

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

連携イメージ

image.png

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

作成

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

1. Slack - IncomingWebhook

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

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

image.png

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 実行例
image.png
     ⬇︎ テスト2 実行例
image.png

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

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

3. APIGateway

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

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

image.png

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

4. Chatwork - Webhook

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

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

image.png

 
上記で設定完了です。
 
 

5. 実装結果

Chatwork
image.png
      ⬇︎
Slack
image.png

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

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

Chatwork
image.png
      ⬇︎
Slack
image.png

と少々残念なことに。

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

Chatwork
image.png
      ⬇︎
Slack
image.png
 
ぱっと見、よくわからない。

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

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

6 最後に

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

改善に向けた課題:

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

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

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

3
2
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
3
2