Slackで疑似ユーザーグループにメンション機能を付ける(GAS+SlackApp+OutgoingWebhook)


はじめに

去年の今頃に、自分が所属している団体でslackを使わなくてはいけなくなり、色々設定した中で特に大変だったのが、以下の機能です

・グループ名に反応し、そのメンバー全員をスレッドでメンションを付ける

例えば、Aグループのメンバーに通知をしたい時は、@Aグループなどとすれば、そのスレッドにメンバーへのメンション(@太郎、@次郎、@花子など)が飛ぶ仕様です。
これ、実はslackの課金機能のユーザーグループを使えば楽っぽいのですが、課金することは許されず、なんとかbotで頑張るしかない状況でした。
やっかいなところは、スレッドにメンションを付けるところで、チャンネルにそのまま投稿して良いなら以下のようにslack botを使えばすぐできることでした。

これだと、スレッドに続けて会話できなくなってしまいます(どこにスレッド付ければいいの?ってなる)。
なので、下のようにしたいのです。

(Aチームという言葉に反応して、スレッドにてAチームの人たちにメンション投げる)

メリット

  • いちいちメンション付けなくてよい(グループの人数が多い場合)
  • 無駄にチャンネルが騒がしくならない

これが結構めんどくさかったので記事にしました。
去年やったことなので、忘れていることもあるかもしれません。
あと、outgoingwebhookは使わなくてもSlackAppだけでもいけそうですね。
またどなたかがすでに記事にされていたらすみません!

やったこと

  • OutgoingWebhookでキーワードを検知、GASに送る
  • GASのコードを編集
  • SlackAppの設定


(イメージ図)

OutgoingWebhook

webhookは外部サービスからslackへと送受信する方法で、Incoming WebhookとOutgoing Webhookがあり、今回は主にOutgoing Webhookを使います。
Outgoing Webhook はSlackのメッセージの中からキーワードを検知し、指定したURLにPOSTすることができます。json形式で返すとレスポンスを返してくれるっぽいでのですが、今回は使いません(スレッドに返す必要があるため)。
まず、このOutgoingWebhookの設定を行います。

アプリの追加

slackのアプリを追加するボタン→検索→outgoing webhookで検索→追加→設定
でアプリの追加、設定を行います。

outgoing webhookを設定

設定を押すとoutgoing webhookのページに飛ぶと思います。
そこで、slackに追加って押すと、設定が始まります。

URLはGASのウェブアプリケーションのURLを貼ります(後述取得)
ここでトークンをメモしておきます。

Slack App

以下のリンクからslackのアプリを作成します。
https://api.slack.com/apps/
Crate New Appを押せば作成が始まり、アプリ(bot)の名前と使うワークスペースを決めます。
OAuth & PermissionsのscopesでBot Token ScopesにAdd an OAuth Scopeからchat:writeを追加します。
(User Token Scopesに追加すると、ユーザー自身としてアクションが起きます)

その後、Install AppからInstall to Workspaceで権限のリクエストを許可し、ワークスペースに追加します。
Bot User OAuth Access Tokenが生成されるので、メモしておきます。

そして、この機能を使いたいチャンネルにアプリを追加します。
チャンネルの設定→その他→アプリの追加からアプリを追加します。

GAS

主に以下の記事を参考にさせていただきました
Slack上のメッセージをGoogleAppsScriptで受け取ってよしなに使う

GoogleAppScriptにコードを書いていきます。まとめると次のようなコードになりました。


function doPost(e) {
  var text = "<@user_id>,<@user_id2>,<@user_id3>";
  var verify_token = "OutgoingWebhookのトークン";
  if (verify_token != e.parameter.token){
  throw new Error("invalid token.");
  }
  var channel = e.parameter.channel_name;
  var ts = e.parameter.timestamp;
  if(e.parameter.thread_ts){
    ts = e.parameter.thread_ts;
  }
  var app = SlackApp.create("SlackAppのトークン");
  var options = {
    thread_ts: ts,
  }
  app.chatPostMessage(channel,text,options );
}

メンションを飛ばす

<@user_id>ではuser_idを指定します。
user_idの取得方法や記述方法は以下の記事を参考にしました。
SlackのIncoming Webhooksでメンションを飛ばす方法
slackのユーザープロフィール→その他→メンバーidをコピーで取得できるみたいです。

Post Data取得

slackapiのドキュメンテーションによればpost Dataは以下のような形で来るらしいです。

token=XXXXXXXXXXXXXXXXXX
team_id=T0001
team_domain=example
channel_id=C2147483705
channel_name=test
thread_ts=1504640714.003543
timestamp=1504640775.000005
user_id=U2147483697
user_name=Steve
text=googlebot: What is the air-speed velocity of an unladen swallow?
trigger_word=googlebot:

このうち、timestampとはそのメッセージが投稿された日時のことで、リンクになっていることから共有・参照することができます。
thread_tsは、thread_timestampの略で、スレッドになっている場合の親のタイムスタンプになります。また、これを使ってそのメッセージがスレッド中かどうか判断することができます。


  var ts = e.parameter.timestamp;
  if(e.parameter.thread_ts){
    ts = e.parameter.thread_ts;;
  }

ここでは、メッセージチャンネルの中に地で打たれたら、そのメッセージのタイムスタンプを、スレッド中の場合はそのスレッドの親のタイムスタンプを変数にいれています。
これは、スレッド中にキーワードが出てもそれに反応し、スレッドの中でそのままメンションを飛ばせるようにするためです。

SlackApp

  var app = SlackApp.create("SlackAppのトークン");
  var options = {
    thread_ts: ts,
  }
  app.chatPostMessage(channel,text,options );

SlackAppのトークンに先ほど作成したBot User OAuth Access Tokenを添付します。
chatPostMessageのoptionのthread_ts使ってスレッドにメッセージを投げます。
ドキュメンテーションには、
Provide another message's ts value to make this message a reply. Avoid using a reply's ts value; use its parent instead.
と書かれてあり、だから前項で親のタイムスタンプがある場合はそれを取得しなくてはいけなかったんですね。
あと、忘れてはいけないのは、SlackAppをLibraryに追加することです(参考)。
SlackAppのLibrary Keyは以下
M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO

add Libraryに追加すると以下のようになります。

ウェブアプリケーションの公開

※GASの仕様が変わったみたいで、新しいエディタだと仕様が違うかもしれません。
公開→ウェブアプリケーションの公開から下のように設定します。

Project versionをNewにすること、Who has access to the app:の覧を「全ユーザー」ではなく、匿名のものも含めること(Anyone, even anonymous)に注意してください。
更新し、生成されたweb app URLを先ほどのOutgoing WebhookのURLに添付します(Outgoing Webhookの更新)。

完成


完成です。このようにスレッド中でもしっかり反応します。

つまずいたところは、
- SlackAppのライブラリを追加しなくてはいけない点
- バージョンをNewにする必要がある点
- 全ユーザーではなく、匿名も可にする必要がある点
- スレッドの取得方法
- チャンネルにアプリを追加するのを忘れていた

でした。

終わりに

スレッドに関して反応する記事が点在としていてまとまっていなさそうだったので、今回の記事を書かせていただきました。
意外に、やることが多くてびっくりです笑
Slack apiの更新で、OutgoingWebhookを使わなくても良さそうなんですが、今回はこの方法を取ってしまいました。
なにか間違いなどあったらすみません・・・