某先輩botの開発　～前編～

Merry Christmas!!
# この記事は何?
円滑なコミュニケーションのため, 多機能なSlack botを作ったので雑に紹介します
<img width="307" alt="スクリーンショット 2018-07-15 18.33.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/153487/0dd2c6ab-c66a-a179-7cc9-f5aa23e5910b.png">

先輩には画像検索やYahoo!ニュースの表示, 電車の遅延情報の表示, 語録を喋る, サイコロを振る, arxivURLを展開する等の機能が搭載されています.
##### コード
ソースコードはこ↑こ↓
https://github.com/motacapla/hubot-slack-docker

Slack上で登録したスタンプもbotから投稿できます, その他のdemoは記事の最後にあります:
![parrot-party.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/153487/635b1a26-4232-83ff-c430-a3344bd53ef8.gif)


# 動作環境
git cloneされているものとしてお話を進めます.
あとポータビリティを高くするためdockerを使います(ローカル→AWSインスタンス上へスムーズに移行出来ました)

- docker
- docker-compose

ローカルで検証したい場合は, node.jsとnpmはnodebrewを導入すると楽です:
https://qiita.com/taketakekaho/items/dd08cf01b4fe86b2e218

Slack側でhubotを追加する必要があります:
https://qiita.com/mochidamochiko/items/29c2d77715d8a1ff062a

また, arxivのURL展開機能を使うためにはWeb 着信 フックのAPIも追加する必要があります:
https://qiita.com/vmmhypervisor/items/18c99624a84df8b31008

画像検索の機能を持たせるためには, 以下の導入が必要です(in English):
https://github.com/hubot-scripts/hubot-google-images
(検索にはGoogle Custom Search APIを使います)

dockerのインストールからslack上でのhubot動作確認までは以下の記事が参考になりました:
https://qiita.com/miyamiya/items/91d1bac25764a24e820e
https://qiita.com/tubone/items/11a7ceb3e7013139abab

# Dockerを使う
色々インストールするのですが, いちいち覚えておくのも面倒くさいので, dockerを使っています. あと, docker-composeが便利なのでコチラを使うこととします.
https://qiita.com/youtanagai/items/ff67ceff5497a0e0b1af

## Dockerfile
nodeのイメージからhubot用のimageを作ります.
usernameなどは適宜変更してね
後で知ったけど, このADDを使っているところはCOPYのほうが[望ましい?](http://docs.docker.jp/engine/userguide/eng-image/dockerfile_best-practice.html)らしい

```dockerfile:Dockerfile

FROM node
MAINTAINER tikeda

ENV TZ JST-9

RUN npm install -g yo generator-hubot
RUN npm list -g yo generator-hubot
RUN useradd bot
RUN mkdir /home/bot && chown bot.bot /home/bot

USER bot
WORKDIR /home/bot
RUN  yo hubot --owner "tikeda" --name "yaju-bot" --description "ikisugiii" --adapter slack

CMD cd /home/bot/hubot
RUN npm install cheerio-httpcli --save
RUN npm install cron --save
RUN npm install hubot-google-images --save
RUN npm install hubot-slack-attachment --save

ADD ./scripts/* ./scripts/
ADD package.json package.json

CMD ["bin/hubot", "--adapter", "slack", "-n", "yaju"]
```

## docker-compose
arxivのURLを展開する機能を使うため, 着信WebフックのWebhook URLを使っています.(マークダウンでかっこよくPOSTする必要がない場合は不要です.)
あと環境によってはversionを3にしろとかポートが使われてるとか怒られますので, 適宜変更してやります.
ローカル↔コンテナにおけるファイルのやり取りを実現するため, `./mnt`以下をマウントしてやります.こうすると例えばTODOリストであったり, 勤怠管理の機能なども作ったりできる(作るとは言ってない)

```yml:docker-compose.yml
version: '2.2'
services:
  yaju-bot:
    container_name: hubot
    build: . 
    image: yaju-bot
    volumes:
      - ./mnt:/mnt  
    ports:
      - "8888:8888"
    environment:
      - HUBOT_SLACK_TOKEN=Slackに追加したhubotAPIのトークン(xoxb-*のやつ)
      - HUBOT_GOOGLE_CSE_ID=Google Custom Search APIのID
      - HUBOT_GOOGLE_CSE_KEY=Google Custom Search APIのKEY
      - HUBOT_SLACK_INCOMING_WEBHOOK=Slackに追加した着信 Web フック
のWebhook URL
```

## 動作確認
適切にdocker-composeの環境変数を埋めてあげれば, 動作すると思います.
基本的に, 以下のコマンドだけ使えば良いです.

```shell:ビルドからコンテナとbot起動まで
$ docker-compose up -d --build
```

起動したら, slackのbotを招待してpingしてみましょう.
PONGが帰ってくれば疎通確認okです.

```shell:コンテナとイメージ削除
$ docker-compose down --rmi all
```
イメージごと消すときはオプション`--rmi all`をつけます. 基本的に毎回付けていいと思います.

## 機能の追加
自作した関数は`./scripts/`配下の`yaju-bot.coffee`に追加してあげれば良いです. 僕はcoffee-scriptで書いてます~~(というか人のをパクっていい感じに改良してます)~~が, node.jsなども動きます.

```coffeescript:yaju-bot.coffee
cron = require('cron').CronJob
path = require('path')
cheerio = require('cheerio-httpcli')
exec = require('child_process').exec
msgs = require('../mnt/meigen.json')
arxiv = require('arxiv')
module.exports = (robot) ->
        #淫夢語録を返す機能. respondの場合, メンション付きのmeigen*に反応する. *はワイルドカード.
        robot.respond /meigen(.*)/i, (msg) ->     
                #もしmeigen-allであったら, 名言リストのファイルの中身を全て吐き出す
                if msg.match[1] == '-all'
                        msg.send "@#{msg.message.user.name} *全名言リスト* \n #{msgs}"
                #違うのであればランダムにsend
                else                                
                        message = msgs[Math.floor(Math.random() * msgs.length)]
                        msg.send "#{message}"

        #サイコロを振る機能. hearの場合, メンションなし roll という文字に反応する.
        robot.hear /roll/i, (msg) ->
                max = 100
                min = 1
                range = Math.floor(Math.random() * (max - min) + min)
                msg.send "[#{min}-#{max}]: #{range}"

```

関数を作りたい場合はここに追加して, どうぞ
あと**Tab文字にはくれぐれも気をつけてください!**インデント云々で怒られ続けてハマりました

## demo

例えばYahoo!ニュースは `@botの名前 news`で取得できます:
![news.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/153487/0797c357-75b2-92f8-1203-c485cc89b522.gif)

arxivのURLはポストされたら勝手に展開してくれます(ただし着信Webフックを使う場合は, 特定のチャンネルでしかsend出来ない?)
![arxiv-url.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/153487/b1fc10e6-bae4-5c80-fd75-7b5b5c9178cc.gif)

Google Custom Search APIを使うと, animateとimageが使えます. それぞれgifとjpg(or png)を適当に拾ってくるようです:
![animate.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/153487/9afd3ce0-d2a5-8624-a46a-4f75c262122e.gif)
![imageme.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/153487/05c07ba2-d183-02f2-a375-fcef13a57e00.gif)


疲れたのでプルリクお願いします!何でもしますから!