intercom 3.9.5 → 4.0.0

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 (81) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +235 -222
  3. data/Rakefile +1 -1
  4. data/changes.txt +3 -0
  5. data/lib/intercom.rb +27 -22
  6. data/lib/intercom/api_operations/archive.rb +2 -1
  7. data/lib/intercom/api_operations/delete.rb +16 -0
  8. data/lib/intercom/api_operations/find.rb +5 -2
  9. data/lib/intercom/api_operations/find_all.rb +4 -3
  10. data/lib/intercom/api_operations/list.rb +4 -1
  11. data/lib/intercom/api_operations/load.rb +4 -2
  12. data/lib/intercom/api_operations/nested_resource.rb +70 -0
  13. data/lib/intercom/api_operations/save.rb +5 -4
  14. data/lib/intercom/api_operations/scroll.rb +4 -5
  15. data/lib/intercom/api_operations/search.rb +3 -2
  16. data/lib/intercom/base_collection_proxy.rb +72 -0
  17. data/lib/intercom/client.rb +20 -25
  18. data/lib/intercom/client_collection_proxy.rb +17 -39
  19. data/lib/intercom/company.rb +8 -0
  20. data/lib/intercom/contact.rb +21 -3
  21. data/lib/intercom/conversation.rb +4 -0
  22. data/lib/intercom/data_attribute.rb +7 -0
  23. data/lib/intercom/deprecated_leads_collection_proxy.rb +22 -0
  24. data/lib/intercom/deprecated_resources.rb +13 -0
  25. data/lib/intercom/errors.rb +3 -0
  26. data/lib/intercom/extended_api_operations/segments.rb +3 -1
  27. data/lib/intercom/extended_api_operations/tags.rb +3 -1
  28. data/lib/intercom/lead.rb +21 -0
  29. data/lib/intercom/lib/typed_json_deserializer.rb +42 -37
  30. data/lib/intercom/note.rb +4 -0
  31. data/lib/intercom/request.rb +37 -33
  32. data/lib/intercom/scroll_collection_proxy.rb +33 -38
  33. data/lib/intercom/search_collection_proxy.rb +30 -65
  34. data/lib/intercom/service/base_service.rb +7 -0
  35. data/lib/intercom/service/company.rb +0 -12
  36. data/lib/intercom/service/contact.rb +21 -10
  37. data/lib/intercom/service/conversation.rb +12 -3
  38. data/lib/intercom/service/data_attribute.rb +20 -0
  39. data/lib/intercom/service/lead.rb +41 -0
  40. data/lib/intercom/service/note.rb +4 -8
  41. data/lib/intercom/service/subscription.rb +2 -2
  42. data/lib/intercom/service/tag.rb +9 -9
  43. data/lib/intercom/service/visitor.rb +17 -8
  44. data/lib/intercom/tag.rb +4 -0
  45. data/lib/intercom/traits/api_resource.rb +28 -17
  46. data/lib/intercom/user.rb +12 -3
  47. data/lib/intercom/utils.rb +13 -2
  48. data/lib/intercom/version.rb +1 -1
  49. data/lib/intercom/visitor.rb +0 -2
  50. data/spec/spec_helper.rb +738 -513
  51. data/spec/unit/intercom/admin_spec.rb +2 -2
  52. data/spec/unit/intercom/base_collection_proxy_spec.rb +30 -0
  53. data/spec/unit/intercom/client_collection_proxy_spec.rb +41 -41
  54. data/spec/unit/intercom/client_spec.rb +25 -26
  55. data/spec/unit/intercom/company_spec.rb +13 -15
  56. data/spec/unit/intercom/contact_spec.rb +289 -33
  57. data/spec/unit/intercom/conversation_spec.rb +29 -7
  58. data/spec/unit/intercom/count_spec.rb +4 -4
  59. data/spec/unit/intercom/data_attribute_spec.rb +40 -0
  60. data/spec/unit/intercom/deprecated_leads_collection_proxy_spec.rb +17 -0
  61. data/spec/unit/intercom/event_spec.rb +9 -11
  62. data/spec/unit/intercom/job_spec.rb +24 -24
  63. data/spec/unit/intercom/lead_spec.rb +57 -0
  64. data/spec/unit/intercom/lib/flat_store_spec.rb +22 -20
  65. data/spec/unit/intercom/message_spec.rb +1 -1
  66. data/spec/unit/intercom/note_spec.rb +4 -10
  67. data/spec/unit/intercom/request_spec.rb +1 -1
  68. data/spec/unit/intercom/scroll_collection_proxy_spec.rb +40 -39
  69. data/spec/unit/intercom/search_collection_proxy_spec.rb +32 -28
  70. data/spec/unit/intercom/segment_spec.rb +2 -2
  71. data/spec/unit/intercom/subscription_spec.rb +5 -6
  72. data/spec/unit/intercom/tag_spec.rb +22 -14
  73. data/spec/unit/intercom/team_spec.rb +2 -2
  74. data/spec/unit/intercom/traits/api_resource_spec.rb +53 -51
  75. data/spec/unit/intercom/user_spec.rb +224 -226
  76. data/spec/unit/intercom/visitor_spec.rb +49 -0
  77. data/spec/unit/intercom_spec.rb +5 -3
  78. metadata +22 -7
  79. data/lib/intercom/customer.rb +0 -10
  80. data/lib/intercom/service/customer.rb +0 -14
  81. data/spec/unit/intercom/visitors_spec.rb +0 -61
data/Rakefile CHANGED
@@ -18,4 +18,4 @@ Rake::TestTask.new("spec:integration") do |spec|
18
18
  end
19
19
 
20
20
  task :spec => "spec:unit"
21
- task :default => :spec
21
+ task :default => :spec
@@ -1,3 +1,6 @@
1
+ 3.9.5
2
+ Add Unstable version support
3
+
1
4
  3.9.4
2
5
  Add handling for Gateway Timeouts
3
6
 
@@ -1,10 +1,11 @@
1
- require "intercom/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'intercom/version'
2
4
  require 'intercom/service/admin'
3
5
  require 'intercom/service/company'
4
6
  require 'intercom/service/contact'
5
7
  require 'intercom/service/conversation'
6
8
  require 'intercom/service/count'
7
- require 'intercom/service/customer'
8
9
  require 'intercom/service/event'
9
10
  require 'intercom/service/message'
10
11
  require 'intercom/service/note'
@@ -13,29 +14,33 @@ require 'intercom/service/subscription'
13
14
  require 'intercom/service/segment'
14
15
  require 'intercom/service/tag'
15
16
  require 'intercom/service/team'
16
- require 'intercom/service/user'
17
17
  require 'intercom/service/visitor'
18
+ require 'intercom/service/user'
19
+ require 'intercom/service/lead'
20
+ require 'intercom/deprecated_resources.rb'
18
21
  require 'intercom/options'
19
22
  require 'intercom/client'
20
- require "intercom/contact"
21
- require "intercom/count"
22
- require "intercom/customer"
23
- require "intercom/user"
24
- require "intercom/company"
25
- require "intercom/note"
26
- require "intercom/job"
27
- require "intercom/tag"
28
- require "intercom/segment"
29
- require "intercom/event"
30
- require "intercom/conversation"
31
- require "intercom/message"
32
- require "intercom/admin"
33
- require "intercom/request"
34
- require "intercom/subscription"
35
- require "intercom/team"
36
- require "intercom/errors"
37
- require "intercom/visitor"
38
- require "json"
23
+ require 'intercom/contact'
24
+ require 'intercom/user'
25
+ require 'intercom/lead'
26
+ require 'intercom/count'
27
+ require 'intercom/company'
28
+ require 'intercom/service/data_attribute'
29
+ require 'intercom/note'
30
+ require 'intercom/job'
31
+ require 'intercom/tag'
32
+ require 'intercom/segment'
33
+ require 'intercom/event'
34
+ require 'intercom/conversation'
35
+ require 'intercom/message'
36
+ require 'intercom/admin'
37
+ require 'intercom/request'
38
+ require 'intercom/subscription'
39
+ require 'intercom/team'
40
+ require 'intercom/errors'
41
+ require 'intercom/visitor'
42
+ require 'intercom/data_attribute'
43
+ require 'json'
39
44
 
40
45
  ##
41
46
  # Intercom is a customer relationship management and messaging tool for web app owners
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'intercom/utils'
2
4
 
3
5
  module Intercom
4
6
  module ApiOperations
5
7
  module Archive
6
8
  def archive(object)
7
- collection_name = Utils.resource_class_to_collection_name(collection_class)
8
9
  @client.delete("/#{collection_name}/#{object.id}", {})
9
10
  object
10
11
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'intercom/utils'
4
+
5
+ module Intercom
6
+ module ApiOperations
7
+ module Delete
8
+ def delete(object)
9
+ @client.delete("/#{collection_name}/#{object.id}", {})
10
+ object
11
+ end
12
+
13
+ alias_method 'archive', 'delete'
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'intercom/utils'
2
4
 
3
5
  module Intercom
@@ -5,14 +7,15 @@ module Intercom
5
7
  module Find
6
8
  def find(params)
7
9
  raise BadRequestError, "#{self}#find takes a hash as its parameter but you supplied #{params.inspect}" unless params.is_a? Hash
8
- collection_name = Utils.resource_class_to_collection_name(collection_class)
10
+
9
11
  if params[:id]
10
12
  id = params.delete(:id)
11
13
  response = @client.get("/#{collection_name}/#{id}", params)
12
14
  else
13
15
  response = @client.get("/#{collection_name}", params)
14
16
  end
15
- raise Intercom::HttpError.new('Http Error - No response entity returned') unless response
17
+ raise Intercom::HttpError, 'Http Error - No response entity returned' unless response
18
+
16
19
  from_api(response)
17
20
  end
18
21
  end
@@ -1,13 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'intercom/client_collection_proxy'
2
4
  require 'intercom/utils'
3
5
 
4
6
  module Intercom
5
7
  module ApiOperations
6
8
  module FindAll
7
-
8
9
  def find_all(params)
9
10
  raise BadRequestError, "#find takes a hash as its parameter but you supplied #{params.inspect}" unless params.is_a? Hash
10
- collection_name = Utils.resource_class_to_collection_name(collection_class)
11
+
11
12
  finder_details = {}
12
13
  if params[:id] && !type_switched_finder?(params)
13
14
  finder_details[:url] = "/#{collection_name}/#{params[:id]}"
@@ -16,7 +17,7 @@ module Intercom
16
17
  finder_details[:url] = "/#{collection_name}"
17
18
  finder_details[:params] = params
18
19
  end
19
- collection_proxy_class.new(collection_name, finder_details: finder_details, client: @client)
20
+ collection_proxy_class.new(collection_name, collection_class, details: finder_details, client: @client)
20
21
  end
21
22
 
22
23
  private
@@ -1,11 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'intercom/client_collection_proxy'
4
+ require 'intercom/base_collection_proxy'
2
5
  require 'intercom/utils'
3
6
 
4
7
  module Intercom
5
8
  module ApiOperations
6
9
  module List
7
10
  def all
8
- ClientCollectionProxy.new(Utils.resource_class_to_collection_name(collection_class), client: @client)
11
+ collection_proxy_class.new(collection_name, collection_class, client: @client)
9
12
  end
10
13
  end
11
14
  end
@@ -1,16 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'intercom/utils'
2
4
 
3
5
  module Intercom
4
6
  module ApiOperations
5
7
  module Load
6
8
  def load(object)
7
- collection_name = Utils.resource_class_to_collection_name(collection_class)
8
9
  if object.id
9
10
  response = @client.get("/#{collection_name}/#{object.id}", {})
10
11
  else
11
12
  raise "Cannot load #{collection_class} as it does not have a valid id."
12
13
  end
13
- raise Intercom::HttpError.new('Http Error - No response entity returned') unless response
14
+ raise Intercom::HttpError, 'Http Error - No response entity returned' unless response
15
+
14
16
  object.from_response(response)
15
17
  end
16
18
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intercom
4
+ module ApiOperations
5
+ module NestedResource
6
+ module ClassMethods
7
+ def nested_resource_methods(resource,
8
+ path: nil,
9
+ operations: nil,
10
+ resource_plural: nil)
11
+ resource_plural ||= Utils.pluralize(resource.to_s)
12
+ path ||= resource_plural
13
+ raise ArgumentError, 'operations array required' if operations.nil?
14
+
15
+ resource_url_method = :"#{resource_plural}_url"
16
+
17
+ resource_name = Utils.resource_class_to_collection_name(self)
18
+
19
+ define_method(resource_url_method.to_sym) do |id, nested_id = nil|
20
+ url = "/#{resource_name}/#{id}/#{path}"
21
+ url += "/#{nested_id}" unless nested_id.nil?
22
+ url
23
+ end
24
+
25
+ operations.each do |operation|
26
+ case operation
27
+ when :create
28
+ define_method(:"create_#{resource}") do |params|
29
+ url = send(resource_url_method, self.id)
30
+ response = client.post(url, params)
31
+ raise_no_response_error unless response
32
+ self.class.from_api(response)
33
+ end
34
+ when :add
35
+ define_method(:"add_#{resource}") do |params|
36
+ url = send(resource_url_method, self.id)
37
+ response = client.post(url, params)
38
+ raise_no_response_error unless response
39
+ self.class.from_api(response)
40
+ end
41
+ when :delete
42
+ define_method(:"remove_#{resource}") do |params|
43
+ url = send(resource_url_method, self.id, params[:id])
44
+ response = client.delete(url, params)
45
+ raise_no_response_error unless response
46
+ self.class.from_api(response)
47
+ end
48
+ when :list
49
+ define_method(resource_plural.to_sym) do
50
+ url = send(resource_url_method, self.id)
51
+ resource_class = Utils.constantize_resource_name(resource.to_s)
52
+ resource_class.collection_proxy_class.new(resource_plural, resource_class, details: { url: url }, client: client)
53
+ end
54
+ else
55
+ raise ArgumentError, "Unknown operation: #{operation.inspect}"
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ def self.included(base)
62
+ base.extend(ClassMethods)
63
+ end
64
+
65
+ private def raise_no_response_error
66
+ raise Intercom::HttpError, 'Http Error - No response entity returned'
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'intercom/utils'
2
4
  require 'ext/sliceable_hash'
3
5
 
@@ -8,8 +10,8 @@ module Intercom
8
10
  private_constant :PARAMS_NOT_PROVIDED
9
11
 
10
12
  def create(params = PARAMS_NOT_PROVIDED)
11
- if collection_class.ancestors.include?(Intercom::Contact) && params == PARAMS_NOT_PROVIDED
12
- params = Hash.new
13
+ if collection_class.ancestors.include?(Intercom::Lead) && params == PARAMS_NOT_PROVIDED
14
+ params = {}
13
15
  elsif params == PARAMS_NOT_PROVIDED
14
16
  raise ArgumentError, '.create requires 1 parameter'
15
17
  end
@@ -20,7 +22,6 @@ module Intercom
20
22
  end
21
23
 
22
24
  def save(object)
23
- collection_name = Utils.resource_class_to_collection_name(collection_class)
24
25
  if id_present?(object) && !posted_updates?(object)
25
26
  response = @client.put("/#{collection_name}/#{object.id}", object.to_submittable_hash)
26
27
  else
@@ -30,7 +31,7 @@ module Intercom
30
31
  end
31
32
 
32
33
  def identity_hash(object)
33
- object.respond_to?(:identity_vars) ? SliceableHash.new(object.to_hash).slice(*(object.identity_vars.map(&:to_s))) : {}
34
+ object.respond_to?(:identity_vars) ? SliceableHash.new(object.to_hash).slice(*object.identity_vars.map(&:to_s)) : {}
34
35
  end
35
36
 
36
37
  private
@@ -1,17 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'intercom/scroll_collection_proxy'
2
4
  require 'intercom/utils'
3
5
 
4
6
  module Intercom
5
7
  module ApiOperations
6
8
  module Scroll
7
-
8
- def scroll()
9
- collection_name = Utils.resource_class_to_collection_name(collection_class)
9
+ def scroll
10
10
  finder_details = {}
11
11
  finder_details[:url] = "/#{collection_name}"
12
- ScrollCollectionProxy.new(collection_name, finder_details: finder_details, client: @client)
12
+ ScrollCollectionProxy.new(collection_name, collection_class, details: finder_details, client: @client)
13
13
  end
14
-
15
14
  end
16
15
  end
17
16
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'intercom/search_collection_proxy'
2
4
  require 'intercom/utils'
3
5
 
@@ -5,12 +7,11 @@ module Intercom
5
7
  module ApiOperations
6
8
  module Search
7
9
  def search(params)
8
- collection_name = Utils.resource_class_to_collection_name(collection_class)
9
10
  search_details = {
10
11
  url: "/#{collection_name}/search",
11
12
  params: params
12
13
  }
13
- SearchCollectionProxy.new(collection_name, search_details: search_details, client: @client)
14
+ SearchCollectionProxy.new(collection_name, collection_class, details: search_details, client: @client)
14
15
  end
15
16
  end
16
17
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'intercom/utils'
4
+
5
+ module Intercom
6
+ class BaseCollectionProxy
7
+ attr_reader :resource_name, :url, :resource_class
8
+
9
+ def initialize(resource_name, resource_class, details: {}, client:, method: 'get')
10
+ @resource_name = resource_name
11
+ @resource_class = resource_class
12
+ @url = (details[:url] || "/#{@resource_name}")
13
+ @params = (details[:params] || {})
14
+ @client = client
15
+ @method = method
16
+ end
17
+
18
+ def each(&block)
19
+ loop do
20
+ response_hash = @client.public_send(@method, @url, payload)
21
+ raise Intercom::HttpError, 'Http Error - No response entity returned' unless response_hash
22
+
23
+ deserialize_response_hash(response_hash, block)
24
+ break unless has_next_link?(response_hash)
25
+ end
26
+ self
27
+ end
28
+
29
+ def [](target_index)
30
+ each_with_index do |item, index|
31
+ return item if index == target_index
32
+ end
33
+ nil
34
+ end
35
+
36
+ include Enumerable
37
+
38
+ private
39
+
40
+ def deserialize_response_hash(response_hash, block)
41
+ top_level_type = response_hash.delete('type')
42
+ top_level_entity_key = if resource_name == 'subscriptions'
43
+ 'items'
44
+ else
45
+ Utils.entity_key_from_type(top_level_type)
46
+ end
47
+ response_hash[top_level_entity_key].each do |object_json|
48
+ block.call Lib::TypedJsonDeserializer.new(object_json, @client).deserialize
49
+ end
50
+ end
51
+
52
+ def has_next_link?(response_hash)
53
+ paging_info = response_hash.delete('pages')
54
+ return false unless paging_info
55
+
56
+ paging_next = paging_info['next']
57
+ if paging_next
58
+ @params[:starting_after] = paging_next['starting_after']
59
+ return true
60
+ else
61
+ return false
62
+ end
63
+ end
64
+
65
+ def payload
66
+ payload = {}
67
+ payload[:per_page] = @params[:per_page] if @params[:per_page]
68
+ payload[:starting_after] = @params[:starting_after] if @params[:starting_after]
69
+ payload
70
+ end
71
+ end
72
+ end
@@ -1,38 +1,35 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Intercom
2
4
  class MisconfiguredClientError < StandardError; end
3
5
  class Client
4
6
  include Options
5
- attr_reader :base_url, :rate_limit_details, :username_part, :password_part, :handle_rate_limit, :timeouts, :api_version
7
+ include DeprecatedResources
8
+ attr_reader :base_url, :rate_limit_details, :token, :handle_rate_limit, :timeouts, :api_version
6
9
 
7
10
  class << self
8
11
  def set_base_url(base_url)
9
- return Proc.new do |o|
12
+ proc do |o|
10
13
  old_url = o.base_url
11
14
  o.send(:base_url=, base_url)
12
- Proc.new { |obj| set_base_url(old_url).call(o) }
15
+ proc { |_obj| set_base_url(old_url).call(o) }
13
16
  end
14
17
  end
15
18
 
16
19
  def set_timeouts(open_timeout: nil, read_timeout: nil)
17
- return Proc.new do |o|
20
+ proc do |o|
18
21
  old_timeouts = o.timeouts
19
22
  timeouts = {}
20
23
  timeouts[:open_timeout] = open_timeout if open_timeout
21
24
  timeouts[:read_timeout] = read_timeout if read_timeout
22
25
  o.send(:timeouts=, timeouts)
23
- Proc.new { |obj| set_timeouts(old_timeouts).call(o) }
26
+ proc { |_obj| set_timeouts(old_timeouts).call(o) }
24
27
  end
25
28
  end
26
29
  end
27
30
 
28
- def initialize(app_id: 'my_app_id', api_key: 'my_api_key', token: nil, base_url:'https://api.intercom.io', handle_rate_limit: false, api_version: nil)
29
- if token
30
- @username_part = token
31
- @password_part = ""
32
- else
33
- @username_part = app_id
34
- @password_part = api_key
35
- end
31
+ def initialize(token: nil, base_url: 'https://api.intercom.io', handle_rate_limit: false, api_version: nil)
32
+ @token = token
36
33
  validate_credentials!
37
34
 
38
35
  @api_version = api_version
@@ -67,10 +64,6 @@ module Intercom
67
64
  Intercom::Service::Counts.new(self)
68
65
  end
69
66
 
70
- def customers
71
- Intercom::Service::Customer.new(self)
72
- end
73
-
74
67
  def events
75
68
  Intercom::Service::Event.new(self)
76
69
  end
@@ -111,6 +104,10 @@ module Intercom
111
104
  Intercom::Service::Job.new(self)
112
105
  end
113
106
 
107
+ def data_attributes
108
+ Intercom::Service::DataAttribute.new(self)
109
+ end
110
+
114
111
  def get(path, params)
115
112
  execute_request Intercom::Request.get(path, params)
116
113
  end
@@ -130,25 +127,23 @@ module Intercom
130
127
  private
131
128
 
132
129
  def validate_credentials!
133
- error = MisconfiguredClientError.new("app_id and api_key must not be nil")
134
- fail error if @username_part.nil?
130
+ error = MisconfiguredClientError.new('an access token must be provided')
131
+ raise error if @token.nil?
135
132
  end
136
133
 
137
134
  def validate_api_version!
138
- error = MisconfiguredClientError.new("api_version must be either nil or a valid API version")
139
- fail error if (@api_version && @api_version != 'Unstable' && Gem::Version.new(@api_version) < Gem::Version.new('1.0'))
135
+ error = MisconfiguredClientError.new('api_version must be either nil or a valid API version')
136
+ raise error if @api_version && @api_version != 'Unstable' && Gem::Version.new(@api_version) < Gem::Version.new('1.0')
140
137
  end
141
138
 
142
139
  def execute_request(request)
143
140
  request.handle_rate_limit = handle_rate_limit
144
- request.execute(@base_url, username: @username_part, secret: @password_part, api_version: @api_version, **timeouts)
141
+ request.execute(@base_url, token: @token, api_version: @api_version, **timeouts)
145
142
  ensure
146
143
  @rate_limit_details = request.rate_limit_details
147
144
  end
148
145
 
149
- def base_url=(new_url)
150
- @base_url = new_url
151
- end
146
+ attr_writer :base_url
152
147
 
153
148
  def timeouts=(timeouts)
154
149
  @timeouts = @timeouts.merge(timeouts)