前置き
社内は 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 に以下のように作成
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が被ってるので、微調整)
{
"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
}
}
{
"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
}
}
といった具合にslackへ通知が飛べばここまで成功です。
※ この段階で気づいたのですが、
通知された情報に投稿者名がなく、アカウントIDしかなかったんですよね。
-> 取り急ぎ連携することを優先するので、ここでは見ないことにします。
3. APIGateway
API-Gateway にて上で定義したLambda関数の呼び出すエンドポイントを作成します。
- リソース作成(任意)
- メソッド作成
-> 上で作成したLambda を指定 - ステージの作成
-> 公開URLの発行
※ リソースを追加した際は、リソースのパスの追加を忘れずに
4. Chatwork - Webhook
-
API設定画面の起動
画面右上のAPI設定
を選択
https://www.chatwork.com/service/packages/chatwork/subpackages/webhook/list.php -
新規作成にて 3.で作ったAPIGatewayのURLをWebhookURLへ登録
上記で設定完了です。
5. 実装結果
ご覧の通り、良い感じに連携できました。 (※投稿者以外は)
も、目的の、通知が使えれば良いんじゃないかな。
一応他も試して見る。
と少々残念なことに。
他、引用や返信を試してみたところ
Chatwork
⬇︎
Slack
ぱっと見、よくわからない。
※ 引用元の発言者の名前が載ってるので誤認しそう
他:
- リアクションは、何も通知されませんでした。
- 投稿済の記事の編集は、編集後の内容でSlackへ通知されました。
(IncomingWebhookの特性上記事の更新は難しいので、今回は末尾に(edited)
を直接付与して誤魔化し)
6 最後に
適当に作ってみたのですが、課題が山積みでした。
Webhookの対応のみでは、完全な通知の連携とまでいかないので、
何らかの通知があったことを知ることに使おうかなと思います。
改善に向けた課題:
- 投稿者の accout_id を名前へ変換
- メンションの変換
- 発言者のサムネイル表示
- 発言内容の絵文字も変換
- 引用元がわかるように
- 添付ファイルも直リンクできるように
- Webhookの接続元の検証の実施 (
X-ChatWorkWebhookSignature
) - 記事の編集通知
APIの仕様上、どこまで対応できるかわかりませんが、
今後時間を見てブラッシュアップしていきたいと思います。
参考: