lita-hcadmin 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,441 @@
1
+ require 'benchmark'
2
+ require 'open-uri'
3
+ require 'faraday'
4
+ require 'base64'
5
+ require 'net/smtp'
6
+ require 'logger'
7
+ require 'open-uri'
8
+
9
+ module Lita
10
+ module Handlers
11
+ class Hcadmin < Handler
12
+ namespace 'hcadmin'
13
+ config :v1_notify_token, type: String, required: true
14
+ config :v1_admin_token, type: String, required: true
15
+ config :v2_admin_token, type: String, required: true
16
+ config :http_proxy, type: String, required: false
17
+ config :email_dist_list
18
+ config :smtp_server
19
+ config :allowed_domains
20
+ config :room_change_admins, type: Array, required: false
21
+ config :account_name, type: String, required: true
22
+ config :email_domain_name, type: Array, required: true
23
+ config :http_logging, type: [TrueClass, FalseClass], default: true, required: false
24
+
25
+ route(/(?:(?:identify room owner))\s+(.+)/i,
26
+ :identify_room_owner,
27
+ help: { 'identify room owner ROOM_NAME' => 'Returns the mention name of the room owner.' })
28
+
29
+ route(/(?:(?:identify hipchat admins))/i,
30
+ :identify_hipchat_admins,
31
+ help: { 'identify hipchat admins' => 'Returns the mention name of the HipChat Admins.' })
32
+
33
+ route(/(?:(?:identify user count))/i,
34
+ :identify_user_count,
35
+ help: { 'identify user count' => 'Returns the count of users in the account.' })
36
+
37
+ route(/(?:(?:identify room count))/i,
38
+ :identify_room_count,
39
+ help: { 'identify room count' => 'Returns the count of rooms in the account.' })
40
+
41
+ route(/(?:(?:identify room change admins))/i,
42
+ :identify_room_change_admins,
43
+ help: { 'identify room change admins' => 'Returns a list of who can change room ownership' })
44
+
45
+ route(/(?:(?:identify status))/i,
46
+ :identify_status,
47
+ help: { 'identify status' => 'Returns the status of HipChat.' })
48
+
49
+ route(/(?:(?:hipchat sponsor))\s+(.+)/i,
50
+ :hipchat_sponsor,
51
+ help: { 'hipchat sponsor EMAIL ADDRESS' => 'Generates an invite to the person being sponsored. Use a valid email address' })
52
+
53
+ route(/(?:(?:room owner change))\s+(.+)/i,
54
+ :room_owner_change,
55
+ help: { 'room owner change owner_mention_name room_name ' => 'When run as a room change admin, updates the room ownership' })
56
+
57
+ route(/(?:(?:room unarchive))/i, # route(/(?:(?:room unarchive))\s+(.+)/i,
58
+ :room_unarchive,
59
+ help: { 'room unarchive room_name ' => 'When run as a room change admin, removes a room from archive' })
60
+
61
+ def hipchat_sponsor(response)
62
+ response.args.each do |r|
63
+ next if 'sponsor'.include?(r)
64
+ if email_domain_name.any? { |w| r[w] } # rubocop:disable Style/GuardClause
65
+ sponsored_user = fetch_user_v2(r.strip)
66
+ sponsored_user_json = parse(sponsored_user[:body], 'sponsor')
67
+ if sponsored_user_json['id'] # rubocop:disable Style/GuardClause
68
+ return response.reply "The email address of #{r} already has an account on #{account_name} of #{sponsored_user_json['id']}"
69
+ else
70
+ response.reply "The email address of #{r} was not found. Generating request to #{email_dist_list}"
71
+ response.reply "Admins have been notified of your request to add #{r}, @#{response.user.name}"
72
+ send_mail(r, email_dist_list, response.user.name, smtp_server)
73
+ return response.reply 'Message to admins sent'
74
+ end
75
+ else
76
+ return response.reply "The email address has to be one of: #{email_domain_name.inspect}"
77
+ end
78
+ end
79
+ response.reply 'something'
80
+ end
81
+
82
+ def identify_status(response)
83
+ status = ''
84
+ time = Benchmark.measure do
85
+ status = fetch_status
86
+ end
87
+ response.reply "Status of hipchat: Code: #{status[:status]} => #{status[:body]} ( #{time.real.to_i} s. to respond )"
88
+ end
89
+
90
+ def identify_user_count(response)
91
+ user_count = ''
92
+ time = Benchmark.measure do
93
+ user_count = fetch_stats
94
+ user_count = parse(user_count[:body], 'users')
95
+ # user_count = parse(fetch_users, 'users')
96
+ end
97
+ response.reply "Users in hipchat: #{user_count} ( #{time.real.to_i} s. to respond )"
98
+ end
99
+
100
+ def identify_room_change_admins(response)
101
+ response.reply 'Users who can change room ownership:'
102
+ time = Benchmark.measure do
103
+ if room_change_admins.first.to_s.empty? # rubocop:disable Style/GuardClause
104
+ return response.reply 'Room change admins: None found from config'
105
+ else
106
+ room_change_admins.each do |a|
107
+ response.reply a.to_s
108
+ end
109
+ end
110
+ end
111
+ response.reply "room change admins: #{room_change_admins.length} found ( #{time.real.to_i} s. to respond )"
112
+ end
113
+
114
+ def identify_room_count(response)
115
+ room_count = ''
116
+ time = Benchmark.measure do
117
+ room_count = fetch_rooms
118
+ room_count = parse(room_count[:body], 'rooms')
119
+ end
120
+ response.reply "Rooms in hipchat: #{room_count.length} ( #{time.real.to_i} s. to respond )"
121
+ end
122
+
123
+ def identify_hipchat_admins(response)
124
+ response.reply 'Admin search takes a moment ...'
125
+ admin_message = nil
126
+ time = Benchmark.measure do
127
+ parse_users = fetch_users
128
+ if parse_users[:status] != 200
129
+ admin_message = "I ran into an HTTP error ( HTTP code: #{parse_users[:status]} )"
130
+ else
131
+ all_users = parse(parse_users[:body], 'users')
132
+ all_users.each do |u|
133
+ next if u['is_group_admin'] == 0
134
+ response.reply u['mention_name']
135
+ end
136
+ admin_message = 'complete'
137
+ end
138
+ end
139
+ response.reply "Admin list: #{admin_message} ( #{time.real.to_i} s. to respond )"
140
+ end
141
+
142
+ def identify_room_owner(response)
143
+ room_name = nil
144
+ reply_message = nil
145
+ room_owner = nil
146
+ time = Benchmark.measure do
147
+ response.matches.each do |match|
148
+ room_name = normalize_room_name(match[0])
149
+ end
150
+ # get room json
151
+ response.reply 'Getting rooms ... one moment'
152
+ room_data = fetch_rooms
153
+
154
+ response.reply 'Getting room id ... another moment'
155
+ room_id = id_from_name(room_name, parse(room_data[:body], 'rooms'))
156
+
157
+ response.reply 'Getting the user name from the user ID ... almost there'
158
+ room_owner = owner_id_from_room_id(room_id, parse(room_data[:body], 'rooms'))
159
+
160
+ if room_owner.nil?
161
+ reply_message = "Room #{room_name} apparently does not have an owner or I could not find a room with that name"
162
+ elsif room_id.nil?
163
+ reply_message = "Room #{room_name} apparently does not have an owner or I could not find a room with that name"
164
+ end
165
+ end
166
+
167
+ if reply_message.nil?
168
+ user_data = fetch_user(room_owner)
169
+ owner_mention = owner_name_from_id(parse(user_data[:body], 'user'))
170
+ reply_message = "The owner of #{room_name} is #{owner_mention}"
171
+ response.reply reply_message
172
+ else
173
+ response.reply reply_message + " ( #{time.real.to_i} s. to respond )"
174
+ end
175
+ end
176
+
177
+ def parse(json, type)
178
+ json = JSON.parse(json)
179
+ case type
180
+ when 'rooms'
181
+ json = json['rooms']
182
+ when 'user'
183
+ json = json['user']
184
+ when 'users'
185
+ json = json['users']
186
+ when 'status'
187
+ json = json['body']
188
+ when 'sponsor'
189
+ json = json
190
+ end
191
+ json
192
+ end
193
+
194
+ def id_from_name(room_name, json)
195
+ room_id = nil
196
+ json.each do |j|
197
+ next unless room_name == j['name'].to_s.downcase.strip
198
+ room_id = j['room_id']
199
+ end
200
+ room_id
201
+ end
202
+
203
+ def owner_id_from_room_id(room_id, json)
204
+ owner_id = nil
205
+ json.each do |j|
206
+ next unless room_id == j['room_id']
207
+ owner_id = j['owner_user_id']
208
+ end
209
+ owner_id
210
+ end
211
+
212
+ def owner_name_from_id(json)
213
+ user_name = json['mention_name']
214
+ user_name
215
+ end
216
+
217
+ def room_owner_change(response) # Length check => owner: 1, change: 2, member_name: 3, room_name: 4, room_name can be multiple words!
218
+ return response.reply 'You are not represented in the room owner change admin group' unless user_in_group(response.user.mention_name, room_change_admins) == true
219
+ return response.reply "Wrong number of arguments; expected format of owner_name & room_name received arguments: #{response.args.values_at(2..response.args.length - 1)}" unless response.args.length > 3
220
+ user_details = user_data('@' + response.args[2].to_s)
221
+ return response.reply "Uh-oh, 404 returned! The user #{response.args[2]} not found" if user_details['id'].nil?
222
+ room_details = room_data(response.args[3..-1].join(' ').to_s)
223
+ return response.reply "Uh-oh, 404 returned! The room #{response.args[3..-1].join(' ')} not found" if room_details['id'].nil?
224
+ room_update = {}
225
+ room_update['name'] = room_details['name']
226
+ room_update['privacy'] = room_details['privacy']
227
+ room_update['is_archived'] = room_details['is_archived']
228
+ room_update['is_guest_accessible'] = room_details['is_guest_accessible']
229
+ room_update['topic'] = room_details['topic']
230
+ room_update['owner'] = { id: user_details['id'].to_s }
231
+ unless JSON.parse(room_update.to_json) #
232
+ return response.reply "Unfortunately, I was not able to present valid date to the API: #{room_update}"
233
+ end
234
+
235
+ update_room = http_put("https://api.hipchat.com/v2/room/#{room_details['id']}?auth_token=#{v2_admin_token}&format=json", room_update)
236
+ response.reply "Room update request sent. HTTP response code: #{update_room.status}"
237
+ end
238
+
239
+ def room_unarchive(response)
240
+ return response.reply 'You are not represented in the room owner change admin group' unless user_in_group(response.user.mention_name, room_change_admins) == true
241
+ return response.reply 'Wrong number of arguments; expected format of room_name received arguments' unless response.args.length > 1
242
+ room_details = room_data(response.args[1..-1].join(' ').to_s)
243
+ return response.reply "Uh-oh, 404 returned! The room #{response.args[1..-1].join(' ')} not found" if room_details['id'].nil?
244
+ room_owner = room_details['owner']['id']
245
+ room_update = {}
246
+ room_update['name'] = room_details['name']
247
+ room_update['privacy'] = room_details['privacy']
248
+ room_update['is_archived'] = false
249
+ room_update['is_guest_accessible'] = room_details['is_guest_accessible']
250
+ room_update['topic'] = room_details['topic']
251
+ room_update['owner'] = { id: room_owner.to_s }
252
+ update_room = http_put("https://api.hipchat.com/v2/room/#{room_details['id']}?auth_token=#{v2_admin_token}&format=json", room_update)
253
+ response.reply "Room update request sent. HTTP response code: #{update_room.status}"
254
+ end
255
+
256
+ def fetch_data(api_v, object_type, object_id)
257
+ object_id = url_encode_name(object_id) if object_id.class == String
258
+ return 'Wrong API version provided' unless api_v == 'v2'
259
+ return "Wrong HipChat object type (#{object_type}). Only accepts 'room' or 'user'" unless %w('room', 'user').any? { |s| s.include?(object_type.to_s) }
260
+ return 'Please provide the object id of the room or user you want information for' if object_id.nil?
261
+ url = "https://api.hipchat.com/v2/#{object_type}/#{object_id}?auth_token=#{v2_admin_token}&format=json"
262
+ proxy = http_proxy || nil
263
+ json = get url, proxy
264
+ json
265
+ end
266
+
267
+ private
268
+
269
+ def user_data(user_name)
270
+ user_check = JSON.parse(fetch_data('v2', 'user', user_name).to_json)
271
+ user_details = JSON.parse(user_check['body'])
272
+ user_details
273
+ end
274
+
275
+ def room_data(room_name)
276
+ room_check = JSON.parse(fetch_data('v2', 'room', room_name).to_json)
277
+ room_details = JSON.parse(room_check['body'])
278
+ room_details
279
+ end
280
+
281
+ def url_encode_name(str)
282
+ URI.encode(str)
283
+ end
284
+
285
+ def user_in_group(user, group)
286
+ group.include?(user) ? true : false
287
+ end
288
+
289
+ def username_from_email(email)
290
+ email_name = email.split('@')[0].strip
291
+ email_name
292
+ end
293
+
294
+ def fetch_rooms # full list
295
+ url = "https://api.hipchat.com/v1/rooms/list?auth_token=#{v1_admin_token}&format=json"
296
+ proxy = http_proxy || nil
297
+ json = get url, proxy
298
+ json
299
+ end
300
+
301
+ def fetch_status # full list
302
+ url = 'https://api.hipchat.com/v2/health-check'
303
+ proxy = http_proxy || nil
304
+ json = get url, proxy
305
+ json
306
+ end
307
+
308
+ def fetch_stats # fast user count
309
+ url = "https://api.hipchat.com/v2/group/171096/statistics?auth_token=#{v2_admin_token}&format=json"
310
+ proxy = http_proxy || nil
311
+ json = get url, proxy
312
+ json
313
+ end
314
+
315
+ def fetch_user(user_id)
316
+ url = "https://api.hipchat.com/v1/users/show?user_id=#{user_id}&auth_token=#{v1_admin_token}&format=json"
317
+ proxy = http_proxy || nil
318
+ json = get url, proxy
319
+ json
320
+ end
321
+
322
+ def fetch_users # full list
323
+ url = "https://api.hipchat.com/v1/users/list?auth_token=#{v1_admin_token}&format=json"
324
+ proxy = http_proxy || nil
325
+ json = get url, proxy
326
+ json
327
+ end
328
+
329
+ def fetch_user_v2(user_context)
330
+ url = "https://api.hipchat.com/v2/user/#{user_context}?auth_token=#{v2_admin_token}&format=json"
331
+ proxy = http_proxy || nil
332
+ json = get url, proxy
333
+ json
334
+ end
335
+
336
+ def email_domain_name
337
+ config.email_domain_name
338
+ end
339
+
340
+ def http_logging
341
+ config.http_logging
342
+ end
343
+
344
+ def account_name
345
+ config.account_name
346
+ end
347
+
348
+ def v1_notify_token
349
+ config.v1_notify_token
350
+ end
351
+
352
+ def v1_admin_token
353
+ config.v1_admin_token
354
+ end
355
+
356
+ def v2_admin_token
357
+ config.v2_admin_token
358
+ end
359
+
360
+ def email_dist_list
361
+ config.email_dist_list
362
+ end
363
+
364
+ def smtp_server
365
+ config.smtp_server
366
+ end
367
+
368
+ def http_proxy
369
+ config.http_proxy
370
+ end
371
+
372
+ def room_change_admins
373
+ config.room_change_admins
374
+ end
375
+
376
+ def normalize_room_name(room_name)
377
+ room_name = room_name.to_s.downcase.strip
378
+ room_name
379
+ end
380
+
381
+ def send_mail(new_user, to_dist_list, from_mention, smtp_server_name)
382
+ message = <<END_OF_EMAIL
383
+ From:#{username_from_email(new_user)} <#{new_user}>
384
+ To: #{username_from_email(to_dist_list)} <#{to_dist_list}>
385
+ Cc: #{username_from_email(new_user)} <#{new_user}>
386
+ MIME-version: 1.0
387
+ Content-type: text/html
388
+ Subject: request access
389
+
390
+
391
+ I have been sponsored by #{from_mention} in HipChat. I'd like an invite.
392
+ END_OF_EMAIL
393
+ Net::SMTP.start(smtp_server_name) do |mail|
394
+ mail.send_message message, new_user, to_dist_list, new_user
395
+ mail.finish
396
+ end
397
+ end
398
+
399
+ def get(url, _proxy = {})
400
+ conn = Faraday.new(url: url) do |f|
401
+ f.request :url_encoded
402
+ f.response :logger if http_logging
403
+ f.adapter Faraday.default_adapter
404
+ end
405
+
406
+ response = conn.get do |g|
407
+ g.options.timeout = 60
408
+ g.options.open_timeout = 60
409
+ g.headers['Content-Type'] = 'application/json'
410
+ g.headers['Accept'] = 'application/json'
411
+ end
412
+
413
+ http_response = { status: response.status, body: response.body }
414
+ http_response
415
+ end
416
+
417
+ def http_put(url, payload, _proxy = {})
418
+ conn = http_conn(url)
419
+ response = conn.put do |c|
420
+ c.options.timeout = 60
421
+ c.options.open_timeout = 60
422
+ c.headers['Content-Type'] = 'application/json'
423
+ c.headers['Accept'] = 'application/json'
424
+ c.body = payload.to_json
425
+ end
426
+ response
427
+ end
428
+
429
+ def http_conn(url)
430
+ @http_conn = Faraday.new(url: url) do |h|
431
+ h.request :url_encoded
432
+ h.response :logger if http_logging
433
+ h.adapter Faraday.default_adapter
434
+ end
435
+ @http_conn
436
+ end
437
+
438
+ Lita.register_handler(self)
439
+ end
440
+ end
441
+ end
@@ -0,0 +1,13 @@
1
+ require 'lita' # rubocop:disable Style/FileName
2
+ require 'lita/version'
3
+ Lita.load_locales Dir[File.expand_path(
4
+ File.join('..', '..', 'locales', '*.yml'), __FILE__
5
+ )]
6
+
7
+ require 'lita/handlers/hcadmin'
8
+ require 'lita/version'
9
+
10
+ Lita::Handlers::Hcadmin.template_root File.expand_path(
11
+ File.join('..', '..', 'templates'),
12
+ __FILE__
13
+ )
@@ -0,0 +1,25 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lita-hcadmin"
3
+ spec.version = "0.3.3"
4
+ spec.authors = ["Jason Walker"]
5
+ spec.email = ["jason.walker@target.com"]
6
+ spec.description = "HipChat admin plugin for Lita"
7
+ spec.summary = "Allow your HipChat admins to interact with the HipChat APIs"
8
+ spec.homepage = "https://github.com/target/lita-hipchat-admin"
9
+ spec.license = "MIT"
10
+ spec.metadata = { "lita_plugin_type" => "handler" }
11
+
12
+ spec.files = `git ls-files`.split($/)
13
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_runtime_dependency "lita", ">= 4.3"
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "pry-byebug"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rack-test"
23
+ spec.add_development_dependency "rspec", ">= 3.0.0"
24
+ spec.add_development_dependency "rest-client"
25
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,4 @@
1
+ en:
2
+ lita:
3
+ handlers:
4
+ hcadmin:
@@ -0,0 +1 @@
1
+ <html>\r\n<head><title>502 Bad Gateway</title></head>\r\n<body bgcolor=\"white\">\r\n<center><h1>502 Bad Gateway</h1></center>\r\n<hr><center>nginx</center>\r\n</body>\r\n</html>\r\n
@@ -0,0 +1,40 @@
1
+ {
2
+ "rooms": [
3
+ {
4
+ "room_id": 31,
5
+ "name": "floppy drive",
6
+ "topic": "",
7
+ "last_active": 55,
8
+ "created": 56,
9
+ "owner_user_id": 2341755,
10
+ "is_archived": false,
11
+ "is_private": true,
12
+ "guest_access_url": null,
13
+ "xmpp_jid": "11_boofar@conf.hipchat.com"
14
+ },
15
+ {
16
+ "room_id": 32,
17
+ "name": "#DOES15",
18
+ "topic": "",
19
+ "last_active": 56,
20
+ "created": 57,
21
+ "owner_user_id": 1291419,
22
+ "is_archived": false,
23
+ "is_private": true,
24
+ "guest_access_url": null,
25
+ "xmpp_jid": "11_boofar@conf.hipchat.com"
26
+ },
27
+ {
28
+ "room_id": 33,
29
+ "name": "11",
30
+ "topic": "",
31
+ "last_active": 58,
32
+ "created": 59,
33
+ "owner_user_id": 2483071,
34
+ "is_archived": false,
35
+ "is_private": true,
36
+ "guest_access_url": null,
37
+ "xmpp_jid": "11_boofar@conf.hipchat.com"
38
+ }
39
+ ]
40
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "avatar_url": null,
3
+ "created": "2015-04-27T17:55:04+00:00",
4
+ "delegate_admin_visibility": null,
5
+ "guest_access_url": null,
6
+ "id": 1460619,
7
+ "is_archived": false,
8
+ "is_guest_accessible": false,
9
+ "last_active": "2016-02-12T17:32:37+00:00",
10
+ "links": {
11
+ "participants": "https://api.hipchat.com/v2/room/55/participant",
12
+ "self": "https://api.hipchat.com/v2/room/55",
13
+ "webhooks": "https://api.hipchat.com/v2/room/55/webhook"
14
+ },
15
+ "name": "Test Room @ Company.com",
16
+ "owner": {
17
+ "id": 66,
18
+ "links": {
19
+ "self": "https://api.hipchat.com/v2/user/66"
20
+ },
21
+ "mention_name": "Solo",
22
+ "name": "Red Solo Cup",
23
+ "version": "D4AFE5D2"
24
+ },
25
+ "participants": [
26
+ {
27
+ "id": 123,
28
+ "links": {
29
+ "self": "https://api.hipchat.com/v2/user/123"
30
+ },
31
+ "mention_name": "Paper",
32
+ "name": "Green Paper Plate",
33
+ "version": "078RPR8X"
34
+ }
35
+ ],
36
+ "privacy": "public",
37
+ "statistics": {
38
+ "links": {
39
+ "self": "https://api.hipchat.com/v2/room/55/statistics"
40
+ }
41
+ },
42
+ "topic": "Room for testing things",
43
+ "version": "RR2FE49I",
44
+ "xmpp_jid": "321_testing__things@conf.hipchat.com"
45
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "links": {
3
+ "self": "https://api.hipchat.com/v2/group/11/statistics"
4
+ },
5
+ "users": 5315
6
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "status": "okay"
3
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "user": {
3
+ "user_id": 55,
4
+ "email": "awesome.sauce@company.com",
5
+ "is_deleted": 0,
6
+ "is_group_admin": 0,
7
+ "name": "Awesome Sauce",
8
+ "mention_name": "AwesomeSauce",
9
+ "photo_url": "https://s3.amazonaws.com/uploads.hipchat.com/photos/55/CweZ4eN82RiAn7s_125.jpg",
10
+ "last_active": 10,
11
+ "created": 9,
12
+ "status": "available",
13
+ "status_message": "",
14
+ "timezone": "America/Chicago",
15
+ "title": "Awesome dude"
16
+ }
17
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "created": "2014-09-19T23:26:09+00:00",
3
+ "email": "valid_user@company.com",
4
+ "group": {
5
+ "id": 22,
6
+ "links": {
7
+ "self": "https://api.hipchat.com/v2/group/123"
8
+ },
9
+ "name": "TestHipChatAccount"
10
+ },
11
+ "id": 11,
12
+ "is_deleted": false,
13
+ "is_group_admin": true,
14
+ "is_guest": false,
15
+ "last_active": "2015-11-23T14:07:33+0000",
16
+ "links": {
17
+ "self": "https://api.hipchat.com/v2/user/boofar"
18
+ },
19
+ "mention_name": "JasonWalker",
20
+ "name": "Jason Walker",
21
+ "photo_url": "https://s3.amazonaws.com/uploads.hipchat.com/photos/foobar/ZeVseMiEejjdTe3_125.jpg",
22
+ "presence": {
23
+ "client": {
24
+ "type": "http://hipchat.com/client/mac",
25
+ "version": "202"
26
+ },
27
+ "is_online": true,
28
+ "show": "chat"
29
+ },
30
+ "roles": [
31
+ "owner",
32
+ "admin",
33
+ "user"
34
+ ],
35
+ "timezone": "America/Chicago",
36
+ "title": "admin of the things",
37
+ "version": "LVNLL4UA",
38
+ "xmpp_jid": "11_11@chat.hipchat.com"
39
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "error": {
3
+ "code": 404,
4
+ "message": "Target user notreal.email@company.com is not a valid user",
5
+ "type": "Not Found"
6
+ }
7
+ }