intercom 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -8
- data/Gemfile +3 -0
- data/README.md +208 -52
- data/changes.txt +3 -0
- data/intercom.gemspec +2 -2
- data/lib/ext/hash.rb +18 -0
- data/lib/intercom.rb +38 -43
- 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 +22 -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 +15 -0
- data/lib/intercom/api_operations/save.rb +44 -0
- data/lib/intercom/collection_proxy.rb +66 -0
- data/lib/intercom/company.rb +29 -0
- data/lib/intercom/conversation.rb +15 -0
- data/lib/intercom/count.rb +21 -0
- data/lib/intercom/errors.rb +52 -0
- data/lib/intercom/event.rb +4 -101
- 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 +52 -0
- data/lib/intercom/message.rb +9 -0
- data/lib/intercom/note.rb +14 -42
- data/lib/intercom/request.rb +40 -4
- data/lib/intercom/segment.rb +14 -0
- data/lib/intercom/tag.rb +19 -78
- data/lib/intercom/traits/api_resource.rb +120 -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 +23 -0
- data/lib/intercom/user.rb +25 -361
- data/lib/intercom/utils.rb +50 -0
- data/lib/intercom/version.rb +1 -1
- data/spec/spec_helper.rb +64 -33
- data/spec/unit/intercom/collection_proxy_spec.rb +34 -0
- data/spec/unit/intercom/event_spec.rb +25 -0
- data/spec/unit/intercom/{flat_store_spec.rb → lib/flat_store_spec.rb} +7 -7
- data/spec/unit/intercom/note_spec.rb +5 -4
- data/spec/unit/intercom/tag_spec.rb +3 -3
- data/spec/unit/intercom/traits/api_resource_spec.rb +79 -0
- data/spec/unit/intercom/user_spec.rb +101 -119
- data/spec/unit/intercom_spec.rb +7 -7
- metadata +50 -26
- data/lib/intercom/flat_store.rb +0 -27
- data/lib/intercom/hashable_object.rb +0 -22
- data/lib/intercom/impression.rb +0 -63
- data/lib/intercom/message_thread.rb +0 -189
- data/lib/intercom/requires_parameters.rb +0 -10
- data/lib/intercom/social_profile.rb +0 -24
- data/lib/intercom/unix_timestamp_unwrapper.rb +0 -12
- data/lib/intercom/user_collection_proxy.rb +0 -52
- data/lib/intercom/user_resource.rb +0 -82
- data/spec/integration/fixtures/v1-user.json +0 -45
- data/spec/integration/fixtures/v1-users-impression.json +0 -3
- data/spec/integration/fixtures/v1-users-message_thread.json +0 -44
- data/spec/integration/fixtures/v1-users-message_threads.json +0 -46
- data/spec/integration/fixtures/v1-users-note.json +0 -49
- data/spec/integration/fixtures/v1-users.json +0 -144
- data/spec/integration/intercom_api_integration_spec.rb +0 -134
- data/spec/unit/intercom/impression_spec.rb +0 -18
- data/spec/unit/intercom/message_thread_spec.rb +0 -74
- data/spec/unit/intercom/user_collection_proxy_spec.rb +0 -46
- data/spec/unit/intercom/user_event_spec.rb +0 -83
- data/spec/unit/intercom/user_resource_spec.rb +0 -13
@@ -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,22 @@
|
|
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 it's 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
|
+
from_api(response)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.extend(ClassMethods)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
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 it's 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,15 @@
|
|
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
|
+
from_response(response)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'intercom/traits/api_resource'
|
2
|
+
|
3
|
+
module Intercom
|
4
|
+
module ApiOperations
|
5
|
+
module Save
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def create(params)
|
9
|
+
instance = self.new(params)
|
10
|
+
instance.mark_fields_as_changed!(params.keys)
|
11
|
+
instance.save
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.included(base)
|
16
|
+
base.extend(ClassMethods)
|
17
|
+
end
|
18
|
+
|
19
|
+
def save
|
20
|
+
collection_name = Utils.resource_class_to_collection_name(self.class)
|
21
|
+
if id_present? && !posted_updates?
|
22
|
+
response = Intercom.put("/#{collection_name}/#{id}", to_submittable_hash)
|
23
|
+
else
|
24
|
+
response = Intercom.post("/#{collection_name}", to_submittable_hash.merge(identity_hash))
|
25
|
+
end
|
26
|
+
from_response(response) if response # may be nil we received back a 202
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def id_present?
|
32
|
+
id && id.to_s != ''
|
33
|
+
end
|
34
|
+
|
35
|
+
def posted_updates?
|
36
|
+
respond_to?(:update_verb) && update_verb == 'post'
|
37
|
+
end
|
38
|
+
|
39
|
+
def identity_hash
|
40
|
+
respond_to?(:identity_vars) ? to_hash.slice(*(identity_vars.map(&:to_s))) : {}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "intercom/utils"
|
2
|
+
require "ext/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
|
+
deserialize_response_hash(response_hash, block)
|
25
|
+
next_page = extract_next_link(response_hash)
|
26
|
+
break if next_page.nil?
|
27
|
+
end
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def [](target_index)
|
32
|
+
self.each_with_index do |item, index|
|
33
|
+
return item if index == target_index
|
34
|
+
end
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
include Enumerable
|
39
|
+
|
40
|
+
def count
|
41
|
+
raise NoMethodError, "undefined method `count' for #{self.class}. Consider using the dedicated Intercom::Count interface if suitable"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def resource_class; @resource_class; end
|
47
|
+
|
48
|
+
def deserialize_response_hash(response_hash, block)
|
49
|
+
top_level_type = response_hash.delete('type')
|
50
|
+
top_level_entity_key = Utils.entity_key_from_type(top_level_type)
|
51
|
+
response_hash[top_level_entity_key].each do |object_json|
|
52
|
+
block.call Lib::TypedJsonDeserializer.new(object_json).deserialize
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def paging_info_present?(response_hash)
|
57
|
+
!!(response_hash['pages'] && response_hash['pages']['type'])
|
58
|
+
end
|
59
|
+
|
60
|
+
def extract_next_link(response_hash)
|
61
|
+
return nil unless paging_info_present?(response_hash)
|
62
|
+
paging_info = response_hash.delete('pages')
|
63
|
+
paging_info["next"]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'intercom/api_operations/count'
|
2
|
+
require 'intercom/api_operations/list'
|
3
|
+
require 'intercom/api_operations/find'
|
4
|
+
require 'intercom/api_operations/find_all'
|
5
|
+
require 'intercom/api_operations/save'
|
6
|
+
require 'intercom/api_operations/load'
|
7
|
+
require 'intercom/extended_api_operations/users'
|
8
|
+
require 'intercom/extended_api_operations/tags'
|
9
|
+
require 'intercom/traits/incrementable_attributes'
|
10
|
+
require 'intercom/traits/api_resource'
|
11
|
+
|
12
|
+
module Intercom
|
13
|
+
class Company
|
14
|
+
include ApiOperations::Count
|
15
|
+
include ApiOperations::List
|
16
|
+
include ApiOperations::Find
|
17
|
+
include ApiOperations::FindAll
|
18
|
+
include ApiOperations::Save
|
19
|
+
include ApiOperations::Load
|
20
|
+
include ExtendedApiOperations::Users
|
21
|
+
include ExtendedApiOperations::Tags
|
22
|
+
include Traits::IncrementableAttributes
|
23
|
+
include Traits::ApiResource
|
24
|
+
|
25
|
+
def identity_vars ; [:id, :company_id] ; end
|
26
|
+
def flat_store_attributes ; [:custom_attributes] ; end
|
27
|
+
def update_verb ; 'post' ; end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'intercom/extended_api_operations/reply'
|
2
|
+
require 'intercom/api_operations/find_all'
|
3
|
+
require 'intercom/api_operations/find'
|
4
|
+
require 'intercom/api_operations/load'
|
5
|
+
require 'intercom/traits/api_resource'
|
6
|
+
|
7
|
+
module Intercom
|
8
|
+
class Conversation
|
9
|
+
include ExtendedApiOperations::Reply
|
10
|
+
include ApiOperations::FindAll
|
11
|
+
include ApiOperations::Find
|
12
|
+
include ApiOperations::Load
|
13
|
+
include Traits::ApiResource
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'intercom/traits/api_resource'
|
2
|
+
require 'intercom/api_operations/find'
|
3
|
+
require 'intercom/traits/generic_handler_binding'
|
4
|
+
require 'intercom/generic_handlers/count'
|
5
|
+
|
6
|
+
module Intercom
|
7
|
+
class Count
|
8
|
+
include ApiOperations::Find
|
9
|
+
include Traits::ApiResource
|
10
|
+
include Traits::GenericHandlerBinding
|
11
|
+
include GenericHandlers::Count
|
12
|
+
|
13
|
+
def self.fetch_for_app
|
14
|
+
Intercom::Count.find({})
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.fetch_broken_down_count(entity_to_count, count_context)
|
18
|
+
Intercom::Count.find(:type => entity_to_count, :count => count_context)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Intercom
|
2
|
+
|
3
|
+
# Base class exception from which all public Intercom exceptions will be derived
|
4
|
+
class IntercomError < StandardError
|
5
|
+
attr_reader :http_code, :application_error_code
|
6
|
+
def initialize(message, http_code: nil, application_error_code: application_error_code)
|
7
|
+
@http_code = http_code
|
8
|
+
@application_error_code = application_error_code
|
9
|
+
super(message)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Raised when the credentials you provide don't match a valid account on Intercom.
|
14
|
+
# Check that you have set <b>Intercom.app_id=</b> and <b>Intercom.app_api_key=</b> correctly.
|
15
|
+
class AuthenticationError < IntercomError; end
|
16
|
+
|
17
|
+
# Raised when something does wrong on within the Intercom API service.
|
18
|
+
class ServerError < IntercomError; end
|
19
|
+
|
20
|
+
# Raised when we have bad gateway errors.
|
21
|
+
class BadGatewayError < IntercomError; end
|
22
|
+
|
23
|
+
# Raised when we reach socket connect timeout
|
24
|
+
class ServiceUnavailableError < IntercomError; end
|
25
|
+
|
26
|
+
# Raised when requesting resources on behalf of a user that doesn't exist in your application on Intercom.
|
27
|
+
class ResourceNotFound < IntercomError; end
|
28
|
+
|
29
|
+
# Raised when the request has a bad syntax
|
30
|
+
class BadRequestError < IntercomError; end
|
31
|
+
|
32
|
+
# Raised when you have exceed the API rate limit
|
33
|
+
class RateLimitExceeded < IntercomError; end
|
34
|
+
|
35
|
+
# Raised when the request throws an error not accounted for
|
36
|
+
class UnexpectedError < IntercomError; end
|
37
|
+
|
38
|
+
# Raised when you try to call a non-setter method that does not exist on an object
|
39
|
+
class Intercom::AttributeNotSetError < IntercomError ; end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Non-public errors (internal to the gem)
|
43
|
+
#
|
44
|
+
|
45
|
+
# Base class exception from which all public Intercom exceptions will be derived
|
46
|
+
class IntercomInternalError < StandardError; end
|
47
|
+
|
48
|
+
# Raised when we attempt to handle a method missing but are unsuccessful
|
49
|
+
class Intercom::NoMethodMissingHandler < IntercomInternalError; end
|
50
|
+
|
51
|
+
class Intercom::DeserializationError < IntercomInternalError; end
|
52
|
+
end
|
data/lib/intercom/event.rb
CHANGED
@@ -1,106 +1,9 @@
|
|
1
|
-
require 'intercom/
|
2
|
-
require 'intercom/
|
3
|
-
|
1
|
+
require 'intercom/api_operations/save'
|
2
|
+
require 'intercom/traits/api_resource'
|
4
3
|
|
5
4
|
module Intercom
|
6
|
-
|
7
|
-
##
|
8
|
-
# Represents an Event
|
9
|
-
#
|
10
|
-
# An event consists of an event_name and a user the event applies to. The user is identified via email or id.
|
11
|
-
# Additionally, a created timestamp is required.
|
12
|
-
#
|
13
|
-
# == Examples
|
14
|
-
#
|
15
|
-
# event = Intercom::Event.create(:event_name => "post", :user => current_user, :created_at => Time.now)
|
16
|
-
#
|
17
|
-
# You can also create an user-event and save it like this:
|
18
|
-
# event = Intercom::Event.new
|
19
|
-
# event.event_name = "publish-post"
|
20
|
-
# event.user = current_user
|
21
|
-
# event.created_at = Time.now
|
22
|
-
# event.metadata = {
|
23
|
-
# :title => 'Gravity Review',
|
24
|
-
# :link => 'https://example.org/posts/22',
|
25
|
-
# :comments => 'https://example.org/posts/22/comments'
|
26
|
-
# }
|
27
|
-
# event.save
|
28
|
-
#
|
29
|
-
# == Batch
|
30
|
-
#
|
31
|
-
# Events can be created in batches, and sent as one request. To do some, create events
|
32
|
-
# without calling .create, as follows:
|
33
|
-
#
|
34
|
-
# event = Intercom::Event.new
|
35
|
-
# event.event_name = "publish-post"
|
36
|
-
# event.user = current_user
|
37
|
-
#
|
38
|
-
# Then pass them to the save_batch_events class method, along with an (optional) default user:
|
39
|
-
#
|
40
|
-
# Intercom::Event.save_batch_events(events, default_user)
|
41
|
-
#
|
42
|
-
# Any events without a user will be assigned to the default_user.
|
43
|
-
#
|
44
|
-
# Note: if you do not supply a created time, the current time in UTC will be used. Events that have the same
|
45
|
-
# user, name, and created time (to second granularity) may be treated as duplicates by the server.
|
46
|
-
|
47
5
|
class Event
|
48
|
-
|
49
|
-
include
|
50
|
-
|
51
|
-
attr_accessor :event_name, :user, :created_at # required
|
52
|
-
attr_accessor :metadata, :type
|
53
|
-
|
54
|
-
def initialize(attributes={})
|
55
|
-
from_hash(attributes)
|
56
|
-
end
|
57
|
-
|
58
|
-
##
|
59
|
-
# Creates a new Event using params and saves it
|
60
|
-
# @see #save
|
61
|
-
def self.create(params)
|
62
|
-
params[:created_at] ||= Time.now
|
63
|
-
requires_parameters(params, %W(event_name user created_at))
|
64
|
-
Event.new(params).save
|
65
|
-
end
|
66
|
-
|
67
|
-
##
|
68
|
-
# Save the Event
|
69
|
-
def save
|
70
|
-
raise ArgumentError.new("Missing User") if user.nil?
|
71
|
-
Event.save_batch_events([self])
|
72
|
-
self
|
73
|
-
end
|
74
|
-
|
75
|
-
##
|
76
|
-
# Save a list of Events, with an optional base_user
|
77
|
-
def self.save_batch_events(events, base_user=nil)
|
78
|
-
hash = { :type => 'event.list', :data => []}
|
79
|
-
hash[:user] = user_hash(base_user) if base_user
|
80
|
-
events.each do |event|
|
81
|
-
hash[:data] << event.event_hash
|
82
|
-
end
|
83
|
-
post_to_intercom(hash)
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.user_hash(user)
|
87
|
-
user.user_id ? { :user_id => user.user_id } : { :email => user.email }
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.post_to_intercom(hash)
|
91
|
-
Intercom.post('/events', hash)
|
92
|
-
end
|
93
|
-
|
94
|
-
def user_hash
|
95
|
-
Event.user_hash(user)
|
96
|
-
end
|
97
|
-
|
98
|
-
def event_hash
|
99
|
-
event = { :event_name => event_name, :created => created_at.nil? ? Time.now.utc.to_i : created_at.to_i }
|
100
|
-
event[:type] = type.nil? ? 'event' : type
|
101
|
-
event[:user] = user_hash unless user.nil?
|
102
|
-
event[:metadata] = metadata unless metadata.nil?
|
103
|
-
event
|
104
|
-
end
|
6
|
+
include ApiOperations::Save
|
7
|
+
include Traits::ApiResource
|
105
8
|
end
|
106
9
|
end
|