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.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +13 -0
  5. data/MIT-LICENSE +21 -0
  6. data/README.md +378 -0
  7. data/Rakefile +21 -0
  8. data/changes.txt +168 -0
  9. data/intercom.gemspec +28 -0
  10. data/lib/data/cacert.pem +3965 -0
  11. data/lib/ext/sliceable_hash.rb +16 -0
  12. data/lib/intercom.rb +176 -0
  13. data/lib/intercom/admin.rb +9 -0
  14. data/lib/intercom/api_operations/convert.rb +19 -0
  15. data/lib/intercom/api_operations/count.rb +16 -0
  16. data/lib/intercom/api_operations/delete.rb +15 -0
  17. data/lib/intercom/api_operations/find.rb +23 -0
  18. data/lib/intercom/api_operations/find_all.rb +33 -0
  19. data/lib/intercom/api_operations/list.rb +17 -0
  20. data/lib/intercom/api_operations/load.rb +16 -0
  21. data/lib/intercom/api_operations/save.rb +51 -0
  22. data/lib/intercom/collection_proxy.rb +71 -0
  23. data/lib/intercom/company.rb +29 -0
  24. data/lib/intercom/contact.rb +22 -0
  25. data/lib/intercom/conversation.rb +17 -0
  26. data/lib/intercom/count.rb +21 -0
  27. data/lib/intercom/errors.rb +61 -0
  28. data/lib/intercom/event.rb +11 -0
  29. data/lib/intercom/extended_api_operations/reply.rb +16 -0
  30. data/lib/intercom/extended_api_operations/tags.rb +14 -0
  31. data/lib/intercom/extended_api_operations/users.rb +17 -0
  32. data/lib/intercom/generic_handlers/base_handler.rb +22 -0
  33. data/lib/intercom/generic_handlers/count.rb +59 -0
  34. data/lib/intercom/generic_handlers/tag.rb +71 -0
  35. data/lib/intercom/generic_handlers/tag_find_all.rb +47 -0
  36. data/lib/intercom/lib/dynamic_accessors.rb +59 -0
  37. data/lib/intercom/lib/dynamic_accessors_on_method_missing.rb +53 -0
  38. data/lib/intercom/lib/flat_store.rb +31 -0
  39. data/lib/intercom/lib/typed_json_deserializer.rb +53 -0
  40. data/lib/intercom/message.rb +9 -0
  41. data/lib/intercom/note.rb +17 -0
  42. data/lib/intercom/notification.rb +20 -0
  43. data/lib/intercom/request.rb +166 -0
  44. data/lib/intercom/segment.rb +14 -0
  45. data/lib/intercom/subscription.rb +15 -0
  46. data/lib/intercom/tag.rb +23 -0
  47. data/lib/intercom/traits/api_resource.rb +132 -0
  48. data/lib/intercom/traits/dirty_tracking.rb +33 -0
  49. data/lib/intercom/traits/generic_handler_binding.rb +29 -0
  50. data/lib/intercom/traits/incrementable_attributes.rb +12 -0
  51. data/lib/intercom/user.rb +30 -0
  52. data/lib/intercom/utils.rb +62 -0
  53. data/lib/intercom/version.rb +3 -0
  54. data/spec/spec_helper.rb +308 -0
  55. data/spec/unit/intercom/admin_spec.rb +9 -0
  56. data/spec/unit/intercom/collection_proxy_spec.rb +34 -0
  57. data/spec/unit/intercom/company_spec.rb +23 -0
  58. data/spec/unit/intercom/contact_spec.rb +25 -0
  59. data/spec/unit/intercom/event_spec.rb +25 -0
  60. data/spec/unit/intercom/lib/flat_store_spec.rb +29 -0
  61. data/spec/unit/intercom/message_spec.rb +21 -0
  62. data/spec/unit/intercom/note_spec.rb +19 -0
  63. data/spec/unit/intercom/notification_spec.rb +68 -0
  64. data/spec/unit/intercom/request_spec.rb +16 -0
  65. data/spec/unit/intercom/subscription_spec.rb +18 -0
  66. data/spec/unit/intercom/tag_spec.rb +23 -0
  67. data/spec/unit/intercom/traits/api_resource_spec.rb +85 -0
  68. data/spec/unit/intercom/user_spec.rb +230 -0
  69. data/spec/unit/intercom_spec.rb +90 -0
  70. 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,9 @@
1
+ require 'intercom/api_operations/list'
2
+ require 'intercom/traits/api_resource'
3
+
4
+ module Intercom
5
+ class Admin
6
+ include ApiOperations::List
7
+ include Traits::ApiResource
8
+ end
9
+ 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