cogniteev-intercom 2.5.4
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 +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +6 -0
- data/Gemfile +13 -0
- data/MIT-LICENSE +21 -0
- data/README.md +378 -0
- data/Rakefile +21 -0
- data/changes.txt +168 -0
- data/intercom.gemspec +28 -0
- data/lib/data/cacert.pem +3965 -0
- data/lib/ext/sliceable_hash.rb +16 -0
- data/lib/intercom.rb +176 -0
- data/lib/intercom/admin.rb +9 -0
- data/lib/intercom/api_operations/convert.rb +19 -0
- data/lib/intercom/api_operations/count.rb +16 -0
- data/lib/intercom/api_operations/delete.rb +15 -0
- data/lib/intercom/api_operations/find.rb +23 -0
- data/lib/intercom/api_operations/find_all.rb +33 -0
- data/lib/intercom/api_operations/list.rb +17 -0
- data/lib/intercom/api_operations/load.rb +16 -0
- data/lib/intercom/api_operations/save.rb +51 -0
- data/lib/intercom/collection_proxy.rb +71 -0
- data/lib/intercom/company.rb +29 -0
- data/lib/intercom/contact.rb +22 -0
- data/lib/intercom/conversation.rb +17 -0
- data/lib/intercom/count.rb +21 -0
- data/lib/intercom/errors.rb +61 -0
- data/lib/intercom/event.rb +11 -0
- data/lib/intercom/extended_api_operations/reply.rb +16 -0
- data/lib/intercom/extended_api_operations/tags.rb +14 -0
- data/lib/intercom/extended_api_operations/users.rb +17 -0
- data/lib/intercom/generic_handlers/base_handler.rb +22 -0
- data/lib/intercom/generic_handlers/count.rb +59 -0
- data/lib/intercom/generic_handlers/tag.rb +71 -0
- data/lib/intercom/generic_handlers/tag_find_all.rb +47 -0
- data/lib/intercom/lib/dynamic_accessors.rb +59 -0
- data/lib/intercom/lib/dynamic_accessors_on_method_missing.rb +53 -0
- data/lib/intercom/lib/flat_store.rb +31 -0
- data/lib/intercom/lib/typed_json_deserializer.rb +53 -0
- data/lib/intercom/message.rb +9 -0
- data/lib/intercom/note.rb +17 -0
- data/lib/intercom/notification.rb +20 -0
- data/lib/intercom/request.rb +166 -0
- data/lib/intercom/segment.rb +14 -0
- data/lib/intercom/subscription.rb +15 -0
- data/lib/intercom/tag.rb +23 -0
- data/lib/intercom/traits/api_resource.rb +132 -0
- data/lib/intercom/traits/dirty_tracking.rb +33 -0
- data/lib/intercom/traits/generic_handler_binding.rb +29 -0
- data/lib/intercom/traits/incrementable_attributes.rb +12 -0
- data/lib/intercom/user.rb +30 -0
- data/lib/intercom/utils.rb +62 -0
- data/lib/intercom/version.rb +3 -0
- data/spec/spec_helper.rb +308 -0
- data/spec/unit/intercom/admin_spec.rb +9 -0
- data/spec/unit/intercom/collection_proxy_spec.rb +34 -0
- data/spec/unit/intercom/company_spec.rb +23 -0
- data/spec/unit/intercom/contact_spec.rb +25 -0
- data/spec/unit/intercom/event_spec.rb +25 -0
- data/spec/unit/intercom/lib/flat_store_spec.rb +29 -0
- data/spec/unit/intercom/message_spec.rb +21 -0
- data/spec/unit/intercom/note_spec.rb +19 -0
- data/spec/unit/intercom/notification_spec.rb +68 -0
- data/spec/unit/intercom/request_spec.rb +16 -0
- data/spec/unit/intercom/subscription_spec.rb +18 -0
- data/spec/unit/intercom/tag_spec.rb +23 -0
- data/spec/unit/intercom/traits/api_resource_spec.rb +85 -0
- data/spec/unit/intercom/user_spec.rb +230 -0
- data/spec/unit/intercom_spec.rb +90 -0
- metadata +214 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
class SliceableHash
|
2
|
+
|
3
|
+
def initialize(hash)
|
4
|
+
@hash = hash
|
5
|
+
end
|
6
|
+
|
7
|
+
# Return a hash that includes only the given keys.
|
8
|
+
def slice(*keys)
|
9
|
+
keys.map! { |key| @hash.convert_key(key) } if @hash.respond_to?(:convert_key, true)
|
10
|
+
keys.each_with_object(@hash.class.new) { |k, hash| hash[k] = @hash[k] if @hash.has_key?(k) && if_string_not_empty(@hash[k]) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def if_string_not_empty(val)
|
14
|
+
val.kind_of?(String) ? !val.empty? : true
|
15
|
+
end
|
16
|
+
end
|
data/lib/intercom.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
require "intercom/version"
|
2
|
+
require "intercom/contact"
|
3
|
+
require "intercom/user"
|
4
|
+
require "intercom/company"
|
5
|
+
require "intercom/note"
|
6
|
+
require "intercom/tag"
|
7
|
+
require "intercom/segment"
|
8
|
+
require "intercom/event"
|
9
|
+
require "intercom/conversation"
|
10
|
+
require "intercom/message"
|
11
|
+
require "intercom/admin"
|
12
|
+
require "intercom/count"
|
13
|
+
require "intercom/request"
|
14
|
+
require "intercom/subscription"
|
15
|
+
require "intercom/notification"
|
16
|
+
require "intercom/utils"
|
17
|
+
require "intercom/errors"
|
18
|
+
require "json"
|
19
|
+
|
20
|
+
##
|
21
|
+
# Intercom is a customer relationship management and messaging tool for web app owners
|
22
|
+
#
|
23
|
+
# This library provides ruby bindings for the Intercom API (https://api.intercom.io)
|
24
|
+
#
|
25
|
+
# == Basic Usage
|
26
|
+
# === Configure Intercom with your access credentials
|
27
|
+
# Intercom.app_id = "my_app_id"
|
28
|
+
# Intercom.app_api_key = "my_api_key"
|
29
|
+
# === Make requests to the API
|
30
|
+
# Intercom::User.find(:email => "bob@example.com")
|
31
|
+
#
|
32
|
+
module Intercom
|
33
|
+
@hostname = "api.intercom.io"
|
34
|
+
@protocol = "https"
|
35
|
+
|
36
|
+
@endpoints = nil
|
37
|
+
@current_endpoint = nil
|
38
|
+
@app_id = nil
|
39
|
+
@app_api_key = nil
|
40
|
+
@rate_limit_details = {}
|
41
|
+
|
42
|
+
def self.app_id=(app_id)
|
43
|
+
@app_id = app_id
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.app_id
|
47
|
+
@app_id
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.app_api_key=(app_api_key)
|
51
|
+
@app_api_key = app_api_key
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.app_api_key
|
55
|
+
@app_api_key
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.rate_limit_details=(rate_limit_details)
|
59
|
+
@rate_limit_details = rate_limit_details
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.rate_limit_details
|
63
|
+
@rate_limit_details
|
64
|
+
end
|
65
|
+
|
66
|
+
# This method is obsolete and used to warn of backwards incompatible changes on upgrading
|
67
|
+
def self.api_key=(val)
|
68
|
+
raise ArgumentError, "#{compatibility_warning_text} #{compatibility_workaround_text} #{related_docs_text}"
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def self.target_base_url
|
74
|
+
raise ArgumentError, "#{configuration_required_text} #{related_docs_text}" if [@app_id, @app_api_key].any?(&:nil?)
|
75
|
+
basic_auth_part = "#{@app_id}:#{@app_api_key}@"
|
76
|
+
current_endpoint.gsub(/(https?:\/\/)(.*)/, "\\1#{basic_auth_part}\\2")
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.related_docs_text
|
80
|
+
"See https://github.com/intercom/intercom-ruby for usage examples."
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.compatibility_warning_text
|
84
|
+
"It looks like you are upgrading from an older version of the intercom-ruby gem. Please note that this new version (#{Intercom::VERSION}) is not backwards compatible. "
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.compatibility_workaround_text
|
88
|
+
"To get rid of this error please set Intercom.app_api_key and don't set Intercom.api_key."
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.configuration_required_text
|
92
|
+
"You must set both Intercom.app_id and Intercom.app_api_key to use this client."
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.send_request_to_path(request)
|
96
|
+
request.execute(target_base_url)
|
97
|
+
rescue Intercom::ServiceUnavailableError => e
|
98
|
+
if endpoints.length > 1
|
99
|
+
retry_on_alternative_endpoint(request)
|
100
|
+
else
|
101
|
+
raise e
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.retry_on_alternative_endpoint(request)
|
106
|
+
@current_endpoint = alternative_random_endpoint
|
107
|
+
request.execute(target_base_url)
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.current_endpoint
|
111
|
+
return @current_endpoint if @current_endpoint && @endpoint_randomized_at > (Time.now - (60 * 5))
|
112
|
+
@endpoint_randomized_at = Time.now
|
113
|
+
@current_endpoint = random_endpoint
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.random_endpoint
|
117
|
+
endpoints.shuffle.first
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.alternative_random_endpoint
|
121
|
+
(endpoints.shuffle - [@current_endpoint]).first
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.post(path, payload_hash)
|
125
|
+
send_request_to_path(Intercom::Request.post(path, payload_hash))
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.delete(path, payload_hash)
|
129
|
+
send_request_to_path(Intercom::Request.delete(path, payload_hash))
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.put(path, payload_hash)
|
133
|
+
send_request_to_path(Intercom::Request.put(path, payload_hash))
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.get(path, params)
|
137
|
+
send_request_to_path(Intercom::Request.get(path, params))
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.check_required_params(params, path=nil) #nodoc
|
141
|
+
return if path.eql?("users")
|
142
|
+
raise ArgumentError.new("Expected params Hash, got #{params.class}") unless params.is_a?(Hash)
|
143
|
+
raise ArgumentError.new("Either email or user_id must be specified") unless params.keys.any? { |key| %W(email user_id).include?(key.to_s) }
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.protocol #nodoc
|
147
|
+
@protocol
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.protocol=(override) #nodoc
|
151
|
+
@protocol = override
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.hostname #nodoc
|
155
|
+
@hostname
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.hostname=(override) #nodoc
|
159
|
+
@hostname = override
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.endpoint=(endpoint) #nodoc
|
163
|
+
self.endpoints = [endpoint]
|
164
|
+
@current_endpoint = nil
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.endpoints=(endpoints) #nodoc
|
168
|
+
@endpoints = endpoints
|
169
|
+
@current_endpoint = nil
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.endpoints
|
173
|
+
@endpoints || ["#{@protocol}://#{hostname}"]
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'intercom/traits/api_resource'
|
2
|
+
|
3
|
+
module Intercom
|
4
|
+
module ApiOperations
|
5
|
+
module Convert
|
6
|
+
def convert(user)
|
7
|
+
from_response(
|
8
|
+
Intercom.post(
|
9
|
+
"/contacts/convert",
|
10
|
+
{
|
11
|
+
contact: { user_id: user_id },
|
12
|
+
user: user.identity_hash
|
13
|
+
}
|
14
|
+
)
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Intercom
|
2
|
+
module ApiOperations
|
3
|
+
module Count
|
4
|
+
module ClassMethods
|
5
|
+
def count
|
6
|
+
singular_resource_name = Utils.resource_class_to_singular_name(self)
|
7
|
+
Intercom::Count.send("#{singular_resource_name}_count")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
base.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'intercom/traits/api_resource'
|
2
|
+
|
3
|
+
module Intercom
|
4
|
+
module ApiOperations
|
5
|
+
module Delete
|
6
|
+
|
7
|
+
def delete
|
8
|
+
collection_name = Utils.resource_class_to_collection_name(self.class)
|
9
|
+
Intercom.delete("/#{collection_name}/#{id}", {})
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Intercom
|
2
|
+
module ApiOperations
|
3
|
+
module Find
|
4
|
+
module ClassMethods
|
5
|
+
def find(params)
|
6
|
+
raise BadRequestError, "#{self}#find takes a hash as its parameter but you supplied #{params.inspect}" unless params.is_a? Hash
|
7
|
+
collection_name = Utils.resource_class_to_collection_name(self)
|
8
|
+
if params[:id]
|
9
|
+
response = Intercom.get("/#{collection_name}/#{params[:id]}", {})
|
10
|
+
else
|
11
|
+
response = Intercom.get("/#{collection_name}", params)
|
12
|
+
end
|
13
|
+
raise Intercom::HttpError.new('Http Error - No response entity returned') unless response
|
14
|
+
from_api(response)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
base.extend(ClassMethods)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'intercom/collection_proxy'
|
2
|
+
|
3
|
+
module Intercom
|
4
|
+
module ApiOperations
|
5
|
+
module FindAll
|
6
|
+
module ClassMethods
|
7
|
+
def find_all(params)
|
8
|
+
raise BadRequestError, "#{self}#find takes a hash as its parameter but you supplied #{params.inspect}" unless params.is_a? Hash
|
9
|
+
collection_name = Utils.resource_class_to_collection_name(self)
|
10
|
+
finder_details = {}
|
11
|
+
if params[:id] && !type_switched_finder?(params)
|
12
|
+
finder_details[:url] = "/#{collection_name}/#{params[:id]}"
|
13
|
+
finder_details[:params] = {}
|
14
|
+
else
|
15
|
+
finder_details[:url] = "/#{collection_name}"
|
16
|
+
finder_details[:params] = params
|
17
|
+
end
|
18
|
+
CollectionProxy.new(collection_name, finder_details)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def type_switched_finder?(params)
|
24
|
+
params.include?(:type)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.included(base)
|
29
|
+
base.extend(ClassMethods)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'intercom/collection_proxy'
|
2
|
+
|
3
|
+
module Intercom
|
4
|
+
module ApiOperations
|
5
|
+
module List # TODO: Should we rename to All
|
6
|
+
module ClassMethods
|
7
|
+
def all
|
8
|
+
CollectionProxy.new(Utils.resource_class_to_collection_name(self))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
base.extend(ClassMethods)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Intercom
|
2
|
+
module ApiOperations
|
3
|
+
module Load
|
4
|
+
def load
|
5
|
+
collection_name = Utils.resource_class_to_collection_name(self.class)
|
6
|
+
if id
|
7
|
+
response = Intercom.get("/#{collection_name}/#{id}", {})
|
8
|
+
else
|
9
|
+
raise "Cannot load #{self.class} as it does not have a valid id."
|
10
|
+
end
|
11
|
+
raise Intercom::HttpError.new('Http Error - No response entity returned') unless response
|
12
|
+
from_response(response)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'intercom/traits/api_resource'
|
2
|
+
|
3
|
+
module Intercom
|
4
|
+
module ApiOperations
|
5
|
+
module Save
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
PARAMS_NOT_PROVIDED = Object.new
|
9
|
+
def create(params = PARAMS_NOT_PROVIDED)
|
10
|
+
if self.ancestors.include?(Intercom::Contact) && params == PARAMS_NOT_PROVIDED
|
11
|
+
params = Hash.new
|
12
|
+
elsif params == PARAMS_NOT_PROVIDED
|
13
|
+
raise ArgumentError, '.create requires 1 parameter'
|
14
|
+
end
|
15
|
+
|
16
|
+
instance = self.new(params)
|
17
|
+
instance.mark_fields_as_changed!(params.keys)
|
18
|
+
instance.save
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(base)
|
23
|
+
base.extend(ClassMethods)
|
24
|
+
end
|
25
|
+
|
26
|
+
def save
|
27
|
+
collection_name = Utils.resource_class_to_collection_name(self.class)
|
28
|
+
if id_present? && !posted_updates?
|
29
|
+
response = Intercom.put("/#{collection_name}/#{id}", to_submittable_hash)
|
30
|
+
else
|
31
|
+
response = Intercom.post("/#{collection_name}", to_submittable_hash.merge(identity_hash))
|
32
|
+
end
|
33
|
+
from_response(response) if response # may be nil we received back a 202
|
34
|
+
end
|
35
|
+
|
36
|
+
def identity_hash
|
37
|
+
respond_to?(:identity_vars) ? SliceableHash.new(to_hash).slice(*(identity_vars.map(&:to_s))) : {}
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def id_present?
|
43
|
+
id && id.to_s != ''
|
44
|
+
end
|
45
|
+
|
46
|
+
def posted_updates?
|
47
|
+
respond_to?(:update_verb) && update_verb == 'post'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "intercom/utils"
|
2
|
+
require "ext/sliceable_hash"
|
3
|
+
|
4
|
+
module Intercom
|
5
|
+
class CollectionProxy
|
6
|
+
|
7
|
+
attr_reader :resource_name
|
8
|
+
|
9
|
+
def initialize(resource_name, finder_details = {})
|
10
|
+
@resource_name = resource_name
|
11
|
+
@resource_class = Utils.constantize_resource_name(resource_name)
|
12
|
+
@finder_url = (finder_details[:url] || "/#{@resource_name}")
|
13
|
+
@finder_params = (finder_details[:params] || {})
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(&block)
|
17
|
+
next_page = nil
|
18
|
+
loop do
|
19
|
+
if next_page
|
20
|
+
response_hash = Intercom.get(next_page, {})
|
21
|
+
else
|
22
|
+
response_hash = Intercom.get(@finder_url, @finder_params)
|
23
|
+
end
|
24
|
+
raise Intercom::HttpError.new('Http Error - No response entity returned') unless response_hash
|
25
|
+
deserialize_response_hash(response_hash, block)
|
26
|
+
next_page = extract_next_link(response_hash)
|
27
|
+
break if next_page.nil?
|
28
|
+
end
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def [](target_index)
|
33
|
+
self.each_with_index do |item, index|
|
34
|
+
return item if index == target_index
|
35
|
+
end
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
include Enumerable
|
40
|
+
|
41
|
+
def count
|
42
|
+
raise NoMethodError, "undefined method `count' for #{self.class}. Consider using the dedicated Intercom::Count interface if suitable"
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def resource_class; @resource_class; end
|
48
|
+
|
49
|
+
def deserialize_response_hash(response_hash, block)
|
50
|
+
top_level_type = response_hash.delete('type')
|
51
|
+
if resource_name == 'subscriptions'
|
52
|
+
top_level_entity_key = 'items'
|
53
|
+
else
|
54
|
+
top_level_entity_key = Utils.entity_key_from_type(top_level_type)
|
55
|
+
end
|
56
|
+
response_hash[top_level_entity_key].each do |object_json|
|
57
|
+
block.call Lib::TypedJsonDeserializer.new(object_json).deserialize
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def paging_info_present?(response_hash)
|
62
|
+
!!(response_hash['pages'] && response_hash['pages']['type'])
|
63
|
+
end
|
64
|
+
|
65
|
+
def extract_next_link(response_hash)
|
66
|
+
return nil unless paging_info_present?(response_hash)
|
67
|
+
paging_info = response_hash.delete('pages')
|
68
|
+
paging_info["next"]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|