ぼくのさいきょうのslack bot

この記事は[東京理科大学 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/tokyo_university_of_science)の12/2の記事です。
昨日は[@piffett](https://qiita.com/piffett)による[apt-getとaptの使い分け](https://qiita.com/piffett/items/a8e3ea4cd6b7bd14f0f0)でした。

こんにちは。[にっし〜](https://twitter.com/nishinishi172)です。
ここではGoでslack botを作る話を書きます。

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

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

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

１つずつ見ていきます

### 1, message_actionへの対応
自分がslack botを狂ったように作っていた1年前は主に2つの選択肢がありました。
slash commandかbotとの対話か、です。しかしながらworkspaceが大きい場合、slash commandもたくさんあるし、botもたくさん入ってるし、で自分で作ったものでも使い方・botの名前を忘れるということが発生していました。
そこで、今回は[actions](https://api.slack.com/interactivity/actions)を使用することにしました。
![actions_ui_preview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178746/86e272be-850d-cfbc-3d37-20b478450ced.png)
actionsであれば、勉強会の開催告知スレから直接開いてもらうこともできるし、この方法が最善だと考えました。
shiimaxxさんのものではbotとの対話に反応するように実装されていたので、次のようなコードを追記することでactionsに対応させました。

```go:main.go
else if message.Type == "message_action" {
...
}
```
簡単にactionsに対応させることができました。
![スクリーンショット 2019-12-02 9.20.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178746/cb9ba8b8-b2cf-c43e-a6ec-659c2df61438.png)

### 2, Datepickerの実装
Datepickerの実装には新しい(2019/2~)UI フレームワークであるBlock Kitが必要です。
公式が[ドキュメント](https://api.slack.com/reference/block-kit/block-elements#datepicker)を用意してくれている他、使っているライブラリ(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に設定してあげます。

```go: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)を使って表示させることができます。

```go: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")
}
```

はいできた！！
![スクリーンショット 2019-12-03 2.59.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178746/1526bede-648c-d68c-f5f5-d98fa7344e2e.png)

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


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