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,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
|