intercom 3.5.10 → 4.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) 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 +418 -216
  6. data/RELEASING.md +9 -0
  7. data/Rakefile +1 -1
  8. data/changes.txt +141 -0
  9. data/intercom.gemspec +1 -2
  10. data/lib/intercom.rb +34 -19
  11. data/lib/intercom/api_operations/archive.rb +16 -0
  12. data/lib/intercom/api_operations/delete.rb +4 -1
  13. data/lib/intercom/api_operations/find.rb +5 -2
  14. data/lib/intercom/api_operations/find_all.rb +4 -3
  15. data/lib/intercom/api_operations/list.rb +4 -1
  16. data/lib/intercom/api_operations/load.rb +4 -2
  17. data/lib/intercom/api_operations/nested_resource.rb +70 -0
  18. data/lib/intercom/api_operations/request_hard_delete.rb +12 -0
  19. data/lib/intercom/api_operations/save.rb +6 -4
  20. data/lib/intercom/api_operations/scroll.rb +4 -5
  21. data/lib/intercom/api_operations/search.rb +18 -0
  22. data/lib/intercom/article.rb +7 -0
  23. data/lib/intercom/base_collection_proxy.rb +72 -0
  24. data/lib/intercom/client.rb +66 -18
  25. data/lib/intercom/client_collection_proxy.rb +17 -39
  26. data/lib/intercom/collection.rb +7 -0
  27. data/lib/intercom/company.rb +8 -0
  28. data/lib/intercom/contact.rb +22 -3
  29. data/lib/intercom/conversation.rb +5 -0
  30. data/lib/intercom/data_attribute.rb +7 -0
  31. data/lib/intercom/deprecated_leads_collection_proxy.rb +22 -0
  32. data/lib/intercom/deprecated_resources.rb +13 -0
  33. data/lib/intercom/errors.rb +44 -4
  34. data/lib/intercom/extended_api_operations/segments.rb +3 -1
  35. data/lib/intercom/extended_api_operations/tags.rb +3 -1
  36. data/lib/intercom/lead.rb +21 -0
  37. data/lib/intercom/lib/typed_json_deserializer.rb +42 -37
  38. data/lib/intercom/note.rb +4 -0
  39. data/lib/intercom/request.rb +162 -95
  40. data/lib/intercom/scroll_collection_proxy.rb +38 -42
  41. data/lib/intercom/search_collection_proxy.rb +47 -0
  42. data/lib/intercom/section.rb +23 -0
  43. data/lib/intercom/segment.rb +4 -0
  44. data/lib/intercom/service/article.rb +20 -0
  45. data/lib/intercom/service/base_service.rb +13 -0
  46. data/lib/intercom/service/collection.rb +24 -0
  47. data/lib/intercom/service/company.rb +4 -2
  48. data/lib/intercom/service/contact.rb +29 -6
  49. data/lib/intercom/service/conversation.rb +23 -2
  50. data/lib/intercom/service/data_attribute.rb +20 -0
  51. data/lib/intercom/service/event.rb +12 -0
  52. data/lib/intercom/service/lead.rb +41 -0
  53. data/lib/intercom/service/note.rb +4 -8
  54. data/lib/intercom/service/section.rb +7 -0
  55. data/lib/intercom/service/tag.rb +8 -8
  56. data/lib/intercom/service/team.rb +17 -0
  57. data/lib/intercom/service/user.rb +4 -2
  58. data/lib/intercom/service/visitor.rb +15 -6
  59. data/lib/intercom/tag.rb +4 -0
  60. data/lib/intercom/team.rb +7 -0
  61. data/lib/intercom/traits/api_resource.rb +48 -27
  62. data/lib/intercom/traits/dirty_tracking.rb +8 -1
  63. data/lib/intercom/user.rb +12 -3
  64. data/lib/intercom/utils.rb +13 -2
  65. data/lib/intercom/version.rb +1 -1
  66. data/lib/intercom/visitor.rb +0 -2
  67. data/spec/spec_helper.rb +881 -436
  68. data/spec/unit/intercom/admin_spec.rb +2 -2
  69. data/spec/unit/intercom/article_spec.rb +40 -0
  70. data/spec/unit/intercom/base_collection_proxy_spec.rb +30 -0
  71. data/spec/unit/intercom/client_collection_proxy_spec.rb +41 -41
  72. data/spec/unit/intercom/client_spec.rb +76 -9
  73. data/spec/unit/intercom/collection_spec.rb +32 -0
  74. data/spec/unit/intercom/company_spec.rb +29 -21
  75. data/spec/unit/intercom/contact_spec.rb +365 -29
  76. data/spec/unit/intercom/conversation_spec.rb +70 -7
  77. data/spec/unit/intercom/count_spec.rb +4 -4
  78. data/spec/unit/intercom/data_attribute_spec.rb +40 -0
  79. data/spec/unit/intercom/deprecated_leads_collection_proxy_spec.rb +17 -0
  80. data/spec/unit/intercom/event_spec.rb +25 -8
  81. data/spec/unit/intercom/job_spec.rb +24 -24
  82. data/spec/unit/intercom/lead_spec.rb +57 -0
  83. data/spec/unit/intercom/lib/flat_store_spec.rb +22 -20
  84. data/spec/unit/intercom/message_spec.rb +1 -1
  85. data/spec/unit/intercom/note_spec.rb +4 -10
  86. data/spec/unit/intercom/request_spec.rb +150 -9
  87. data/spec/unit/intercom/scroll_collection_proxy_spec.rb +40 -39
  88. data/spec/unit/intercom/search_collection_proxy_spec.rb +60 -0
  89. data/spec/unit/intercom/section_spec.rb +32 -0
  90. data/spec/unit/intercom/segment_spec.rb +2 -2
  91. data/spec/unit/intercom/subscription_spec.rb +5 -6
  92. data/spec/unit/intercom/tag_spec.rb +22 -14
  93. data/spec/unit/intercom/team_spec.rb +21 -0
  94. data/spec/unit/intercom/traits/api_resource_spec.rb +129 -47
  95. data/spec/unit/intercom/user_spec.rb +227 -217
  96. data/spec/unit/intercom/visitor_spec.rb +49 -0
  97. data/spec/unit/intercom_spec.rb +5 -3
  98. metadata +63 -26
  99. data/.travis.yml +0 -6
  100. data/lib/intercom/extended_api_operations/users.rb +0 -16
  101. data/spec/unit/intercom/visitors_spec.rb +0 -61
@@ -1,32 +1,34 @@
1
- require "intercom/utils"
1
+ # frozen_string_literal: true
2
2
 
3
- module Intercom
4
- class ScrollCollectionProxy
3
+ require 'intercom/utils'
4
+ require 'intercom/base_collection_proxy'
5
5
 
6
- attr_reader :resource_name, :scroll_url, :resource_class, :scroll_param, :records
6
+ module Intercom
7
+ class ScrollCollectionProxy < BaseCollectionProxy
8
+ attr_reader :scroll_url, :scroll_param, :records
7
9
 
8
- def initialize(resource_name, finder_details: {}, client:)
10
+ def initialize(resource_name, resource_class, details: {}, client:)
9
11
  @resource_name = resource_name
10
- @resource_class = Utils.constantize_resource_name(resource_name)
11
- @scroll_url = (finder_details[:url] || "/#{@resource_name}") + '/scroll'
12
+ @resource_class = resource_class
13
+ @scroll_url = (details[:url] || "/#{@resource_name}") + '/scroll'
12
14
  @client = client
13
-
14
15
  end
15
16
 
16
- def next(scroll_parameter=nil)
17
+ def next(scroll_parameter = nil)
17
18
  @records = []
18
- if not scroll_parameter
19
- #First time so do initial get without scroll_param
20
- response_hash = @client.get(@scroll_url, '')
21
- else
22
- #Not first call so use get next page
23
- response_hash = @client.get(@scroll_url, scroll_param: scroll_parameter)
24
- end
25
- raise Intercom::HttpError.new('Http Error - No response entity returned') unless response_hash
19
+ response_hash = if !scroll_parameter
20
+ # First time so do initial get without scroll_param
21
+ @client.get(@scroll_url, '')
22
+ else
23
+ # Not first call so use get next page
24
+ @client.get(@scroll_url, scroll_param: scroll_parameter)
25
+ end
26
+ raise Intercom::HttpError, 'Http Error - No response entity returned' unless response_hash
27
+
26
28
  @scroll_param = extract_scroll_param(response_hash)
27
- top_level_entity_key = deserialize_response_hash(response_hash)
29
+ top_level_entity_key = entity_key_from_response(response_hash)
28
30
  response_hash[top_level_entity_key] = response_hash[top_level_entity_key].map do |object_json|
29
- Lib::TypedJsonDeserializer.new(object_json).deserialize
31
+ Lib::TypedJsonDeserializer.new(object_json, @client).deserialize
30
32
  end
31
33
  @records = response_hash[@resource_name]
32
34
  self
@@ -35,47 +37,41 @@ module Intercom
35
37
  def each(&block)
36
38
  scroll_param = nil
37
39
  loop do
38
- if not scroll_param
39
- response_hash = @client.get(@scroll_url, '')
40
- else
41
- response_hash = @client.get(@scroll_url, scroll_param: scroll_param)
42
- end
43
- raise Intercom::HttpError.new('Http Error - No response entity returned') unless response_hash
44
- response_hash[deserialize_response_hash(response_hash)].each do |object_json|
45
- block.call Lib::TypedJsonDeserializer.new(object_json).deserialize
40
+ response_hash = if !scroll_param
41
+ @client.get(@scroll_url, '')
42
+ else
43
+ @client.get(@scroll_url, scroll_param: scroll_param)
44
+ end
45
+ raise Intercom::HttpError, 'Http Error - No response entity returned' unless response_hash
46
+
47
+ top_level_entity_key = entity_key_from_response(response_hash)
48
+ response_hash[top_level_entity_key].each do |object_json|
49
+ block.call Lib::TypedJsonDeserializer.new(object_json, @client).deserialize
46
50
  end
47
51
  scroll_param = extract_scroll_param(response_hash)
48
- break if not records_present?(response_hash)
52
+ break unless records_present?(response_hash)
49
53
  end
50
54
  self
51
55
  end
52
56
 
53
- def [](target_index)
54
- self.each_with_index do |item, index|
55
- return item if index == target_index
56
- end
57
- nil
58
- end
59
-
60
- include Enumerable
61
-
62
57
  private
63
58
 
64
- def deserialize_response_hash(response_hash)
65
- top_level_type = response_hash.delete('type')
59
+ def entity_key_from_response(response_hash)
60
+ top_level_type = response_hash['type']
66
61
  if resource_name == 'subscriptions'
67
- top_level_entity_key = 'items'
62
+ 'items'
68
63
  else
69
- top_level_entity_key = Utils.entity_key_from_type(top_level_type)
64
+ Utils.entity_key_from_type(top_level_type)
70
65
  end
71
66
  end
72
67
 
73
68
  def records_present?(response_hash)
74
- (response_hash[@resource_name].length > 0)
69
+ !response_hash[entity_key_from_response(response_hash)].empty?
75
70
  end
76
71
 
77
72
  def extract_scroll_param(response_hash)
78
73
  return nil unless records_present?(response_hash)
74
+
79
75
  response_hash['scroll_param']
80
76
  end
81
77
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'intercom/utils'
4
+ require 'intercom/base_collection_proxy'
5
+
6
+ module Intercom
7
+ class SearchCollectionProxy < BaseCollectionProxy
8
+ def initialize(resource_name, resource_class, details: {}, client:)
9
+ super(resource_name, resource_class, details: details, client: client, method: 'post')
10
+ end
11
+
12
+ private
13
+
14
+ def payload
15
+ payload = {
16
+ query: @params[:query]
17
+ }
18
+ if sort_field || sort_order
19
+ payload[:sort] = {}
20
+ payload[:sort][:field] = sort_field if sort_field
21
+ payload[:sort][:order] = sort_order if sort_order
22
+ end
23
+ if per_page || starting_after
24
+ payload[:pagination] = {}
25
+ payload[:pagination][:per_page] = per_page if per_page
26
+ payload[:pagination][:starting_after] = starting_after if starting_after
27
+ end
28
+ payload
29
+ end
30
+
31
+ def sort_field
32
+ @params[:sort_field]
33
+ end
34
+
35
+ def sort_order
36
+ @params[:sort_order]
37
+ end
38
+
39
+ def per_page
40
+ @params[:per_page]
41
+ end
42
+
43
+ def starting_after
44
+ @params[:starting_after]
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,23 @@
1
+ require 'intercom/api_operations/list'
2
+ require 'intercom/api_operations/find'
3
+ require 'intercom/api_operations/save'
4
+ require 'intercom/api_operations/delete'
5
+
6
+ module Intercom
7
+ module Service
8
+ class Section < BaseService
9
+ include ApiOperations::List
10
+ include ApiOperations::Find
11
+ include ApiOperations::Save
12
+ include ApiOperations::Delete
13
+
14
+ def collection_class
15
+ Intercom::Section
16
+ end
17
+
18
+ def collection_name
19
+ 'help_center/sections'
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,5 +3,9 @@ require 'intercom/traits/api_resource'
3
3
  module Intercom
4
4
  class Segment
5
5
  include Traits::ApiResource
6
+
7
+ def self.collection_proxy_class
8
+ Intercom::BaseCollectionProxy
9
+ end
6
10
  end
7
11
  end
@@ -0,0 +1,20 @@
1
+ require 'intercom/service/base_service'
2
+ require 'intercom/api_operations/find'
3
+ require 'intercom/api_operations/list'
4
+ require 'intercom/api_operations/delete'
5
+ require 'intercom/api_operations/save'
6
+
7
+ module Intercom
8
+ module Service
9
+ class Article < BaseService
10
+ include ApiOperations::Find
11
+ include ApiOperations::List
12
+ include ApiOperations::Delete
13
+ include ApiOperations::Save
14
+
15
+ def collection_class
16
+ Intercom::Article
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'intercom/client_collection_proxy'
4
+
1
5
  module Intercom
2
6
  module Service
3
7
  class BaseService
@@ -11,8 +15,17 @@ module Intercom
11
15
  raise NotImplementedError
12
16
  end
13
17
 
18
+ def collection_proxy_class
19
+ Intercom::ClientCollectionProxy
20
+ end
21
+
22
+ def collection_name
23
+ @collection_name ||= Utils.resource_class_to_collection_name(collection_class)
24
+ end
25
+
14
26
  def from_api(api_response)
15
27
  object = collection_class.new
28
+ object.client = @client
16
29
  object.from_response(api_response)
17
30
  object
18
31
  end
@@ -0,0 +1,24 @@
1
+ require 'intercom/service/base_service'
2
+ require 'intercom/api_operations/list'
3
+ require 'intercom/api_operations/find'
4
+ require 'intercom/api_operations/delete'
5
+ require 'intercom/api_operations/save'
6
+
7
+ module Intercom
8
+ module Service
9
+ class Collection < BaseService
10
+ include ApiOperations::List
11
+ include ApiOperations::Find
12
+ include ApiOperations::Delete
13
+ include ApiOperations::Save
14
+
15
+ def collection_class
16
+ Intercom::Collection
17
+ end
18
+
19
+ def collection_name
20
+ "help_center/collections"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,22 +1,24 @@
1
1
  require 'intercom/service/base_service'
2
+ require 'intercom/api_operations/delete'
2
3
  require 'intercom/api_operations/list'
4
+ require 'intercom/api_operations/scroll'
3
5
  require 'intercom/api_operations/find'
4
6
  require 'intercom/api_operations/find_all'
5
7
  require 'intercom/api_operations/save'
6
8
  require 'intercom/api_operations/load'
7
- require 'intercom/extended_api_operations/users'
8
9
  require 'intercom/extended_api_operations/tags'
9
10
  require 'intercom/extended_api_operations/segments'
10
11
 
11
12
  module Intercom
12
13
  module Service
13
14
  class Company < BaseService
15
+ include ApiOperations::Delete
14
16
  include ApiOperations::Find
15
17
  include ApiOperations::FindAll
16
18
  include ApiOperations::Load
17
19
  include ApiOperations::List
20
+ include ApiOperations::Scroll
18
21
  include ApiOperations::Save
19
- include ExtendedApiOperations::Users
20
22
  include ExtendedApiOperations::Tags
21
23
  include ExtendedApiOperations::Segments
22
24
 
@@ -2,11 +2,9 @@ require 'intercom/service/base_service'
2
2
  require 'intercom/api_operations/load'
3
3
  require 'intercom/api_operations/list'
4
4
  require 'intercom/api_operations/find'
5
- require 'intercom/api_operations/find_all'
6
5
  require 'intercom/api_operations/save'
7
- require 'intercom/api_operations/scroll'
8
- require 'intercom/api_operations/convert'
9
6
  require 'intercom/api_operations/delete'
7
+ require 'intercom/api_operations/search'
10
8
 
11
9
  module Intercom
12
10
  module Service
@@ -14,15 +12,40 @@ module Intercom
14
12
  include ApiOperations::Load
15
13
  include ApiOperations::List
16
14
  include ApiOperations::Find
17
- include ApiOperations::FindAll
18
15
  include ApiOperations::Save
19
- include ApiOperations::Scroll
20
- include ApiOperations::Convert
21
16
  include ApiOperations::Delete
17
+ include ApiOperations::Search
22
18
 
23
19
  def collection_class
24
20
  Intercom::Contact
25
21
  end
22
+
23
+ def collection_proxy_class
24
+ Intercom::BaseCollectionProxy
25
+ end
26
+
27
+ def merge(lead, user)
28
+ raise_invalid_merge_error unless lead.role == 'lead' && user.role == 'user'
29
+
30
+ response = @client.post('/contacts/merge', from: lead.id, into: user.id)
31
+ raise Intercom::HttpError, 'Http Error - No response entity returned' unless response
32
+
33
+ user.from_response(response)
34
+ end
35
+
36
+ def archive(contact)
37
+ @client.post("/#{collection_name}/#{contact.id}/archive", {})
38
+ contact
39
+ end
40
+
41
+ def unarchive(contact)
42
+ @client.post("/#{collection_name}/#{contact.id}/unarchive", {})
43
+ contact
44
+ end
45
+
46
+ private def raise_invalid_merge_error
47
+ raise Intercom::InvalidMergeError, 'Merging can only be performed on a lead into a user'
48
+ end
26
49
  end
27
50
  end
28
51
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'intercom/service/base_service'
2
4
  require 'intercom/api_operations/find_all'
3
5
  require 'intercom/api_operations/find'
@@ -9,9 +11,11 @@ module Intercom
9
11
  module Service
10
12
  class Conversation < BaseService
11
13
  include ApiOperations::FindAll
14
+ include ApiOperations::List
12
15
  include ApiOperations::Find
13
16
  include ApiOperations::Load
14
17
  include ApiOperations::Save
18
+ include ApiOperations::Search
15
19
 
16
20
  def collection_class
17
21
  Intercom::Conversation
@@ -24,7 +28,13 @@ module Intercom
24
28
  def reply(reply_data)
25
29
  id = reply_data.delete(:id)
26
30
  collection_name = Utils.resource_class_to_collection_name(collection_class)
27
- response = @client.post("/#{collection_name}/#{id}/reply", reply_data.merge(:conversation_id => id))
31
+ response = @client.post("/#{collection_name}/#{id}/reply", reply_data.merge(conversation_id: id))
32
+ collection_class.new.from_response(response)
33
+ end
34
+
35
+ def reply_to_last(reply_data)
36
+ collection_name = Utils.resource_class_to_collection_name(collection_class)
37
+ response = @client.post("/#{collection_name}/last/reply", reply_data)
28
38
  collection_class.new.from_response(response)
29
39
  end
30
40
 
@@ -36,10 +46,21 @@ module Intercom
36
46
  reply reply_data.merge(message_type: 'close', type: 'admin')
37
47
  end
38
48
 
49
+ def snooze(reply_data)
50
+ reply_data.fetch(:snoozed_until) { raise 'snoozed_until field is required' }
51
+ reply reply_data.merge(message_type: 'snoozed', type: 'admin')
52
+ end
53
+
39
54
  def assign(reply_data)
40
- assignee_id = reply_data.fetch(:assignee_id) { fail 'assignee_id is required' }
55
+ assignee_id = reply_data.fetch(:assignee_id) { raise 'assignee_id is required' }
41
56
  reply reply_data.merge(message_type: 'assignment', assignee_id: assignee_id, type: 'admin')
42
57
  end
58
+
59
+ def run_assignment_rules(id)
60
+ collection_name = Utils.resource_class_to_collection_name(collection_class)
61
+ response = @client.post("/#{collection_name}/#{id}/run_assignment_rules", {})
62
+ collection_class.new.from_response(response)
63
+ end
43
64
  end
44
65
  end
45
66
  end
@@ -0,0 +1,20 @@
1
+ require 'intercom/service/base_service'
2
+ require 'intercom/api_operations/load'
3
+ require 'intercom/api_operations/list'
4
+ require 'intercom/api_operations/find_all'
5
+ require 'intercom/api_operations/save'
6
+
7
+ module Intercom
8
+ module Service
9
+ class DataAttribute < BaseService
10
+ include ApiOperations::Load
11
+ include ApiOperations::List
12
+ include ApiOperations::FindAll
13
+ include ApiOperations::Save
14
+
15
+ def collection_class
16
+ Intercom::DataAttribute
17
+ end
18
+ end
19
+ end
20
+ 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