delighted 1.8.0 → 2.0.0rc1
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 +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
|