ぼくのさいきょうのslack bot


この記事は東京理科大学 Advent Calendar 2019の12/2の記事です。
昨日は@piffettによるapt-getとaptの使い分けでした。

こんにちは。にっし〜です。
ここではGoでslack botを作る話を書きます。

はじめに

ここでは主にgoでの実装についてだけ書いて、slackへの導入だったり諸々は前提として話を進めます。
また、AWS Lambdaでの実装はここに追記するか別途記事にする予定です。

経緯

バイト先で勉強会を運営しているのですが、参加登録だったり、終了後のアンケートを全てGoogle formを使って集計していました。
Google App Scriptを使って諸々自動化するなどの涙ぐましい努力()をしてきたのですが、流石に辛くなってきました。
AWSの社用アカウントをいただいたのをきっかけにGoで書き直して、slack内で全て完結する構成にしようと考えました。
ただ、これに割ける時間はそこまで多くはなく、先人の実装例があれば嬉しいなぁと思っていた矢先、shiimaxxさんのこちらを見つけました。
https://github.com/shiimaxx/slack-coffeebot
これをforkして機能を足していけば最速で欲しいものが完成させられるだろうということで、自分がforkして諸々実装したものがこちらです。
https://github.com/nisshii0313/slack-coffeebot

やったこと

欲しかった機能は次の2つです。
- message_actionへの対応
- Datepickerの実装

1つずつ見ていきます

1, message_actionへの対応

自分がslack botを狂ったように作っていた1年前は主に2つの選択肢がありました。
slash commandかbotとの対話か、です。しかしながらworkspaceが大きい場合、slash commandもたくさんあるし、botもたくさん入ってるし、で自分で作ったものでも使い方・botの名前を忘れるということが発生していました。
そこで、今回はactionsを使用することにしました。

actionsであれば、勉強会の開催告知スレから直接開いてもらうこともできるし、この方法が最善だと考えました。
shiimaxxさんのものではbotとの対話に反応するように実装されていたので、次のようなコードを追記することでactionsに対応させました。

main.go
else if message.Type == "message_action" {
...
}

簡単にactionsに対応させることができました。

2, Datepickerの実装

Datepickerの実装には新しい(2019/2~)UI フレームワークであるBlock Kitが必要です。
公式がドキュメントを用意してくれている他、使っているライブラリ(https://github.com/nlopes/slack) もv0.6.0からblock-kitに対応してくれています。優しい世界!!
ということでこれらに従って実装していきます。
まずは

Gopkg.toml
[[constraint]]
  name = "github.com/nlopes/slack"
  version = "v0.6.0"

と書いてdep ensureします。
これでblock-kitに対応したライブラリが使えるようになりました。

あとは
https://github.com/nlopes/slack/blob/445280bcb9c1b02b4a88b1ee9aa7afd735b2dc55/examples/blocks/blocks.go
あたりでも見ながらblockmessageを構築していきます。
blockを組み合わせる感じがコンポーネントを組み合わせてwebページを作る感じと似てるなって思いました。

以下Datepickerのblockの作り方です。
NewDatePickerBlockElementしたものをNewSectionBlockのAccessoryに設定してあげます。

main.go
func datepicker(userID string) slack.MsgOption {
    dateText := slack.NewTextBlockObject("plain_text", "date_sample", false, false)
    datePick := slack.NewDatePickerBlockElement("sample")
    dateSection := slack.NewSectionBlock(dateText, nil, slack.NewAccessory(datePick))

    return slack.MsgOptionBlocks(
        dateSection,
    )
}

最後にblock-kitのslackへの投稿方法です。
上でMsgOptionで返したものを第二引数にして、PostMessageメソッド(nlopes/slack)を使って表示させることができます。

main.go
picker := datepicker(message.User.ID)
if _, _, err := s.slackClient.PostMessage(message.Channel.ID, picker); err != nil {
    log.Print("[ERROR] Failed to post message")
}

はいできた!!

以上です。ちょうど12月3日午前3時になりました。あらかたの投稿は2日のうちに済ませてたから許してね!

<<追記>> 2019/12/10
google calendarと紐付ける実装を追記しました。
これからも小規模な改善はするかもしれませんが、一旦はこれで完成です!!