lita-hipchat 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 161a81fd8834b27403dfd7e86aa4b0b733e099bd
4
+ data.tar.gz: 7904f55d5dcc2d0731673f93ba787c9db8f5d1be
5
+ SHA512:
6
+ metadata.gz: a2c21e123f3b466bc7ebc355bcc3fc91d47c2d775b10729543e12a0f0ab5635cee9ab3c34e820897d34b8f66052b513e09928a07fbb08b05afb339d0bab4a986
7
+ data.tar.gz: fd312cce8cd98d536fbf8d009d7613b5c85daaa56611023d32293a40f111c8095eb36ce937f1eaafc83b706d17eb239fb5aa6d10c937588e32df0b1065041abd
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ lita_config.rb
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ script: bundle exec rspec
5
+ before_install:
6
+ - gem update --system
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # lita-hipchat
2
+
3
+ [![Build Status](https://travis-ci.org/jimmycuadra/lita-hipchat.png)](https://travis-ci.org/jimmycuadra/lita-hipchat)
4
+ [![Code Climate](https://codeclimate.com/github/jimmycuadra/lita-hipchat.png)](https://codeclimate.com/github/jimmycuadra/lita-hipchat)
5
+ [![Coverage Status](https://coveralls.io/repos/jimmycuadra/lita-hipchat/badge.png)](https://coveralls.io/r/jimmycuadra/lita-hipchat)
6
+
7
+ **lita-hipchat** is an adapter for [Lita](https://github.com/jimmycuadra/lita) that allows you to use the robot with [HipChat](https://www.hipchat.com/).
8
+
9
+ ## Installation
10
+
11
+ Add lita-hipchat to your Lita instance's Gemfile:
12
+
13
+ ``` ruby
14
+ gem "lita-hipchat"
15
+ ```
16
+
17
+ ## Configuration
18
+
19
+ Values for all of the following attributes can be found on the "XMPP/Jabber info" page of the account settings on the HipChat website. A JID (Jabber ID) looks like "12345_123456@chat.hipchat.com".
20
+
21
+ ### Required attributes
22
+
23
+ * `jid` (String) - The JID of your robot's HipChat account. Default: `nil`.
24
+ * `password` (String) - The password for your robot's HipChat account. Default: `nil`.
25
+
26
+ ### Optional attributes
27
+
28
+ * `debug` (Boolean) - If `true`, turns on the underlying Jabber library's (xmpp4r) logger, which is fairly verbose. Default: `false`.
29
+ * `rooms` (Symbol, Array<String>) - An array of room JIDs that Lita should join upon connection. Can also be the symbol `:all`, which will cause Lita to discover and join all rooms. Default: `nil` (no rooms).
30
+ * `muc_domain` (String) - The XMPP Multi-User Chat domain to use. Default: `"conf.hipchat.com"`.
31
+
32
+ **Note: You must set the robot's name to the value shown as "Room nickname" on the XMPP settings page.**
33
+
34
+ There's no need to set `config.robot.mention_name` manually. The adapter will load the proper mention name from the XMPP roster upon connection.
35
+
36
+ ### Example
37
+
38
+ ``` ruby
39
+ Lita.configure do |config|
40
+ config.robot.name = "Lita Bot"
41
+ config.robot.adapter = :hipchat
42
+ config.adapter.jid = "12345_123456@chat.hipchat.com"
43
+ config.adapter.password = "secret"
44
+ config.adapter.debug = false
45
+ config.adapter.rooms = :all
46
+ config.adapter.muc_domain = "conf.hipchat.com"
47
+ end
48
+ ```
49
+
50
+ ## License
51
+
52
+ [MIT](http://opensource.org/licenses/MIT)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,67 @@
1
+ module Lita
2
+ module Adapters
3
+ class HipChat < Adapter
4
+ class Callback
5
+ attr_reader :robot, :roster
6
+
7
+ def initialize(robot, roster)
8
+ @robot = robot
9
+ @roster = roster
10
+ end
11
+
12
+ def private_message(client)
13
+ client.add_message_callback do |m|
14
+ next if m.type == :error || m.body.nil?
15
+ user = user_by_jid(m.from)
16
+ source = Source.new(user)
17
+ message = Message.new(robot, m.body, source)
18
+ message.command!
19
+ Lita.logger.debug("Dispatching PM to Lita from #{user.id}.")
20
+ robot.receive(message)
21
+ end
22
+ end
23
+
24
+ def muc_message(muc)
25
+ muc.on_message do |time, nick, text|
26
+ user = user_by_name(nick)
27
+ source = Source.new(user, muc.jid.bare.to_s)
28
+ message = Message.new(robot, text, source)
29
+ Lita.logger.debug(
30
+ "Dispatching message to Lita from #{user.id} in MUC #{muc.jid}."
31
+ )
32
+ robot.receive(message)
33
+ end
34
+ end
35
+
36
+ def roster_update
37
+ roster.add_update_callback do |old_item, item|
38
+ jid = item.attributes["jid"]
39
+ Lita.logger.debug("Updating record for user with ID: #{jid}.")
40
+ create_user(item.attributes)
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def create_user(user_data)
47
+ User.create(
48
+ user_data["jid"],
49
+ name: user_data["name"],
50
+ mention_name: user_data["mention_name"]
51
+ )
52
+ end
53
+
54
+ def user_by_jid(jid)
55
+ Lita.logger.debug("Looking up user with JID: #{jid}.")
56
+ create_user(roster[jid].attributes)
57
+ end
58
+
59
+ def user_by_name(name)
60
+ Lita.logger.debug("Looking up user with name: #{name}.")
61
+ jid = roster.items.detect { |jid, item| item.iname == name }.first
62
+ user_by_jid(jid)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,131 @@
1
+ require "lita/encoding_patches"
2
+ require "lita/adapters/hipchat/callback"
3
+
4
+ require "xmpp4r"
5
+ require "xmpp4r/roster/helper/roster"
6
+ require "xmpp4r/muc/helper/simplemucclient"
7
+ require "xmpp4r/muc/helper/mucbrowser"
8
+
9
+ module Lita
10
+ module Adapters
11
+ class HipChat < Adapter
12
+ class Connector
13
+ attr_reader :robot, :client, :roster
14
+
15
+ def initialize(robot, jid, password, debug: false)
16
+ @robot = robot
17
+ @jid = normalized_jid(jid, "chat.hipchat.com", "bot")
18
+ @password = password
19
+ @client = Jabber::Client.new(@jid)
20
+ if debug
21
+ Lita.logger.info("Enabling Jabber log.")
22
+ Jabber.debug = true
23
+ end
24
+ end
25
+
26
+ def jid
27
+ @jid.to_s
28
+ end
29
+
30
+ def connect
31
+ client_connect
32
+ load_roster
33
+ register_message_callback
34
+ send_presence
35
+ end
36
+
37
+ def join_rooms(muc_domain, rooms)
38
+ rooms.each do |room_name|
39
+ muc = Jabber::MUC::SimpleMUCClient.new(client)
40
+ room_jid = normalized_jid(room_name, muc_domain, robot.name)
41
+ mucs[room_jid.bare.to_s] = muc
42
+ register_muc_message_callback(muc)
43
+ Lita.logger.info("Joining room: #{room_jid}.")
44
+ muc.join(room_jid)
45
+ end
46
+ end
47
+
48
+ def list_rooms(muc_domain)
49
+ Lita.logger.debug("Querying server for list of rooms.")
50
+ browser = Jabber::MUC::MUCBrowser.new(client)
51
+ browser.muc_rooms(muc_domain).map { |jid, name| jid.to_s }
52
+ end
53
+
54
+ def message_jid(user_jid, strings)
55
+ strings.each do |s|
56
+ Lita.logger.debug("Sending message to JID #{user_jid}: #{s}")
57
+ message = Jabber::Message.new(user_jid, s)
58
+ message.type = :chat
59
+ client.send(message)
60
+ end
61
+ end
62
+
63
+ def message_muc(room_jid, strings)
64
+ muc = mucs[room_jid]
65
+ strings.each do |s|
66
+ Lita.logger.debug("Sending message to MUC #{room_jid}: #{s}")
67
+ muc.say(s)
68
+ end if muc
69
+ end
70
+
71
+ def mucs
72
+ @mucs ||= {}
73
+ end
74
+
75
+ def set_topic(room_jid, topic)
76
+ muc = mucs[room_jid]
77
+ if muc
78
+ Lita.logger.debug("Setting topic for MUC #{room_jid}: #{topic}")
79
+ muc.subject = topic
80
+ end
81
+ end
82
+
83
+ def shut_down
84
+ Lita.logger.info("Disconnecting from HipChat.")
85
+ client.close
86
+ end
87
+
88
+ private
89
+
90
+ def send_presence
91
+ Lita.logger.debug("Sending initial XMPP presence.")
92
+ client.send(Jabber::Presence.new(:chat))
93
+ end
94
+
95
+ def client_connect
96
+ Lita.logger.info("Connecting to HipChat.")
97
+ client.connect
98
+ Lita.logger.debug("Authenticating with HipChat.")
99
+ client.auth(@password)
100
+ end
101
+
102
+ def register_message_callback
103
+ Callback.new(robot, roster).private_message(client)
104
+ end
105
+
106
+ def register_muc_message_callback(muc)
107
+ Callback.new(robot, roster).muc_message(muc)
108
+ end
109
+
110
+ def load_roster
111
+ Lita.logger.debug("Loading roster.")
112
+ @roster = Jabber::Roster::Helper.new(client, false)
113
+ Callback.new(robot, roster).roster_update
114
+ roster.get_roster
115
+ roster.wait_for_roster
116
+ robot.mention_name = roster[jid].attributes["mention_name"]
117
+ end
118
+
119
+ def normalized_jid(jid, domain, resource)
120
+ jid = Jabber::JID.new(jid)
121
+ jid.resource = resource
122
+ unless jid.node
123
+ jid.node = jid.domain
124
+ jid.domain = domain
125
+ end
126
+ jid
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,70 @@
1
+ require "lita"
2
+ require "lita/adapters/hipchat/connector"
3
+
4
+ module Lita
5
+ module Adapters
6
+ class HipChat < Adapter
7
+ require_configs :jid, :password
8
+
9
+ attr_reader :connector
10
+
11
+ def initialize(robot)
12
+ super
13
+
14
+ set_default_config_values
15
+
16
+ @connector = Connector.new(
17
+ robot,
18
+ config.jid,
19
+ config.password,
20
+ debug: config.debug
21
+ )
22
+ end
23
+
24
+ def run
25
+ connector.connect
26
+ connector.join_rooms(config.muc_domain, rooms)
27
+ sleep
28
+ rescue Interrupt
29
+ shut_down
30
+ end
31
+
32
+ def send_messages(target, strings)
33
+ if target.room
34
+ connector.message_muc(target.room, strings)
35
+ else
36
+ connector.message_jid(target.user.id, strings)
37
+ end
38
+ end
39
+
40
+ def set_topic(target, topic)
41
+ connector.set_topic(target.room, topic)
42
+ end
43
+
44
+ def shut_down
45
+ connector.shut_down
46
+ end
47
+
48
+ private
49
+
50
+ def config
51
+ Lita.config.adapter
52
+ end
53
+
54
+ def rooms
55
+ if config.rooms == :all
56
+ connector.list_rooms(config.muc_domain)
57
+ else
58
+ Array(config.rooms)
59
+ end
60
+ end
61
+
62
+ def set_default_config_values
63
+ config.debug = false if config.debug.nil?
64
+ config.muc_domain = "conf.hipchat.com" if config.muc_domain.nil?
65
+ end
66
+ end
67
+
68
+ Lita.register_adapter(:hipchat, HipChat)
69
+ end
70
+ end
@@ -0,0 +1,27 @@
1
+ # xmpp4r and REXML are bad and should feel bad.
2
+ # https://github.com/ln/xmpp4r/issues/3#issuecomment-1739952
3
+ require 'socket'
4
+ class TCPSocket
5
+ def external_encoding
6
+ Encoding::BINARY
7
+ end
8
+ end
9
+
10
+ require 'rexml/source'
11
+ class REXML::IOSource
12
+ alias_method :encoding_assign, :encoding=
13
+ def encoding=(value)
14
+ encoding_assign(value) if value
15
+ end
16
+ end
17
+
18
+ begin
19
+ # OpenSSL is optional and can be missing
20
+ require 'openssl'
21
+ class OpenSSL::SSL::SSLSocket
22
+ def external_encoding
23
+ Encoding::BINARY
24
+ end
25
+ end
26
+ rescue
27
+ end
@@ -0,0 +1 @@
1
+ require "lita/adapters/hipchat"
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lita-hipchat"
3
+ spec.version = "0.0.1"
4
+ spec.authors = ["Jimmy Cuadra"]
5
+ spec.email = ["jimmy@jimmycuadra.com"]
6
+ spec.description = %q{A HipChat adapter for Lita.}
7
+ spec.summary = %q{A HipChat adapter for the Lita chat robot.}
8
+ spec.homepage = "https://github.com/jimmycuadra/lita-hipchat"
9
+ spec.license = "MIT"
10
+
11
+ spec.files = `git ls-files`.split($/)
12
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
13
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
14
+ spec.require_paths = ["lib"]
15
+
16
+ spec.add_runtime_dependency "lita", "~> 1.1"
17
+ spec.add_runtime_dependency "xmpp4r", "~> 0.5"
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "rake"
21
+ spec.add_development_dependency "rspec", ">= 2.14.0.rc1"
22
+ spec.add_development_dependency "simplecov"
23
+ spec.add_development_dependency "coveralls"
24
+ end
@@ -0,0 +1,110 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Adapters::HipChat::Callback do
4
+ subject { described_class.new(robot, roster) }
5
+
6
+ let(:robot) { double("Lita::Robot") }
7
+ let(:roster) do
8
+ double("Jabber::Roster::Helper", items: { "user_id" => roster_item })
9
+ end
10
+ let(:user) { double("Lita::User", id: "user_id") }
11
+ let(:source) { double("Lita::Source") }
12
+ let(:message) { double("Lita::Message") }
13
+ let(:roster_item) do
14
+ double("Jabber::Roster::RosterItem", attributes: {
15
+ "jid" => "user_id",
16
+ "name" => "Carl",
17
+ "mention_name" => "@Carl"
18
+ }, iname: "Carl")
19
+ end
20
+
21
+ before do
22
+ allow(roster).to receive(:[]).with("user_id").and_return(roster_item)
23
+ allow(Lita::User).to receive(:create).with(
24
+ "user_id",
25
+ name: "Carl",
26
+ mention_name: "@Carl"
27
+ ).and_return(user)
28
+ end
29
+
30
+ it "has a robot" do
31
+ expect(subject.robot).to eq(robot)
32
+ end
33
+
34
+ it "has a roster" do
35
+ expect(subject.roster).to eq(roster)
36
+ end
37
+
38
+ describe "#private_message" do
39
+ let(:client) { double("Jabber::Client") }
40
+ let(:jabber_message) do
41
+ double("Jabber::Message", type: :chat, from: "user_id", body: "foo")
42
+ end
43
+
44
+ before do
45
+ allow(client).to receive(:add_message_callback).and_yield(jabber_message)
46
+ end
47
+
48
+ it "sends the message to the robot with the proper source and body" do
49
+ allow(Lita::Source).to receive(:new).with(user).and_return(source)
50
+ allow(Lita::Message).to receive(:new).with(
51
+ robot,
52
+ "foo",
53
+ source
54
+ ).and_return(message)
55
+ expect(message).to receive(:command!)
56
+ expect(robot).to receive(:receive).with(message)
57
+ subject.private_message(client)
58
+ end
59
+
60
+ it "skips the message if it's an error type" do
61
+ allow(jabber_message).to receive(:type).and_return(:error)
62
+ expect(robot).not_to receive(:receive)
63
+ subject.private_message(client)
64
+ end
65
+
66
+ it "skips the message if the body is nil" do
67
+ allow(jabber_message).to receive(:body).and_return(nil)
68
+ expect(robot).not_to receive(:receive)
69
+ subject.private_message(client)
70
+ end
71
+ end
72
+
73
+ describe "#muc_message" do
74
+ let(:jid) { double("Jabber::JID", bare: "room_id") }
75
+ let(:muc) { double("Jabber::MUC::SimpleMUCClient", jid: jid) }
76
+
77
+ before do
78
+ allow(muc).to receive(:on_message).and_yield(nil, "Carl", "foo")
79
+ end
80
+
81
+ it "sends the message to the robot with the proper source and body" do
82
+ allow(Lita::Source).to receive(:new).with(
83
+ user,
84
+ "room_id"
85
+ ).and_return(source)
86
+ allow(Lita::Message).to receive(:new).with(
87
+ robot,
88
+ "foo",
89
+ source
90
+ ).and_return(message)
91
+ expect(robot).to receive(:receive).with(message)
92
+ subject.muc_message(muc)
93
+ end
94
+ end
95
+
96
+ describe "#roster_update" do
97
+ before do
98
+ allow(roster).to receive(:add_update_callback).and_yield(nil, roster_item)
99
+ end
100
+
101
+ it "finds/creates a user object for the roster item" do
102
+ expect(Lita::User).to receive(:create).with(
103
+ "user_id",
104
+ name: "Carl",
105
+ mention_name: "@Carl"
106
+ )
107
+ subject.roster_update
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,200 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Adapters::HipChat::Connector do
4
+ subject { described_class.new(robot, "user", "secret") }
5
+
6
+ let(:client) { double("Jabber::Client").as_null_object }
7
+ let(:robot) { double("Lita::Robot", name: "Lita" ) }
8
+
9
+ before { allow(subject).to receive(:client).and_return(client) }
10
+
11
+ it "sets the JID properly when only a node is supplied" do
12
+ subject = described_class.new(robot, "user", "secret")
13
+ expect(subject.jid).to eq("user@chat.hipchat.com/bot")
14
+ end
15
+
16
+ it "sets the JID properly when a node and domain are supplied" do
17
+ subject = described_class.new(robot, "user@example.com", "secret")
18
+ expect(subject.jid).to eq("user@example.com/bot")
19
+ end
20
+
21
+ it "sets the JID properly when a resource is supplied" do
22
+ subject = described_class.new(robot, "user@example.com/wrong", "secret")
23
+ expect(subject.jid).to eq("user@example.com/bot")
24
+ end
25
+
26
+ it "turns on the xmpp4r logger if debug: true is supplied" do
27
+ expect(Jabber).to receive(:debug=).with(true)
28
+ subject = described_class.new(robot, "user", "secret", debug: true)
29
+ end
30
+
31
+ describe "#connect" do
32
+ let(:presence) { double("Jabber::Presence") }
33
+ let(:roster) { double("Jabber::Roster::Helper").as_null_object }
34
+ let(:callback) { double("Lita::Adapters::HipChat::Callback") }
35
+
36
+ before do
37
+ allow(Jabber::Presence).to receive(:new).and_return(presence)
38
+ allow(Jabber::Roster::Helper).to receive(:new).with(
39
+ client,
40
+ false
41
+ ).and_return(roster)
42
+ allow(Lita::Adapters::HipChat::Callback).to receive(:new).and_return(
43
+ callback
44
+ )
45
+ allow(callback).to receive(:private_message)
46
+ allow(callback).to receive(:roster_update)
47
+ allow(robot).to receive(:mention_name=)
48
+ end
49
+
50
+ it "connects to HipChat" do
51
+ expect(subject.client).to receive(:connect)
52
+ subject.connect
53
+ end
54
+
55
+ it "authenticates with the supplied password" do
56
+ expect(subject.client).to receive(:auth).with("secret")
57
+ subject.connect
58
+ end
59
+
60
+ it "sends an initial presence of :chat" do
61
+ expect(Jabber::Presence).to receive(:new).with(:chat).and_return(presence)
62
+ expect(subject.client).to receive(:send).with(presence)
63
+ subject.connect
64
+ end
65
+
66
+ it "registers a message callback" do
67
+ expect(Lita::Adapters::HipChat::Callback).to receive(:new).with(
68
+ robot,
69
+ roster
70
+ ).and_return(callback)
71
+ expect(callback).to receive(:private_message).with(client)
72
+ subject.connect
73
+ end
74
+
75
+ it "loads a roster" do
76
+ expect(roster).to receive(:wait_for_roster)
77
+ subject.connect
78
+ end
79
+
80
+ it "assigns the robot's mention_name with info from the roster" do
81
+ allow(roster).to receive(:[]).with(subject.jid).and_return(
82
+ double("Jabber::Roster::RosterItem", attributes: {
83
+ "mention_name" => "LitaBot"
84
+ })
85
+ )
86
+ expect(robot).to receive(:mention_name=).with("LitaBot")
87
+ subject.connect
88
+ end
89
+ end
90
+
91
+ describe "#join rooms" do
92
+ let(:muc_domain) { "conf.hipchat.com" }
93
+ let(:rooms) { ["muc_1", "muc_2"] }
94
+ let(:muc_1) { double("Jabber::MUC::SimpleMUCClient").as_null_object }
95
+ let(:muc_2) { double("Jabber::MUC::SimpleMUCClient").as_null_object }
96
+ let(:callback) { double("Lita::Adapters::HipChat::Callback") }
97
+ let(:roster) { double("Jabber::Roster::Helper") }
98
+
99
+ before do
100
+ allow(Jabber::MUC::SimpleMUCClient).to receive(:new).with(
101
+ client
102
+ ).and_return(muc_1, muc_2)
103
+ allow(Lita::Adapters::HipChat::Callback).to receive(:new).and_return(
104
+ callback
105
+ )
106
+ allow(callback).to receive(:muc_message)
107
+ allow(subject).to receive(:roster).and_return(roster)
108
+ end
109
+
110
+ it "creates a SimpleMUCClient for each room" do
111
+ subject.join_rooms(muc_domain, rooms)
112
+ expect(subject.mucs).to eq(
113
+ "muc_1@conf.hipchat.com" => muc_1,
114
+ "muc_2@conf.hipchat.com" => muc_2,
115
+ )
116
+ end
117
+
118
+ it "registers a message callback for each room" do
119
+ expect(Lita::Adapters::HipChat::Callback).to receive(:new).with(
120
+ robot,
121
+ roster
122
+ ).and_return(callback)
123
+ expect(callback).to receive(:muc_message).with(muc_1)
124
+ expect(callback).to receive(:muc_message).with(muc_2)
125
+ subject.join_rooms(muc_domain, rooms)
126
+ end
127
+
128
+ it "joins each room" do
129
+ expect(muc_1).to receive(:join)
130
+ expect(muc_2).to receive(:join)
131
+ subject.join_rooms(muc_domain, rooms)
132
+ end
133
+ end
134
+
135
+ describe "#list_rooms" do
136
+ let(:browser) { double("Jabber::MUC::MUCBrowser") }
137
+
138
+ before do
139
+ allow(Jabber::MUC::MUCBrowser).to receive(:new).with(client).and_return(
140
+ browser
141
+ )
142
+ end
143
+
144
+ it "returns an array of room JIDs for the MUC domain" do
145
+ allow(browser).to receive(:muc_rooms).with("conf.hipchat.com").and_return(
146
+ "123_456@conf.hipchat.com" => "Room 1",
147
+ "789_012@conf.hipchat.com" => "Room 2"
148
+ )
149
+ expect(subject.list_rooms("conf.hipchat.com")).to eq([
150
+ "123_456@conf.hipchat.com",
151
+ "789_012@conf.hipchat.com"
152
+ ])
153
+ end
154
+ end
155
+
156
+ describe "#message_jid" do
157
+ let(:message_1) { double("Jabber::Message") }
158
+ let(:message_2) { double("Jabber::Message") }
159
+
160
+ it "sends the messages to the user" do
161
+ allow(Jabber::Message).to receive(:new).with("jid", "foo").and_return(
162
+ message_1
163
+ )
164
+ allow(Jabber::Message).to receive(:new).with("jid", "bar").and_return(
165
+ message_2
166
+ )
167
+ expect(message_1).to receive(:type=).with(:chat)
168
+ expect(message_2).to receive(:type=).with(:chat)
169
+ expect(client).to receive(:send).with(message_1)
170
+ expect(client).to receive(:send).with(message_2)
171
+ subject.message_jid("jid", ["foo", "bar"])
172
+ end
173
+ end
174
+
175
+ describe "#message_muc" do
176
+ it "sends the messages to the room" do
177
+ muc = double("Jabber::MUC::SimpleMUCClient")
178
+ allow(subject).to receive(:mucs).and_return("jid" => muc)
179
+ expect(muc).to receive(:say).with("foo")
180
+ expect(muc).to receive(:say).with("bar")
181
+ subject.message_muc("jid", ["foo", "bar"])
182
+ end
183
+ end
184
+
185
+ describe "#set_topic" do
186
+ it "sets the room's topic to the supplied message" do
187
+ muc = double("Jabber::MUC::SimpleMUCClient")
188
+ allow(subject).to receive(:mucs).and_return("jid" => muc)
189
+ expect(muc).to receive(:subject=).with("New topic")
190
+ subject.set_topic("jid", "New topic")
191
+ end
192
+ end
193
+
194
+ describe "#shut_down" do
195
+ it "closes the client connection" do
196
+ expect(subject.client).to receive(:close)
197
+ subject.shut_down
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,119 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Adapters::HipChat do
4
+ before do
5
+ Lita.config.adapter.jid = "jid"
6
+ Lita.config.adapter.password = "secret"
7
+ Lita.config.adapter.rooms = nil
8
+ Lita.config.adapter.muc_domain = nil
9
+ allow(Lita).to receive(:logger).and_return(double("Logger").as_null_object)
10
+ allow(described_class::Connector).to receive(:new).and_return(connector)
11
+ end
12
+
13
+ subject { described_class.new(robot) }
14
+
15
+ let(:robot) { double("Lita::Robot") }
16
+ let(:connector) { double("Lita::Adapters::HipChat::Connector") }
17
+
18
+ it "registers with Lita" do
19
+ expect(Lita.adapters[:hipchat]).to eql(described_class)
20
+ end
21
+
22
+ it "requires config.jid and config.password" do
23
+ Lita.instance_variable_set(:@config, nil)
24
+ expect(Lita.logger).to receive(:fatal).with(/jid, password/)
25
+ expect { subject }.to raise_error(SystemExit)
26
+ end
27
+
28
+ describe "#run" do
29
+ before do
30
+ allow(subject.connector).to receive(:connect)
31
+ allow(subject.connector).to receive(:join_rooms)
32
+ allow(subject).to receive(:sleep)
33
+ end
34
+
35
+ it "connects to HipChat" do
36
+ expect(subject.connector).to receive(:connect)
37
+ subject.run
38
+ end
39
+
40
+ it "joins rooms with a custom muc_domain" do
41
+ Lita.config.adapter.muc_domain = "foo.bar.com"
42
+ expect(subject.connector).to receive(:join_rooms).with(
43
+ "foo.bar.com",
44
+ anything
45
+ )
46
+ subject.run
47
+ end
48
+
49
+ it "joins all rooms when config.rooms is :all" do
50
+ all_rooms = ["room_1_id", "room_2_id"]
51
+ Lita.config.adapter.rooms = :all
52
+ allow(subject.connector).to receive(:list_rooms).with(
53
+ "conf.hipchat.com"
54
+ ).and_return(all_rooms)
55
+ expect(subject.connector).to receive(:join_rooms).with(
56
+ "conf.hipchat.com",
57
+ all_rooms
58
+ )
59
+ subject.run
60
+ end
61
+
62
+ it "joins rooms specified by config.rooms" do
63
+ custom_rooms = ["my_room_1_id", "my_room_2_id"]
64
+ Lita.config.adapter.rooms = custom_rooms
65
+ expect(subject.connector).to receive(:join_rooms).with(
66
+ "conf.hipchat.com",
67
+ custom_rooms
68
+ )
69
+ subject.run
70
+ end
71
+
72
+ it "sleeps the main thread" do
73
+ expect(subject).to receive(:sleep)
74
+ subject.run
75
+ end
76
+
77
+ it "disconnects gracefully on interrupt" do
78
+ expect(subject).to receive(:shut_down)
79
+ allow(subject).to receive(:sleep).and_raise(Interrupt)
80
+ subject.run
81
+ end
82
+ end
83
+
84
+ describe "#send_messages" do
85
+ it "sends messages to rooms" do
86
+ source = double("Lita::Source", room: "room_id")
87
+ expect(subject.connector).to receive(:message_muc).with(
88
+ "room_id",
89
+ ["Hello!"]
90
+ )
91
+ subject.send_messages(source, ["Hello!"])
92
+ end
93
+
94
+ it "sends private messages to users" do
95
+ user = double("Lita::User", id: "user_id")
96
+ source = double("Lita::Source", room: nil, user: user)
97
+ expect(subject.connector).to receive(:message_jid).with(
98
+ "user_id",
99
+ ["Hello!"]
100
+ )
101
+ subject.send_messages(source, ["Hello!"])
102
+ end
103
+ end
104
+
105
+ describe "#set_topic" do
106
+ it "sets a new topic for a room" do
107
+ source = double("Lita::Source", room: "room_id")
108
+ expect(subject.connector).to receive(:set_topic).with("room_id", "Topic")
109
+ subject.set_topic(source, "Topic")
110
+ end
111
+ end
112
+
113
+ describe "#shut_down" do
114
+ it "shuts down the connector" do
115
+ expect(subject.connector).to receive(:shut_down)
116
+ subject.shut_down
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,18 @@
1
+ require "simplecov"
2
+ require "coveralls"
3
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
4
+ SimpleCov::Formatter::HTMLFormatter,
5
+ Coveralls::SimpleCov::Formatter
6
+ ]
7
+ SimpleCov.start
8
+
9
+ require "lita-hipchat"
10
+ require "lita/rspec"
11
+
12
+ RSpec.configure do |config|
13
+ config.include Lita::RSpec
14
+
15
+ config.before do
16
+ allow(Lita).to receive(:logger).and_return(double("Logger").as_null_object)
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lita-hipchat
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jimmy Cuadra
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lita
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: xmpp4r
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: 2.14.0.rc1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: 2.14.0.rc1
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: coveralls
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: A HipChat adapter for Lita.
112
+ email:
113
+ - jimmy@jimmycuadra.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .travis.yml
120
+ - Gemfile
121
+ - README.md
122
+ - Rakefile
123
+ - lib/lita-hipchat.rb
124
+ - lib/lita/adapters/hipchat.rb
125
+ - lib/lita/adapters/hipchat/callback.rb
126
+ - lib/lita/adapters/hipchat/connector.rb
127
+ - lib/lita/encoding_patches.rb
128
+ - lita-hipchat.gemspec
129
+ - spec/lita/adapters/hipchat/callback_spec.rb
130
+ - spec/lita/adapters/hipchat/connector_spec.rb
131
+ - spec/lita/adapters/hipchat_spec.rb
132
+ - spec/spec_helper.rb
133
+ homepage: https://github.com/jimmycuadra/lita-hipchat
134
+ licenses:
135
+ - MIT
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.0.3
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: A HipChat adapter for the Lita chat robot.
157
+ test_files:
158
+ - spec/lita/adapters/hipchat/callback_spec.rb
159
+ - spec/lita/adapters/hipchat/connector_spec.rb
160
+ - spec/lita/adapters/hipchat_spec.rb
161
+ - spec/spec_helper.rb
162
+ has_rdoc: