lita-hipchat 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: