xmpp4r-hipchat 0.0.4 → 0.1.0
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 +4 -4
- data/.gitignore +19 -0
- data/README.md +3 -3
- data/lib/xmpp4r-hipchat.rb +12 -0
- data/lib/xmpp4r/hipchat/version.rb +1 -1
- data/lib/xmpp4r/muc/helper/hipchat_client.rb +145 -152
- data/lib/xmpp4r/muc/hipchat/kick_message.rb +32 -0
- data/lib/xmpp4r/muc/hipchat/message.rb +55 -0
- data/lib/xmpp4r/muc/hipchat/presence.rb +52 -0
- data/lib/xmpp4r/muc/hipchat/received_message.rb +33 -0
- data/lib/xmpp4r/muc/hipchat/received_presence.rb +32 -0
- data/lib/xmpp4r/muc/hipchat/received_stanza.rb +42 -0
- data/lib/xmpp4r/muc/hipchat/room_data.rb +46 -0
- data/lib/xmpp4r/muc/hipchat/user_data.rb +50 -0
- data/lib/xmpp4r/muc/hipchat/vcard.rb +40 -0
- data/spec/integration/muc/clienttester.rb +149 -0
- data/spec/integration/muc/tc_muc_hipchat_client.rb +110 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/unit/hipchat_client_spec.rb +55 -0
- data/xmpp4r-hipchat.gemspec +4 -4
- metadata +45 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd02f79e1cc61f8bdd46302cbe12327ce2bbfeab
|
4
|
+
data.tar.gz: 965a232d7d9358dc15d7d2d50ba6ef4040491fca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0196c7eb22c8717f3455c233cd2561870dc4e959e3d608a2d84be9525c85c5557ecf6784274c9cc281cead2f0e2712cee7a923922920143759d5f1b04ae0eb58'
|
7
|
+
data.tar.gz: 2fdb5fac322cc4fcd6d501c3d57be8c95ab3f0f51a01e2ceb5f2272326e2eb64edd7d66235728250202ee4b8a948a134bb1fdf63f4c05b7401957781d6cece52
|
data/.gitignore
ADDED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# XMPP4R-Hipchat
|
2
2
|
|
3
|
-
|
3
|
+
This is a HipChat / Slack XMPP adapter using XMPP4R lib.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,7 +18,7 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
Please refer to [Hipbot](https://github.com/pewniak747/hipbot) source code for up-to-date usage example. This gem is still in development.
|
22
22
|
|
23
23
|
## Contributing
|
24
24
|
|
data/lib/xmpp4r-hipchat.rb
CHANGED
@@ -6,4 +6,16 @@ require 'xmpp4r/muc/iq/mucadmin'
|
|
6
6
|
require 'xmpp4r/dataforms'
|
7
7
|
require 'xmpp4r/roster'
|
8
8
|
require 'xmpp4r/vcard'
|
9
|
+
|
10
|
+
require 'xmpp4r/muc/hipchat/message'
|
11
|
+
require 'xmpp4r/muc/hipchat/kick_message'
|
12
|
+
|
13
|
+
require 'xmpp4r/muc/hipchat/presence'
|
14
|
+
|
15
|
+
require 'xmpp4r/muc/hipchat/received_stanza'
|
16
|
+
require 'xmpp4r/muc/hipchat/received_presence'
|
17
|
+
require 'xmpp4r/muc/hipchat/received_message'
|
18
|
+
require 'xmpp4r/muc/hipchat/room_data'
|
19
|
+
require 'xmpp4r/muc/hipchat/vcard'
|
20
|
+
require 'xmpp4r/muc/hipchat/user_data'
|
9
21
|
require 'xmpp4r/muc/helper/hipchat_client'
|
@@ -1,224 +1,217 @@
|
|
1
1
|
module Jabber
|
2
2
|
module MUC
|
3
3
|
class HipchatClient
|
4
|
-
|
4
|
+
attr_reader :my_jid
|
5
5
|
|
6
|
-
def initialize
|
7
|
-
|
8
|
-
self.stream = Client.new(my_jid.strip) # TODO: Error Handling
|
9
|
-
Jabber::debuglog "Stream initialized"
|
10
|
-
self.chat_domain = my_jid.domain
|
6
|
+
def initialize jid, conference_host = nil
|
7
|
+
@my_jid = JID.new(jid)
|
11
8
|
|
12
|
-
@
|
9
|
+
@presence = HipChat::Presence.new(my_jid)
|
10
|
+
@message = HipChat::Message.new(my_jid)
|
11
|
+
|
12
|
+
@conference_host = conference_host
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
xmuc.password = password
|
15
|
+
def name
|
16
|
+
my_jid.resource
|
17
|
+
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
19
|
+
def name= resource
|
20
|
+
my_jid.resource = resource
|
21
|
+
end
|
24
22
|
|
25
|
-
|
26
|
-
|
23
|
+
## Actions
|
24
|
+
|
25
|
+
def join room_id, fetch_history = false
|
26
|
+
jid = JID.new(room_id, conference_host)
|
27
|
+
Jabber::debuglog "Joining #{jid}"
|
28
|
+
@presence.get_join(jid, fetch_history).send_to(stream)
|
27
29
|
end
|
28
30
|
|
29
|
-
def exit
|
30
|
-
|
31
|
+
def exit room_id, reason = nil
|
32
|
+
jid = JID.new(room_id, conference_host)
|
31
33
|
Jabber::debuglog "Exiting #{jid}"
|
32
|
-
|
34
|
+
@presence.get_leave(jid, reason).send_to(stream)
|
33
35
|
end
|
34
36
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
def set_presence status = nil, type = :available, room_id = nil
|
38
|
+
room_jid = room_id ? JID.new(room_id, conference_host) : nil
|
39
|
+
Jabber::debuglog "Setting presence to #{type} in #{room_jid} with #{status}"
|
40
|
+
@presence.get_status(type, room_jid, status).send_to(stream)
|
39
41
|
end
|
40
42
|
|
41
|
-
def
|
42
|
-
|
43
|
+
def kick user_ids, room_id
|
44
|
+
room_jid = JID.new(room_id, conference_host)
|
45
|
+
user_jids = user_ids.map{ |id| JID.new(id, chat_host) }
|
46
|
+
Jabber::debuglog "Kicking #{user_jids} from #{room_jid}"
|
47
|
+
HipChat::KickMessage.new(my_jid).make(room_jid, user_jids).send_to(stream)
|
43
48
|
end
|
44
49
|
|
45
|
-
def
|
46
|
-
|
50
|
+
def invite user_ids, room_id
|
51
|
+
room_jid = JID.new(room_id, conference_host)
|
52
|
+
user_jids = user_ids.map{ |id| JID.new(id, chat_host) }
|
53
|
+
Jabber::debuglog "Inviting #{user_jids} to #{room_jid}"
|
54
|
+
@message.get_invite(room_jid, user_jids).send_to(stream)
|
47
55
|
end
|
48
56
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
block.call(*args)
|
53
|
-
end
|
54
|
-
end
|
57
|
+
def send_message type, recipient_id, text, subject = nil
|
58
|
+
jid = JID.new(recipient_id, type == :chat ? chat_host : conference_host)
|
59
|
+
@message.get_text(type, jid, text, subject).send_to(stream)
|
55
60
|
end
|
56
61
|
|
57
|
-
|
58
|
-
pres = Presence.new(:chat, reason)
|
59
|
-
pres.type = type
|
60
|
-
pres.to = to if to
|
61
|
-
pres.from = my_jid
|
62
|
-
pres.add(xmuc) if xmuc
|
63
|
-
stream.send(pres) { |r| block.call(r) }
|
64
|
-
end
|
65
|
-
|
66
|
-
def kick(recipients, room_jid)
|
67
|
-
iq = Iq.new(:set, room_jid)
|
68
|
-
iq.from = my_jid
|
69
|
-
iq.add(IqQueryMUCAdmin.new)
|
70
|
-
recipients.each do |recipient|
|
71
|
-
item = IqQueryMUCAdminItem.new
|
72
|
-
item.nick = recipient
|
73
|
-
item.role = :none
|
74
|
-
iq.query.add(item)
|
75
|
-
end
|
76
|
-
stream.send_with_id(iq)
|
77
|
-
end
|
62
|
+
## Fetching
|
78
63
|
|
79
|
-
def
|
80
|
-
|
81
|
-
msg.from = my_jid
|
82
|
-
msg.to = room_jid
|
83
|
-
x = msg.add(XMUCUser.new)
|
84
|
-
recipients.each do |jid|
|
85
|
-
x.add(XMUCUserInvite.new(jid))
|
86
|
-
end
|
87
|
-
stream.send(msg)
|
64
|
+
def get_rooms
|
65
|
+
HipChat::RoomData.get_rooms_data(stream, conference_host)
|
88
66
|
end
|
89
67
|
|
90
|
-
def
|
91
|
-
|
92
|
-
|
93
|
-
message.from = my_jid
|
94
|
-
message.subject = subject
|
68
|
+
def get_users
|
69
|
+
HipChat::UserData.get_users_data(stream)
|
70
|
+
end
|
95
71
|
|
96
|
-
|
97
|
-
|
98
|
-
stream.send(message)
|
99
|
-
sleep(0.2)
|
100
|
-
end
|
72
|
+
def get_user_details user_id
|
73
|
+
HipChat::VCard.get_details(stream, user_id)
|
101
74
|
end
|
102
75
|
|
76
|
+
## Connection
|
77
|
+
|
103
78
|
def connect password
|
104
79
|
stream.connect
|
105
80
|
Jabber::debuglog "Connected to stream"
|
106
81
|
stream.auth(password)
|
107
82
|
Jabber::debuglog "Authenticated"
|
108
|
-
@muc_browser = MUCBrowser.new(stream)
|
109
|
-
Jabber::debuglog "MUCBrowser initialized"
|
110
|
-
self.conference_domain = @muc_browser.muc_rooms(chat_domain).keys.first
|
111
|
-
Jabber::debuglog "No conference domain found" if conference_domain.nil?
|
112
|
-
@roster = Roster::Helper.new(stream) # TODO: Error handling
|
113
|
-
@vcard = Vcard::Helper.new(stream) # TODO: Error handling
|
114
83
|
true
|
115
84
|
end
|
116
85
|
|
117
|
-
def
|
118
|
-
stream.
|
119
|
-
|
120
|
-
|
86
|
+
def keep_alive password
|
87
|
+
if stream.is_disconnected?
|
88
|
+
Jabber::debuglog "Stream disconnected. Connecting again..."
|
89
|
+
connect(password)
|
90
|
+
end
|
121
91
|
end
|
122
92
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
details = {}
|
132
|
-
item.first.children.each{ |c| details[c.name] = c.text }
|
133
|
-
rooms << {
|
134
|
-
item: item,
|
135
|
-
details: details
|
136
|
-
}
|
93
|
+
## Callbacks
|
94
|
+
|
95
|
+
CALLBACKS = %w(lobby_presence room_presence room_message private_message room_invite room_topic error)
|
96
|
+
|
97
|
+
CALLBACKS.each do |callback_name|
|
98
|
+
define_method("on_#{callback_name}") do |prio = 0, ref = nil, &block|
|
99
|
+
callbacks[callback_name.to_sym].add(prio, ref) do |*args|
|
100
|
+
block.call(*args)
|
137
101
|
end
|
138
102
|
end
|
139
|
-
rooms
|
140
103
|
end
|
141
104
|
|
142
|
-
def
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
105
|
+
def activate_callbacks
|
106
|
+
stream.add_stanza_callback(0, self) do |stanza|
|
107
|
+
case stanza.name
|
108
|
+
when 'message'
|
109
|
+
handle_message(HipChat::ReceivedMessage.new(stanza))
|
110
|
+
when 'presence'
|
111
|
+
handle_presence(HipChat::ReceivedPresence.new(stanza, chat_host))
|
112
|
+
end
|
150
113
|
end
|
151
|
-
|
152
|
-
|
153
|
-
def get_user_details user_jid
|
154
|
-
vcard = @vcard.get(user_jid)
|
155
|
-
{
|
156
|
-
email: vcard['EMAIL/USERID'],
|
157
|
-
title: vcard['TITLE'],
|
158
|
-
photo: vcard['PHOTO'],
|
159
|
-
}
|
114
|
+
Jabber::debuglog "Callbacks activated"
|
160
115
|
end
|
161
116
|
|
162
117
|
def deactivate_callbacks
|
163
|
-
stream.
|
164
|
-
stream.delete_message_callback(self)
|
118
|
+
stream.delete_stanza_callback(self)
|
165
119
|
Jabber::debuglog "Callbacks deactivated"
|
166
120
|
end
|
167
121
|
|
168
122
|
private
|
169
123
|
|
170
|
-
def
|
171
|
-
|
172
|
-
|
173
|
-
|
124
|
+
def chat_host
|
125
|
+
my_jid.domain
|
126
|
+
end
|
127
|
+
|
128
|
+
def conference_host
|
129
|
+
@conference_host ||= begin
|
130
|
+
MUCBrowser.new(stream).muc_rooms(chat_host).keys.first.domain
|
131
|
+
end
|
132
|
+
rescue => e
|
133
|
+
Jabber.logger.error("Conference host not found")
|
134
|
+
nil
|
135
|
+
end
|
136
|
+
|
137
|
+
def stream
|
138
|
+
@stream ||= Client.new(my_jid.strip) # TODO: Error Handling
|
139
|
+
end
|
140
|
+
|
141
|
+
def callbacks
|
142
|
+
@callbacks ||= Hash.new { |hash, key| hash[key] = CallbackList.new }
|
143
|
+
end
|
174
144
|
|
175
|
-
|
176
|
-
|
145
|
+
def handle_presence presence
|
146
|
+
if presence.lobby?
|
147
|
+
callbacks[:lobby_presence].process(
|
148
|
+
presence.sender_id,
|
149
|
+
presence.type
|
150
|
+
)
|
177
151
|
else
|
178
|
-
|
152
|
+
callbacks[:room_presence].process(
|
153
|
+
presence.room_id,
|
154
|
+
# presence.user_id,
|
155
|
+
presence.sender_name,
|
156
|
+
presence.type,
|
157
|
+
presence.role,
|
158
|
+
)
|
179
159
|
end
|
180
160
|
end
|
181
161
|
|
182
|
-
def handle_message
|
183
|
-
|
184
|
-
|
185
|
-
elsif message.type == :chat
|
162
|
+
def handle_message message
|
163
|
+
case message.type
|
164
|
+
when :chat
|
186
165
|
handle_private_message(message)
|
187
|
-
|
188
|
-
|
189
|
-
|
166
|
+
when :groupchat
|
167
|
+
if message.topic?
|
168
|
+
handle_room_topic(message)
|
169
|
+
else
|
170
|
+
handle_group_message(message)
|
171
|
+
end
|
172
|
+
when :error
|
190
173
|
handle_error(message)
|
174
|
+
else
|
175
|
+
handle_invite(message)
|
191
176
|
end
|
192
177
|
end
|
193
178
|
|
194
|
-
def handle_invite
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
@callbacks[:invite].process(room_jid, user_name, room_name, topic)
|
179
|
+
def handle_invite message
|
180
|
+
callbacks[:room_invite].process(
|
181
|
+
message.room_id,
|
182
|
+
message.room_name,
|
183
|
+
)
|
200
184
|
end
|
201
185
|
|
202
|
-
def handle_private_message
|
203
|
-
|
204
|
-
|
205
|
-
|
186
|
+
def handle_private_message message
|
187
|
+
callbacks[:private_message].process(
|
188
|
+
message.sender_id,
|
189
|
+
message.body,
|
190
|
+
)
|
206
191
|
end
|
207
192
|
|
208
|
-
def handle_group_message
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
193
|
+
def handle_group_message message
|
194
|
+
callbacks[:room_message].process(
|
195
|
+
message.room_id,
|
196
|
+
message.sender_name,
|
197
|
+
message.body,
|
198
|
+
)
|
214
199
|
end
|
215
200
|
|
216
|
-
def
|
217
|
-
|
201
|
+
def handle_room_topic message
|
202
|
+
callbacks[:room_topic].process(
|
203
|
+
message.room_id,
|
204
|
+
message.topic,
|
205
|
+
)
|
218
206
|
end
|
219
207
|
|
220
|
-
def
|
221
|
-
|
208
|
+
def handle_error message
|
209
|
+
callbacks[:error].process(
|
210
|
+
message.room_id,
|
211
|
+
message.user_id,
|
212
|
+
message.body,
|
213
|
+
message.topic,
|
214
|
+
)
|
222
215
|
end
|
223
216
|
end
|
224
217
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Jabber
|
2
|
+
module MUC
|
3
|
+
module HipChat
|
4
|
+
class KickMessage < Iq
|
5
|
+
def initialize my_jid
|
6
|
+
super(:set)
|
7
|
+
self.from = my_jid
|
8
|
+
self.add(IqQueryMUCAdmin.new)
|
9
|
+
end
|
10
|
+
|
11
|
+
def make room_jid, recipients
|
12
|
+
self.to = room_jid
|
13
|
+
|
14
|
+
recipients.each do |recipient|
|
15
|
+
add_recipient(recipient)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_recipient nick
|
20
|
+
item = IqQueryMUCAdminItem.new
|
21
|
+
item.nick = nick
|
22
|
+
item.role = :none
|
23
|
+
self.query.add(item)
|
24
|
+
end
|
25
|
+
|
26
|
+
def send_to(stream)
|
27
|
+
stream.send_with_id(self)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Jabber
|
2
|
+
module MUC
|
3
|
+
module HipChat
|
4
|
+
class Message < Jabber::Message
|
5
|
+
def initialize my_jid
|
6
|
+
super()
|
7
|
+
@my_jid = my_jid
|
8
|
+
self.from = my_jid
|
9
|
+
@semaphore = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_text type, jid, text, subject = nil
|
13
|
+
self.dup.tap do |d|
|
14
|
+
recipient = JID.new(jid)
|
15
|
+
recipient.resource ||= recipient.node
|
16
|
+
|
17
|
+
d.body = text.to_s
|
18
|
+
d.to = recipient
|
19
|
+
d.type = type
|
20
|
+
d.subject = subject if subject
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_invite room_jid, recipient_jids
|
25
|
+
self.dup.tap do |d|
|
26
|
+
d.to = JID.new(room_jid)
|
27
|
+
|
28
|
+
recipient_jids.each do |recipient_jid|
|
29
|
+
d.add_recipient(recipient_jid)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_recipient jid
|
35
|
+
xmuc_user.add(XMUCUserInvite.new(jid))
|
36
|
+
end
|
37
|
+
|
38
|
+
def send_to stream, &block
|
39
|
+
Thread.new do
|
40
|
+
@semaphore.synchronize {
|
41
|
+
stream.send(self, &block)
|
42
|
+
sleep(0.2)
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def xmuc_user
|
50
|
+
@xmuc_user ||= add(XMUCUser.new)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Jabber
|
2
|
+
module MUC
|
3
|
+
module HipChat
|
4
|
+
class Presence < Jabber::Presence
|
5
|
+
def initialize my_jid
|
6
|
+
super(:chat)
|
7
|
+
@my_jid = my_jid
|
8
|
+
self.from = my_jid
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_leave jid, reason = nil
|
12
|
+
get_status(:unavailable, room_jid(jid), reason)
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_join jid, fetch_history = false
|
16
|
+
get_status(:available, room_jid(jid)) # TODO: Handle all join responses
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_status type, to = nil, status = nil, fetch_history = false
|
20
|
+
self.dup.tap do |d|
|
21
|
+
d.set_status(status)
|
22
|
+
d.set_type(type)
|
23
|
+
d.no_history! unless fetch_history
|
24
|
+
d.to = to
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def no_history!
|
29
|
+
element = REXML::Element.new('history').tap do |h|
|
30
|
+
h.add_attribute('maxstanzas', '0')
|
31
|
+
end
|
32
|
+
|
33
|
+
xmuc = XMUC.new
|
34
|
+
xmuc.add_element(element)
|
35
|
+
self.add(xmuc)
|
36
|
+
end
|
37
|
+
|
38
|
+
def send_to stream, &block
|
39
|
+
stream.send(self, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def room_jid jid
|
45
|
+
JID.new(jid).tap do |j|
|
46
|
+
j.resource = @my_jid.resource
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Jabber
|
2
|
+
module MUC
|
3
|
+
module HipChat
|
4
|
+
class ReceivedMessage < ReceivedStanza
|
5
|
+
alias_method :recipient_id, :user_id
|
6
|
+
|
7
|
+
def topic
|
8
|
+
@stanza.subject.to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
def body
|
12
|
+
@stanza.body.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
## Invite
|
16
|
+
|
17
|
+
def topic?
|
18
|
+
@stanza.children.first.name == "subject"
|
19
|
+
end
|
20
|
+
|
21
|
+
def invite?
|
22
|
+
!@stanza.x.nil? &&
|
23
|
+
@stanza.x.kind_of?(XMUCUser) &&
|
24
|
+
@stanza.x.first.kind_of?(XMUCUserInvite)
|
25
|
+
end
|
26
|
+
|
27
|
+
def room_name
|
28
|
+
@stanza.children.last.first_element_text('name')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Jabber
|
2
|
+
module MUC
|
3
|
+
module HipChat
|
4
|
+
class ReceivedPresence < ReceivedStanza
|
5
|
+
def initialize stanza, chat_host
|
6
|
+
super stanza
|
7
|
+
@is_lobby = chat_host == host
|
8
|
+
end
|
9
|
+
|
10
|
+
def lobby?
|
11
|
+
@is_lobby
|
12
|
+
end
|
13
|
+
|
14
|
+
def type
|
15
|
+
super || @stanza.show || :available
|
16
|
+
end
|
17
|
+
|
18
|
+
## Room presence
|
19
|
+
|
20
|
+
def role
|
21
|
+
item.affiliation if item
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def host
|
27
|
+
@stanza.from.domain if @stanza.from
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Jabber
|
2
|
+
module MUC
|
3
|
+
module HipChat
|
4
|
+
class ReceivedStanza
|
5
|
+
def initialize stanza
|
6
|
+
@stanza = stanza
|
7
|
+
end
|
8
|
+
|
9
|
+
# Presence Types: :available, :unavailable, ...
|
10
|
+
# Message Types: :chat, :groupchat, :error, ...
|
11
|
+
def type
|
12
|
+
@stanza.type
|
13
|
+
end
|
14
|
+
|
15
|
+
# User ID is available in presences and private messages
|
16
|
+
def user_id
|
17
|
+
item.jid.node if item
|
18
|
+
end
|
19
|
+
|
20
|
+
def sender_id
|
21
|
+
@stanza.from.node
|
22
|
+
end
|
23
|
+
alias_method :room_id, :sender_id
|
24
|
+
|
25
|
+
# Used in room message or presence
|
26
|
+
def sender_name
|
27
|
+
@stanza.from.resource
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def item
|
33
|
+
@item ||= begin
|
34
|
+
if @stanza.x.respond_to?(:items)
|
35
|
+
@stanza.x.items.first
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Jabber
|
2
|
+
module MUC
|
3
|
+
module HipChat
|
4
|
+
class RoomData
|
5
|
+
# ATTRIBUTES = [:id, :topic, :privacy, :is_archived, :guest_url, :owner, :last_active, :num_participants]
|
6
|
+
attr_accessor :attributes
|
7
|
+
|
8
|
+
def initialize room
|
9
|
+
@room = room
|
10
|
+
@attributes = {
|
11
|
+
"name" => name,
|
12
|
+
"id" => id,
|
13
|
+
}
|
14
|
+
|
15
|
+
room.first.children.each do |c|
|
16
|
+
@attributes[c.name] ||= c.text
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def name
|
21
|
+
@room.iname
|
22
|
+
end
|
23
|
+
|
24
|
+
def id
|
25
|
+
@room.jid.node
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def get_rooms_data stream, conference_host
|
30
|
+
iq = Iq.new(:get, conference_host)
|
31
|
+
iq.from = stream.jid
|
32
|
+
iq.add(Discovery::IqQueryDiscoItems.new)
|
33
|
+
|
34
|
+
rooms = []
|
35
|
+
stream.send_with_id(iq) do |answer|
|
36
|
+
answer.query.each_element('item') do |item|
|
37
|
+
rooms << self.new(item)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
rooms
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Jabber
|
2
|
+
module MUC
|
3
|
+
module HipChat
|
4
|
+
class UserData
|
5
|
+
def initialize user
|
6
|
+
@user = user
|
7
|
+
end
|
8
|
+
|
9
|
+
def id
|
10
|
+
@user.jid.node
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
@user.iname
|
15
|
+
end
|
16
|
+
|
17
|
+
def mention
|
18
|
+
@user.attributes['mention_name']
|
19
|
+
end
|
20
|
+
|
21
|
+
def attributes
|
22
|
+
{
|
23
|
+
name: name,
|
24
|
+
mention: mention,
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def get_users_data stream
|
30
|
+
@stream ||= stream
|
31
|
+
@roster ||= Roster::Helper.new(stream, false) # TODO: Error handling
|
32
|
+
|
33
|
+
loop do
|
34
|
+
rosterget = Iq.new_rosterget
|
35
|
+
rosterget.id = "roster_1"
|
36
|
+
@stream.send(rosterget)
|
37
|
+
@roster.wait_for_roster
|
38
|
+
break if @roster.items.any?
|
39
|
+
sleep(2)
|
40
|
+
end
|
41
|
+
|
42
|
+
@roster.items.map do |_, item|
|
43
|
+
self.new(item)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Jabber
|
2
|
+
module MUC
|
3
|
+
module HipChat
|
4
|
+
class VCard
|
5
|
+
def initialize vcard
|
6
|
+
@vcard = vcard
|
7
|
+
end
|
8
|
+
|
9
|
+
def email
|
10
|
+
@vcard['EMAIL/USERID']
|
11
|
+
end
|
12
|
+
|
13
|
+
def title
|
14
|
+
@vcard['TITLE']
|
15
|
+
end
|
16
|
+
|
17
|
+
def photo
|
18
|
+
@vcard['PHOTO']
|
19
|
+
end
|
20
|
+
|
21
|
+
def attributes
|
22
|
+
{
|
23
|
+
email: email,
|
24
|
+
title: title,
|
25
|
+
photo: photo,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def get_details stream, user_id
|
31
|
+
@vcard_helper ||= Vcard::Helper.new(stream)
|
32
|
+
user_jid = JID.new(user_id, stream.host)
|
33
|
+
vcard = @vcard_helper.get(user_jid)
|
34
|
+
VCard.new(vcard)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
2
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
3
|
+
# Website::http://home.gna.org/xmpp4r/
|
4
|
+
|
5
|
+
$:.unshift '../lib'
|
6
|
+
require 'xmpp4r'
|
7
|
+
require 'test/unit'
|
8
|
+
require 'socket'
|
9
|
+
require 'xmpp4r/semaphore'
|
10
|
+
|
11
|
+
# Jabber::debug = true
|
12
|
+
$ctdebug = false
|
13
|
+
# $ctdebug = true
|
14
|
+
|
15
|
+
# This is sane for tests:
|
16
|
+
Thread::abort_on_exception = true
|
17
|
+
|
18
|
+
# Turn $VERBOSE off to suppress warnings about redefinition
|
19
|
+
oldverbose = $VERBOSE
|
20
|
+
$VERBOSE = false
|
21
|
+
|
22
|
+
module Jabber
|
23
|
+
##
|
24
|
+
# The ClientTester is a mix-in which provides a setup and teardown
|
25
|
+
# method to prepare a Stream object (@client) and the method
|
26
|
+
# interfacing as the "server side":
|
27
|
+
# * send(xml):: Send a stanza to @client
|
28
|
+
#
|
29
|
+
# The server side is a stream, too: add your callbacks to @server
|
30
|
+
#
|
31
|
+
# ClientTester is written to test complex helper classes.
|
32
|
+
module ClientTester
|
33
|
+
@@SOCKET_PORT = 65223
|
34
|
+
|
35
|
+
def setup
|
36
|
+
servlisten = TCPServer.new(@@SOCKET_PORT)
|
37
|
+
serverwait = Semaphore.new
|
38
|
+
stream = '<stream:stream xmlns:stream="http://etherx.jabber.org/streams">'
|
39
|
+
|
40
|
+
@state = 0
|
41
|
+
@states = []
|
42
|
+
|
43
|
+
Thread.new do
|
44
|
+
Thread.current.abort_on_exception = true
|
45
|
+
serversock = servlisten.accept
|
46
|
+
servlisten.close
|
47
|
+
serversock.sync = true
|
48
|
+
@server = Stream.new
|
49
|
+
@server.add_xml_callback do |xml|
|
50
|
+
if xml.prefix == 'stream' and xml.name == 'stream'
|
51
|
+
send(stream)
|
52
|
+
true
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
@server.start(serversock)
|
58
|
+
|
59
|
+
serverwait.run
|
60
|
+
end
|
61
|
+
|
62
|
+
clientsock = TCPSocket.new('localhost', @@SOCKET_PORT)
|
63
|
+
clientsock.sync = true
|
64
|
+
@client = Stream.new
|
65
|
+
#=begin
|
66
|
+
class << @client
|
67
|
+
def jid
|
68
|
+
begin
|
69
|
+
#raise
|
70
|
+
rescue
|
71
|
+
puts $!.backtrace.join("\n")
|
72
|
+
end
|
73
|
+
JID.new('test@test.com/test')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
#=end
|
77
|
+
@client.start(clientsock)
|
78
|
+
|
79
|
+
@processdone_wait = Semaphore.new
|
80
|
+
@nextstate_wait = Semaphore.new
|
81
|
+
serverwait.wait
|
82
|
+
@server.add_stanza_callback { |stanza|
|
83
|
+
# Client prepares everything, then calls wait_state. Problem: because
|
84
|
+
# of a race condition, it is possible that we receive the stanza before
|
85
|
+
# what to do with it is defined. We busy-wait on @states here.
|
86
|
+
n = 0
|
87
|
+
while @state >= @states.size and n < 1000
|
88
|
+
Thread.pass
|
89
|
+
n += 1
|
90
|
+
end
|
91
|
+
if n == 1000
|
92
|
+
puts "Unmanaged stanza in state. Maybe processed by helper?" if $ctdebug
|
93
|
+
else
|
94
|
+
begin
|
95
|
+
puts "Calling #{@states[@state]} for #{stanza.to_s}" if $ctdebug
|
96
|
+
@states[@state].call(stanza)
|
97
|
+
rescue Exception => e
|
98
|
+
puts "Exception in state: #{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
99
|
+
end
|
100
|
+
@state += 1
|
101
|
+
@nextstate_wait.wait
|
102
|
+
@processdone_wait.run
|
103
|
+
end
|
104
|
+
|
105
|
+
false
|
106
|
+
}
|
107
|
+
@client.send(stream) { |reply| true }
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def teardown
|
112
|
+
# In some cases, we might lost count of some stanzas
|
113
|
+
# (for example, if the handler raises an exception)
|
114
|
+
# so we can't block forever.
|
115
|
+
n = 0
|
116
|
+
while @client.processing > 0 and n < 1000
|
117
|
+
Thread::pass
|
118
|
+
n += 1
|
119
|
+
end
|
120
|
+
n = 0
|
121
|
+
while @server.processing > 0 and n < 1000
|
122
|
+
Thread::pass
|
123
|
+
n += 1
|
124
|
+
end
|
125
|
+
@client.close
|
126
|
+
@server.close
|
127
|
+
end
|
128
|
+
|
129
|
+
def send(xml)
|
130
|
+
@server.send(xml)
|
131
|
+
end
|
132
|
+
|
133
|
+
def state(&block)
|
134
|
+
@states << block
|
135
|
+
end
|
136
|
+
|
137
|
+
def wait_state
|
138
|
+
@nextstate_wait.run
|
139
|
+
@processdone_wait.wait
|
140
|
+
end
|
141
|
+
|
142
|
+
def skip_state
|
143
|
+
@nextstate_wait.run
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Restore the old $VERBOSE setting
|
149
|
+
$VERBOSE = oldverbose
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'xmpp4r/../../test/lib/clienttester'
|
4
|
+
require 'xmpp4r/muc'
|
5
|
+
require 'xmpp4r/semaphore'
|
6
|
+
# require_relative '../lib/xmpp4r/muc/hipchat_client'
|
7
|
+
include Jabber
|
8
|
+
|
9
|
+
class HipchatClientTest < Test::Unit::TestCase
|
10
|
+
include ClientTester
|
11
|
+
|
12
|
+
def test_new1
|
13
|
+
m = MUC::HipchatClient.new(@client.jid)
|
14
|
+
assert_equal(@client.jid, m.my_jid)
|
15
|
+
assert_equal(@client.jid.domain, m.chat_domain)
|
16
|
+
assert_equal(nil, m.conference_domain)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_complex
|
20
|
+
# Jabber.debug = true
|
21
|
+
m = MUC::HipchatClient.new(@client.jid)
|
22
|
+
m.stream = @client
|
23
|
+
|
24
|
+
block_args = []
|
25
|
+
wait = Semaphore.new
|
26
|
+
block = lambda { |*a| block_args = a; wait.run }
|
27
|
+
m.on_message(&block)
|
28
|
+
m.on_private_message(&block)
|
29
|
+
m.on_presence(&block)
|
30
|
+
m.on_invite(&block)
|
31
|
+
# m.on_leave(&block)
|
32
|
+
# m.on_self_leave(&block)
|
33
|
+
|
34
|
+
state { |pres|
|
35
|
+
assert_kind_of(Presence, pres)
|
36
|
+
assert_equal(@client.jid, pres.from)
|
37
|
+
assert_equal(JID.new('darkcave@macbeth.shakespeare.lit/test'), pres.to)
|
38
|
+
send("<presence from='darkcave@macbeth.shakespeare.lit/firstwitch' to='hag66@shakespeare.lit/pda'>" +
|
39
|
+
"<x xmlns='http://jabber.org/protocol/muc#user'><item affiliation='owner' role='moderator'/></x>" +
|
40
|
+
"</presence>" +
|
41
|
+
"<presence from='darkcave@macbeth.shakespeare.lit/secondwitch' to='hag66@shakespeare.lit/pda'>" +
|
42
|
+
"<x xmlns='http://jabber.org/protocol/muc#user'><item affiliation='admin' role='moderator'/></x>" +
|
43
|
+
"</presence>" +
|
44
|
+
"<presence from='darkcave@macbeth.shakespeare.lit/thirdwitch' to='hag66@shakespeare.lit/pda'>" +
|
45
|
+
"<x xmlns='http://jabber.org/protocol/muc#user'><item affiliation='member' role='participant'/></x>" +
|
46
|
+
"</presence>")
|
47
|
+
}
|
48
|
+
# m.my_jid = JID.new('hag66@shakespeare.lit/pda')
|
49
|
+
assert_equal(m, m.join('darkcave@macbeth.shakespeare.lit/thirdwitch'))
|
50
|
+
wait_state
|
51
|
+
|
52
|
+
state { |msg|
|
53
|
+
assert_kind_of(Message, msg)
|
54
|
+
assert_equal(:groupchat, msg.type)
|
55
|
+
assert_equal(JID.new('hag66@shakespeare.lit/pda'), msg.from)
|
56
|
+
assert_equal(JID.new('darkcave@macbeth.shakespeare.lit'), msg.to)
|
57
|
+
# assert_equal('TestCasing room', msg.subject)
|
58
|
+
assert_nil(msg.body)
|
59
|
+
send(msg.set_from('darkcave@macbeth.shakespeare.lit/thirdwitch').set_to('hag66@shakespeare.lit/pda'))
|
60
|
+
}
|
61
|
+
# assert_nil(m.subject)
|
62
|
+
# wait.wait
|
63
|
+
# m.subject = 'TestCasing room'
|
64
|
+
# wait_state
|
65
|
+
# wait.wait
|
66
|
+
|
67
|
+
# FIXME : **Intermittently** failing (especially during RCOV run) at this line with:
|
68
|
+
# 1) Failure:
|
69
|
+
# test_complex(HipchatClientTest) [./test/muc/tc_muc_HipchatClient.rb:71]:
|
70
|
+
# <[nil, "thirdwitch", "TestCasing room"]> expected but was
|
71
|
+
# <[nil, "secondwitch"]>.
|
72
|
+
#
|
73
|
+
#assert_equal([nil, 'thirdwitch', 'TestCasing room'], block_args)
|
74
|
+
|
75
|
+
# FIXME : **Intermittently** failing (especially during RCOV run) at this line with:
|
76
|
+
# 1) Failure:
|
77
|
+
# test_complex(HipchatClientTest) [./test/muc/tc_muc_HipchatClient.rb:80]:
|
78
|
+
# <"TestCasing room"> expected but was
|
79
|
+
# <nil>.
|
80
|
+
#
|
81
|
+
#assert_equal('TestCasing room', m.subject)
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_kick
|
86
|
+
m = MUC::HipchatClient.new(@client.jid)
|
87
|
+
m.stream = @client
|
88
|
+
|
89
|
+
state { |presence|
|
90
|
+
send("<presence from='test@test/test'/>")
|
91
|
+
}
|
92
|
+
m.join('test@test/test')
|
93
|
+
wait_state
|
94
|
+
|
95
|
+
state { |iq|
|
96
|
+
assert_kind_of(Iq, iq)
|
97
|
+
assert_equal('http://jabber.org/protocol/muc#admin', iq.queryns)
|
98
|
+
assert_kind_of(MUC::IqQueryMUCAdmin, iq.query)
|
99
|
+
assert_equal(1, iq.query.items.size)
|
100
|
+
assert_equal('pistol', iq.query.items[0].nick)
|
101
|
+
assert_equal(:none, iq.query.items[0].role)
|
102
|
+
assert_equal('Avaunt, you cullion!', iq.query.items[0].reason)
|
103
|
+
a = iq.answer(false)
|
104
|
+
a.type = :result
|
105
|
+
send(a)
|
106
|
+
}
|
107
|
+
m.kick('pistol', 'Avaunt, you cullion!')
|
108
|
+
wait_state
|
109
|
+
end
|
110
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Jabber
|
4
|
+
module MUC
|
5
|
+
describe HipchatClient do
|
6
|
+
let(:client_jid){ '00000_000000@chat.hipchat.com' }
|
7
|
+
let(:room_jid){ '00000_room@conf.hipchat.com' }
|
8
|
+
|
9
|
+
subject{ described_class.new(client_jid) }
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
it 'assigns JID' do
|
13
|
+
expect(subject.my_jid.to_s).to eq(client_jid)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'assigns chat host' do
|
17
|
+
expect(subject.chat_host).to eq('chat.hipchat.com')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'creates new stream client' do
|
21
|
+
expect(subject.stream).to be_instance_of(Jabber::Client)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#exit' do
|
26
|
+
it 'sets unavailable presence' do
|
27
|
+
expect(subject).to receive(:set_presence).with(:unavailable, anything, anything)
|
28
|
+
subject.exit(room_jid)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#join' do
|
33
|
+
it 'sets available presence' do
|
34
|
+
expect(subject).to receive(:set_presence).with(:available, anything, anything, anything)
|
35
|
+
subject.join(room_jid)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#name' do
|
40
|
+
it 'returns JID resource' do
|
41
|
+
subject.name = 'client name'
|
42
|
+
expect(subject.name).to eq('client name')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#set_presence' do
|
47
|
+
it 'sends a new presence to the stream' do
|
48
|
+
expect(subject.stream).to receive(:send).with(kind_of(Jabber::Presence))
|
49
|
+
subject.set_presence(:type)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/xmpp4r-hipchat.gemspec
CHANGED
@@ -5,9 +5,8 @@ Gem::Specification.new do |spec|
|
|
5
5
|
spec.name = 'xmpp4r-hipchat'
|
6
6
|
spec.version = XMPP4R::HipChat::VERSION
|
7
7
|
spec.authors = ['Bartosz Kopiński']
|
8
|
-
spec.email = ['bartosz
|
9
|
-
spec.
|
10
|
-
spec.summary = 'HipChat client extension to XMPP4R'
|
8
|
+
spec.email = ['bartosz@kopinski.pl']
|
9
|
+
spec.summary = 'HipChat / Slack XMPP Client'
|
11
10
|
spec.homepage = 'https://github.com/bartoszkopinski/xmpp4r-hipchat'
|
12
11
|
spec.license = 'MIT'
|
13
12
|
|
@@ -15,5 +14,6 @@ Gem::Specification.new do |spec|
|
|
15
14
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
15
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
16
|
spec.require_paths = ['lib']
|
18
|
-
spec.add_runtime_dependency 'xmpp4r', ['~> 0.5']
|
17
|
+
spec.add_runtime_dependency 'xmpp4r', ['~> 0.5.6']
|
18
|
+
spec.add_development_dependency 'rspec', ['>= 2.13.0']
|
19
19
|
end
|
metadata
CHANGED
@@ -1,36 +1,51 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xmpp4r-hipchat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bartosz Kopiński
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: xmpp4r
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.5.6
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
-
|
26
|
+
version: 0.5.6
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.13.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.13.0
|
41
|
+
description:
|
28
42
|
email:
|
29
|
-
- bartosz
|
43
|
+
- bartosz@kopinski.pl
|
30
44
|
executables: []
|
31
45
|
extensions: []
|
32
46
|
extra_rdoc_files: []
|
33
47
|
files:
|
48
|
+
- ".gitignore"
|
34
49
|
- Gemfile
|
35
50
|
- LICENSE
|
36
51
|
- LICENSE.txt
|
@@ -39,6 +54,19 @@ files:
|
|
39
54
|
- lib/xmpp4r-hipchat.rb
|
40
55
|
- lib/xmpp4r/hipchat/version.rb
|
41
56
|
- lib/xmpp4r/muc/helper/hipchat_client.rb
|
57
|
+
- lib/xmpp4r/muc/hipchat/kick_message.rb
|
58
|
+
- lib/xmpp4r/muc/hipchat/message.rb
|
59
|
+
- lib/xmpp4r/muc/hipchat/presence.rb
|
60
|
+
- lib/xmpp4r/muc/hipchat/received_message.rb
|
61
|
+
- lib/xmpp4r/muc/hipchat/received_presence.rb
|
62
|
+
- lib/xmpp4r/muc/hipchat/received_stanza.rb
|
63
|
+
- lib/xmpp4r/muc/hipchat/room_data.rb
|
64
|
+
- lib/xmpp4r/muc/hipchat/user_data.rb
|
65
|
+
- lib/xmpp4r/muc/hipchat/vcard.rb
|
66
|
+
- spec/integration/muc/clienttester.rb
|
67
|
+
- spec/integration/muc/tc_muc_hipchat_client.rb
|
68
|
+
- spec/spec_helper.rb
|
69
|
+
- spec/unit/hipchat_client_spec.rb
|
42
70
|
- xmpp4r-hipchat.gemspec
|
43
71
|
homepage: https://github.com/bartoszkopinski/xmpp4r-hipchat
|
44
72
|
licenses:
|
@@ -50,18 +78,22 @@ require_paths:
|
|
50
78
|
- lib
|
51
79
|
required_ruby_version: !ruby/object:Gem::Requirement
|
52
80
|
requirements:
|
53
|
-
- -
|
81
|
+
- - ">="
|
54
82
|
- !ruby/object:Gem::Version
|
55
83
|
version: '0'
|
56
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
85
|
requirements:
|
58
|
-
- -
|
86
|
+
- - ">="
|
59
87
|
- !ruby/object:Gem::Version
|
60
88
|
version: '0'
|
61
89
|
requirements: []
|
62
90
|
rubyforge_project:
|
63
|
-
rubygems_version: 2.
|
91
|
+
rubygems_version: 2.6.13
|
64
92
|
signing_key:
|
65
93
|
specification_version: 4
|
66
|
-
summary: HipChat
|
67
|
-
test_files:
|
94
|
+
summary: HipChat / Slack XMPP Client
|
95
|
+
test_files:
|
96
|
+
- spec/integration/muc/clienttester.rb
|
97
|
+
- spec/integration/muc/tc_muc_hipchat_client.rb
|
98
|
+
- spec/spec_helper.rb
|
99
|
+
- spec/unit/hipchat_client_spec.rb
|