intercom 3.5.10 → 3.9.5

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.
Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +35 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +5 -0
  4. data/Gemfile +1 -4
  5. data/README.md +152 -83
  6. data/RELEASING.md +9 -0
  7. data/changes.txt +116 -0
  8. data/intercom.gemspec +1 -2
  9. data/lib/intercom.rb +4 -0
  10. data/lib/intercom/api_operations/{delete.rb → archive.rb} +4 -2
  11. data/lib/intercom/api_operations/find_all.rb +1 -1
  12. data/lib/intercom/api_operations/request_hard_delete.rb +12 -0
  13. data/lib/intercom/api_operations/search.rb +17 -0
  14. data/lib/intercom/client.rb +42 -5
  15. data/lib/intercom/customer.rb +10 -0
  16. data/lib/intercom/errors.rb +41 -4
  17. data/lib/intercom/request.rb +144 -81
  18. data/lib/intercom/search_collection_proxy.rb +82 -0
  19. data/lib/intercom/service/base_service.rb +6 -0
  20. data/lib/intercom/service/company.rb +14 -2
  21. data/lib/intercom/service/contact.rb +4 -2
  22. data/lib/intercom/service/conversation.rb +12 -0
  23. data/lib/intercom/service/customer.rb +14 -0
  24. data/lib/intercom/service/event.rb +12 -0
  25. data/lib/intercom/service/subscription.rb +2 -2
  26. data/lib/intercom/service/tag.rb +1 -1
  27. data/lib/intercom/service/team.rb +17 -0
  28. data/lib/intercom/service/user.rb +4 -2
  29. data/lib/intercom/service/visitor.rb +2 -2
  30. data/lib/intercom/team.rb +7 -0
  31. data/lib/intercom/traits/api_resource.rb +4 -9
  32. data/lib/intercom/version.rb +1 -1
  33. data/spec/spec_helper.rb +124 -2
  34. data/spec/unit/intercom/client_collection_proxy_spec.rb +5 -5
  35. data/spec/unit/intercom/client_spec.rb +69 -1
  36. data/spec/unit/intercom/company_spec.rb +20 -16
  37. data/spec/unit/intercom/contact_spec.rb +6 -0
  38. data/spec/unit/intercom/conversation_spec.rb +15 -0
  39. data/spec/unit/intercom/event_spec.rb +19 -0
  40. data/spec/unit/intercom/request_spec.rb +150 -9
  41. data/spec/unit/intercom/search_collection_proxy_spec.rb +56 -0
  42. data/spec/unit/intercom/team_spec.rb +21 -0
  43. data/spec/unit/intercom/traits/api_resource_spec.rb +34 -7
  44. data/spec/unit/intercom/user_spec.rb +15 -3
  45. metadata +33 -22
  46. data/.travis.yml +0 -6
  47. data/lib/intercom/extended_api_operations/users.rb +0 -16
@@ -0,0 +1,82 @@
1
+ require "intercom/utils"
2
+
3
+ module Intercom
4
+ class SearchCollectionProxy
5
+
6
+ attr_reader :resource_name, :resource_class
7
+
8
+ def initialize(resource_name, search_details: {}, client:)
9
+ @resource_name = resource_name
10
+ @resource_class = Utils.constantize_resource_name(resource_name)
11
+ @search_url = search_details[:url]
12
+ @search_params = search_details[:params]
13
+ @client = client
14
+ end
15
+
16
+ def each(&block)
17
+ loop do
18
+ response_hash = @client.post(@search_url, payload)
19
+ raise Intercom::HttpError.new('Http Error - No response entity returned') unless response_hash
20
+ deserialize_response_hash(response_hash, block)
21
+ break unless has_next_link?(response_hash)
22
+ end
23
+ self
24
+ end
25
+
26
+ def [](target_index)
27
+ self.each_with_index do |item, index|
28
+ return item if index == target_index
29
+ end
30
+ nil
31
+ end
32
+
33
+ include Enumerable
34
+
35
+ private
36
+
37
+ def deserialize_response_hash(response_hash, block)
38
+ top_level_type = response_hash.delete('type')
39
+ top_level_entity_key = Utils.entity_key_from_type(top_level_type)
40
+ response_hash[top_level_entity_key].each do |object_json|
41
+ block.call Lib::TypedJsonDeserializer.new(object_json).deserialize
42
+ end
43
+ end
44
+
45
+ def has_next_link?(response_hash)
46
+ paging_info = response_hash.delete('pages')
47
+ paging_next = paging_info["next"]
48
+ if paging_next
49
+ @search_params[:starting_after] = paging_next["starting_after"]
50
+ return true
51
+ else
52
+ return false
53
+ end
54
+ end
55
+
56
+ def payload
57
+ payload = {
58
+ query: @search_params[:query]
59
+ }
60
+ if @search_params[:sort_field] || @search_params[:sort_order]
61
+ payload[:sort] = {}
62
+ if @search_params[:sort_field]
63
+ payload[:sort][:field] = @search_params[:sort_field]
64
+ end
65
+ if @search_params[:sort_order]
66
+ payload[:sort][:order] = @search_params[:sort_order]
67
+ end
68
+ end
69
+ if @search_params[:per_page] || @search_params[:starting_after]
70
+ payload[:pagination] = {}
71
+ if @search_params[:per_page]
72
+ payload[:pagination][:per_page] = @search_params[:per_page]
73
+ end
74
+ if @search_params[:starting_after]
75
+ payload[:pagination][:starting_after] = @search_params[:starting_after]
76
+ end
77
+ end
78
+ return payload
79
+ end
80
+
81
+ end
82
+ end
@@ -1,3 +1,5 @@
1
+ require 'intercom/client_collection_proxy'
2
+
1
3
  module Intercom
2
4
  module Service
3
5
  class BaseService
@@ -11,6 +13,10 @@ module Intercom
11
13
  raise NotImplementedError
12
14
  end
13
15
 
16
+ def collection_proxy_class
17
+ Intercom::ClientCollectionProxy
18
+ end
19
+
14
20
  def from_api(api_response)
15
21
  object = collection_class.new
16
22
  object.from_response(api_response)
@@ -1,10 +1,10 @@
1
1
  require 'intercom/service/base_service'
2
2
  require 'intercom/api_operations/list'
3
+ require 'intercom/api_operations/scroll'
3
4
  require 'intercom/api_operations/find'
4
5
  require 'intercom/api_operations/find_all'
5
6
  require 'intercom/api_operations/save'
6
7
  require 'intercom/api_operations/load'
7
- require 'intercom/extended_api_operations/users'
8
8
  require 'intercom/extended_api_operations/tags'
9
9
  require 'intercom/extended_api_operations/segments'
10
10
 
@@ -15,14 +15,26 @@ module Intercom
15
15
  include ApiOperations::FindAll
16
16
  include ApiOperations::Load
17
17
  include ApiOperations::List
18
+ include ApiOperations::Scroll
18
19
  include ApiOperations::Save
19
- include ExtendedApiOperations::Users
20
20
  include ExtendedApiOperations::Tags
21
21
  include ExtendedApiOperations::Segments
22
22
 
23
23
  def collection_class
24
24
  Intercom::Company
25
25
  end
26
+
27
+ def users_by_intercom_company_id(id)
28
+ get_users(url: "/companies/#{id}/users")
29
+ end
30
+
31
+ def users_by_company_id(id)
32
+ get_users(url: "/companies", params: { company_id: id, type: "user" })
33
+ end
34
+
35
+ private def get_users(url:, params: {})
36
+ ClientCollectionProxy.new("users", finder_details: { url: url, params: params }, client: @client)
37
+ end
26
38
  end
27
39
  end
28
40
  end
@@ -6,7 +6,8 @@ require 'intercom/api_operations/find_all'
6
6
  require 'intercom/api_operations/save'
7
7
  require 'intercom/api_operations/scroll'
8
8
  require 'intercom/api_operations/convert'
9
- require 'intercom/api_operations/delete'
9
+ require 'intercom/api_operations/archive'
10
+ require 'intercom/api_operations/request_hard_delete'
10
11
 
11
12
  module Intercom
12
13
  module Service
@@ -18,7 +19,8 @@ module Intercom
18
19
  include ApiOperations::Save
19
20
  include ApiOperations::Scroll
20
21
  include ApiOperations::Convert
21
- include ApiOperations::Delete
22
+ include ApiOperations::Archive
23
+ include ApiOperations::RequestHardDelete
22
24
 
23
25
  def collection_class
24
26
  Intercom::Contact
@@ -9,6 +9,7 @@ module Intercom
9
9
  module Service
10
10
  class Conversation < BaseService
11
11
  include ApiOperations::FindAll
12
+ include ApiOperations::List
12
13
  include ApiOperations::Find
13
14
  include ApiOperations::Load
14
15
  include ApiOperations::Save
@@ -28,6 +29,12 @@ module Intercom
28
29
  collection_class.new.from_response(response)
29
30
  end
30
31
 
32
+ def reply_to_last(reply_data)
33
+ collection_name = Utils.resource_class_to_collection_name(collection_class)
34
+ response = @client.post("/#{collection_name}/last/reply", reply_data)
35
+ collection_class.new.from_response(response)
36
+ end
37
+
31
38
  def open(reply_data)
32
39
  reply reply_data.merge(message_type: 'open', type: 'admin')
33
40
  end
@@ -36,6 +43,11 @@ module Intercom
36
43
  reply reply_data.merge(message_type: 'close', type: 'admin')
37
44
  end
38
45
 
46
+ def snooze(reply_data)
47
+ snoozed_until = reply_data.fetch(:snoozed_until) { fail 'snoozed_until field is required' }
48
+ reply reply_data.merge(message_type: 'snoozed', type: 'admin')
49
+ end
50
+
39
51
  def assign(reply_data)
40
52
  assignee_id = reply_data.fetch(:assignee_id) { fail 'assignee_id is required' }
41
53
  reply reply_data.merge(message_type: 'assignment', assignee_id: assignee_id, type: 'admin')
@@ -0,0 +1,14 @@
1
+ require 'intercom/service/base_service'
2
+ require 'intercom/api_operations/search'
3
+
4
+ module Intercom
5
+ module Service
6
+ class Customer < BaseService
7
+ include ApiOperations::Search
8
+
9
+ def collection_class
10
+ Intercom::Customer
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,8 +1,16 @@
1
+ require 'intercom/client_collection_proxy'
1
2
  require 'intercom/service/base_service'
2
3
  require 'intercom/api_operations/save'
3
4
  require 'intercom/api_operations/bulk/submit'
4
5
 
5
6
  module Intercom
7
+ class EventCollectionProxy < ClientCollectionProxy
8
+
9
+ def paging_info_present?(response_hash)
10
+ !!(response_hash['pages'])
11
+ end
12
+ end
13
+
6
14
  module Service
7
15
  class Event < BaseService
8
16
  include ApiOperations::FindAll
@@ -12,6 +20,10 @@ module Intercom
12
20
  def collection_class
13
21
  Intercom::Event
14
22
  end
23
+
24
+ def collection_proxy_class
25
+ Intercom::EventCollectionProxy
26
+ end
15
27
  end
16
28
  end
17
29
  end
@@ -2,7 +2,7 @@ require 'intercom/api_operations/list'
2
2
  require 'intercom/api_operations/find_all'
3
3
  require 'intercom/api_operations/find'
4
4
  require 'intercom/api_operations/save'
5
- require 'intercom/api_operations/delete'
5
+ require 'intercom/api_operations/archive'
6
6
 
7
7
  module Intercom
8
8
  module Service
@@ -11,7 +11,7 @@ module Intercom
11
11
  include ApiOperations::Find
12
12
  include ApiOperations::FindAll
13
13
  include ApiOperations::Save
14
- include ApiOperations::Delete
14
+ include ApiOperations::Archive
15
15
 
16
16
  def collection_class
17
17
  Intercom::Subscription
@@ -9,7 +9,7 @@ module Intercom
9
9
  include ApiOperations::Save
10
10
  include ApiOperations::List
11
11
  include ApiOperations::FindAll
12
- include ApiOperations::Delete
12
+ include ApiOperations::Archive
13
13
 
14
14
  def collection_class
15
15
  Intercom::Tag
@@ -0,0 +1,17 @@
1
+ require 'intercom/service/base_service'
2
+ require 'intercom/api_operations/list'
3
+ require 'intercom/api_operations/find'
4
+
5
+ module Intercom
6
+ module Service
7
+ class Team < BaseService
8
+ include ApiOperations::List
9
+ include ApiOperations::Find
10
+
11
+ def collection_class
12
+ Intercom::Team
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -5,8 +5,9 @@ require 'intercom/api_operations/scroll'
5
5
  require 'intercom/api_operations/find'
6
6
  require 'intercom/api_operations/find_all'
7
7
  require 'intercom/api_operations/save'
8
- require 'intercom/api_operations/delete'
8
+ require 'intercom/api_operations/archive'
9
9
  require 'intercom/api_operations/bulk/submit'
10
+ require 'intercom/api_operations/request_hard_delete'
10
11
  require 'intercom/extended_api_operations/tags'
11
12
  require 'intercom/extended_api_operations/segments'
12
13
 
@@ -19,7 +20,8 @@ module Intercom
19
20
  include ApiOperations::Find
20
21
  include ApiOperations::FindAll
21
22
  include ApiOperations::Save
22
- include ApiOperations::Delete
23
+ include ApiOperations::Archive
24
+ include ApiOperations::RequestHardDelete
23
25
  include ApiOperations::Bulk::Submit
24
26
  include ExtendedApiOperations::Tags
25
27
  include ExtendedApiOperations::Segments
@@ -5,7 +5,7 @@ require 'intercom/api_operations/find'
5
5
  require 'intercom/api_operations/find_all'
6
6
  require 'intercom/api_operations/save'
7
7
  require 'intercom/api_operations/convert'
8
- require 'intercom/api_operations/delete'
8
+ require 'intercom/api_operations/archive'
9
9
 
10
10
  module Intercom
11
11
  module Service
@@ -16,7 +16,7 @@ module Intercom
16
16
  include ApiOperations::FindAll
17
17
  include ApiOperations::Save
18
18
  include ApiOperations::Convert
19
- include ApiOperations::Delete
19
+ include ApiOperations::Archive
20
20
 
21
21
  def collection_class
22
22
  Intercom::Visitor
@@ -0,0 +1,7 @@
1
+ require 'intercom/traits/api_resource'
2
+
3
+ module Intercom
4
+ class Team
5
+ include Traits::ApiResource
6
+ end
7
+ end
@@ -24,7 +24,6 @@ module Intercom
24
24
 
25
25
  def from_hash(hash)
26
26
  hash.each do |attribute, value|
27
- next if type_field?(attribute)
28
27
  initialize_property(attribute, value)
29
28
  end
30
29
  initialize_missing_flat_store_attributes if respond_to? :flat_store_attributes
@@ -78,13 +77,13 @@ module Intercom
78
77
  end
79
78
 
80
79
  def custom_attribute_field?(attribute)
81
- attribute == 'custom_attributes'
80
+ attribute.to_s == 'custom_attributes'
82
81
  end
83
-
82
+
84
83
  def message_from_field?(attribute, value)
85
84
  attribute.to_s == 'from' && value.is_a?(Hash) && value['type']
86
85
  end
87
-
86
+
88
87
  def message_to_field?(attribute, value)
89
88
  attribute.to_s == 'to' && value.is_a?(Hash) && value['type']
90
89
  end
@@ -94,7 +93,7 @@ module Intercom
94
93
  !custom_attribute_field?(attribute) &&
95
94
  !message_from_field?(attribute, value) &&
96
95
  !message_to_field?(attribute, value) &&
97
- attribute != 'metadata'
96
+ attribute.to_s != 'metadata'
98
97
  end
99
98
 
100
99
  def typed_value?(value)
@@ -106,10 +105,6 @@ module Intercom
106
105
  self.send(setter_method, value)
107
106
  end
108
107
 
109
- def type_field?(attribute)
110
- attribute == 'type'
111
- end
112
-
113
108
  def initialize_missing_flat_store_attributes
114
109
  flat_store_attributes.each do |attribute|
115
110
  unless instance_variables_excluding_dirty_tracking_field.map(&:to_s).include? "@#{attribute}"
@@ -1,3 +1,3 @@
1
1
  module Intercom #:nodoc:
2
- VERSION = "3.5.10"
2
+ VERSION = "3.9.5"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,17 @@
1
1
  require 'intercom'
2
2
  require 'minitest/autorun'
3
3
  require 'mocha/setup'
4
+ require 'webmock'
5
+ require 'time'
6
+ require 'pry'
7
+ include WebMock::API
8
+
9
+ def test_customer(email="bob@example.com")
10
+ customer = test_user(email)
11
+ customer["type"] = "customer"
12
+ customer["role"] = "user"
13
+ customer
14
+ end
4
15
 
5
16
  def test_user(email="bob@example.com")
6
17
  {
@@ -135,6 +146,35 @@ def test_admin
135
146
  }
136
147
  end
137
148
 
149
+ def test_team_list
150
+ {
151
+ "type"=> "team.list",
152
+ "teams" => [
153
+ {
154
+ "type"=> "team",
155
+ "id"=> "2744328",
156
+ "name"=> "the_a_team",
157
+ "admin_ids"=> [646303, 814860],
158
+ },
159
+ {
160
+ "type"=> "team",
161
+ "id"=> "814865",
162
+ "name"=> "BA_App",
163
+ "admin_ids" => [492881, 1195856]
164
+ },
165
+ ]
166
+ }
167
+ end
168
+
169
+ def test_team
170
+ {
171
+ "type" => "team",
172
+ "id" => "2744328",
173
+ "name" => "the_a_team",
174
+ "admin_ids" => [646303, 814860]
175
+ }
176
+ end
177
+
138
178
  def test_company
139
179
  {
140
180
  "type" => "company",
@@ -225,6 +265,22 @@ def page_of_users(include_next_link= false)
225
265
  }
226
266
  end
227
267
 
268
+ def page_of_customers(include_starting_after= false)
269
+ {
270
+ "type"=>"customer.list",
271
+ "pages"=>
272
+ {
273
+ "type"=>"pages",
274
+ "next"=> (include_starting_after ? { "page" => 2, "starting_after" => "EnCrYpTeDsTrInG" } : nil),
275
+ "page"=>1,
276
+ "per_page"=>50,
277
+ "total_pages"=>7
278
+ },
279
+ "customers"=> [test_customer("user1@example.com"), test_customer("user2@example.com"), test_customer("user3@example.com")],
280
+ "total_count"=>314
281
+ }
282
+ end
283
+
228
284
  def users_scroll(include_users= false)
229
285
  {
230
286
  "type"=>"user.list",
@@ -233,7 +289,7 @@ def users_scroll(include_users= false)
233
289
  }
234
290
  end
235
291
 
236
- def users_pagination(include_next_link=false, per_page=0, page=0, total_pages=0, total_count=0, user_list=[])
292
+ def users_pagination(include_next_link:, per_page:, page:, total_pages:, total_count:, user_list:)
237
293
  {
238
294
  "type"=>"user.list",
239
295
  "pages"=>
@@ -289,6 +345,56 @@ def test_conversation
289
345
  }
290
346
  end
291
347
 
348
+ def test_conversation_list
349
+ {
350
+ "type" => "conversation.list",
351
+ "pages" => {
352
+ "type" => "pages",
353
+ "page" => 1,
354
+ "per_page" => 20,
355
+ "total_pages" => 1
356
+ },
357
+ "conversations" => [
358
+ {
359
+ "type" => "conversation",
360
+ "id" => "147",
361
+ "created_at" => 1400850973,
362
+ "updated_at" => 1400857494,
363
+ "conversation_message" => {
364
+ "type" => "conversation_message",
365
+ "subject" => "",
366
+ "body" => "<p>Hi Alice,</p>\n\n<p>We noticed you using our Product, do you have any questions?</p> \n<p>- Jane</p>",
367
+ "author" => {
368
+ "type" => "admin",
369
+ "id" => "25"
370
+ },
371
+ "attachments" => [
372
+ {
373
+ "name" => "signature",
374
+ "url" => "http =>//someurl.com/signature.jpg"
375
+ }
376
+ ]
377
+ },
378
+ "user" => {
379
+ "type" => "user",
380
+ "id" => "536e564f316c83104c000020"
381
+ },
382
+ "assignee" => {
383
+ "type" => "admin",
384
+ "id" => "25"
385
+ },
386
+ "open" => true,
387
+ "read" => true,
388
+ "conversation_parts" => {
389
+ "type" => "conversation_part.list",
390
+ "conversation_parts" => [
391
+ ]
392
+ }
393
+ }
394
+ ]
395
+ }
396
+ end
397
+
292
398
  def segment
293
399
  {
294
400
  "type" => "segment",
@@ -568,11 +674,27 @@ def test_event_list
568
674
  "type" => "event.list",
569
675
  "events" => [ test_event ],
570
676
  "pages" => {
571
- "next" => "https =>//api.intercom.io/events?type=user&intercom_user_id=55a3b&before=144474756550"
677
+ "next" => "https://api.intercom.io/events?type=user&intercom_user_id=55a3b&before=144474756550"
572
678
  }
573
679
  }
574
680
  end
575
681
 
682
+ def tomorrow
683
+ (DateTime.now.to_time + 1).to_i
684
+ end
685
+
686
+ def page_of_events(include_next_link=false)
687
+ {
688
+ "type" => "event.list",
689
+ "events" => [ test_event ],
690
+ "pages" =>
691
+ {
692
+ "next" => (include_next_link ? "https://api.intercom.io/events?type=user&intercom_user_id=55a3b&before=144474756550" : nil),
693
+ }
694
+ }
695
+ end
696
+
697
+
576
698
  def error_on_modify_frozen
577
699
  RUBY_VERSION =~ /1.8/ ? TypeError : RuntimeError
578
700
  end