情報共有を効率化 - Slackの分報チャンネルにあるリンクを拾うSlack Botを作ってみた

f:id:jxpress:20191221002017j:plain

こちらはJX通信社 Advent Calendar 2019 の21日目の記事です。どうも、何でも屋のkainです。

きっかけ

昨日の朝、弊社メンバーからこんな投稿がありました。

メンバーの投稿

弊社の分報チャンネルでは、今やってることや困ってることなど以外に、それぞれが読んだリンクを雑に投稿しています。中には有意義な情報も多く、それぞれの分報チャンネルでキュレーションメディアを運営している、といった様子です。

一応、チームや分野ごとの記事共有用のチャンネルもありますが、分報チャンネルに投稿した後に、いちいち投稿するのが手間というのもあり、利用機会は限られています。なので、メンバーはSlackのチャンネルを徘徊して、情報収集を行う必要がありました

そこで、「ここを見ればおk」とったチャンネル(=情報収集チャンネル)作れないかと思い、アドベントカレンダーのネタに困っていたのでサクッと作ってみました。

どうやるか

Slack Appには、Slack内で発生したイベント情報を購読するため機能(Event Subscription)があります。開発者は事前に設定したRequest URLに対して、Slack上で特定の操作(メッセージ投稿、リアクションなど)が行われるたび、イベント情報が送られてきます。

今回欲しいのは、「特定のチャンネル(分報チャンネル)でリンクが含まれたメッセージが投稿された」というイベント情報です。そこで、Event Subscription機能のうち、Bot Eventの message.channels (Botユーザーが参加しているチャンネルの投稿)を購読し、こちら側でリンクが含まれているかどうかを選別 → 情報収集チャンネルへ投稿するようにします。

なので、運用は「チャンネルにBotユーザーを招待」すれば、勝手にリンクを拾ってくれて、情報共有チャンネルに投稿してくれます。

作ってみる

まずは、Slack Appをポチポチして作ります。こちらから、「Create App」をクリックし「アプリ名」を決め「ワークスペース」を選択して完了です。そしたら、Basic Information設定画面にあるApp CredentialsのSigning Secretと、OAuth & Permissions設定画面のBot User OAuth Access Tokenをメモしておいてください。

次に、投稿を受け取る処理を書いていきます。弊社はPythonユーザーが多いのでサクッと検証する際にはPythonを使うことが多いです。下記スクリプトを利用する際は、 {{ 情報収集チャンネル名 }} を適宜書き換えてください。

# app.py
import os

from flask import Flask, request, jsonify
from slack import WebClient
from slackeventsapi import SlackEventAdapter

SLACK_BOT_TOKEN = os.environ['SLACK_BOT_TOKEN']  # メモした
SLACK_SIGNING_SECRET = os.environ["SLACK_SIGNING_SECRET"]
SLACK_CHANNEL = "{{ 情報収集チャンネル名 }}"

app = Flask(__name__)
slack_client = WebClient(token=SLACK_BOT_TOKEN)
slack_events_adapter = SlackEventAdapter(SLACK_SIGNING_SECRET, "/", app)


@slack_events_adapter.on('message')
def handle_message_channels_event(data):
    event = data['event']

    # リンクを抽出し投稿
    for block in event.get('blocks') or []:
        for section in block['elements']:
            for i in section['elements']:
                if i['type'] != 'link':
                    continue

                slack_client.chat_postMessage(
                    channel=SLACK_CHANNEL, text=i['url'], unfurl_links=True
                )


if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 5000)))

Slackの公式ライブラリのpython-slack-events-apiは、処理をイベント種類ごとに書くことができて大変便利です。

動かしてみる

こちらのスクリプトを動かしてみます。

$ pip install flask slackclient slackeventsapi
$ export SLACK_BOT_TOKEN={{ Bot User OAuth Access Token }}
$ export SLACK_SIGNING_SECRET={{ App CredentialsのSigning Secret }}
$ FLASK_APP=app.py FLASK_DEBUG=1 flask run

このままではSlackからのイベントを受け取れないので、ngrokを使ってインターネット空間にプロキシします。

$ ngrok http 5000

表示されたForwarding URLのうちhttpsのものをメモしておき、Slack AppのEvent Subscriptions設定画面のRequest URL欄に入力します。

これで準備完了です。Botユーザーを分報チャンネルに招待してから、リンクを投稿してみます。

f:id:jxpress:20191221003227j:plain

すると、情報収集チャンネルでもリンクが共有されます。

最後に

メンバーの投稿を見たのがたまたま東京から九州方面に向かう飛行機の搭乗前で、目的地に着くまでの間に完成しました。Slack Appはとても簡単にパワフルな機能を実装できるので、ぜひ業務に活用してみてください。