cogniteev-intercom 2.5.4
Sign up to get free protection for your applications and to get access to all the features.
- 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,53 @@
|
|
1
|
+
module Intercom
|
2
|
+
module Lib
|
3
|
+
class DynamicAccessorsOnMethodMissing
|
4
|
+
|
5
|
+
attr_reader :method_sym, :method_string, :arguments, :object, :klass
|
6
|
+
|
7
|
+
def initialize(method_sym, *arguments, object)
|
8
|
+
@method_sym = method_sym
|
9
|
+
@method_string = method_sym.to_s
|
10
|
+
@arguments = arguments
|
11
|
+
@klass = object.class
|
12
|
+
@object = object
|
13
|
+
end
|
14
|
+
|
15
|
+
def define_accessors_or_call(&block)
|
16
|
+
return yield if not_an_accessor?
|
17
|
+
if setter?
|
18
|
+
Lib::DynamicAccessors.define_accessors(attribute_name, *arguments, object)
|
19
|
+
object.send(method_sym, *arguments)
|
20
|
+
else # getter
|
21
|
+
if trying_to_access_private_variable?
|
22
|
+
yield
|
23
|
+
else
|
24
|
+
raise Intercom::AttributeNotSetError, attribute_not_set_error_message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def not_an_accessor?
|
32
|
+
(method_string.end_with? '?') || (method_string.end_with? '!') || arguments.length > 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def setter?
|
36
|
+
method_string.end_with? '='
|
37
|
+
end
|
38
|
+
|
39
|
+
def attribute_name
|
40
|
+
method_string.gsub(/=$/, '')
|
41
|
+
end
|
42
|
+
|
43
|
+
def trying_to_access_private_variable?
|
44
|
+
object.instance_variable_defined?("@#{method_string}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def attribute_not_set_error_message
|
48
|
+
"'#{method_string}' called on #{klass} but it has not been set an " +
|
49
|
+
"attribute or does not exist as a method"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Intercom
|
2
|
+
module Lib
|
3
|
+
|
4
|
+
# Sub-class of {Hash} for storing custom data attributes.
|
5
|
+
# Doesn't allow nested Hashes or Arrays. And requires {String} or {Symbol} keys.
|
6
|
+
class FlatStore < Hash
|
7
|
+
|
8
|
+
def initialize(attributes={})
|
9
|
+
(attributes).each do |key, value|
|
10
|
+
validate_key_and_value(key, value)
|
11
|
+
self[key] = value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def []=(key, value)
|
16
|
+
validate_key_and_value(key, value)
|
17
|
+
super(key.to_s, value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](key)
|
21
|
+
super(key.to_s)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def validate_key_and_value(key, value)
|
26
|
+
raise ArgumentError.new("This does not support nested data structures (key: #{key}, value: #{value}") if value.is_a?(Array) || value.is_a?(Hash)
|
27
|
+
raise ArgumentError.new("Key must be String or Symbol: #{key}") unless key.is_a?(String) || key.is_a?(Symbol)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Intercom
|
2
|
+
module Lib
|
3
|
+
|
4
|
+
# Responsibility: To decide whether we are deserializing a collection or an
|
5
|
+
# entity of a particular type and to dispatch deserialization
|
6
|
+
class TypedJsonDeserializer
|
7
|
+
attr_reader :json
|
8
|
+
|
9
|
+
def initialize(json)
|
10
|
+
@json = json
|
11
|
+
end
|
12
|
+
|
13
|
+
def deserialize
|
14
|
+
if blank_object_type?(object_type)
|
15
|
+
raise DeserializationError, "No type field was found to facilitate deserialization"
|
16
|
+
elsif list_object_type?(object_type)
|
17
|
+
deserialize_collection(json[object_entity_key])
|
18
|
+
else # singular object type
|
19
|
+
deserialize_object(json)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def blank_object_type?(object_type)
|
26
|
+
object_type.nil? || object_type == ''
|
27
|
+
end
|
28
|
+
|
29
|
+
def list_object_type?(object_type)
|
30
|
+
object_type.end_with?('.list')
|
31
|
+
end
|
32
|
+
|
33
|
+
def deserialize_collection(collection_json)
|
34
|
+
return [] if collection_json == nil
|
35
|
+
collection_json.map { |item_json| TypedJsonDeserializer.new(item_json).deserialize }
|
36
|
+
end
|
37
|
+
|
38
|
+
def deserialize_object(object_json)
|
39
|
+
entity_class = Utils.constantize_singular_resource_name(object_entity_key)
|
40
|
+
entity_class.from_api(object_json)
|
41
|
+
end
|
42
|
+
|
43
|
+
def object_type
|
44
|
+
@object_type ||= json['type']
|
45
|
+
end
|
46
|
+
|
47
|
+
def object_entity_key
|
48
|
+
@object_entity_key ||= Utils.entity_key_from_type(object_type)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'intercom/api_operations/save'
|
2
|
+
require 'intercom/api_operations/list'
|
3
|
+
require 'intercom/api_operations/find_all'
|
4
|
+
require 'intercom/api_operations/find'
|
5
|
+
require 'intercom/api_operations/load'
|
6
|
+
require 'intercom/traits/api_resource'
|
7
|
+
|
8
|
+
module Intercom
|
9
|
+
class Note
|
10
|
+
include ApiOperations::Save
|
11
|
+
include ApiOperations::List
|
12
|
+
include ApiOperations::FindAll
|
13
|
+
include ApiOperations::Find
|
14
|
+
include ApiOperations::Load
|
15
|
+
include Traits::ApiResource
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'net/https'
|
3
|
+
|
4
|
+
module Intercom
|
5
|
+
class Request
|
6
|
+
attr_accessor :path, :net_http_method
|
7
|
+
|
8
|
+
def initialize(path, net_http_method)
|
9
|
+
self.path = path
|
10
|
+
self.net_http_method = net_http_method
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_common_headers(method, base_uri)
|
14
|
+
method.basic_auth(CGI.unescape(base_uri.user), CGI.unescape(base_uri.password))
|
15
|
+
method.add_field('AcceptEncoding', 'gzip, deflate')
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.get(path, params)
|
19
|
+
new(path, Net::HTTP::Get.new(append_query_string_to_url(path, params), default_headers))
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.post(path, form_data)
|
23
|
+
new(path, method_with_body(Net::HTTP::Post, path, form_data))
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.delete(path, params)
|
27
|
+
new(path, method_with_body(Net::HTTP::Delete, path, params))
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.put(path, form_data)
|
31
|
+
new(path, method_with_body(Net::HTTP::Put, path, form_data))
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.method_with_body(http_method, path, params)
|
35
|
+
request = http_method.send(:new, path, default_headers)
|
36
|
+
request.body = params.to_json
|
37
|
+
request["Content-Type"] = "application/json"
|
38
|
+
request
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.default_headers
|
42
|
+
{'Accept-Encoding' => 'gzip, deflate', 'Accept' => 'application/vnd.intercom.3+json', 'User-Agent' => "Intercom-Ruby/#{Intercom::VERSION}"}
|
43
|
+
end
|
44
|
+
|
45
|
+
def client(uri)
|
46
|
+
net = Net::HTTP.new(uri.host, uri.port)
|
47
|
+
if uri.is_a?(URI::HTTPS)
|
48
|
+
net.use_ssl = true
|
49
|
+
net.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
50
|
+
net.ca_file = File.join(File.dirname(__FILE__), '../data/cacert.pem')
|
51
|
+
end
|
52
|
+
net.read_timeout = 90
|
53
|
+
net.open_timeout = 30
|
54
|
+
net
|
55
|
+
end
|
56
|
+
|
57
|
+
def execute(target_base_url=nil)
|
58
|
+
base_uri = URI.parse(target_base_url)
|
59
|
+
set_common_headers(net_http_method, base_uri)
|
60
|
+
begin
|
61
|
+
client(base_uri).start do |http|
|
62
|
+
begin
|
63
|
+
response = http.request(net_http_method)
|
64
|
+
set_rate_limit_details(response)
|
65
|
+
decoded_body = decode_body(response)
|
66
|
+
parsed_body = parse_body(decoded_body, response)
|
67
|
+
raise_errors_on_failure(response)
|
68
|
+
parsed_body
|
69
|
+
rescue Timeout::Error
|
70
|
+
raise Intercom::ServiceUnavailableError.new('Service Unavailable [request timed out]')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
rescue Timeout::Error
|
74
|
+
raise Intercom::ServiceConnectionError.new('Failed to connect to service [connection attempt timed out]')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def decode_body(response)
|
79
|
+
decode(response['content-encoding'], response.body)
|
80
|
+
end
|
81
|
+
|
82
|
+
def parse_body(decoded_body, response)
|
83
|
+
parsed_body = nil
|
84
|
+
return parsed_body if decoded_body.nil? || decoded_body.strip.empty?
|
85
|
+
begin
|
86
|
+
parsed_body = JSON.parse(decoded_body)
|
87
|
+
rescue JSON::ParserError => _
|
88
|
+
raise_errors_on_failure(response)
|
89
|
+
end
|
90
|
+
raise_application_errors_on_failure(parsed_body, response.code.to_i) if parsed_body['type'] == 'error.list'
|
91
|
+
parsed_body
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_rate_limit_details(response)
|
95
|
+
rate_limit_details = {}
|
96
|
+
rate_limit_details[:limit] = response['X-RateLimit-Limit'].to_i if response['X-RateLimit-Limit']
|
97
|
+
rate_limit_details[:remaining] = response['X-RateLimit-Remaining'].to_i if response['X-RateLimit-Remaining']
|
98
|
+
rate_limit_details[:reset_at] = Time.at(response['X-RateLimit-Reset'].to_i) if response['X-RateLimit-Reset']
|
99
|
+
Intercom.rate_limit_details = rate_limit_details
|
100
|
+
end
|
101
|
+
|
102
|
+
def decode(content_encoding, body)
|
103
|
+
return body if (!body) || body.empty? || content_encoding != 'gzip'
|
104
|
+
Zlib::GzipReader.new(StringIO.new(body)).read
|
105
|
+
end
|
106
|
+
|
107
|
+
def raise_errors_on_failure(res)
|
108
|
+
if res.code.to_i.eql?(404)
|
109
|
+
raise Intercom::ResourceNotFound.new('Resource Not Found')
|
110
|
+
elsif res.code.to_i.eql?(401)
|
111
|
+
raise Intercom::AuthenticationError.new('Unauthorized')
|
112
|
+
elsif res.code.to_i.eql?(403)
|
113
|
+
raise Intercom::AuthenticationError.new('Forbidden')
|
114
|
+
elsif res.code.to_i.eql?(500)
|
115
|
+
raise Intercom::ServerError.new('Server Error')
|
116
|
+
elsif res.code.to_i.eql?(502)
|
117
|
+
raise Intercom::BadGatewayError.new('Bad Gateway Error')
|
118
|
+
elsif res.code.to_i.eql?(503)
|
119
|
+
raise Intercom::ServiceUnavailableError.new('Service Unavailable')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def raise_application_errors_on_failure(error_list_details, http_code)
|
124
|
+
# Currently, we don't support multiple errors
|
125
|
+
error_details = error_list_details['errors'].first
|
126
|
+
error_code = error_details['type'] || error_details['code']
|
127
|
+
parsed_http_code = (http_code > 0 ? http_code : nil)
|
128
|
+
error_context = {
|
129
|
+
:http_code => parsed_http_code,
|
130
|
+
:application_error_code => error_code
|
131
|
+
}
|
132
|
+
case error_code
|
133
|
+
when 'unauthorized', 'forbidden'
|
134
|
+
raise Intercom::AuthenticationError.new(error_details['message'], error_context)
|
135
|
+
when "bad_request", "missing_parameter", 'parameter_invalid'
|
136
|
+
raise Intercom::BadRequestError.new(error_details['message'], error_context)
|
137
|
+
when "not_found"
|
138
|
+
raise Intercom::ResourceNotFound.new(error_details['message'], error_context)
|
139
|
+
when "rate_limit_exceeded"
|
140
|
+
raise Intercom::RateLimitExceeded.new(error_details['message'], error_context)
|
141
|
+
when 'service_unavailable'
|
142
|
+
raise Intercom::ServiceUnavailableError.new(error_details['message'], error_context)
|
143
|
+
when 'conflict'
|
144
|
+
raise Intercom::MultipleMatchingUsersError.new(error_details['message'], error_context)
|
145
|
+
when nil, ''
|
146
|
+
raise Intercom::UnexpectedError.new(message_for_unexpected_error_without_type(error_details, parsed_http_code), error_context)
|
147
|
+
else
|
148
|
+
raise Intercom::UnexpectedError.new(message_for_unexpected_error_with_type(error_details, parsed_http_code), error_context)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def message_for_unexpected_error_with_type(error_details, parsed_http_code)
|
153
|
+
"The error of type '#{error_details['type']}' is not recognized. It occurred with the message: #{error_details['message']} and http_code: '#{parsed_http_code}'. Please contact Intercom with these details."
|
154
|
+
end
|
155
|
+
|
156
|
+
def message_for_unexpected_error_without_type(error_details, parsed_http_code)
|
157
|
+
"An unexpected error occured. It occurred with the message: #{error_details['message']} and http_code: '#{parsed_http_code}'. Please contact Intercom with these details."
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.append_query_string_to_url(url, params)
|
161
|
+
return url if params.empty?
|
162
|
+
query_string = params.map { |k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&')
|
163
|
+
url + "?#{query_string}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'intercom/api_operations/count'
|
2
|
+
require 'intercom/api_operations/find'
|
3
|
+
require 'intercom/api_operations/save'
|
4
|
+
require 'intercom/traits/api_resource'
|
5
|
+
|
6
|
+
module Intercom
|
7
|
+
class Segment
|
8
|
+
include ApiOperations::List
|
9
|
+
include ApiOperations::Find
|
10
|
+
include ApiOperations::Save
|
11
|
+
include ApiOperations::Count
|
12
|
+
include Traits::ApiResource
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'intercom/api_operations/list'
|
2
|
+
require 'intercom/api_operations/find_all'
|
3
|
+
require 'intercom/api_operations/save'
|
4
|
+
require 'intercom/api_operations/delete'
|
5
|
+
require 'intercom/traits/api_resource'
|
6
|
+
|
7
|
+
module Intercom
|
8
|
+
class Subscription
|
9
|
+
include ApiOperations::List
|
10
|
+
include ApiOperations::Find
|
11
|
+
include ApiOperations::Save
|
12
|
+
include ApiOperations::Delete
|
13
|
+
include Traits::ApiResource
|
14
|
+
end
|
15
|
+
end
|
data/lib/intercom/tag.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'intercom/api_operations/count'
|
2
|
+
require 'intercom/api_operations/save'
|
3
|
+
require 'intercom/api_operations/list'
|
4
|
+
require 'intercom/api_operations/find'
|
5
|
+
require 'intercom/api_operations/find_all'
|
6
|
+
require 'intercom/traits/api_resource'
|
7
|
+
require 'intercom/traits/generic_handler_binding'
|
8
|
+
require 'intercom/generic_handlers/tag'
|
9
|
+
require 'intercom/generic_handlers/tag_find_all'
|
10
|
+
|
11
|
+
module Intercom
|
12
|
+
class Tag
|
13
|
+
include ApiOperations::Count
|
14
|
+
include ApiOperations::Save
|
15
|
+
include ApiOperations::List
|
16
|
+
include ApiOperations::Find
|
17
|
+
include ApiOperations::FindAll
|
18
|
+
include Traits::ApiResource
|
19
|
+
include Traits::GenericHandlerBinding
|
20
|
+
include GenericHandlers::Tag
|
21
|
+
include GenericHandlers::TagFindAll
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'intercom/lib/flat_store'
|
2
|
+
require 'intercom/lib/dynamic_accessors'
|
3
|
+
require 'intercom/lib/dynamic_accessors_on_method_missing'
|
4
|
+
require 'intercom/traits/dirty_tracking'
|
5
|
+
require 'intercom/lib/typed_json_deserializer'
|
6
|
+
|
7
|
+
module Intercom
|
8
|
+
module Traits
|
9
|
+
|
10
|
+
module ApiResource
|
11
|
+
include DirtyTracking
|
12
|
+
|
13
|
+
attr_accessor :id
|
14
|
+
|
15
|
+
def initialize(attributes = {})
|
16
|
+
from_hash(attributes)
|
17
|
+
end
|
18
|
+
|
19
|
+
def from_response(response)
|
20
|
+
from_hash(response)
|
21
|
+
reset_changed_fields!
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def from_hash(hash)
|
26
|
+
hash.each do |attribute, value|
|
27
|
+
next if type_field?(attribute)
|
28
|
+
initialize_property(attribute, value)
|
29
|
+
end
|
30
|
+
initialize_missing_flat_store_attributes if respond_to? :flat_store_attributes
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_hash
|
35
|
+
instance_variables_excluding_dirty_tracking_field.inject({}) do |hash, variable|
|
36
|
+
hash[variable.to_s.delete("@")] = instance_variable_get(variable)
|
37
|
+
hash
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_submittable_hash
|
42
|
+
submittable_hash = {}
|
43
|
+
to_hash.each do |attribute, value|
|
44
|
+
submittable_hash[attribute] = value if submittable_attribute?(attribute, value)
|
45
|
+
end
|
46
|
+
submittable_hash
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing(method_sym, *arguments, &block)
|
50
|
+
Lib::DynamicAccessorsOnMethodMissing.new(method_sym, *arguments, self).
|
51
|
+
define_accessors_or_call { super }
|
52
|
+
end
|
53
|
+
|
54
|
+
def flat_store_attribute?(attribute)
|
55
|
+
(respond_to?(:flat_store_attributes)) && (flat_store_attributes.map(&:to_s).include?(attribute.to_s))
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def initialize_property(attribute, value)
|
61
|
+
Lib::DynamicAccessors.define_accessors(attribute, value, self) unless accessors_already_defined?(attribute)
|
62
|
+
set_property(attribute, value)
|
63
|
+
end
|
64
|
+
|
65
|
+
def accessors_already_defined?(attribute)
|
66
|
+
respond_to?(attribute) && respond_to?("#{attribute}=")
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_property(attribute, value)
|
70
|
+
if typed_value?(value) && !custom_attribute_field?(attribute) && !message_from_field?(attribute, value) && !message_to_field?(attribute, value)
|
71
|
+
value_to_set = Intercom::Lib::TypedJsonDeserializer.new(value).deserialize
|
72
|
+
elsif flat_store_attribute?(attribute)
|
73
|
+
value_to_set = Intercom::Lib::FlatStore.new(value)
|
74
|
+
else
|
75
|
+
value_to_set = value
|
76
|
+
end
|
77
|
+
call_setter_for_attribute(attribute, value_to_set)
|
78
|
+
end
|
79
|
+
|
80
|
+
def custom_attribute_field?(attribute)
|
81
|
+
attribute == 'custom_attributes'
|
82
|
+
end
|
83
|
+
|
84
|
+
def message_from_field?(attribute, value)
|
85
|
+
attribute.to_s == 'from' && value.is_a?(Hash) && value['type']
|
86
|
+
end
|
87
|
+
|
88
|
+
def message_to_field?(attribute, value)
|
89
|
+
attribute.to_s == 'to' && value.is_a?(Hash) && value['type']
|
90
|
+
end
|
91
|
+
|
92
|
+
def typed_value?(value)
|
93
|
+
value.is_a? Hash and !!value['type']
|
94
|
+
end
|
95
|
+
|
96
|
+
def call_setter_for_attribute(attribute, value)
|
97
|
+
setter_method = "#{attribute.to_s}="
|
98
|
+
self.send(setter_method, value)
|
99
|
+
end
|
100
|
+
|
101
|
+
def type_field?(attribute)
|
102
|
+
attribute == 'type'
|
103
|
+
end
|
104
|
+
|
105
|
+
def initialize_missing_flat_store_attributes
|
106
|
+
flat_store_attributes.each do |attribute|
|
107
|
+
unless instance_variables_excluding_dirty_tracking_field.map(&:to_s).include? "@#{attribute}"
|
108
|
+
initialize_property(attribute, {})
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def submittable_attribute?(attribute, value)
|
114
|
+
# FlatStores always submitted, even if not changed, as we don't track their dirtyness
|
115
|
+
value.is_a?(Intercom::Lib::FlatStore) || field_changed?(attribute)
|
116
|
+
end
|
117
|
+
|
118
|
+
module ClassMethods
|
119
|
+
def from_api(api_response)
|
120
|
+
object = self.new
|
121
|
+
object.from_response(api_response)
|
122
|
+
object
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.included(base)
|
127
|
+
base.extend(ClassMethods)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|