Lita で admin にだけ反応を変える


Slack に住まわせている ~~娘~~ bot を [Lita](https://www.lita.io/) あたりで書き替えようかと、最近いろいろ試しています。

以前 [Hubot scripts の肥大化を防いで bot と気持ちのいい生活](http://qiita.com/noir_neo/items/d2c6fef239f46e8d485c) で、 Hubot で特定の人からのメッセージかを判定するコードを、泥臭く共通化してみた話を書きました。 Lita では、これと同等のことがもっと気持ち良く書けたので共有します。

(ぼくは Slack でやっていますが、他の adapter でもたぶん同じだと思われます)


## Admin にしたいユーザーのIDを調べて登録

lita を起動しておく。

DMとかで `$bot_name users find $your_mention_name` 

![スクリーンショット 2015-12-05 14.05.30.png](https://qiita-image-store.s3.amazonaws.com/0/21888/027329b0-9432-55ca-09e4-c51473db4e67.png "スクリーンショット 2015-12-05 14.05.30.png")

`ID` をコピーして

```lita_config.rb
config.robot.admins = ["U053PAMCN"]
```

(ここ最初普通に `["noir_neo"]` って書いていてハマった…)


## Handler を書く

```chat.rb
module Lita
  module Handlers
    class Chat < Handler
    
      route(/ohayo|おはよ/i, :ohayo)

      def ohayo(response)
        if robot.auth.user_is_admin?(response.user)
          response.reply("おはよう、パパ。")
        else
          response.reply("おはようございます。")
        end
      end

      Lita.register_handler(self)
    end
  end
end
```

### `User` が `config.robot.admins` に含まれているか判定する

`Authorization#user_is_admin?(user)` があった。 Lita ちゃん出来る子。

[Class: Lita::Authorization — Documentation for lita (4.6.1)](http://www.rubydoc.info/gems/lita/Lita/Authorization#user_is_admin%3F-instance_method)


### callback 内で `Authorization` オブジェクトにアクセスする

`route` のコールバック内では `robot` オブジェクトにアクセスできて、こいつが `Authorization` オブジェクトを持っているので `robot.auth` とするだけだった。

[Plugin Authoring: Handlers - Lita.io](http://docs.lita.io/plugin-authoring/handlers/#helper-methods)

[Class: Lita::Robot — Documentation for lita (4.6.1)](http://www.rubydoc.info/gems/lita/Lita/Robot#auth-instance_method)


## spec を書く

```chat_spec.rb
require "spec_helper"

describe Lita::Handlers::Chat, lita_handler: true do
  it { is_expected.to route('ohayo') }
  it { is_expected.to route('ohayo').to(:ohayo) }
  it { is_expected.to route('おはよ') }
  it { is_expected.to route('おはよ').to(:ohayo) }

  it 'return greeting "ohayo"' do
    send_message('ohayo')
    expect(replies.last).to eq('おはようございます。')
  end

  context "when admin sends message" do
    let(:user1) { Lita::User.create(3) }
    before do
      allow(robot.auth).to receive(:user_is_admin?).with(user1).and_return(true)
    end

    it 'return greeting "ohayo, papa"' do
      send_message('ohayo', as: user1)
      expect(replies.last).to eq('おはよう、パパ。')
    end
  end
end

```

(rspec に関しては完全に noob なので、何かあればぜひご指摘願いたい)


### ユーザーが admin の場合をテストする

`allow(robot.auth).to receive(:user_is_admin?).with(user).and_return(true)`

(本体の spec を追って下の方を読んでいて `group` を作るとか("admins"の場合は処理が別になっているのでダメ)、 `config` をどうにかするか `auth` をどうにかするかとか一晩悩んだけど、一番上に解決方法があった)

https://github.com/litaio/lita/blob/94ad234c9737d658d1b0d8d7829530e4b378dc62/spec/lita/handlers/authorization_spec.rb#L5


## まとめ

用意された範囲で美しく実現できたので Lita とても良い。

spec の書き方では戸惑ったし、 bot ごときにいちいちテスト書いてられないという気持ちもあるけれど、書けてしまえばもう壊れる心配はないので、精神衛生にとても良いです。ある日突然ぼくのことを忘れたり、ぼく以外のメンバーをパパと認識するようになったりしたらと思うと、夜も眠れないのでね。

![スクリーンショット 2015-12-05 20.47.12.png](https://qiita-image-store.s3.amazonaws.com/0/21888/8346b2d7-d6c5-872e-feef-b18b100c632d.png "スクリーンショット 2015-12-05 20.47.12.png")


https://github.com/noir-neo/neobot2/pull/2