初めてのrubyでLineBotを使った秘書botを作ってみた

Linebotのトライアルが出てから数ヶ月。
超今更ですが、LineBot経由でgoogle calendar APIを叩いて遊んでみました。

サーバーサイドはもともとjavaでやってましたが、proxy経由でのアクセスがどうにもうまくできずにrubyにしてみました。
前から触ってみたかったしちょうどよかった

### 下準備（固定IPの用意）
Linebotは固定IPアドレスからのhttps接続が必要です。
無料で試す方法はいくつかありますが、今回はHeroku + fixieというプラグインを使います。

fixieを使用可能にすると、IPアドレスとproxyURLが取得できます。
LINE developerのServer IP WhitelistにfixieのIPアドレスを追加しましょう。
<img src="https://qiita-image-store.s3.amazonaws.com/0/118585/21c5ce7c-bc94-31f1-f964-1a0aa8620cb8.png" width="３２0">
取得したproxy経由でLINEサーバーにアクセスすることで、IPアドレスが固定化できるようです。
ただし500アクセス/月までだそうです。
### 下準備(LINEサーバからのcallback処理の設定）
同じくLINE developerでLINEサーバからのコールバック処理を受けつけるURLを設定します。
![160712-0008.png](https://qiita-image-store.s3.amazonaws.com/0/118585/21bf6726-cf54-0259-a3fe-f91653c977ec.png)

このエンドポイントをroutes.rbにも設定しておきます。

```ruby:routes.rb
Rails.application.routes.draw do
  post '/callback' => 'application#bot_call_back'
 end
```

### callback処理
LINEサーバからのcallback処理でJSONで返ってくるので、いい感じに処理してあげます。
アカウント追加時やメッセージ受取時で返ってくる値が異なります。
詳細は[BOT API Reference](https://developers.line.me/bot-api/api-reference#receiving_messages)参照。

```ruby:application_controller.rb
  def bot_call_back
    # レスポンスから必要な情報を取得
    response = JSON.parse(request.body.read)
    result = response['result']
    content = result[0]['content']
    op_type = content['opType']
    from_arr = [content['from']] #midは配列にする
    content_text = content['text']

    # 友達追加時の処理
    # op_type=4の場合：アカウント追加時
    # op_type=8の場合：アカウントブロック時
    if op_type.present? && op_type == 4
      @mids = content['params']
      profile = user_profile(@mids)
      display_name = profile['contacts'][0]['displayName']

    else
      # メッセージ受取処理
  end

```

### メッセージ送信
メッセージを送信する場合は、[https://trialbot-api.line.me/v1/events](https://trialbot-api.line.me/v1/events)にPOSTするだけです。

```ruby:line_module.rb
  # メッセージ送信処理
  #:@param[String[]] mid_array
  #:@param[String] content_text
  #:@raise[] 送信失敗時エラー
  def send_message(mid_arr, content_text)
    target_url = Settings.LINE_ENDPOINT_EVENTS
    content = Content.new({content_type:1, to_type:1, text:content_text}) #=>content_type、to_typeは固定値
    post_data = Messages.new({to:mid_arr, content:content})
    begin
      response = RestClient.post(target_url, post_data.to_json, HEADERS)
      result = JSON.parse(response)
    rescue => e
      raise e
    end
  end
```

httpのHEADERには下記を設定しましょう。
Content-Type: application/json; charser=UTF-8
X-Line-ChannelID: Channel ID
X-Line-ChannelSecret: Channel secret
X-Line-Trusted-User-With-ACL: Channel MID

この情報はLINE developerに記載してあります。
![160713-0001.png](https://qiita-image-store.s3.amazonaws.com/0/118585/d635725a-de2f-1306-944e-e7a372cf945c.png)

てな感じで他にも画像やスタンプを送信できたりしますが、今回主に使ったところはこんな感じ。

### 機能一覧
今回はgoogleカレンダーの情報を教えてくれる簡易秘書を作ってみました。
下記QRを読み込めば使えますが、googleAPIの認証結果（refresh token)がDBに格納されますので個人情報が気になる方はご遠慮ください。
（トライアルなので50人まで＋fixieのアクセス数制限あり）
<img src="https://qiita-image-store.s3.amazonaws.com/0/118585/684b927a-c375-3d28-112a-81ed55eb8b34.png" width="160">
秘書といえばダークナイトのアルフレッド・・・

- google認証  
botアカウントを追加すると、google認証URLが送られてきます。
認証するとエラー画面に遷移してしまいますので、ブラウザ閉じて何か問いかけてみてください。  
<img src="https://qiita-image-store.s3.amazonaws.com/0/118585/f700bed4-b7a8-0751-fdc1-590b383f87ba.png" width="200">  

- 予定確認、空き時間調査
「明日の予定」や「今週の空き時間」などの問いかけに反応します。
<img src="https://qiita-image-store.s3.amazonaws.com/0/118585/bf380159-fab9-2115-bd26-045213e0dc3a.png" width="200">
カレンダーを共有している人の予定も取得できます
<img src="https://qiita-image-store.s3.amazonaws.com/0/118585/d760d48b-9940-d33c-342e-d795655c7689.png" width="200">
日付や人名についてはgooの固有表現抽出APIから判定しています。

共有している人と共通で空いてる時間帯を抽出し、「どの日時で登録しますか？」みたいなメニュー提示までしたいところです。

### ここがイケてない
今回のはまりポイントはjavaでのproxy経由がめんどくさかったこと（だからrubyに乗り換えた）の他に、google認証結果とLINEアカウントの紐付け方法です。

google認証結果には当然ながら、LINEの情報は含まれないので下記のように非常に煩雑な処理となっています。
1. bot追加→google認証ページにアクセス
2. 認証結果を仮ユーザとしてDBに格納
3. google認証後、botに何かつぶやくと認証したメルアドを求められる
4. 認証に使ったメルアドとLINEのmidを紐付けてDBに本ユーザとして格納。
以後、LINEのmidからgoogle認証のrefresh_tokenを取得してカレンダーへアクセス。

もっと簡単にできないかしら。。
そもそもgoogle認証結果ってDBに格納して良いんでしょうか・・・
### 参考ページ
[LINE developer](https://developers.line.me/)
[LINE BOT をとりあえずタダで Heroku で動かす](http://qiita.com/yuya_takeyama/items/0660a59d13e2cd0b2516)
[HOWTO access the Google Calendar API with Ruby](http://readysteadycode.com/howto-access-the-google-calendar-api-with-ruby)