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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 24e928b7535e1d51f72461238850e824b27b3920
4
- data.tar.gz: 86001bae9ecc475902d0ce5f2d4ed1cc15d6f686
2
+ SHA256:
3
+ metadata.gz: 3ce86b0edf1b9df5dab8e46ba0fc4213c6c14667b7a4fe28d441e03fbf1b747e
4
+ data.tar.gz: 9eee58a5c861c75a0e7b33e6aacf54648da80fd8969ebeadac75e1d418fb95dc
5
5
  SHA512:
6
- metadata.gz: 1c62db83772abc00c2a6c1524c8a18f998b953ca227d8f521eaf2a3cb10e7457b078eac3d8d8473668e83c646e8f515a32700435fbc7a59edf715585f87e4eb7
7
- data.tar.gz: 0cfa475365360aa17f5e7b81c215e07607eed6d10f867ba5269ef840c62aa88ca032944d613d11d7159b224593cbf0e2b67282aa1da5acdcad9621a7a99904fe
6
+ metadata.gz: f759a34fe7d102ae00aa9e1b048cdebc9c5731c3fad3bd502af77db8e16b311d4782465a5a47d4885c883435e930433b24b4972676cd72ecf85f5f37b954f1f8
7
+ data.tar.gz: cc905c3739263c36fdf92ccf62407c814721828e70ae50e36d1d7e79218abb58fbfd73209b21b56585c553915e86db53dfab54e17bcfa407c146ed4fa630b903
data/.travis.yml CHANGED
@@ -1,12 +1,11 @@
1
1
  language: ruby
2
2
  before_install: gem update bundler
3
3
  rvm:
4
+ - ruby-head
5
+ - 2.5
4
6
  - 2.2
5
7
  - 2.1
6
8
  - 2.0
7
9
  - 1.9.3
8
- - 1.9.2
9
- - 1.8.7
10
10
  - jruby-18mode
11
11
  - jruby-19mode
12
- - ree
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'
@@ -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
- headers = default_headers.dup.merge('Accept' => 'application/json')
14
+ request_get(path, {params: params})[:json]
15
+ end
14
16
 
15
- uri = URI.parse(File.join(@api_base_url, path))
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
@@ -38,4 +38,8 @@ module Delighted
38
38
  class ServiceUnavailableError < Error
39
39
  # 503, maintenance or overloaded
40
40
  end
41
+
42
+ class PaginationError < StandardError
43
+ # e.g. pagination completed
44
+ end
41
45
  end
@@ -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
@@ -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,7 @@
1
+ module Delighted
2
+ class AutopilotConfiguration < Resource
3
+ self.path = "/autopilot"
4
+
5
+ include Operations::Retrieve
6
+ end
7
+ end
@@ -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
@@ -3,5 +3,7 @@ module Delighted
3
3
  self.path = "/people"
4
4
 
5
5
  include Operations::Create
6
+ include Operations::Delete
7
+ include Operations::List
6
8
  end
7
9
  end
@@ -1,3 +1,3 @@
1
1
  module Delighted
2
- VERSION = "1.7.0"
2
+ VERSION = "2.1.0rc1"
3
3
  end
@@ -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.7.0
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: 2017-10-18 00:00:00.000000000 Z
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: '0'
129
+ version: 1.3.1
125
130
  requirements: []
126
131
  rubyforge_project:
127
- rubygems_version: 2.6.13
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