delighted 1.8.0 → 2.0.0rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -3
- data/CHANGELOG.md +11 -0
- data/README.md +24 -2
- data/lib/delighted.rb +2 -0
- data/lib/delighted/client.rb +16 -3
- data/lib/delighted/errors.rb +4 -0
- data/lib/delighted/http_response.rb +22 -0
- data/lib/delighted/list_resource.rb +45 -0
- data/lib/delighted/operations/list.rb +15 -0
- data/lib/delighted/resources/person.rb +1 -0
- data/lib/delighted/version.rb +1 -1
- data/test/delighted_test.rb +123 -0
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 935f134ce42d4fd9df625582e5983ca52097c1025266d1b12bdc0e3a8d1c6a82
|
4
|
+
data.tar.gz: 1c05ac2216de6f94213ba2fd47f5d039af4ad751a342495524af59b162ed7161
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a799887d2859ceb0efa8f3fa72be34c3fc25ecca0f681616ecab1a2d5eed711dea5056bd0077676ce6681cf6125f79abcb01c1e09e68c893e3630d703ef09399
|
7
|
+
data.tar.gz: 9f6b6c2d5443e892c75c733f3b7e466d5cfbf21aeef923e0a87d3d5db85c35d744b9a1f8f45deb3fd802a06e27cb0a5bdf693e888535bf77a5e622c453caf356
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -49,6 +49,28 @@ updated_person1 = Delighted::Person.create(:email => "foo+test1@delighted.com",
|
|
49
49
|
:name => "James Scott", :send => false)
|
50
50
|
```
|
51
51
|
|
52
|
+
Listing all people:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
# List all people, auto pagination
|
56
|
+
# Note: Make sure to handle the possible rate limits error
|
57
|
+
people = Delighted::Person.list
|
58
|
+
begin
|
59
|
+
people.auto_paging_each do |person|
|
60
|
+
# Do something with person
|
61
|
+
end
|
62
|
+
rescue Delighted::RateLimitError => e
|
63
|
+
# Indicates how long to wait before making this request again
|
64
|
+
e.retry_after
|
65
|
+
retry
|
66
|
+
end
|
67
|
+
|
68
|
+
# For convenience, this method can use a sleep to automatically handle rate limits
|
69
|
+
people.auto_paging_each({ auto_handle_rate_limits: true }) do |person|
|
70
|
+
# Do something with person
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
52
74
|
Unsubscribing people:
|
53
75
|
|
54
76
|
```ruby
|
@@ -56,7 +78,7 @@ Unsubscribing people:
|
|
56
78
|
Delighted::Unsubscribe.create(:person_email => "foo+test1@delighted.com")
|
57
79
|
```
|
58
80
|
|
59
|
-
Listing people who have unsubscribed:
|
81
|
+
Listing people who have unsubscribed (auto pagination not supported):
|
60
82
|
|
61
83
|
```ruby
|
62
84
|
# List all people who have unsubscribed, 20 per page, first 2 pages
|
@@ -64,7 +86,7 @@ survey_responses_page1 = Delighted::Unsubscribe.all
|
|
64
86
|
survey_responses_page2 = Delighted::Unsubscribe.all(:page => 2)
|
65
87
|
```
|
66
88
|
|
67
|
-
Listing people whose emails have bounced:
|
89
|
+
Listing people whose emails have bounced (auto pagination not supported):
|
68
90
|
|
69
91
|
```ruby
|
70
92
|
# List all people whose emails have bounced, 20 per page, first 2 pages
|
data/lib/delighted.rb
CHANGED
@@ -9,9 +9,11 @@ require 'delighted/version'
|
|
9
9
|
require 'delighted/utils'
|
10
10
|
require 'delighted/json'
|
11
11
|
|
12
|
+
require 'delighted/list_resource'
|
12
13
|
require 'delighted/enumerable_resource_collection'
|
13
14
|
require 'delighted/resource'
|
14
15
|
require 'delighted/operations/all'
|
16
|
+
require 'delighted/operations/list'
|
15
17
|
require 'delighted/operations/create'
|
16
18
|
require 'delighted/operations/retrieve'
|
17
19
|
require 'delighted/operations/update'
|
data/lib/delighted/client.rb
CHANGED
@@ -2,6 +2,7 @@ module Delighted
|
|
2
2
|
class Client
|
3
3
|
DEFAULT_API_BASE_URL = "https://api.delightedapp.com/v1"
|
4
4
|
DEFAULT_HTTP_ADAPTER = HTTPAdapter.new
|
5
|
+
DEFAULT_ACCEPT_HEADER = "application/json"
|
5
6
|
|
6
7
|
def initialize(opts = {})
|
7
8
|
@api_key = opts[:api_key] or raise ArgumentError, "You must provide an API key by setting Delighted.api_key = '123abc' or passing { :api_key => '123abc' } when instantiating Delighted::Client.new"
|
@@ -10,13 +11,21 @@ module Delighted
|
|
10
11
|
end
|
11
12
|
|
12
13
|
def get_json(path, params = {})
|
13
|
-
|
14
|
+
request_get(path, {params: params})[:json]
|
15
|
+
end
|
14
16
|
|
15
|
-
|
17
|
+
def request_get(path, opts = {})
|
18
|
+
accept_header = opts.fetch(:accept_header, DEFAULT_ACCEPT_HEADER)
|
19
|
+
params = opts.fetch(:params, {})
|
20
|
+
|
21
|
+
headers = default_headers.dup.merge('Accept' => accept_header)
|
22
|
+
|
23
|
+
path = File.join(@api_base_url, path) unless is_full_url(path)
|
24
|
+
uri = URI.parse(path)
|
16
25
|
uri.query = Utils.to_query(params) unless params.empty?
|
17
26
|
|
18
27
|
response = @http_adapter.request(:get, uri, headers)
|
19
|
-
handle_json_response(response)
|
28
|
+
{ json: handle_json_response(response), response: response }
|
20
29
|
end
|
21
30
|
|
22
31
|
def post_json(path, params = {})
|
@@ -76,5 +85,9 @@ module Delighted
|
|
76
85
|
'User-Agent' => "Delighted RubyGem #{Delighted::VERSION}"
|
77
86
|
}.freeze
|
78
87
|
end
|
88
|
+
|
89
|
+
def is_full_url(url)
|
90
|
+
!!(URI::regexp(%w(http https)) =~ url)
|
91
|
+
end
|
79
92
|
end
|
80
93
|
end
|
data/lib/delighted/errors.rb
CHANGED
@@ -12,6 +12,11 @@ module Delighted
|
|
12
12
|
get_header_value("content-type")
|
13
13
|
end
|
14
14
|
|
15
|
+
def next_link
|
16
|
+
link_header = get_header_value("link")
|
17
|
+
parse_link_header(link_header)[:next]
|
18
|
+
end
|
19
|
+
|
15
20
|
def retry_after
|
16
21
|
if value = get_header_value("retry-after")
|
17
22
|
value.to_i
|
@@ -37,5 +42,22 @@ module Delighted
|
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
45
|
+
|
46
|
+
def parse_link_header(header_value)
|
47
|
+
links = {}
|
48
|
+
parts = Array(header_value)
|
49
|
+
.map { |v| v.split(",") }
|
50
|
+
.flatten
|
51
|
+
.map(&:strip)
|
52
|
+
# Parse each part into a named link
|
53
|
+
parts.each do |part|
|
54
|
+
section = part.split(';')
|
55
|
+
next if section.length < 2
|
56
|
+
url = section[0][/<(.*)>/,1]
|
57
|
+
name = section[1][/rel="?([^"]*)"?/,1].to_sym
|
58
|
+
links[name] = url
|
59
|
+
end
|
60
|
+
links
|
61
|
+
end
|
40
62
|
end
|
41
63
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Delighted
|
2
|
+
class ListResource
|
3
|
+
def initialize(klass, path, opts, client)
|
4
|
+
@class = klass
|
5
|
+
@path = path
|
6
|
+
@opts = opts
|
7
|
+
@client = client
|
8
|
+
@iteration_count = 0
|
9
|
+
@done = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def auto_paging_each(opts = {})
|
13
|
+
raise PaginationError, "pagination completed" if @done
|
14
|
+
|
15
|
+
auto_handle_rate_limits = opts.fetch(:auto_handle_rate_limits, false)
|
16
|
+
loop do
|
17
|
+
begin
|
18
|
+
# Get next (or first) page
|
19
|
+
if @iteration_count == 0
|
20
|
+
data = @client.request_get(@path, { params: @opts })
|
21
|
+
else
|
22
|
+
data = @client.request_get(@next_link)
|
23
|
+
end
|
24
|
+
rescue Delighted::RateLimitedError => e
|
25
|
+
if auto_handle_rate_limits
|
26
|
+
sleep e.retry_after
|
27
|
+
retry
|
28
|
+
else
|
29
|
+
raise
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
@iteration_count += 1
|
34
|
+
@next_link = data[:response].next_link
|
35
|
+
|
36
|
+
data[:json].map do |attributes|
|
37
|
+
yield @class.new(attributes)
|
38
|
+
end
|
39
|
+
|
40
|
+
break if @next_link.nil?
|
41
|
+
end
|
42
|
+
@done = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Delighted
|
2
|
+
module Operations
|
3
|
+
module List
|
4
|
+
def self.included(klass)
|
5
|
+
klass.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def list(opts = {}, client = Delighted.shared_client)
|
10
|
+
ListResource.new(self, path, Utils.serialize_values(opts), client)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/delighted/version.rb
CHANGED
data/test/delighted_test.rb
CHANGED
@@ -38,6 +38,129 @@ class Delighted::MetricsTest < Delighted::TestCase
|
|
38
38
|
end
|
39
39
|
|
40
40
|
class Delighted::PeopleTest < Delighted::TestCase
|
41
|
+
def test_listing_people_auto_paginate
|
42
|
+
uri = URI.parse("https://api.delightedapp.com/v1/people")
|
43
|
+
uri_next = URI.parse("https://api.delightedapp.com/v1/people.json?page_info=123456789")
|
44
|
+
headers = { "Authorization" => @auth_header, "Accept" => "application/json", "User-Agent" => "Delighted RubyGem #{Delighted::VERSION}" }
|
45
|
+
|
46
|
+
# First request mock
|
47
|
+
example_person1 = {:person_id => "4945", :email => "foo@example.com", :name => "Gold"}
|
48
|
+
example_person2 = {:person_id => "4946", :email => "foo+2@example.com", :name => "Silver"}
|
49
|
+
response = Delighted::HTTPResponse.new(200, {"Link" => "<#{uri_next}>; rel=\"next\""}, Delighted::JSON.dump([example_person1,example_person2]))
|
50
|
+
mock_http_adapter.expects(:request).with(:get, uri, headers).once.returns(response)
|
51
|
+
|
52
|
+
# Next request mock
|
53
|
+
example_person_next = {:person_id => "4947", :email => "foo+3@example.com", :name => "Bronze"}
|
54
|
+
response = Delighted::HTTPResponse.new(200, {}, Delighted::JSON.dump([example_person_next]))
|
55
|
+
mock_http_adapter.expects(:request).with(:get, uri_next, headers).once.returns(response)
|
56
|
+
|
57
|
+
persons_all = []
|
58
|
+
Delighted::Person.list.auto_paging_each do |p|
|
59
|
+
persons_all << p
|
60
|
+
end
|
61
|
+
|
62
|
+
assert_equal 3, persons_all.size
|
63
|
+
|
64
|
+
first_person = persons_all[0]
|
65
|
+
assert_kind_of Delighted::Person, first_person
|
66
|
+
assert_equal "Gold", first_person.name
|
67
|
+
assert_equal example_person1, first_person.to_hash
|
68
|
+
second_person = persons_all[1]
|
69
|
+
assert_kind_of Delighted::Person, second_person
|
70
|
+
assert_equal "Silver", second_person.name
|
71
|
+
assert_equal example_person2, second_person.to_hash
|
72
|
+
third_person = persons_all[2]
|
73
|
+
assert_kind_of Delighted::Person, third_person
|
74
|
+
assert_equal "Bronze", third_person.name
|
75
|
+
assert_equal example_person_next, third_person.to_hash
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_listing_people_rate_limited
|
79
|
+
uri = URI.parse("https://api.delightedapp.com/v1/people")
|
80
|
+
uri_next = URI.parse("https://api.delightedapp.com/v1/people.json?page_info=123456789")
|
81
|
+
headers = { "Authorization" => @auth_header, "Accept" => "application/json", "User-Agent" => "Delighted RubyGem #{Delighted::VERSION}" }
|
82
|
+
|
83
|
+
# First request mock
|
84
|
+
example_person1 = {:person_id => "4945", :email => "foo@example.com", :name => "Gold"}
|
85
|
+
response = Delighted::HTTPResponse.new(200, {"Link" => "<#{uri_next}>; rel=\"next\""}, Delighted::JSON.dump([example_person1]))
|
86
|
+
mock_http_adapter.expects(:request).with(:get, uri, headers).once.returns(response)
|
87
|
+
|
88
|
+
# Next rate limited request mock
|
89
|
+
response = Delighted::HTTPResponse.new(429, { "Retry-After" => "10" }, {})
|
90
|
+
mock_http_adapter.expects(:request).with(:get, uri_next, headers).once.returns(response)
|
91
|
+
|
92
|
+
persons_all = []
|
93
|
+
exception = assert_raises Delighted::RateLimitedError do
|
94
|
+
Delighted::Person.list.auto_paging_each({ :auto_handle_rate_limits => false }) do |p|
|
95
|
+
persons_all << p
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
assert_equal 10, exception.retry_after
|
100
|
+
|
101
|
+
assert_equal 1, persons_all.size
|
102
|
+
first_person = persons_all[0]
|
103
|
+
assert_kind_of Delighted::Person, first_person
|
104
|
+
assert_equal "Gold", first_person.name
|
105
|
+
assert_equal example_person1, first_person.to_hash
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_listing_people_auto_handle_rate_limits
|
109
|
+
uri = URI.parse("https://api.delightedapp.com/v1/people")
|
110
|
+
uri_next = URI.parse("https://api.delightedapp.com/v1/people.json?page_info=123456789")
|
111
|
+
headers = { "Authorization" => @auth_header, "Accept" => "application/json", "User-Agent" => "Delighted RubyGem #{Delighted::VERSION}" }
|
112
|
+
|
113
|
+
# First request mock
|
114
|
+
example_person1 = {:person_id => "4945", :email => "foo@example.com", :name => "Gold"}
|
115
|
+
response = Delighted::HTTPResponse.new(200, {"Link" => "<#{uri_next}>; rel=\"next\""}, Delighted::JSON.dump([example_person1]))
|
116
|
+
mock_http_adapter.expects(:request).with(:get, uri, headers).once.returns(response)
|
117
|
+
|
118
|
+
# Next rate limited request mock, then accepted request
|
119
|
+
response_rate_limited = Delighted::HTTPResponse.new(429, { "Retry-After" => "3" }, {})
|
120
|
+
example_person_next = {:person_id => "4947", :email => "foo+next@example.com", :name => "Silver"}
|
121
|
+
response_ok = Delighted::HTTPResponse.new(200, {}, Delighted::JSON.dump([example_person_next]))
|
122
|
+
mock_http_adapter.expects(:request).with(:get, uri_next, headers).twice.returns(response_rate_limited, response_ok)
|
123
|
+
|
124
|
+
persons_all = []
|
125
|
+
people = Delighted::Person.list
|
126
|
+
people.expects(:sleep).with(3)
|
127
|
+
people.auto_paging_each({ :auto_handle_rate_limits => true }) do |p|
|
128
|
+
persons_all << p
|
129
|
+
end
|
130
|
+
|
131
|
+
assert_equal 2, persons_all.size
|
132
|
+
first_person = persons_all[0]
|
133
|
+
assert_kind_of Delighted::Person, first_person
|
134
|
+
assert_equal "Gold", first_person.name
|
135
|
+
assert_equal example_person1, first_person.to_hash
|
136
|
+
next_person = persons_all[1]
|
137
|
+
assert_kind_of Delighted::Person, next_person
|
138
|
+
assert_equal "Silver", next_person.name
|
139
|
+
assert_equal example_person_next, next_person.to_hash
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_listing_people_auto_paginate_second_call
|
143
|
+
uri = URI.parse("https://api.delightedapp.com/v1/people")
|
144
|
+
headers = { "Authorization" => @auth_header, "Accept" => "application/json", "User-Agent" => "Delighted RubyGem #{Delighted::VERSION}" }
|
145
|
+
|
146
|
+
# First request mock
|
147
|
+
example_person1 = {:person_id => "4945", :email => "foo@example.com", :name => "Gold"}
|
148
|
+
response = Delighted::HTTPResponse.new(200, {}, Delighted::JSON.dump([example_person1]))
|
149
|
+
mock_http_adapter.expects(:request).with(:get, uri, headers).once.returns(response)
|
150
|
+
|
151
|
+
persons_all = []
|
152
|
+
people = Delighted::Person.list
|
153
|
+
people.auto_paging_each do |p|
|
154
|
+
persons_all << p
|
155
|
+
end
|
156
|
+
|
157
|
+
assert_equal 1, persons_all.size
|
158
|
+
|
159
|
+
assert_raises Delighted::PaginationError do
|
160
|
+
people.auto_paging_each
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
41
164
|
def test_creating_or_updating_a_person
|
42
165
|
uri = URI.parse("https://api.delightedapp.com/v1/people")
|
43
166
|
headers = { 'Authorization' => @auth_header, "Accept" => "application/json", 'Content-Type' => 'application/json', 'User-Agent' => "Delighted RubyGem #{Delighted::VERSION}" }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delighted
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Dodwell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|
@@ -88,9 +88,11 @@ files:
|
|
88
88
|
- lib/delighted/http_adapter.rb
|
89
89
|
- lib/delighted/http_response.rb
|
90
90
|
- lib/delighted/json.rb
|
91
|
+
- lib/delighted/list_resource.rb
|
91
92
|
- lib/delighted/operations/all.rb
|
92
93
|
- lib/delighted/operations/create.rb
|
93
94
|
- lib/delighted/operations/delete.rb
|
95
|
+
- lib/delighted/operations/list.rb
|
94
96
|
- lib/delighted/operations/retrieve.rb
|
95
97
|
- lib/delighted/operations/update.rb
|
96
98
|
- lib/delighted/resource.rb
|
@@ -120,12 +122,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
122
|
version: '0'
|
121
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
124
|
requirements:
|
123
|
-
- - "
|
125
|
+
- - ">"
|
124
126
|
- !ruby/object:Gem::Version
|
125
|
-
version:
|
127
|
+
version: 1.3.1
|
126
128
|
requirements: []
|
127
129
|
rubyforge_project:
|
128
|
-
rubygems_version: 2.7.6
|
130
|
+
rubygems_version: 2.7.6.2
|
129
131
|
signing_key:
|
130
132
|
specification_version: 4
|
131
133
|
summary: Delighted is the fastest and easiest way to gather actionable feedback from
|