Go 言語で Mattermost Bot を作成する


法政大学情報科学部 2 年の阿部哲也です。
今回は大好きな Go 言語で Mattermost の BOT を作成してみました。

# Mattermost とは

Mattermost (マターモスト) とは、オープンソースのセルフホスティング式のチャットツール。

自分で構築する Slack みたいな感じ！

# Mattermost を Docker compose で構築

docker-compose が導入されていることを確認します。

```
 >> docker-compose -v
docker-compose version 1.16.1, build 6d1ac21
```

git clone で mattermost をクローンします。

```
git clone https://github.com/mattermost/mattermost-docker.git
```

起動します。

```
cd mattermost-docker
docker-compose up -d
```

なにも設定を変えていない場合は、http://localhost で起動を確認できます。
私は VMware (IP: 192.168.202.129) で構築したので、http://192.168.202.129 で確認できました！

# Mattermost の設定

 - 日本語に設定します。

左上の三本線 → [Account Settings] → [Display] → [Language] の Edit → 日本語を選びます。

 - 内部通信を許可します。
 
左上の三本線 → [システムコンソール] → [環境] → [開発者]
[信用されていない内部通信を許可する] に以下を追加します。

```
127.0.0.1 localhost 自分のIP
```
自分の場合は、

```
127.0.0.1 localhost 192.168.202.129
```
のように設定しました。

 - スラッシュコマンドの有効化

左上の三本線 → [統合機能] → [スラッシュコマンドを追加する]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1773603/6f4da44a-4d9a-c417-2dfb-cf26141ba208.png)

[更新する]で操作を終了します。

# Go 言語で簡単な BOT を作成する

```
package main

import (
	"fmt"
	"net/http"
)

//slashコマンドを受け付ける
func slash(w http.ResponseWriter,r *http.Request) {
	text := r.FormValue("text")
	fmt.Fprintf(w,"hello %v",text)
}

func main() {
	http.HandleFunc("/slash",slash)
	http.ListenAndServe(":8090",nil)
}
```

/slash hogehoge を打つことで、Mattermost から、http://192.168.202.129:8090/slash/hogehoge に POST される。

Go 言語が hogehoge をパラメータ名として受け取り、それを printf で、mattermost で表示される。

という流れで、Mattermost で表示されます。

# Bot を作成

 - Bot の作成を有効化します

[システムコンソール] → [統合機能] → [Botアカウント]

Botアカウントの作成を有効にするを有効

 - BOT を作成

[統合機能] → [Botアカウント] → [Botアカウントを追加する]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1773603/afbcaefe-0153-5f47-9323-7d590a907b27.png)

更新するを押して終了

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1773603/50ac6916-ef82-fea9-679c-288d31709e51.png)


終了する前に、トークンを控えておくことが大切！

 - チャンネル ID を取得

チャンネル名の右の下矢印 → 情報を表示する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1773603/b1575ea0-533f-9100-8de5-615c4cb7084a.png)

URL の下に小さく ID が載っています。

この時点で、Bot が正しく動作するのか確かめます。
コマンドライン上で以下を入力します。

```
BODY='{
  "channel_id": "1ngefhpjojyabd9fc7n8twt3xh",
  "message": "Hello!"
}'

curl -i \
  -H 'Authorization: Bearer jmkk43ic3ib3tenmhycbfj7jre' \
  -H 'Content-Type: application/json' \
  -d "$BODY" \
  --trace-ascii - http://192.168.202.129:80/api/v4/posts
```

channel_id には、さっき確認したチャンネル IDを、Authorization には、Bot のトークンを入力してください。
Bearer は消さないように注意！

うまくいくと以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1773603/1003297b-7038-5962-b8ee-c7ee9ac67013.png)


# Go 言語でプログラムの作成

```
package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"bytes"
	"os"
	"strings"
	"encoding/json"
)

// アクセストークン、URL を定義
const ACCESSTOKEN = "Bearer jmkk43ic3ib3tenmhycbfj7jre"
const ENDPOINT = "http://192.168.202.129:80/api/v4/posts"

type BODY struct {
	ChannelId string `json:"channel_id"`
	Message string `json:"message"`
}

func HTTPPost(mes string) {

	//debug用
	debug := strings.Split(mes,"_")[0]

	//BODYの作成
	requestBody := new(BODY)
	requestBody.ChannelId = "1ngefhpjojyabd9fc7n8twt3xh"
	requestBody.Message = mes

	// ボディをJSONに変換
	json_body, _ := json.Marshal(requestBody)

	//リクエストを作成する
	req, _ := http.NewRequest("POST", ENDPOINT, bytes.NewBuffer(json_body))
	req.Header.Set("Authorization", ACCESSTOKEN)
	req.Header.Set("Content-Type", "application/json")

	//リクエストを送信
	client := new(http.Client)
	resp,err := client.Do(req)

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	//デバッグ用 POSTの内容を確認
	if debug=="debug" {
		//リクエストの内容確認
		dump, _ := httputil.DumpRequestOut(req, true)
		fmt.Printf("%s", dump)

		//POST の内容を確認
		dumpResp, _ := httputil.DumpResponse(resp, true)
		fmt.Printf("%s", dumpResp)
	}
}

//slashコマンドを受け付ける
func slash(w http.ResponseWriter,r *http.Request) {
	text := r.FormValue("text")
	//fmt.Fprintf(w,"hello %v",text)

	//http postする
	HTTPPost(text)
}

func main() {
	http.HandleFunc("/slash",slash)
	http.ListenAndServe(":8090",nil)
}
```

ずっと 403 エラーが出ていました。以下にまとめました。

https://qiita.com/AbeTetsuya20/items/7d7991990b3186263e80

GitLab と連携した Bot を現在作成しています。

# 参考

https://qiita.com/yyoshiki41/items/fc878494e19b9de93d56