button 1.2.0 → 2.0.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 CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- Mjg5ZThjM2ExMjhiYmFiNjU1MTZhMzViYTIzY2NlYTNiNzc4NGM1ZQ==
5
- data.tar.gz: !binary |-
6
- ODBkYTM3Nzc4ZjdiODU2MDEwZWJiN2FkZTg3NTRkOTJhZTU3NGMxOQ==
2
+ SHA1:
3
+ metadata.gz: c08ec518d065b7b8546110e37a06ba0b8da850ee
4
+ data.tar.gz: dadccf3559487db05b8618cd01e11ba71558e655
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MWI4ODgzNjg0YTBkMjE5NTFiZDQ0YmI2M2MzZjJjYTg5MmE5ZGU0YWM2MjZj
10
- ZjVjMjMxZGI4YTM4MmExNTM0ZDljOTg4NDRjMjIzZGIzYzlkMzJjMWE5N2U0
11
- YmRiMzZiMTQ2MDZmNGQwMDI1Y2M3OTAxNTYwNWRiNTA1M2Y3ODU=
12
- data.tar.gz: !binary |-
13
- YmY1MGY3NjE4OTliYTU3Y2FjMTUwNjMwODkzMjYzZDNhNjg5YWI2MmU2OWUz
14
- N2IzMjE1Yzg2OTVkZjM4YmU0NjMxNmMwYWMwNzI4YTE0YTAyZWEzNDk1MmU0
15
- MzMxYWNhYjgxNjk1NGZiMTEyNDgwZjNkODliNTE0NTZiNDhiNDM=
6
+ metadata.gz: 0075f1a015a55e2524fd68c90593514bf935803f9965745342e4e4cc542cf1a269c846745392291982b9d24a6dbb06e4c9649b1e260c925aa1fe4971defbf05c
7
+ data.tar.gz: 953d707ea24f530da5d70bfb4dfdbab8f97240400266d37fd44706915230173df70d9da2e478484960c6843456532ddf6023c32083999c3456e9e066a42d32af
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ 2.0.0 January 6, 2017
2
+ - Add `Accounts` resource
3
+ - Add `Merchants` resource
4
+ - Completely change `Button::Response` interface
5
+
1
6
  1.2.0 January 4, 2017
2
7
  - Add `Button::Utils::webhook_authentic?` function
3
8
 
data/README.md CHANGED
@@ -28,7 +28,7 @@ client = Button::Client.new('sk-XXX')
28
28
 
29
29
  The client will always attempt to raise a `Button::ButtonClientError` in an error condition.
30
30
 
31
- All API requests will return a `Button::Response` instance, which supports accessing data properties from the API response as methods. To access the raw response hash, use `#to_hash`. For instance:
31
+ All API requests will return a `Button::Response` instance. To access the response data, invoke `#data`.
32
32
 
33
33
  ```ruby
34
34
  require 'button'
@@ -41,17 +41,17 @@ rescue Button::ButtonClientError => error
41
41
  puts error
42
42
  end
43
43
 
44
- puts response
44
+ puts response
45
45
  # => Button::Response(button_order_id: btnorder-XXX, total: 60, ... )
46
46
 
47
- puts response.button_order_id
48
- # => btnorder-XXX
49
-
50
- puts response.to_hash()
47
+ puts response.data
51
48
  # => {:button_order_id=>'btnorder-29de0b1436075ea6', :total=>60, ... }
49
+
50
+ puts response.data[:button_order_id]
51
+ # => btnorder-XXX
52
52
  ```
53
53
 
54
- n.b. the keys of the response hash will always be symbols.
54
+ _n.b. the keys of the response hash will always be symbols._
55
55
 
56
56
  ## Configuration
57
57
 
@@ -77,7 +77,75 @@ The supported options are as follows:
77
77
 
78
78
  ## Resources
79
79
 
80
- We currently expose only one resource to manage, `Orders`.
80
+ We currently expose the following resources to manage:
81
+
82
+ * [`Accounts`](#accounts)
83
+ * [`Merchants`](#merchants)
84
+ * [`Orders`](#orders)
85
+
86
+ ### Accounts
87
+
88
+ ##### all
89
+
90
+ ```ruby
91
+ require 'button'
92
+
93
+ client = Button::Client.new('sk-XXX')
94
+
95
+ response = client.accounts.all
96
+
97
+ puts response
98
+ # => Button::Response(2 elements)
99
+ ```
100
+
101
+ ##### transactions
102
+
103
+ _n.b. transactions is a paged endpoint. Take care to inspect `response.next_cursor` in case there's more data to be read._
104
+
105
+ Along with the required account id, you may also pass the following optional arguments as a Hash as the second argument:
106
+
107
+ * `:cursor` (String): An API cursor to fetch a specific set of results.
108
+ * `:start` (ISO-8601 datetime String): Fetch transactions after this time.
109
+ * `:end` (ISO-8601 datetime String): Fetch transactions before this time.
110
+
111
+ ```ruby
112
+ require 'button'
113
+
114
+ client = Button::Client.new('sk-XXX')
115
+
116
+ response = client.accounts.transactions('acc-XXX')
117
+ cursor = response.next_cursor
118
+
119
+ puts response
120
+ # => Button::Response(75 elements)
121
+
122
+ # Unpage all results
123
+ #
124
+ while !cursor.nil? do
125
+ response = client.accounts.transactions('acc-XXX', cursor: cursor)
126
+ cursor = response.next_cursor
127
+ end
128
+ ```
129
+
130
+ ### Merchants
131
+
132
+ ##### all
133
+
134
+ You may also pass the following optional arguments as a Hash as the first argument:
135
+
136
+ * `:status` (String): Partnership status to filter by. One of ('approved', 'pending', or 'available')
137
+ * `:currency` (ISO-4217 String): Currency code to filter returned rates by
138
+
139
+ ```ruby
140
+ require 'button'
141
+
142
+ client = Button::Client.new('sk-XXX')
143
+
144
+ response = client.merchants.all(status: 'pending', currency: 'GBP')
145
+
146
+ puts response
147
+ # => Button::Response(23 elements)
148
+ ```
81
149
 
82
150
  ### Orders
83
151
 
@@ -98,7 +166,7 @@ response = client.orders.create({
98
166
  btn_ref: 'srctok-XXX'
99
167
  })
100
168
 
101
- puts response
169
+ puts response
102
170
  # => Button::Response(button_order_id: btnorder-XXX, total: 50, ... )
103
171
  ```
104
172
 
@@ -111,9 +179,10 @@ client = Button::Client.new('sk-XXX')
111
179
 
112
180
  response = client.orders.get('btnorder-XXX')
113
181
 
114
- puts response
182
+ puts response
115
183
  # => Button::Response(button_order_id: btnorder-XXX, total: 50, ... )
116
184
  ```
185
+
117
186
  ##### Update
118
187
 
119
188
  ```ruby
@@ -123,7 +192,7 @@ client = Button::Client.new('sk-XXX')
123
192
 
124
193
  response = client.orders.update('btnorder-XXX', total: 60)
125
194
 
126
- puts response
195
+ puts response
127
196
  # => Button::Response(button_order_id: btnorder-XXX, total: 60, ... )
128
197
  ```
129
198
 
@@ -140,6 +209,38 @@ puts response
140
209
  # => Button::Response()
141
210
  ```
142
211
 
212
+ ## Response
213
+
214
+ An instance of the `Button::Response` class will be returned by all API methods. It is used to read the response data as well as collect any meta data about the response, like potential next and previous cursors to more data in a paged endpoint.
215
+
216
+ ### Methods
217
+
218
+ #### data
219
+
220
+ returns the underlying response data
221
+
222
+ ```ruby
223
+ require 'button'
224
+
225
+ client = Button::Client.new('sk-XXX')
226
+
227
+ response = client.accounts.all
228
+
229
+ puts response
230
+ # => Button::Response(2 elements)
231
+
232
+ puts response.data
233
+ # => [ { ... }, { ... } ]
234
+ ```
235
+
236
+ #### next_cursor
237
+
238
+ For any paged resource, `#next_cursor` will return a cursor to supply for the next page of results. If `#next_cursor` returns `nil`, then there are no more results.
239
+
240
+ #### prev_cursor
241
+
242
+ For any paged resource, `#prev_cursor` will return a cursor to supply for the previous page of results. If `#prev_cursor` returns `nil`, then there are no more results, err.. backwards.
243
+
143
244
  ## Utils
144
245
 
145
246
  Utils houses generic helpers useful in a Button Integration.
data/lib/button/client.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'button/resources/accounts'
2
+ require 'button/resources/merchants'
1
3
  require 'button/resources/orders'
2
4
  require 'button/errors'
3
5
 
@@ -23,6 +25,8 @@ module Button
23
25
 
24
26
  config_with_defaults = merge_defaults(config)
25
27
 
28
+ @accounts = Accounts.new(api_key, config_with_defaults)
29
+ @merchants = Merchants.new(api_key, config_with_defaults)
26
30
  @orders = Orders.new(api_key, config_with_defaults)
27
31
  end
28
32
 
@@ -37,7 +41,7 @@ module Button
37
41
  }
38
42
  end
39
43
 
40
- attr_reader :orders
44
+ attr_reader :accounts, :merchants, :orders
41
45
  private :merge_defaults
42
46
  end
43
47
  end
@@ -0,0 +1,39 @@
1
+ require 'button/resources/resource'
2
+
3
+ module Button
4
+ # https://www.usebutton.com/developers/api-reference/
5
+ #
6
+ class Accounts < Resource
7
+ def path(account_id = nil)
8
+ return "/v1/affiliation/accounts/#{account_id}/transactions" if account_id
9
+ '/v1/affiliation/accounts'
10
+ end
11
+
12
+ # Gets a list of available accounts
13
+ #
14
+ # @return [Button::Response] the API response
15
+ #
16
+ def all
17
+ api_get(path)
18
+ end
19
+
20
+ # Gets a list of transactions for an account
21
+ #
22
+ # @param [String] account_id the account id to look up transactions for
23
+ # @option [String] cursor the account id to look up transactions for
24
+ # @option [ISO-8601 datetime String] start The start date to filter
25
+ # transactions
26
+ # @option [ISO-8601 datetime String] end The end date to filter
27
+ # transactions
28
+ # @return [Button::Response] the API response
29
+ #
30
+ def transactions(account_id, opts = {})
31
+ query = {}
32
+ query['cursor'] = opts[:cursor] if opts[:cursor]
33
+ query['start'] = opts[:start] if opts[:start]
34
+ query['end'] = opts[:end] if opts[:end]
35
+
36
+ api_get(path(account_id), query)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,23 @@
1
+ require 'button/resources/resource'
2
+
3
+ module Button
4
+ # https://www.usebutton.com/developers/api-reference/
5
+ #
6
+ class Merchants < Resource
7
+ # Gets a list of available merchants
8
+ #
9
+ # @option [String] status The status to filter by. One of ('approved',
10
+ # 'pending', or 'available')
11
+ # @option [ISO-4217 String] currency Currency code to filter returned rates
12
+ # by
13
+ # @return [Button::Response] the API response
14
+ #
15
+ def all(opts = {})
16
+ query = {}
17
+ query['status'] = opts[:status] if opts[:status]
18
+ query['currency'] = opts[:currency] if opts[:currency]
19
+
20
+ api_get('/v1/merchants', query)
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,4 @@
1
+ require 'uri'
1
2
  require 'net/http'
2
3
  require 'json'
3
4
 
@@ -43,10 +44,13 @@ module Button
43
44
  # Performs an HTTP GET at the provided path.
44
45
  #
45
46
  # @param [String] path the HTTP path
47
+ # @param [Hash=] query optional query params to send
46
48
  # @return [Button::Response] the API response
47
49
  #
48
- def api_get(path)
49
- api_request(Net::HTTP::Get.new(path))
50
+ def api_get(path, query = nil)
51
+ uri = URI(path)
52
+ uri.query = URI.encode_www_form(query) if query
53
+ api_request(Net::HTTP::Get.new(uri.to_s))
50
54
  end
51
55
 
52
56
  # Performs an HTTP POST at the provided path.
@@ -94,9 +98,11 @@ module Button
94
98
 
95
99
  raise ButtonClientError, "Invalid response: #{parsed}" unless parsed[:meta].is_a?(Hash)
96
100
 
97
- status = parsed[:meta][:status]
101
+ meta = parsed[:meta]
102
+ status = meta[:status]
103
+ response_data = parsed.fetch(:object, parsed.fetch(:objects, {}))
98
104
 
99
- return Response.new(parsed[:object]) if status == 'ok'
105
+ return Response.new(meta, response_data) if status == 'ok'
100
106
  raise ButtonClientError, "Unknown status: #{status}" unless status == 'error'
101
107
  raise ButtonClientError, parsed[:error][:message] if parsed[:error].is_a?(Hash)
102
108
  raise ButtonClientError, "Invalid response: #{parsed}"
@@ -1,3 +1,6 @@
1
+ require 'cgi'
2
+ require 'uri'
3
+
1
4
  module Button
2
5
  # Response is a simple proxy class for easy value unpacking from an API
3
6
  # response. It is constructed with a hash and proxies method calls on the
@@ -5,33 +8,59 @@ module Button
5
8
  #
6
9
  # ## Usage
7
10
  #
8
- # response = Button::Response.new({ :a => 1, :b => "two" })
9
- # puts response.a
10
- # puts response.to_hash
11
+ # response = Button::Response.new({
12
+ # prev: 'https://bloop.net/?cursor=1989',
13
+ # next: 'https://bloop.net/?cursor=1991'
14
+ # }, :a => 1, :b => "two")
15
+ #
16
+ # puts response.data
17
+ # puts response.next_cursor
18
+ # puts response.prev_cursor
11
19
  #
12
20
  class Response
13
- def initialize(attrs)
14
- @attrs = attrs || {}
21
+ def initialize(meta, response_data)
22
+ @meta = meta
23
+ @response_data = response_data
15
24
  end
16
25
 
17
26
  def to_s
18
- values = @attrs.reduce([]) do |acc, (name, value)|
19
- acc + ["#{name}: #{value || 'nil'}"]
20
- end.join(', ')
27
+ repr = ''
28
+
29
+ if @response_data.is_a?(Hash)
30
+ repr = @response_data.reduce([]) do |acc, (name, value)|
31
+ acc + ["#{name}: #{value || 'nil'}"]
32
+ end.join(', ')
33
+ elsif @response_data.is_a?(Array)
34
+ repr = "#{@response_data.size} elements"
35
+ end
36
+
37
+ "Button::Response(#{repr})"
38
+ end
21
39
 
22
- "Button::Response(#{values})"
40
+ def data
41
+ @response_data
23
42
  end
24
43
 
25
- def to_hash
26
- @attrs
44
+ def next_cursor
45
+ Response.format_cursor(@meta.fetch(:next, nil))
27
46
  end
28
47
 
29
- def method_missing(attr)
30
- @attrs[attr] || super
48
+ def prev_cursor
49
+ Response.format_cursor(@meta.fetch(:prev, nil))
31
50
  end
32
51
 
33
- def respond_to_missing?(method_name, include_private = false)
34
- @attrs.key?(method_name) || super
52
+ class << self
53
+ def format_cursor(cursor_url)
54
+ return nil unless cursor_url
55
+
56
+ parsed = URI(cursor_url)
57
+ return nil unless parsed.query
58
+
59
+ query = CGI.parse(parsed.query)
60
+ cursor = query.fetch('cursor', [])
61
+
62
+ cursor.empty? ? nil : cursor[0]
63
+ end
35
64
  end
36
65
  end
37
66
  end
@@ -1,3 +1,3 @@
1
1
  module Button
2
- VERSION = '1.2.0'.freeze
2
+ VERSION = '2.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: button
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Button
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-04 00:00:00.000000000 Z
11
+ date: 2017-01-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Button is a contextual acquisition channel and closed-loop attribution
14
14
  and affiliation system for mobile commerce.
@@ -24,6 +24,8 @@ files:
24
24
  - lib/button.rb
25
25
  - lib/button/client.rb
26
26
  - lib/button/errors.rb
27
+ - lib/button/resources/accounts.rb
28
+ - lib/button/resources/merchants.rb
27
29
  - lib/button/resources/orders.rb
28
30
  - lib/button/resources/resource.rb
29
31
  - lib/button/response.rb
@@ -39,17 +41,17 @@ require_paths:
39
41
  - lib
40
42
  required_ruby_version: !ruby/object:Gem::Requirement
41
43
  requirements:
42
- - - ! '>='
44
+ - - ">="
43
45
  - !ruby/object:Gem::Version
44
46
  version: 1.9.3
45
47
  required_rubygems_version: !ruby/object:Gem::Requirement
46
48
  requirements:
47
- - - ! '>='
49
+ - - ">="
48
50
  - !ruby/object:Gem::Version
49
51
  version: '0'
50
52
  requirements: []
51
53
  rubyforge_project:
52
- rubygems_version: 2.4.8
54
+ rubygems_version: 2.5.1
53
55
  signing_key:
54
56
  specification_version: 4
55
57
  summary: ruby client for the Button Order API