slack-ruby-bot 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 875e496a2ad1228dd53fb09a429cef5d26bb2b33
4
- data.tar.gz: 115852404bdba1534728728a3cd56cf818c4ac0e
3
+ metadata.gz: 59c7b21c6857323515327cf3b14c4cd79bdfe25b
4
+ data.tar.gz: ae4beccb7a8d933d2f7b6fffb170241fad4a85d4
5
5
  SHA512:
6
- metadata.gz: e7442eeded435d0f5b23b63310086946170f8c15b51b9bf4d45592a01197aa3eaf95ef27df7bbaa6bab1290c538b0ebb1847f030d5979cc7e43db0385a7c00bd
7
- data.tar.gz: 670e97f790446e1974429ac8dad199e6a3312356df6b55f28ed605e9464262468c9527f0b0f6a768ad9e7f125d8d652c704722db96d018e7a6cea92358b3b65e
6
+ metadata.gz: 213767e2c36e1287e2916e24652b4ed873a3fb9bc84ff60e16bb7e6fcdf847d11dd622174421bed755febf65bf934bfc3000a3d3f0874afab7751b7c0bfc3db0
7
+ data.tar.gz: aaff927afb06fce22a67e090bf4954cea920a383a84277bf681a00e5c29154f8ff66b5c9ed979625bd03b2a1cf1f79d28b9beb37e0d53fe370bc12aa49ef77da
@@ -1,5 +1,5 @@
1
1
  # This configuration was generated by `rubocop --auto-gen-config`
2
- # on 2016-02-02 07:10:58 -0500 using RuboCop version 0.32.1.
2
+ # on 2016-02-09 15:33:27 -0500 using RuboCop version 0.32.1.
3
3
  # The point is for the user to remove these configuration records
4
4
  # one by one as the offenses are removed from the code base.
5
5
  # Note that changes in the inspected code, or installation of new
@@ -11,27 +11,32 @@ Lint/HandleExceptions:
11
11
 
12
12
  # Offense count: 6
13
13
  Metrics/AbcSize:
14
- Max: 28
14
+ Max: 42
15
+
16
+ # Offense count: 1
17
+ # Configuration parameters: CountComments.
18
+ Metrics/ClassLength:
19
+ Max: 102
15
20
 
16
21
  # Offense count: 2
17
22
  Metrics/CyclomaticComplexity:
18
- Max: 8
23
+ Max: 12
19
24
 
20
- # Offense count: 126
25
+ # Offense count: 130
21
26
  # Configuration parameters: AllowURI, URISchemes.
22
27
  Metrics/LineLength:
23
28
  Max: 158
24
29
 
25
- # Offense count: 6
30
+ # Offense count: 7
26
31
  # Configuration parameters: CountComments.
27
32
  Metrics/MethodLength:
28
- Max: 21
33
+ Max: 27
29
34
 
30
35
  # Offense count: 2
31
36
  Metrics/PerceivedComplexity:
32
- Max: 8
37
+ Max: 12
33
38
 
34
- # Offense count: 19
39
+ # Offense count: 20
35
40
  Style/Documentation:
36
41
  Enabled: false
37
42
 
@@ -1,3 +1,9 @@
1
+ ### 0.7.0 (3/6/2016)
2
+
3
+ * Improved regular expression matching performance with less matching per command - [@dblock](https://github.com/dblock).
4
+ * Don't attempt to pre-authenticate via `auth!`, use RealTime client local store - [@dblock](https://github.com/dblock).
5
+ * Extended `match` with `scan` that can make multiple captures - [@dblock](https://github.com/dblock).
6
+
1
7
  ### 0.6.2 (2/4/2016)
2
8
 
3
9
  * [#44](https://github.com/dblock/slack-ruby-bot/pull/44): Bot graceful shutdown - [@accessd](https://github.com/accessd).
data/README.md CHANGED
@@ -17,7 +17,7 @@ A generic Slack bot framework written in Ruby on top of [slack-ruby-client](http
17
17
 
18
18
  ## Stable Release
19
19
 
20
- You're reading the documentation for the **stable** release of slack-ruby-bot. See [CHANGELOG](CHANGELOG.md) for a history of changes and [UPGRADING](UPGRADING.md) for how to upgrade to more recent versions.
20
+ You're reading the documentation for the **stable** release of slack-ruby-bot, 0.7.0. See [CHANGELOG](CHANGELOG.md) for a history of changes and [UPGRADING](UPGRADING.md) for how to upgrade to more recent versions.
21
21
 
22
22
  ## Usage
23
23
 
@@ -125,6 +125,20 @@ end
125
125
 
126
126
  ![](screenshots/weather.gif)
127
127
 
128
+ You can also capture multiple matchers with `scan`.
129
+
130
+ ```ruby
131
+ class Market < SlackRubyBot::Bot
132
+ scan(/(\[A-Z]{2,5})/) do |client, data, stocks|
133
+ # lookup stock market price
134
+ end
135
+ end
136
+ ```
137
+
138
+ ![](screenshots/market.gif)
139
+
140
+ See [examples/market](examples/market/marketbot.rb) for a working example.
141
+
128
142
  ### SlackRubyBot::Commands::Base
129
143
 
130
144
  The `SlackRubyBot::Bot` class is DSL sugar deriving from `SlackRubyBot::Commands::Base`. For more involved bots you can organize the bot implementation into subclasses of `SlackRubyBot::Commands::Base` manually. By default a command class responds, case-insensitively, to its name. A class called `Phone` that inherits from `SlackRubyBot::Commands::Base` responds to `phone` and `Phone` and calls the `call` method when implemented.
@@ -223,11 +237,9 @@ You may want to integrate a bot or multiple bots into other systems, in which ca
223
237
  ```ruby
224
238
  EM.run do
225
239
  bot1 = SlackRubyBot::Server.new(token: token1, aliases: ['bot1'])
226
- bot1.auth!
227
240
  bot1.start_async
228
241
 
229
242
  bot2 = SlackRubyBot::Server.new(token: token2, send_gifs: false, aliases: ['bot2'])
230
- bot2.auth!
231
243
  bot2.start_async
232
244
  end
233
245
  ```
@@ -1,6 +1,16 @@
1
1
  Upgrading SlackRubyBot
2
2
  ======================
3
3
 
4
+ ### Upgrading to >= 0.7.0
5
+
6
+ #### Simplify Match Expression Checking
7
+
8
+ The regular expression parser for commands will now include a `nil` value for `expression` when an expression is not present. You can therefore no longer rely on checking `match.names.include?('expression')`, instead check `match['expression']`.
9
+
10
+ #### Remove any bot.auth! calls
11
+
12
+ SlackRubyBot 0.6.x versions invoked a method called `auth!`, which caused a pre-flight authentication via Slack Web API `auth_test` method and collected a number of properties, such as client and team ID or name. This method has been removed in favor of using data available in the `Slack::RealTime::Client` local store introduced in [slack-ruby-client#54](https://github.com/dblock/slack-ruby-client/issues/54). Remove any explicit calls to this method.
13
+
4
14
  ### Upgrading to >= 0.6.0
5
15
 
6
16
  While entirely compatible with the 0.5.x series, a number of methods have been deprecated and will be removed in the next release.
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'slack-ruby-bot', path: '../..'
4
+ gem 'yahoo-finance'
@@ -0,0 +1 @@
1
+ console: bundle exec ruby marketbot.rb
@@ -0,0 +1,24 @@
1
+ require 'slack-ruby-bot'
2
+ require 'yahoo-finance'
3
+
4
+ class MarketBot < SlackRubyBot::Bot
5
+ scan(/([A-Z]{2,5}+)/) do |client, data, stocks|
6
+ YahooFinance::Client.new.quotes(stocks, [:name, :symbol, :last_trade_price, :change, :change_in_percent]).each do |quote|
7
+ next if quote.symbol == 'N/A'
8
+ client.web_client.chat_postMessage(
9
+ channel: data.channel,
10
+ as_user: true,
11
+ attachments: [
12
+ {
13
+ fallback: "#{quote.name} (#{quote.symbol}): $#{quote.last_trade_price}",
14
+ title: "#{quote.name} (#{quote.symbol})",
15
+ text: "$#{quote.last_trade_price} (#{quote.change_in_percent})",
16
+ color: quote.change.to_f > 0 ? '#00FF00' : '#FF0000'
17
+ }
18
+ ]
19
+ )
20
+ end
21
+ end
22
+ end
23
+
24
+ MarketBot.run
@@ -21,15 +21,16 @@ module SlackRubyBot
21
21
 
22
22
  private
23
23
 
24
- def auth!
25
- super
24
+ def hello(client, _data)
26
25
  SlackRubyBot.configure do |config|
27
- config.url = client.auth['url']
28
- config.team = client.auth['team']
29
- config.user = client.auth['user']
30
- config.team_id = client.auth['team_id']
31
- config.user_id = client.auth['user_id']
32
- end
26
+ config.url = "https://#{client.team.domain}.slack.com"
27
+ config.team = client.team.name
28
+ config.team_id = client.team.id
29
+ config.user = client.self.name
30
+ config.user_id = client.self.id
31
+ logger.info "Welcome #{config.user} to the #{config.team} team."
32
+ end if client.team && client.self
33
+ super
33
34
  end
34
35
 
35
36
  def reset!
@@ -1,7 +1,6 @@
1
1
  module SlackRubyBot
2
2
  class Client < Slack::RealTime::Client
3
3
  include Loggable
4
- attr_accessor :auth
5
4
  attr_accessor :aliases
6
5
  attr_accessor :send_gifs
7
6
 
@@ -14,14 +13,14 @@ module SlackRubyBot
14
13
  def names
15
14
  [
16
15
  SlackRubyBot::Config.user,
17
- auth ? auth['user'] : nil,
16
+ self.self ? self.self.name : nil,
18
17
  aliases,
19
18
  SlackRubyBot::Config.aliases,
20
- auth ? "<@#{auth['user_id'].downcase}>" : nil,
19
+ self.self && self.self.id ? "<@#{self.self.id.downcase}>" : nil,
21
20
  SlackRubyBot::Config.user_id ? "<@#{SlackRubyBot::Config.user_id.downcase}>" : nil,
22
- auth ? "<@#{auth['user_id'].downcase}>:" : nil,
21
+ self.self && self.self.id ? "<@#{self.self.id.downcase}>:" : nil,
23
22
  SlackRubyBot::Config.user_id ? "<@#{SlackRubyBot::Config.user_id.downcase}>:" : nil,
24
- auth ? "#{auth['user']}:" : nil,
23
+ self.self && self.self.name ? "#{self.self.name.downcase}:" : nil,
25
24
  SlackRubyBot::Config.user ? "#{SlackRubyBot::Config.user}:" : nil
26
25
  ].compact.flatten
27
26
  end
@@ -35,11 +34,11 @@ module SlackRubyBot
35
34
  end
36
35
 
37
36
  def name
38
- SlackRubyBot.config.user || (auth && auth['user'])
37
+ SlackRubyBot.config.user || (self.self && self.self.name)
39
38
  end
40
39
 
41
40
  def url
42
- SlackRubyBot.config.url || (auth && auth['url'])
41
+ SlackRubyBot.config.url || super
43
42
  end
44
43
 
45
44
  def say(options = {})
@@ -29,44 +29,53 @@ module SlackRubyBot
29
29
  end
30
30
 
31
31
  def operator(*values, &block)
32
- values.each do |value|
33
- match Regexp.new("^(?<operator>\\#{value})(?<expression>.*)$", Regexp::IGNORECASE), &block
34
- end
32
+ values = values.map { |value| Regexp.escape(value) }.join('|')
33
+ match Regexp.new("^(?<operator>#{values})(?<expression>.*)$", Regexp::IGNORECASE), &block
35
34
  end
36
35
 
37
36
  def command(*values, &block)
38
- values.each do |value|
39
- escaped = Regexp.escape(value)
40
- match Regexp.new("^(?<bot>[[:alnum:][:punct:]@<>]*)[\\s]+(?<command>#{escaped})$", Regexp::IGNORECASE), &block
41
- match Regexp.new("^(?<bot>[[:alnum:][:punct:]@<>]*)[\\s]+(?<command>#{escaped})[\\s]+(?<expression>.*)$", Regexp::IGNORECASE), &block
42
- end
37
+ values = values.map { |value| Regexp.escape(value) }.join('|')
38
+ match Regexp.new("^(?<bot>[[:alnum:][:punct:]@<>]*)[\\s]+(?<command>#{values})([\\s]+(?<expression>.*)|)$", Regexp::IGNORECASE), &block
43
39
  end
44
40
 
45
41
  def invoke(client, data)
46
42
  finalize_routes!
47
43
  expression, text = parse(client, data)
48
44
  called = false
49
- routes.each_pair do |route, method|
50
- match = route.match(expression)
51
- match ||= route.match(text) if text
52
- next unless match
53
- next if match.names.include?('bot') && !client.name?(match['bot'])
45
+ routes.each_pair do |route, options|
46
+ match_method = options[:match_method]
47
+ case match_method
48
+ when :match
49
+ match = route.match(expression)
50
+ match ||= route.match(text) if text
51
+ next unless match
52
+ next if match.names.include?('bot') && !client.name?(match['bot'])
53
+ when :scan
54
+ match = expression.scan(route)
55
+ next unless match.any?
56
+ end
54
57
  called = true
55
- if method
56
- method.call(client, data, match)
58
+ call = options[:call]
59
+ if call
60
+ call.call(client, data, match)
57
61
  elsif respond_to?(:call)
58
62
  send(:call, client, data, match)
59
63
  else
60
64
  fail NotImplementedError, data.text
61
65
  end
62
66
  break
63
- end
67
+ end if expression
64
68
  called
65
69
  end
66
70
 
67
71
  def match(match, &block)
68
72
  self.routes ||= {}
69
- self.routes[match] = block
73
+ self.routes[match] = { match_method: :match, call: block }
74
+ end
75
+
76
+ def scan(match, &block)
77
+ self.routes ||= {}
78
+ self.routes[match] = { match_method: :scan, call: block }
70
79
  end
71
80
 
72
81
  private
@@ -4,7 +4,8 @@ module SlackRubyBot
4
4
  extend Base
5
5
 
6
6
  def hello(client, _data)
7
- logger.info "Successfully connected to #{client.url || 'slack'}."
7
+ return unless client && client.team
8
+ logger.info "Successfully connected to https://#{client.team.domain}.slack.com."
8
9
  end
9
10
  end
10
11
  end
@@ -10,18 +10,4 @@ shared_examples 'a slack ruby bot' do
10
10
  expect { subject }.to raise_error RuntimeError, "Missing ENV['SLACK_API_TOKEN']."
11
11
  end
12
12
  end
13
- context 'configured', vcr: { cassette_name: 'auth_test' } do
14
- context 'run' do
15
- before do
16
- subject.send(:auth!)
17
- end
18
- it 'succeeds auth' do
19
- expect(subject.config.url).to eq 'https://rubybot.slack.com/'
20
- expect(subject.config.team).to eq 'team_name'
21
- expect(subject.config.user).to eq 'user_name'
22
- expect(subject.config.team_id).to eq 'TDEADBEEF'
23
- expect(subject.config.user_id).to eq 'UBAADFOOD'
24
- end
25
- end
26
- end
27
13
  end
@@ -16,7 +16,6 @@ module SlackRubyBot
16
16
  end
17
17
 
18
18
  def run
19
- auth!
20
19
  loop do
21
20
  handle_execeptions do
22
21
  handle_signals
@@ -25,11 +24,6 @@ module SlackRubyBot
25
24
  end
26
25
  end
27
26
 
28
- def auth!
29
- client.auth = client.web_client.auth_test
30
- logger.info "Welcome '#{client.auth['user']}' to the '#{client.auth['team']}' team at #{client.auth['url']}."
31
- end
32
-
33
27
  def start!
34
28
  @stopping = false
35
29
  @async = false
@@ -47,6 +41,11 @@ module SlackRubyBot
47
41
  client.stop! if @client
48
42
  end
49
43
 
44
+ def hello!
45
+ return unless client.self && client.team
46
+ logger.info "Welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com."
47
+ end
48
+
50
49
  def restart!(wait = 1)
51
50
  @async ? start_async : start!
52
51
  rescue StandardError => e
@@ -1,3 +1,3 @@
1
1
  module SlackRubyBot
2
- VERSION = '0.6.2'
2
+ VERSION = '0.7.0'
3
3
  end
Binary file
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.files = `git ls-files`.split("\n")
12
12
  s.test_files = `git ls-files -- spec/*`.split("\n")
13
13
  s.require_paths = ['lib']
14
- s.homepage = 'http://github.com/dblock/slack-ruby-bot'
14
+ s.homepage = 'https://github.com/dblock/slack-ruby-bot'
15
15
  s.licenses = ['MIT']
16
16
  s.summary = 'The easiest way to write a Slack bot in Ruby.'
17
17
  s.add_dependency 'hashie'
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::Commands do
4
+ let! :command do
5
+ Class.new(SlackRubyBot::Commands::Base) do
6
+ command 'set' do |client, data, match|
7
+ if match['expression']
8
+ k, v = match['expression'].split(/\W+/, 2)
9
+ client.say(channel: data.channel, text: "#{match[:command]}: #{k}=#{v}")
10
+ else
11
+ client.say(channel: data.channel, text: "#{match[:command]}")
12
+ end
13
+ end
14
+ end
15
+ end
16
+ def app
17
+ SlackRubyBot::App.new
18
+ end
19
+ it 'parses expression' do
20
+ expect(message: "#{SlackRubyBot.config.user} set").to respond_with_slack_message('set')
21
+ expect(message: "#{SlackRubyBot.config.user} set x").to respond_with_slack_message('set: x=')
22
+ expect(message: "#{SlackRubyBot.config.user} set x y").to respond_with_slack_message('set: x=y')
23
+ end
24
+ end
@@ -6,7 +6,7 @@ describe SlackRubyBot::Commands do
6
6
  command 'nil_text'
7
7
 
8
8
  def self.call(_client, data, _match)
9
- send_message cilent, data.channel, nil
9
+ send_message client, data.channel, nil
10
10
  end
11
11
  end
12
12
  end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::Commands do
4
+ let! :command do
5
+ Class.new(SlackRubyBot::Commands::Base) do
6
+ scan(/(\$[A-Z]+)/) do |client, data, captures|
7
+ client.say(channel: data.channel, text: "There were #{captures.count} captures: #{captures.join(', ')}.")
8
+ end
9
+ end
10
+ end
11
+ def app
12
+ SlackRubyBot::App.new
13
+ end
14
+ it 'captures' do
15
+ expect(message: 'quote $YHOO and $MSFT').to respond_with_slack_message('There were 2 captures: $YHOO, $MSFT.')
16
+ end
17
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack-ruby-bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Doubrovkine
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-04 00:00:00.000000000 Z
11
+ date: 2016-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -185,6 +185,9 @@ files:
185
185
  - Rakefile
186
186
  - TUTORIAL.md
187
187
  - UPGRADING.md
188
+ - examples/market/Gemfile
189
+ - examples/market/Procfile
190
+ - examples/market/marketbot.rb
188
191
  - examples/minimal/Gemfile
189
192
  - examples/minimal/Procfile
190
193
  - examples/minimal/pongbot.rb
@@ -212,7 +215,6 @@ files:
212
215
  - lib/slack-ruby-bot/hooks/hello.rb
213
216
  - lib/slack-ruby-bot/hooks/message.rb
214
217
  - lib/slack-ruby-bot/rspec.rb
215
- - lib/slack-ruby-bot/rspec/support/fixtures/slack/auth_test.yml
216
218
  - lib/slack-ruby-bot/rspec/support/fixtures/slack/migration_in_progress.yml
217
219
  - lib/slack-ruby-bot/rspec/support/slack-ruby-bot/it_behaves_like_a_slack_bot.rb
218
220
  - lib/slack-ruby-bot/rspec/support/slack-ruby-bot/respond_with_error.rb
@@ -227,6 +229,7 @@ files:
227
229
  - screenshots/aliases.gif
228
230
  - screenshots/demo.gif
229
231
  - screenshots/dms.gif
232
+ - screenshots/market.gif
230
233
  - screenshots/register-bot.png
231
234
  - screenshots/weather.gif
232
235
  - slack-ruby-bot.gemspec
@@ -241,6 +244,7 @@ files:
241
244
  - spec/slack-ruby-bot/commands/commands_spaces_spec.rb
242
245
  - spec/slack-ruby-bot/commands/commands_spec.rb
243
246
  - spec/slack-ruby-bot/commands/commands_with_block_spec.rb
247
+ - spec/slack-ruby-bot/commands/commands_with_expression_spec.rb
244
248
  - spec/slack-ruby-bot/commands/direct_messages_spec.rb
245
249
  - spec/slack-ruby-bot/commands/empty_text_spec.rb
246
250
  - spec/slack-ruby-bot/commands/help_spec.rb
@@ -251,6 +255,7 @@ files:
251
255
  - spec/slack-ruby-bot/commands/not_implemented_spec.rb
252
256
  - spec/slack-ruby-bot/commands/operators_spec.rb
253
257
  - spec/slack-ruby-bot/commands/operators_with_block_spec.rb
258
+ - spec/slack-ruby-bot/commands/scan_spec.rb
254
259
  - spec/slack-ruby-bot/commands/send_gif_spec.rb
255
260
  - spec/slack-ruby-bot/commands/send_message_spec.rb
256
261
  - spec/slack-ruby-bot/commands/send_message_with_gif_spec.rb
@@ -262,7 +267,7 @@ files:
262
267
  - spec/slack-ruby-bot/support/loggable_spec.rb
263
268
  - spec/slack-ruby-bot/version_spec.rb
264
269
  - spec/spec_helper.rb
265
- homepage: http://github.com/dblock/slack-ruby-bot
270
+ homepage: https://github.com/dblock/slack-ruby-bot
266
271
  licenses:
267
272
  - MIT
268
273
  metadata: {}
@@ -297,6 +302,7 @@ test_files:
297
302
  - spec/slack-ruby-bot/commands/commands_spaces_spec.rb
298
303
  - spec/slack-ruby-bot/commands/commands_spec.rb
299
304
  - spec/slack-ruby-bot/commands/commands_with_block_spec.rb
305
+ - spec/slack-ruby-bot/commands/commands_with_expression_spec.rb
300
306
  - spec/slack-ruby-bot/commands/direct_messages_spec.rb
301
307
  - spec/slack-ruby-bot/commands/empty_text_spec.rb
302
308
  - spec/slack-ruby-bot/commands/help_spec.rb
@@ -307,6 +313,7 @@ test_files:
307
313
  - spec/slack-ruby-bot/commands/not_implemented_spec.rb
308
314
  - spec/slack-ruby-bot/commands/operators_spec.rb
309
315
  - spec/slack-ruby-bot/commands/operators_with_block_spec.rb
316
+ - spec/slack-ruby-bot/commands/scan_spec.rb
310
317
  - spec/slack-ruby-bot/commands/send_gif_spec.rb
311
318
  - spec/slack-ruby-bot/commands/send_message_spec.rb
312
319
  - spec/slack-ruby-bot/commands/send_message_with_gif_spec.rb
@@ -1,16 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: post
5
- uri: https://slack.com/api/auth.test
6
- body:
7
- string: token=token
8
- response:
9
- status:
10
- code: 200
11
- message: OK
12
- body:
13
- encoding: UTF-8
14
- string: '{"ok":true,"url":"https:\/\/rubybot.slack.com\/","team":"team_name","user":"user_name","team_id":"TDEADBEEF","user_id":"UBAADFOOD"}'
15
- http_version:
16
- recorded_at: Tue, 28 Apr 2015 12:55:22 GMT