lita-hcadmin 0.3.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,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
+ }