intercom 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -8
  3. data/Gemfile +3 -0
  4. data/README.md +208 -52
  5. data/changes.txt +3 -0
  6. data/intercom.gemspec +2 -2
  7. data/lib/ext/hash.rb +18 -0
  8. data/lib/intercom.rb +38 -43
  9. data/lib/intercom/api_operations/count.rb +16 -0
  10. data/lib/intercom/api_operations/delete.rb +15 -0
  11. data/lib/intercom/api_operations/find.rb +22 -0
  12. data/lib/intercom/api_operations/find_all.rb +33 -0
  13. data/lib/intercom/api_operations/list.rb +17 -0
  14. data/lib/intercom/api_operations/load.rb +15 -0
  15. data/lib/intercom/api_operations/save.rb +44 -0
  16. data/lib/intercom/collection_proxy.rb +66 -0
  17. data/lib/intercom/company.rb +29 -0
  18. data/lib/intercom/conversation.rb +15 -0
  19. data/lib/intercom/count.rb +21 -0
  20. data/lib/intercom/errors.rb +52 -0
  21. data/lib/intercom/event.rb +4 -101
  22. data/lib/intercom/extended_api_operations/reply.rb +16 -0
  23. data/lib/intercom/extended_api_operations/tags.rb +14 -0
  24. data/lib/intercom/extended_api_operations/users.rb +17 -0
  25. data/lib/intercom/generic_handlers/base_handler.rb +22 -0
  26. data/lib/intercom/generic_handlers/count.rb +59 -0
  27. data/lib/intercom/generic_handlers/tag.rb +71 -0
  28. data/lib/intercom/generic_handlers/tag_find_all.rb +47 -0
  29. data/lib/intercom/lib/dynamic_accessors.rb +59 -0
  30. data/lib/intercom/lib/dynamic_accessors_on_method_missing.rb +53 -0
  31. data/lib/intercom/lib/flat_store.rb +31 -0
  32. data/lib/intercom/lib/typed_json_deserializer.rb +52 -0
  33. data/lib/intercom/message.rb +9 -0
  34. data/lib/intercom/note.rb +14 -42
  35. data/lib/intercom/request.rb +40 -4
  36. data/lib/intercom/segment.rb +14 -0
  37. data/lib/intercom/tag.rb +19 -78
  38. data/lib/intercom/traits/api_resource.rb +120 -0
  39. data/lib/intercom/traits/dirty_tracking.rb +33 -0
  40. data/lib/intercom/traits/generic_handler_binding.rb +29 -0
  41. data/lib/intercom/traits/incrementable_attributes.rb +23 -0
  42. data/lib/intercom/user.rb +25 -361
  43. data/lib/intercom/utils.rb +50 -0
  44. data/lib/intercom/version.rb +1 -1
  45. data/spec/spec_helper.rb +64 -33
  46. data/spec/unit/intercom/collection_proxy_spec.rb +34 -0
  47. data/spec/unit/intercom/event_spec.rb +25 -0
  48. data/spec/unit/intercom/{flat_store_spec.rb → lib/flat_store_spec.rb} +7 -7
  49. data/spec/unit/intercom/note_spec.rb +5 -4
  50. data/spec/unit/intercom/tag_spec.rb +3 -3
  51. data/spec/unit/intercom/traits/api_resource_spec.rb +79 -0
  52. data/spec/unit/intercom/user_spec.rb +101 -119
  53. data/spec/unit/intercom_spec.rb +7 -7
  54. metadata +50 -26
  55. data/lib/intercom/flat_store.rb +0 -27
  56. data/lib/intercom/hashable_object.rb +0 -22
  57. data/lib/intercom/impression.rb +0 -63
  58. data/lib/intercom/message_thread.rb +0 -189
  59. data/lib/intercom/requires_parameters.rb +0 -10
  60. data/lib/intercom/social_profile.rb +0 -24
  61. data/lib/intercom/unix_timestamp_unwrapper.rb +0 -12
  62. data/lib/intercom/user_collection_proxy.rb +0 -52
  63. data/lib/intercom/user_resource.rb +0 -82
  64. data/spec/integration/fixtures/v1-user.json +0 -45
  65. data/spec/integration/fixtures/v1-users-impression.json +0 -3
  66. data/spec/integration/fixtures/v1-users-message_thread.json +0 -44
  67. data/spec/integration/fixtures/v1-users-message_threads.json +0 -46
  68. data/spec/integration/fixtures/v1-users-note.json +0 -49
  69. data/spec/integration/fixtures/v1-users.json +0 -144
  70. data/spec/integration/intercom_api_integration_spec.rb +0 -134
  71. data/spec/unit/intercom/impression_spec.rb +0 -18
  72. data/spec/unit/intercom/message_thread_spec.rb +0 -74
  73. data/spec/unit/intercom/user_collection_proxy_spec.rb +0 -46
  74. data/spec/unit/intercom/user_event_spec.rb +0 -83
  75. 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
@@ -1,106 +1,9 @@
1
- require 'intercom/requires_parameters'
2
- require 'intercom/hashable_object'
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
- extend RequiresParameters
49
- include HashableObject
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