delighted 1.7.0 → 2.1.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 +5 -5
- data/.travis.yml +2 -3
- data/CHANGELOG.md +30 -0
- data/README.md +109 -2
- data/lib/delighted.rb +6 -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/delete.rb +20 -0
- data/lib/delighted/operations/list.rb +15 -0
- data/lib/delighted/resource.rb +14 -0
- data/lib/delighted/resources/autopilot_configuration.rb +7 -0
- data/lib/delighted/resources/autopilot_membership.rb +28 -0
- data/lib/delighted/resources/person.rb +2 -0
- data/lib/delighted/version.rb +1 -1
- data/test/delighted_test.rb +368 -0
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3ce86b0edf1b9df5dab8e46ba0fc4213c6c14667b7a4fe28d441e03fbf1b747e
|
4
|
+
data.tar.gz: 9eee58a5c861c75a0e7b33e6aacf54648da80fd8969ebeadac75e1d418fb95dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f759a34fe7d102ae00aa9e1b048cdebc9c5731c3fad3bd502af77db8e16b311d4782465a5a47d4885c883435e930433b24b4972676cd72ecf85f5f37b954f1f8
|
7
|
+
data.tar.gz: cc905c3739263c36fdf92ccf62407c814721828e70ae50e36d1d7e79218abb58fbfd73209b21b56585c553915e86db53dfab54e17bcfa407c146ed4fa630b903
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
## 2.1.0rc1 (unreleased)
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- Add `Delighted::AutopilotConfiguration.retrieve`
|
6
|
+
- Add `Delighted::AutopilotMembership.list`
|
7
|
+
- Add `Delighted::AutopilotMembership.create`
|
8
|
+
- Add `Delighted::AutopilotMembership.delete`
|
9
|
+
|
10
|
+
Compatibility changes:
|
11
|
+
|
12
|
+
- Replace deprecated `URI::regexp` with `URI::DEFAULT_PARSER.make_regexp`
|
13
|
+
|
14
|
+
## 2.0.0 (2020-03-18)
|
15
|
+
|
16
|
+
Features:
|
17
|
+
|
18
|
+
- Add `Delighted::Person.list`
|
19
|
+
|
20
|
+
Compatibility changes:
|
21
|
+
|
22
|
+
- Add support for Ruby 2.7
|
23
|
+
- Drop support for Ruby 1.8.7, 1.9.2, and ree
|
24
|
+
|
25
|
+
## 1.8.0 (2018-05-22)
|
26
|
+
|
27
|
+
Features:
|
28
|
+
|
29
|
+
- Add `Delighted::Person.delete`
|
30
|
+
|
1
31
|
## 1.7.0 (2017-10-18)
|
2
32
|
|
3
33
|
Features:
|
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
|
@@ -72,6 +94,17 @@ survey_responses_page1 = Delighted::Bounce.all
|
|
72
94
|
survey_responses_page2 = Delighted::Bounce.all(:page => 2)
|
73
95
|
```
|
74
96
|
|
97
|
+
Deleting a person and all of the data associated with them:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
# Delete by person id
|
101
|
+
Delighted::Person.delete(:id => 42)
|
102
|
+
# Delete by email address
|
103
|
+
Delighted::Person.delete(:email => "test@example.com")
|
104
|
+
# Delete by phone number (must be E.164 format)
|
105
|
+
Delighted::Person.delete(:phone_number => "+14155551212")
|
106
|
+
```
|
107
|
+
|
75
108
|
Deleting pending survey requests
|
76
109
|
|
77
110
|
```ruby
|
@@ -138,6 +171,80 @@ filtered_survey_responses = Delighted::SurveyResponse.all(:page => 5,
|
|
138
171
|
:until => Time.utc(2013, 11, 01))
|
139
172
|
```
|
140
173
|
|
174
|
+
Getting Autopilot state:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
email_autopilot_state = Delighted::AutopilotConfiguration.retrieve("email")
|
178
|
+
sms_autopilot_state = Delighted::AutopilotConfiguration.retrieve("sms")
|
179
|
+
```
|
180
|
+
|
181
|
+
Listing Autopilot members:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
email_autopilot_members = Delighted::AutopilotMembership::Email.list
|
185
|
+
begin
|
186
|
+
email_autopilot_members.auto_paging_each do |membership|
|
187
|
+
# Do something with membership
|
188
|
+
end
|
189
|
+
rescue Delighted::RateLimitError => e
|
190
|
+
# Indicates how long to wait before making this request again
|
191
|
+
e.retry_after
|
192
|
+
retry
|
193
|
+
end
|
194
|
+
|
195
|
+
# For convenience, this method can use a sleep to automatically handle rate limits
|
196
|
+
email_autopilot_members.auto_paging_each({ auto_handle_rate_limits: true }) do |membership|
|
197
|
+
# Do something with membership
|
198
|
+
end
|
199
|
+
```
|
200
|
+
|
201
|
+
Look up specific Autopilot member:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
Delighted::AutopilotMembership::Email
|
205
|
+
.list(person_email: "foo+test1@delighted.com") # or person_id or person_phone_number
|
206
|
+
.auto_paging_each({ auto_handle_rate_limits: true }) do |membership|
|
207
|
+
# Do something with membership. If no membership for this person exists,
|
208
|
+
# this block will never be called.
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
Add a person to Autopilot:
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
props = {
|
216
|
+
"Shoe Type" => "Sneaker",
|
217
|
+
"Handedness" => "Left"
|
218
|
+
}
|
219
|
+
result = Delighted::AutopilotMembership::Email.create(
|
220
|
+
person_email: "foo+test1@delighted.com",
|
221
|
+
properties: props
|
222
|
+
)
|
223
|
+
```
|
224
|
+
|
225
|
+
Update a person in Autopilot:
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
props = {
|
229
|
+
"Shoe Type" => "Sandal",
|
230
|
+
"Handedness" => "Left"
|
231
|
+
}
|
232
|
+
result = Delighted::AutopilotMembership::Email.create(
|
233
|
+
person_email: "foo+test1@delighted.com",
|
234
|
+
properties: props
|
235
|
+
)
|
236
|
+
```
|
237
|
+
|
238
|
+
Remove a person from Autopilot:
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
result = Delighted::AutopilotMembership::Sms.delete(
|
242
|
+
person_phone_number: "+15555551212"
|
243
|
+
)
|
244
|
+
|
245
|
+
result = Delighted::AutopilotMembership::Sms.delete(person_id: "433523")
|
246
|
+
```
|
247
|
+
|
141
248
|
Retrieving metrics:
|
142
249
|
|
143
250
|
```ruby
|
data/lib/delighted.rb
CHANGED
@@ -9,12 +9,15 @@ 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'
|
20
|
+
require 'delighted/operations/delete'
|
18
21
|
|
19
22
|
require 'delighted/resources/bounce'
|
20
23
|
require 'delighted/resources/metrics'
|
@@ -23,6 +26,9 @@ require 'delighted/resources/survey_request'
|
|
23
26
|
require 'delighted/resources/survey_response'
|
24
27
|
require 'delighted/resources/unsubscribe'
|
25
28
|
|
29
|
+
require 'delighted/resources/autopilot_configuration'
|
30
|
+
require 'delighted/resources/autopilot_membership'
|
31
|
+
|
26
32
|
require 'delighted/errors'
|
27
33
|
require 'delighted/http_response'
|
28
34
|
require 'delighted/http_adapter'
|
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::DEFAULT_PARSER.make_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,20 @@
|
|
1
|
+
module Delighted
|
2
|
+
module Operations
|
3
|
+
module Delete
|
4
|
+
def self.included(klass)
|
5
|
+
klass.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def path(id = nil)
|
10
|
+
id ? "#{@path}/#{CGI.escape(id)}" : @path
|
11
|
+
end
|
12
|
+
|
13
|
+
def delete(id_hash, client = Delighted.shared_client)
|
14
|
+
id = identifier_string(id_hash)
|
15
|
+
client.delete_json(path(id))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
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/resource.rb
CHANGED
@@ -11,6 +11,20 @@ module Delighted
|
|
11
11
|
def singleton_resource?
|
12
12
|
!!@singleton_resource
|
13
13
|
end
|
14
|
+
|
15
|
+
def identifier_string(identifier_hash)
|
16
|
+
raise ArgumentError, "must pass Hash" unless Hash === identifier_hash
|
17
|
+
raise ArgumentError, "must pass exactly one identifier name and value" unless identifier_hash.size == 1
|
18
|
+
|
19
|
+
identifier_key = identifier_hash.keys.first
|
20
|
+
identifier_value = identifier_hash.values.first
|
21
|
+
|
22
|
+
if identifier_key.to_s == "id"
|
23
|
+
identifier_value.to_s
|
24
|
+
else
|
25
|
+
"#{identifier_key}:#{identifier_value}"
|
26
|
+
end
|
27
|
+
end
|
14
28
|
end
|
15
29
|
|
16
30
|
undef :id if method_defined?(:id)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Delighted
|
2
|
+
class AutopilotMembership < Resource
|
3
|
+
# This is a class purely so that Sms and Email share a common semantic base class
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def delete(person_id_hash, client = Delighted.shared_client)
|
7
|
+
json = client.delete_json(path, person_id_hash)
|
8
|
+
json.merge(:person => Person.new(json[:person]))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Sms < AutopilotMembership
|
13
|
+
self.path = "/autopilot/sms/memberships"
|
14
|
+
self.expandable_attributes = { :person => Person, :next_survey_request => SurveyRequest }
|
15
|
+
|
16
|
+
include Operations::List
|
17
|
+
include Operations::Create
|
18
|
+
end
|
19
|
+
|
20
|
+
class Email < AutopilotMembership
|
21
|
+
self.path = "/autopilot/email/memberships"
|
22
|
+
self.expandable_attributes = { :person => Person, :next_survey_request => SurveyRequest }
|
23
|
+
|
24
|
+
include Operations::List
|
25
|
+
include Operations::Create
|
26
|
+
end
|
27
|
+
end
|
28
|
+
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}" }
|
@@ -80,6 +203,43 @@ class Delighted::PeopleTest < Delighted::TestCase
|
|
80
203
|
assert_kind_of Hash, result
|
81
204
|
assert_equal({ :ok => true }, result)
|
82
205
|
end
|
206
|
+
|
207
|
+
def test_deleting_a_person_with_multiple_identifiers
|
208
|
+
assert_raises(ArgumentError) { Delighted::Person.delete(:id => 57, :email => "foo@example.com") }
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_deleting_a_person_by_id
|
212
|
+
uri = URI.parse("https://api.delightedapp.com/v1/people/57")
|
213
|
+
headers = { 'Authorization' => @auth_header, "Accept" => "application/json", 'Content-Type' => 'application/json', 'User-Agent' => "Delighted RubyGem #{Delighted::VERSION}" }
|
214
|
+
response = Delighted::HTTPResponse.new(202, {}, Delighted::JSON.dump({ :ok => true }))
|
215
|
+
mock_http_adapter.expects(:request).with(:delete, uri, headers, nil).once.returns(response)
|
216
|
+
|
217
|
+
result = Delighted::Person.delete(:id => 57)
|
218
|
+
assert_kind_of Hash, result
|
219
|
+
assert_equal({ :ok => true }, result)
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_deleting_a_person_by_email
|
223
|
+
uri = URI.parse("https://api.delightedapp.com/v1/people/email%3Afoo%40bar.com")
|
224
|
+
headers = { 'Authorization' => @auth_header, "Accept" => "application/json", 'Content-Type' => 'application/json', 'User-Agent' => "Delighted RubyGem #{Delighted::VERSION}" }
|
225
|
+
response = Delighted::HTTPResponse.new(202, {}, Delighted::JSON.dump({ :ok => true }))
|
226
|
+
mock_http_adapter.expects(:request).with(:delete, uri, headers, nil).once.returns(response)
|
227
|
+
|
228
|
+
result = Delighted::Person.delete(:email => "foo@bar.com")
|
229
|
+
assert_kind_of Hash, result
|
230
|
+
assert_equal({ :ok => true }, result)
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_deleting_a_person_by_phone_number
|
234
|
+
uri = URI.parse("https://api.delightedapp.com/v1/people/phone_number%3A%2B14155551212")
|
235
|
+
headers = { 'Authorization' => @auth_header, "Accept" => "application/json", 'Content-Type' => 'application/json', 'User-Agent' => "Delighted RubyGem #{Delighted::VERSION}" }
|
236
|
+
response = Delighted::HTTPResponse.new(202, {}, Delighted::JSON.dump({ :ok => true }))
|
237
|
+
mock_http_adapter.expects(:request).with(:delete, uri, headers, nil).once.returns(response)
|
238
|
+
|
239
|
+
result = Delighted::Person.delete(:phone_number => "+14155551212")
|
240
|
+
assert_kind_of Hash, result
|
241
|
+
assert_equal({ :ok => true }, result)
|
242
|
+
end
|
83
243
|
end
|
84
244
|
|
85
245
|
class Delighted::SurveyResponseTest < Delighted::TestCase
|
@@ -227,3 +387,211 @@ class Delighted::BouncesTest < Delighted::TestCase
|
|
227
387
|
end
|
228
388
|
end
|
229
389
|
|
390
|
+
class Delighted::AutopilotConfigurationsTest < Delighted::TestCase
|
391
|
+
def test_getting_sms_autopilot_configuration
|
392
|
+
uri = URI.parse("https://api.delightedapp.com/v1/autopilot/sms")
|
393
|
+
headers = { 'Authorization' => @auth_header, "Accept" => "application/json", 'User-Agent' => "Delighted RubyGem #{Delighted::VERSION}" }
|
394
|
+
response = Delighted::HTTPResponse.new(200, {}, Delighted::JSON.dump({ :platform_id => 'sms', :active => true, :frequency => 7776000, :created_at => 1611253998, :updated_at => 1618421598 }))
|
395
|
+
mock_http_adapter.expects(:request).with(:get, uri, headers).once.returns(response)
|
396
|
+
|
397
|
+
configuration = Delighted::AutopilotConfiguration.retrieve('sms')
|
398
|
+
assert_kind_of Delighted::AutopilotConfiguration, configuration
|
399
|
+
assert_equal({ :platform_id => 'sms', :active => true, :frequency => 7776000, :created_at => 1611253998, :updated_at => 1618421598 }, configuration.to_hash)
|
400
|
+
assert_equal 'sms', configuration.platform_id
|
401
|
+
assert_equal true, configuration.active
|
402
|
+
assert_equal 7776000, configuration.frequency
|
403
|
+
assert_equal 1611253998, configuration.created_at
|
404
|
+
assert_equal 1618421598, configuration.updated_at
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
class Delighted::AutopilotMembershipsTest < Delighted::TestCase
|
409
|
+
def test_listing_autopilot_memberships
|
410
|
+
first_membership = {
|
411
|
+
:created_at => 1611253998,
|
412
|
+
:updated_at => 1618421598,
|
413
|
+
:person => {
|
414
|
+
:id => "34",
|
415
|
+
:name => "Leslie",
|
416
|
+
:email => "leslie@example.com",
|
417
|
+
:created_at => 1611365037,
|
418
|
+
:phone_number => "+1555555112",
|
419
|
+
:last_sent_at => nil
|
420
|
+
},
|
421
|
+
:next_survey_request => {
|
422
|
+
:id => "42",
|
423
|
+
:created_at => 1614043237,
|
424
|
+
:survey_scheduled_at => 1620087437,
|
425
|
+
:properties => { :"Purchase Experience" => "Web", :"State" => "OR" }
|
426
|
+
}
|
427
|
+
}
|
428
|
+
second_membership = {
|
429
|
+
:created_at => 1611243998,
|
430
|
+
:updated_at => 1618420598,
|
431
|
+
:person => {
|
432
|
+
:id => "42",
|
433
|
+
:name => "Taylor",
|
434
|
+
:email => "taylor@example.com",
|
435
|
+
:created_at => 1611242998,
|
436
|
+
:phone_number => "+1555551212",
|
437
|
+
:last_sent_at => 1611242998
|
438
|
+
},
|
439
|
+
:next_survey_request => {
|
440
|
+
:id => "3445",
|
441
|
+
:created_at => 1614043437,
|
442
|
+
:survey_scheduled_at => 1620087837,
|
443
|
+
:properties => { :"Purchase Experience" => "Mobile", :"State" => "CA" }
|
444
|
+
}
|
445
|
+
}
|
446
|
+
third_membership = {
|
447
|
+
:created_at => 1611143998,
|
448
|
+
:updated_at => 1618320598,
|
449
|
+
:person => {
|
450
|
+
:id => "47",
|
451
|
+
:name => "Casey",
|
452
|
+
:email => "casey@example.com",
|
453
|
+
:created_at => 1610242998,
|
454
|
+
:phone_number => "+1555551234",
|
455
|
+
:last_sent_at => 1610242998
|
456
|
+
},
|
457
|
+
:next_survey_request => {
|
458
|
+
:id => "3449",
|
459
|
+
:created_at => 1614063437,
|
460
|
+
:survey_scheduled_at => 1620097837,
|
461
|
+
:properties => { :"Purchase Experience" => "Store", :"State" => "WA" }
|
462
|
+
}
|
463
|
+
}
|
464
|
+
uri = URI.parse("https://api.delightedapp.com/v1/autopilot/sms/memberships")
|
465
|
+
uri_next = URI.parse("https://api.delightedapp.com/v1/autopilot/sms/memberships?page_info=123456789")
|
466
|
+
headers = { "Authorization" => @auth_header, "Accept" => "application/json", "User-Agent" => "Delighted RubyGem #{Delighted::VERSION}" }
|
467
|
+
|
468
|
+
# First request mock
|
469
|
+
response = Delighted::HTTPResponse.new(200, {"Link" => "<#{uri_next}>; rel=\"next\""}, Delighted::JSON.dump([first_membership, second_membership]))
|
470
|
+
mock_http_adapter.expects(:request).with(:get, uri, headers).once.returns(response)
|
471
|
+
|
472
|
+
# Next request mock
|
473
|
+
response = Delighted::HTTPResponse.new(200, {}, Delighted::JSON.dump([third_membership]))
|
474
|
+
mock_http_adapter.expects(:request).with(:get, uri_next, headers).once.returns(response)
|
475
|
+
|
476
|
+
memberships = []
|
477
|
+
Delighted::AutopilotMembership::Sms.list.auto_paging_each do |membership|
|
478
|
+
memberships << membership
|
479
|
+
end
|
480
|
+
|
481
|
+
assert_equal 3, memberships.size
|
482
|
+
assert_kind_of Delighted::AutopilotMembership::Sms, memberships[0]
|
483
|
+
assert_kind_of Delighted::Person, memberships[0].person
|
484
|
+
assert_kind_of Delighted::SurveyRequest, memberships[0].next_survey_request
|
485
|
+
assert_equal 1611253998, memberships[0].created_at
|
486
|
+
assert_equal "34", memberships[0].person.id
|
487
|
+
assert_nil memberships[0].person.last_sent_at
|
488
|
+
assert_equal first_membership[:person].reject { |k,_| k == :id }, memberships[0].person.to_hash
|
489
|
+
assert_equal "+1555555112", memberships[0].person.phone_number
|
490
|
+
assert_equal 1620087437, memberships[0].next_survey_request.survey_scheduled_at
|
491
|
+
assert_equal first_membership[:next_survey_request][:properties], memberships[0].next_survey_request.properties
|
492
|
+
assert_kind_of Delighted::AutopilotMembership, memberships[1]
|
493
|
+
assert_equal 1611242998, memberships[1].person.last_sent_at
|
494
|
+
end
|
495
|
+
|
496
|
+
def test_listing_specific_autopilot_memberships
|
497
|
+
specific_membership = {
|
498
|
+
:created_at => 1611253998,
|
499
|
+
:updated_at => 1618421598,
|
500
|
+
:person => {
|
501
|
+
:id => "34",
|
502
|
+
:name => "Leslie",
|
503
|
+
:email => "leslie@example.com",
|
504
|
+
:created_at => 1611365037,
|
505
|
+
:phone_number => "+1555555112",
|
506
|
+
:last_sent_at => nil
|
507
|
+
},
|
508
|
+
:next_survey_request => {
|
509
|
+
:id => "42",
|
510
|
+
:created_at => 1614043237,
|
511
|
+
:survey_scheduled_at => 1620087437,
|
512
|
+
:properties => {
|
513
|
+
:"Purchase Experience" => "Web",
|
514
|
+
:"State" => "OR"
|
515
|
+
}
|
516
|
+
}
|
517
|
+
}
|
518
|
+
uri = URI.parse("https://api.delightedapp.com/v1/autopilot/sms/memberships?person_id=34")
|
519
|
+
headers = { "Authorization" => @auth_header, "Accept" => "application/json", "User-Agent" => "Delighted RubyGem #{Delighted::VERSION}" }
|
520
|
+
response = Delighted::HTTPResponse.new(200, {}, Delighted::JSON.dump([specific_membership]))
|
521
|
+
mock_http_adapter.expects(:request).with(:get, uri, headers).once.returns(response)
|
522
|
+
|
523
|
+
memberships = []
|
524
|
+
Delighted::AutopilotMembership::Sms.list(person_id: 34).auto_paging_each do |membership|
|
525
|
+
memberships << membership
|
526
|
+
end
|
527
|
+
|
528
|
+
assert_equal 1, memberships.size
|
529
|
+
assert_kind_of Delighted::AutopilotMembership::Sms, memberships[0]
|
530
|
+
assert_kind_of Delighted::Person, memberships[0].person
|
531
|
+
assert_kind_of Delighted::SurveyRequest, memberships[0].next_survey_request
|
532
|
+
assert_equal 1, memberships.size
|
533
|
+
end
|
534
|
+
|
535
|
+
def test_adding_autopilot_membership
|
536
|
+
params = {
|
537
|
+
person_email: "leslie@example.com",
|
538
|
+
person_name: "Leslie",
|
539
|
+
properties: {
|
540
|
+
:"Purchase Experience" => "Web",
|
541
|
+
:"State" => "OR"
|
542
|
+
}
|
543
|
+
}
|
544
|
+
uri = URI.parse("https://api.delightedapp.com/v1/autopilot/email/memberships")
|
545
|
+
headers = { "Authorization" => @auth_header, "Accept" => "application/json", 'Content-Type' => 'application/json', "User-Agent" => "Delighted RubyGem #{Delighted::VERSION}" }
|
546
|
+
response = Delighted::HTTPResponse.new(200, {}, Delighted::JSON.dump({ person: { id: "333", name: params[:person_name], email: params[:person_email] }, properties: params[:properties] }))
|
547
|
+
mock_http_adapter.expects(:request).with(:post, uri, headers, Delighted::JSON.dump(params)).once.returns(response)
|
548
|
+
|
549
|
+
result = Delighted::AutopilotMembership::Email.create(params)
|
550
|
+
|
551
|
+
assert_kind_of Delighted::AutopilotMembership::Email, result
|
552
|
+
assert_kind_of Delighted::Person, result.person
|
553
|
+
assert_equal params[:properties], result.properties
|
554
|
+
assert_equal params[:person_email], result.person.email
|
555
|
+
assert_equal params[:person_name], result.person.name
|
556
|
+
assert result.person.id
|
557
|
+
assert_equal params[:properties], result.properties
|
558
|
+
end
|
559
|
+
|
560
|
+
def test_updating_autopilot_membership
|
561
|
+
params = {
|
562
|
+
person_id: "333",
|
563
|
+
properties: {
|
564
|
+
:"Purchase Experience" => "Web",
|
565
|
+
:"State" => "OR"
|
566
|
+
}
|
567
|
+
}
|
568
|
+
uri = URI.parse("https://api.delightedapp.com/v1/autopilot/sms/memberships")
|
569
|
+
headers = { "Authorization" => @auth_header, "Accept" => "application/json", 'Content-Type' => 'application/json', "User-Agent" => "Delighted RubyGem #{Delighted::VERSION}" }
|
570
|
+
response = Delighted::HTTPResponse.new(200, {}, Delighted::JSON.dump({ person: { id: "333", name: "Leslie", email: "leslie@example.com", phone_numer: "+15555551212" }, properties: params[:properties] }))
|
571
|
+
mock_http_adapter.expects(:request).with(:post, uri, headers, Delighted::JSON.dump(params)).once.returns(response)
|
572
|
+
|
573
|
+
result = Delighted::AutopilotMembership::Sms.create(params)
|
574
|
+
|
575
|
+
assert_kind_of Delighted::AutopilotMembership::Sms, result
|
576
|
+
assert_kind_of Delighted::Person, result.person
|
577
|
+
assert_equal params[:properties], result.properties
|
578
|
+
assert_equal "leslie@example.com", result.person.email
|
579
|
+
assert_equal "Leslie", result.person.name
|
580
|
+
assert_equal "333", result.person.id
|
581
|
+
assert_equal params[:properties], result.properties
|
582
|
+
end
|
583
|
+
|
584
|
+
def test_removing_autopilot_membership
|
585
|
+
uri = URI.parse("https://api.delightedapp.com/v1/autopilot/sms/memberships")
|
586
|
+
headers = { "Authorization" => @auth_header, "Accept" => "application/json", 'Content-Type' => 'application/json', "User-Agent" => "Delighted RubyGem #{Delighted::VERSION}" }
|
587
|
+
response = Delighted::HTTPResponse.new(200, {}, Delighted::JSON.dump({ person: { id: "333", name: "Leslie", email: "leslie@example.com"} }))
|
588
|
+
mock_http_adapter.expects(:request).with(:delete, uri, headers, Delighted::JSON.dump({person_id: "455"})).once.returns(response)
|
589
|
+
|
590
|
+
result = Delighted::AutopilotMembership::Sms.delete(:person_id => "455")
|
591
|
+
|
592
|
+
assert_kind_of Hash, result
|
593
|
+
assert_equal "leslie@example.com", result[:person].email
|
594
|
+
assert_equal "Leslie", result[:person].name
|
595
|
+
assert_equal "333", result[:person].id
|
596
|
+
end
|
597
|
+
end
|
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: 1.
|
4
|
+
version: 2.1.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: 2021-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|
@@ -88,11 +88,16 @@ 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
|
94
|
+
- lib/delighted/operations/delete.rb
|
95
|
+
- lib/delighted/operations/list.rb
|
93
96
|
- lib/delighted/operations/retrieve.rb
|
94
97
|
- lib/delighted/operations/update.rb
|
95
98
|
- lib/delighted/resource.rb
|
99
|
+
- lib/delighted/resources/autopilot_configuration.rb
|
100
|
+
- lib/delighted/resources/autopilot_membership.rb
|
96
101
|
- lib/delighted/resources/bounce.rb
|
97
102
|
- lib/delighted/resources/metrics.rb
|
98
103
|
- lib/delighted/resources/person.rb
|
@@ -119,12 +124,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
119
124
|
version: '0'
|
120
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
126
|
requirements:
|
122
|
-
- - "
|
127
|
+
- - ">"
|
123
128
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
129
|
+
version: 1.3.1
|
125
130
|
requirements: []
|
126
131
|
rubyforge_project:
|
127
|
-
rubygems_version: 2.6.
|
132
|
+
rubygems_version: 2.7.6.2
|
128
133
|
signing_key:
|
129
134
|
specification_version: 4
|
130
135
|
summary: Delighted is the fastest and easiest way to gather actionable feedback from
|