sammcj-lita-xmpp 1.0.3

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b7dddd7dffe3f344d9176d78190eaf974645a927
4
+ data.tar.gz: 0bf9e9af2a0e2d47cadb91747869831779137b63
5
+ SHA512:
6
+ metadata.gz: 63f0dac7ce26f2b4ca8b27fc938d46cb17ec550badec2c00d0e68562e77691f175b8464943e2798b3a0994658fa2cd5ac3a383459669489e9dfc7293707f1bdd
7
+ data.tar.gz: 2bb048652ac839261dc4fdabe3ffaa2ae37d4f33353f743872b5af79ddb81f2678fb097106f2d68a16f5b24a408ec5dc95b525bb067179e402abe236b7dd9c2b
@@ -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
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ script: bundle exec rspec
5
+ before_install:
6
+ - gem update --system
7
+ notifications:
8
+ webhooks:
9
+ urls:
10
+ - https://lita-freenode.herokuapp.com/travis
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2013 Jimmy Cuadra
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,48 @@
1
+ # lita-xmpp
2
+
3
+ WIP, probably has some bugs.
4
+
5
+ **lita-xmpp** is an adapter for [Lita](https://github.com/jimmycuadra/lita) that allows you to use the robot with [HipChat](https://www.hipchat.com/).
6
+
7
+ ## Installation
8
+
9
+ Add lita-xmpp to your Lita instance's Gemfile:
10
+
11
+ ``` ruby
12
+ gem "lita-xmpp"
13
+ ```
14
+
15
+ ## Configuration
16
+
17
+
18
+ ### Required attributes
19
+
20
+ * `jid` (String) - The JID of your robot's account. Default: `nil`.
21
+ * `password` (String) - The password for your robot's account. Default: `nil`.
22
+
23
+ ### Optional attributes
24
+
25
+ * `debug` (Boolean) - If `true`, turns on the underlying Jabber library's (xmpp4r) logger, which is fairly verbose. Default: `false`.
26
+ * `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).
27
+ * `muc_domain` (String) - The XMPP Multi-User Chat domain to use.
28
+
29
+ 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.
30
+
31
+ ### Example
32
+
33
+ ``` ruby
34
+ Lita.configure do |config|
35
+ config.robot.name = "Lita Bot"
36
+ config.robot.adapter = :xmpp
37
+ config.adapter.jid = "12345_123456@myserver.com"
38
+ config.adapter.password = "secret"
39
+ config.adapter.debug = false
40
+ config.adapter.rooms = :all
41
+ config.adapter.muc_domain = "conf.myserver.com"
42
+ config.mention_name = "bot"
43
+ end
44
+ ```
45
+
46
+ ## License
47
+
48
+ [MIT](http://opensource.org/licenses/MIT)
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ require "lita/adapters/xmpp"
@@ -0,0 +1,78 @@
1
+ require "lita"
2
+ require "lita/adapters/xmpp/connector"
3
+
4
+ module Lita
5
+ module Adapters
6
+ class Xmpp < 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
+ connect_domain: config.connect_domain
22
+ )
23
+ end
24
+
25
+ def run
26
+ connector.connect
27
+ connector.join_rooms(config.muc_domain, rooms)
28
+ sleep
29
+ rescue Interrupt
30
+ shut_down
31
+ end
32
+
33
+ def send_messages(target, strings)
34
+ if target.room
35
+ connector.message_muc(target.room, strings)
36
+ else
37
+ connector.message_jid(target.user.id, strings)
38
+ end
39
+ end
40
+
41
+ def send_raw_messages(target, strings)
42
+ if target.room
43
+ connector.message_muc(target.room, strings, true)
44
+ else
45
+ connector.message_jid(target.user.id, strings)
46
+ end
47
+ end
48
+
49
+ def set_topic(target, topic)
50
+ connector.set_topic(target.room, topic)
51
+ end
52
+
53
+ def shut_down
54
+ connector.shut_down
55
+ end
56
+
57
+ private
58
+
59
+ def config
60
+ Lita.config.adapter
61
+ end
62
+
63
+ def rooms
64
+ if config.rooms == :all
65
+ connector.list_rooms(config.muc_domain)
66
+ else
67
+ Array(config.rooms)
68
+ end
69
+ end
70
+
71
+ def set_default_config_values
72
+ config.debug = false if config.debug.nil?
73
+ end
74
+ end
75
+
76
+ Lita.register_adapter(:xmpp, Xmpp)
77
+ end
78
+ end
@@ -0,0 +1,85 @@
1
+ module Lita
2
+ module Adapters
3
+ class Xmpp < Adapter
4
+ class Callback
5
+ attr_reader :robot, :roster
6
+
7
+ def initialize(robot, roster)
8
+ @robot = robot
9
+ @roster = roster
10
+ @start_time = Time.now.utc
11
+ end
12
+
13
+ def private_message(client)
14
+ client.add_message_callback do |m|
15
+ next if m.type == :error || m.body.nil?
16
+ user = user_by_jid(m.from)
17
+ source = Source.new(user)
18
+ message = Message.new(robot, m.body, source)
19
+ message.command!
20
+ Lita.logger.debug("Dispatching PM to Lita from #{user.id}.")
21
+ robot.receive(message)
22
+ end
23
+ end
24
+
25
+ def muc_message(muc)
26
+ muc.on_message do |time, nick, text|
27
+ if time.is_a?(Time) && time < @start_time
28
+ Lita.logger.debug "#{time} < #{@start_time} Skipping #{nick}: #{text}"
29
+ next
30
+ else
31
+ user = user_by_name(nick)
32
+ source = Source.new(user, muc.jid.bare.to_s)
33
+ message = Message.new(robot, text, source)
34
+ Lita.logger.debug(
35
+ "Dispatching message to Lita from #{user.id} in MUC #{muc.jid}."
36
+ )
37
+ robot.receive(message)
38
+ end
39
+ end
40
+ end
41
+
42
+ def roster_update
43
+ roster.add_update_callback do |old_item, item|
44
+ jid = item.attributes["jid"]
45
+ Lita.logger.debug("Updating record for user with ID: #{jid}.")
46
+ create_user(item.attributes)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def jid_without_domain(jid)
53
+ jid.to_s.sub(/@.*/, '')
54
+ end
55
+
56
+ def create_user(user_data)
57
+ name = user_data['name'].downcase.gsub(/\s+/, '.')
58
+ User.create(
59
+ user_data["jid"],
60
+ name: name,
61
+ mention_name: jid_without_domain(user_data['jid'])
62
+ )
63
+ end
64
+
65
+ def user_by_jid(jid)
66
+ Lita.logger.debug("Looking up user with JID: #{jid}.")
67
+ create_user(roster[jid].attributes)
68
+ end
69
+
70
+ def user_by_name(name)
71
+ Lita.logger.info("Looking up user with name: #{name}.")
72
+ items = roster.items.detect { |jid, item| jid_without_domain(jid) == name }
73
+
74
+ if items
75
+ Lita.logger.info("Looking up user by jid: #{items.first}.")
76
+ user_by_jid(items.first)
77
+ else
78
+ Lita.logger.warn "No user with the name #{name.inspect} was found in the roster"
79
+ User.new(nil, name: name)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,138 @@
1
+ require "lita/encoding_patches"
2
+ require "lita/adapters/xmpp/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 Xmpp < Adapter
12
+ class Connector
13
+ attr_reader :robot, :client, :roster
14
+
15
+ def initialize(robot, jid, password, debug: false, connect_domain: nil)
16
+ @robot = robot
17
+ @jid = jid
18
+ @password = password
19
+ @client = Jabber::Client.new(@jid)
20
+ @connect_domain = connect_domain
21
+
22
+ if debug
23
+ Lita.logger.info("Enabling Jabber log.")
24
+ Jabber.debug = true
25
+ end
26
+ end
27
+
28
+ def jid
29
+ @jid.to_s
30
+ end
31
+
32
+ def connect
33
+ client_connect
34
+ load_roster
35
+ register_message_callback
36
+ send_presence
37
+ end
38
+
39
+ def join_rooms(muc_domain, rooms)
40
+ rooms.each do |room_name|
41
+ muc = Jabber::MUC::SimpleMUCClient.new(client)
42
+ room_jid = normalized_jid(room_name, muc_domain, robot.name)
43
+ mucs[room_jid.bare.to_s] = muc
44
+ register_muc_message_callback(muc)
45
+ Lita.logger.info("Joining room: #{room_jid}.")
46
+ muc.join(room_jid)
47
+ end
48
+ end
49
+
50
+ def list_rooms(muc_domain)
51
+ Lita.logger.debug("Querying server for list of rooms.")
52
+ browser = Jabber::MUC::MUCBrowser.new(client)
53
+ browser.muc_rooms(muc_domain).map { |jid, name| jid.to_s }
54
+ end
55
+
56
+ def message_jid(user_jid, strings)
57
+ strings.each do |s|
58
+ Lita.logger.debug("Sending message to JID #{user_jid}: #{s}")
59
+ message = Jabber::Message.new(user_jid, s)
60
+ message.type = :chat
61
+ client.send(message)
62
+ end
63
+ end
64
+
65
+ def message_muc(room_jid, strings, raw = false)
66
+ if muc = mucs[room_jid]
67
+ if raw
68
+ Lita.logger.debug("Sending raw message to MUC #{room_jid}: #{strings}")
69
+ muc.send(strings)
70
+ else
71
+ strings.each do |s|
72
+ Lita.logger.debug("Sending message to MUC #{room_jid}: #{s}")
73
+ muc.say(s)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ def mucs
80
+ @mucs ||= {}
81
+ end
82
+
83
+ def set_topic(room_jid, topic)
84
+ muc = mucs[room_jid]
85
+ if muc
86
+ Lita.logger.debug("Setting topic for MUC #{room_jid}: #{topic}")
87
+ muc.subject = topic
88
+ end
89
+ end
90
+
91
+ def shut_down
92
+ Lita.logger.info("Disconnecting from XMPP.")
93
+ client.close
94
+ end
95
+
96
+ private
97
+
98
+ def send_presence
99
+ Lita.logger.debug("Sending initial XMPP presence.")
100
+ client.send(Jabber::Presence.new(:chat))
101
+ end
102
+
103
+ def client_connect
104
+ Lita.logger.info("Connecting to XMPP. #{@connect_domain}")
105
+ client.connect(@connect_domain)
106
+ Lita.logger.debug("Authenticating with XMPP.")
107
+ client.auth(@password)
108
+ end
109
+
110
+ def register_message_callback
111
+ Callback.new(robot, roster).private_message(client)
112
+ end
113
+
114
+ def register_muc_message_callback(muc)
115
+ Callback.new(robot, roster).muc_message(muc)
116
+ end
117
+
118
+ def load_roster
119
+ Lita.logger.debug("Loading roster.")
120
+ @roster = Jabber::Roster::Helper.new(client, false)
121
+ Callback.new(robot, roster).roster_update
122
+ roster.get_roster
123
+ roster.wait_for_roster
124
+ end
125
+
126
+ def normalized_jid(jid, domain, resource)
127
+ jid = Jabber::JID.new(jid)
128
+ jid.resource = resource
129
+ unless jid.node
130
+ jid.node = jid.domain
131
+ jid.domain = domain
132
+ end
133
+ jid
134
+ end
135
+ end
136
+ end
137
+ end
138
+ 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,24 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "sammcj-lita-xmpp"
3
+ spec.version = "1.0.3"
4
+ spec.authors = ["Justin Mazzi"]
5
+ spec.email = ["jmazzi@gmail.com"]
6
+ spec.description = %q{A XMPP adapter for Lita.}
7
+ spec.summary = %q{A XMPP adapter for the Lita chat robot.}
8
+ spec.homepage = "https://github.com/jmazzi/lita-xmpp"
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", ">= 2.0"
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"
22
+ spec.add_development_dependency "simplecov"
23
+ spec.add_development_dependency "coveralls"
24
+ end
@@ -0,0 +1,126 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Adapters::HipChat::Callback, lita: true 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
+
95
+ it "creates a temporary source user if the JID isn't in the roster" do
96
+ roster = double("Jabber::Roster::Helper", items: {})
97
+ allow(muc).to receive(:on_message).and_yield(nil, "Unknown", "foo")
98
+ allow(Lita::Source).to receive(:new).with(
99
+ an_instance_of(Lita::User),
100
+ "room_id"
101
+ ).and_return(source)
102
+ allow(Lita::Message).to receive(:new).with(
103
+ robot,
104
+ "foo",
105
+ source
106
+ ).and_return(message)
107
+ expect(robot).to receive(:receive).with(message)
108
+ subject.muc_message(muc)
109
+ end
110
+ end
111
+
112
+ describe "#roster_update" do
113
+ before do
114
+ allow(roster).to receive(:add_update_callback).and_yield(nil, roster_item)
115
+ end
116
+
117
+ it "finds/creates a user object for the roster item" do
118
+ expect(Lita::User).to receive(:create).with(
119
+ "user_id",
120
+ name: "Carl",
121
+ mention_name: "@Carl"
122
+ )
123
+ subject.roster_update
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,200 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Adapters::HipChat::Connector, lita: true 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,121 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Adapters::HipChat do
4
+ before do
5
+ Lita.configure do |config|
6
+ config.adapter.jid = "jid"
7
+ config.adapter.password = "secret"
8
+ config.adapter.rooms = nil
9
+ config.adapter.muc_domain = nil
10
+ end
11
+
12
+ allow(described_class::Connector).to receive(:new).and_return(connector)
13
+ end
14
+
15
+ subject { described_class.new(robot) }
16
+
17
+ let(:robot) { double("Lita::Robot") }
18
+ let(:connector) { double("Lita::Adapters::HipChat::Connector") }
19
+
20
+ it "registers with Lita" do
21
+ expect(Lita.adapters[:hipchat]).to eql(described_class)
22
+ end
23
+
24
+ it "requires config.jid and config.password" do
25
+ Lita.clear_config
26
+ expect(Lita.logger).to receive(:fatal).with(/jid, password/)
27
+ expect { subject }.to raise_error(SystemExit)
28
+ end
29
+
30
+ describe "#run" do
31
+ before do
32
+ allow(subject.connector).to receive(:connect)
33
+ allow(subject.connector).to receive(:join_rooms)
34
+ allow(subject).to receive(:sleep)
35
+ end
36
+
37
+ it "connects to HipChat" do
38
+ expect(subject.connector).to receive(:connect)
39
+ subject.run
40
+ end
41
+
42
+ it "joins rooms with a custom muc_domain" do
43
+ Lita.config.adapter.muc_domain = "foo.bar.com"
44
+ expect(subject.connector).to receive(:join_rooms).with(
45
+ "foo.bar.com",
46
+ anything
47
+ )
48
+ subject.run
49
+ end
50
+
51
+ it "joins all rooms when config.rooms is :all" do
52
+ all_rooms = ["room_1_id", "room_2_id"]
53
+ Lita.config.adapter.rooms = :all
54
+ allow(subject.connector).to receive(:list_rooms).with(
55
+ "conf.hipchat.com"
56
+ ).and_return(all_rooms)
57
+ expect(subject.connector).to receive(:join_rooms).with(
58
+ "conf.hipchat.com",
59
+ all_rooms
60
+ )
61
+ subject.run
62
+ end
63
+
64
+ it "joins rooms specified by config.rooms" do
65
+ custom_rooms = ["my_room_1_id", "my_room_2_id"]
66
+ Lita.config.adapter.rooms = custom_rooms
67
+ expect(subject.connector).to receive(:join_rooms).with(
68
+ "conf.hipchat.com",
69
+ custom_rooms
70
+ )
71
+ subject.run
72
+ end
73
+
74
+ it "sleeps the main thread" do
75
+ expect(subject).to receive(:sleep)
76
+ subject.run
77
+ end
78
+
79
+ it "disconnects gracefully on interrupt" do
80
+ expect(subject).to receive(:shut_down)
81
+ allow(subject).to receive(:sleep).and_raise(Interrupt)
82
+ subject.run
83
+ end
84
+ end
85
+
86
+ describe "#send_messages" do
87
+ it "sends messages to rooms" do
88
+ source = double("Lita::Source", room: "room_id")
89
+ expect(subject.connector).to receive(:message_muc).with(
90
+ "room_id",
91
+ ["Hello!"]
92
+ )
93
+ subject.send_messages(source, ["Hello!"])
94
+ end
95
+
96
+ it "sends private messages to users" do
97
+ user = double("Lita::User", id: "user_id")
98
+ source = double("Lita::Source", room: nil, user: user)
99
+ expect(subject.connector).to receive(:message_jid).with(
100
+ "user_id",
101
+ ["Hello!"]
102
+ )
103
+ subject.send_messages(source, ["Hello!"])
104
+ end
105
+ end
106
+
107
+ describe "#set_topic" do
108
+ it "sets a new topic for a room" do
109
+ source = double("Lita::Source", room: "room_id")
110
+ expect(subject.connector).to receive(:set_topic).with("room_id", "Topic")
111
+ subject.set_topic(source, "Topic")
112
+ end
113
+ end
114
+
115
+ describe "#shut_down" do
116
+ it "shuts down the connector" do
117
+ expect(subject.connector).to receive(:shut_down)
118
+ subject.shut_down
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,10 @@
1
+ require "simplecov"
2
+ require "coveralls"
3
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
4
+ SimpleCov::Formatter::HTMLFormatter,
5
+ Coveralls::SimpleCov::Formatter
6
+ ]
7
+ SimpleCov.start { add_filter "/spec/" }
8
+
9
+ require "lita-hipchat"
10
+ require "lita/rspec"
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sammcj-lita-xmpp
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Justin Mazzi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-04 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: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
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'
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'
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 XMPP adapter for Lita.
112
+ email:
113
+ - jmazzi@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".travis.yml"
120
+ - Gemfile
121
+ - LICENSE
122
+ - README.md
123
+ - Rakefile
124
+ - lib/lita-xmpp.rb
125
+ - lib/lita/adapters/xmpp.rb
126
+ - lib/lita/adapters/xmpp/callback.rb
127
+ - lib/lita/adapters/xmpp/connector.rb
128
+ - lib/lita/encoding_patches.rb
129
+ - lita-xmpp.gemspec
130
+ - spec/lita/adapters/hipchat/callback_spec.rb
131
+ - spec/lita/adapters/hipchat/connector_spec.rb
132
+ - spec/lita/adapters/hipchat_spec.rb
133
+ - spec/spec_helper.rb
134
+ homepage: https://github.com/jmazzi/lita-xmpp
135
+ licenses:
136
+ - MIT
137
+ metadata: {}
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project:
154
+ rubygems_version: 2.2.2
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: A XMPP adapter for the Lita chat robot.
158
+ test_files:
159
+ - spec/lita/adapters/hipchat/callback_spec.rb
160
+ - spec/lita/adapters/hipchat/connector_spec.rb
161
+ - spec/lita/adapters/hipchat_spec.rb
162
+ - spec/spec_helper.rb