intercom 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/README.md +27 -8
- data/README.rdoc +1 -0
- data/Rakefile +18 -3
- data/intercom.gemspec +3 -5
- data/lib/data/cacert.pem +3965 -0
- data/lib/intercom.rb +91 -26
- data/lib/intercom/impression.rb +47 -0
- data/lib/intercom/message_thread.rb +128 -0
- data/lib/intercom/shallow_hash.rb +8 -0
- data/lib/intercom/social_profile.rb +43 -0
- data/lib/intercom/unix_timestamp_unwrapper.rb +11 -0
- data/lib/intercom/user.rb +133 -0
- data/lib/intercom/user_resource.rb +75 -0
- data/lib/intercom/version.rb +2 -2
- data/spec/integration/intercom_api_integration_spec.rb +28 -0
- data/spec/unit/intercom/impression_spec.rb +18 -0
- data/spec/unit/intercom/message_thread_spec.rb +74 -0
- data/spec/unit/intercom/user_resource_spec.rb +13 -0
- data/spec/unit/intercom/user_spec.rb +133 -0
- data/spec/unit/intercom_spec.rb +57 -0
- data/spec/unit/spec_helper.rb +80 -0
- metadata +41 -44
- data/Guardfile +0 -5
- data/spec/intercom_spec.rb +0 -36
- data/spec/spec_helper.rb +0 -35
data/lib/intercom.rb
CHANGED
@@ -1,53 +1,118 @@
|
|
1
1
|
require "intercom/version"
|
2
|
+
require "intercom/user_resource"
|
3
|
+
require "intercom/user"
|
4
|
+
require "intercom/message_thread"
|
5
|
+
require "intercom/impression"
|
2
6
|
require "rest_client"
|
3
|
-
require
|
7
|
+
require "json"
|
4
8
|
|
9
|
+
##
|
10
|
+
# Intercom is a customer relationship management and messaging tool for web app owners
|
11
|
+
#
|
12
|
+
# This library provides ruby bindings for the Intercom API (https://api.intercom.io)
|
13
|
+
#
|
14
|
+
# == Basic Usage
|
15
|
+
# === Configure Intercom with your access credentials
|
16
|
+
# Intercom.app_id = "my_app_id"
|
17
|
+
# Intercom.secret_key = "my_secret_key"
|
18
|
+
# === Make requests to the API
|
19
|
+
# Intercom::User.find(:email => "bob@example.com")
|
20
|
+
#
|
5
21
|
module Intercom
|
22
|
+
@hostname = "api.intercom.io"
|
23
|
+
@protocol = "https"
|
24
|
+
@app_id = nil
|
25
|
+
@secret_key = nil
|
26
|
+
|
27
|
+
##
|
28
|
+
# Set the id of the application you want to interact with.
|
29
|
+
# When logged into your intercom console, the app_id is in the url after /apps (eg https://www.intercom.io/apps/<app-id>)
|
6
30
|
def self.app_id=(app_id)
|
7
31
|
@app_id = app_id
|
8
32
|
end
|
9
33
|
|
34
|
+
##
|
35
|
+
# Set the secret key to gain access to your application data.
|
36
|
+
# When logged into your intercom console, you can view/create api keys in the settings menu
|
10
37
|
def self.secret_key=(secret_key)
|
11
38
|
@secret_key = secret_key
|
12
39
|
end
|
13
40
|
|
14
|
-
|
15
|
-
|
41
|
+
|
42
|
+
private
|
43
|
+
def self.url_for_path(path)
|
44
|
+
raise ArgumentError, "You must set both Intercom.app_id and Intercom.secret_key to use this client. See https://github.com/intercom/intercom for usage examples." if [@app_id, @secret_key].any?(&:nil?)
|
45
|
+
"#{protocol}://#{@app_id}:#{@secret_key}@#{hostname}/v1/#{path}"
|
16
46
|
end
|
17
47
|
|
18
|
-
def self.
|
19
|
-
|
48
|
+
def self.post(path, payload_hash)
|
49
|
+
execute_request(:post, path, {}, {:content_type => :json, :accept => :json}, payload_hash)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.put(path, payload_hash)
|
53
|
+
execute_request(:put, path, {}, {:content_type => :json, :accept => :json}, payload_hash)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.get(path, params)
|
57
|
+
execute_request(:get, path, params)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.require_email_or_user_id(params)
|
61
|
+
raise ArgumentError.new("Expected params Hash, got #{params.class}") unless params.is_a?(Hash)
|
62
|
+
raise ArgumentError.new("Either email or user_id must be specified") unless params.keys.any? { |key| %W(email user_id).include?(key.to_s) }
|
20
63
|
end
|
21
64
|
|
22
65
|
def self.execute_request(method, path, params = {}, headers = {}, payload = nil)
|
23
|
-
|
24
|
-
args =
|
66
|
+
method.eql?(:get) ? require_email_or_user_id(params) : require_email_or_user_id(payload)
|
67
|
+
args =rest_client_args(method, path, params, headers, payload)
|
68
|
+
begin
|
69
|
+
response = RestClient::Request.execute(args)
|
70
|
+
JSON.parse(response.body)
|
71
|
+
rescue RestClient::ResourceNotFound
|
72
|
+
raise ResourceNotFound.new
|
73
|
+
rescue RestClient::Unauthorized
|
74
|
+
raise AuthenticationError.new
|
75
|
+
rescue RestClient::InternalServerError
|
76
|
+
raise ServerError.new
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.rest_client_args(method, path, params, headers, payload)
|
81
|
+
url = url_for_path(path)
|
82
|
+
{
|
25
83
|
:method => method,
|
26
84
|
:url => url,
|
27
|
-
:headers => {:params => params}.merge(headers),
|
85
|
+
:headers => {:params => params}.merge(headers).merge(:accept => :json),
|
28
86
|
:open_timeout => 10,
|
29
|
-
:payload => payload,
|
30
|
-
:timeout => 30
|
87
|
+
:payload => payload.nil? ? nil : payload.to_json,
|
88
|
+
:timeout => 30,
|
89
|
+
:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
|
90
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), 'data/cacert.pem')
|
31
91
|
}
|
32
|
-
RestClient::Request.execute(args)
|
33
92
|
end
|
34
93
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
94
|
+
def self.protocol #nodoc
|
95
|
+
@protocol
|
96
|
+
end
|
39
97
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
98
|
+
def self.protocol=(override)
|
99
|
+
@protocol = override
|
100
|
+
end
|
44
101
|
|
45
|
-
|
46
|
-
|
47
|
-
|
102
|
+
def self.hostname
|
103
|
+
@hostname
|
104
|
+
end
|
48
105
|
|
49
|
-
|
50
|
-
|
51
|
-
|
106
|
+
def self.hostname=(override)
|
107
|
+
@hostname = override
|
108
|
+
end
|
109
|
+
|
110
|
+
class AuthenticationError < StandardError;
|
111
|
+
end
|
112
|
+
|
113
|
+
class ServerError < StandardError;
|
114
|
+
end
|
115
|
+
|
116
|
+
class ResourceNotFound < StandardError;
|
52
117
|
end
|
53
|
-
end
|
118
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'intercom/user_resource'
|
2
|
+
|
3
|
+
module Intercom
|
4
|
+
|
5
|
+
##
|
6
|
+
# Represents a users interaction with your app (eg page view, or using a particular feature)
|
7
|
+
class Impression < UserResource
|
8
|
+
##
|
9
|
+
# Records that a user has interacted with your application, including the 'location' within the app they used
|
10
|
+
def self.create(params)
|
11
|
+
Impression.new(params).save
|
12
|
+
end
|
13
|
+
|
14
|
+
def save
|
15
|
+
response = Intercom.post("users/impressions", to_hash)
|
16
|
+
self.update_from_api_response(response)
|
17
|
+
end
|
18
|
+
|
19
|
+
def user_ip=(user_ip)
|
20
|
+
@attributes["user_ip"] = user_ip
|
21
|
+
end
|
22
|
+
|
23
|
+
def user_ip
|
24
|
+
@attributes["user_ip"]
|
25
|
+
end
|
26
|
+
|
27
|
+
def location=(location)
|
28
|
+
@attributes["location"] = location
|
29
|
+
end
|
30
|
+
|
31
|
+
def location
|
32
|
+
@attributes["location"]
|
33
|
+
end
|
34
|
+
|
35
|
+
def user_agent=(user_agent)
|
36
|
+
@attributes["user_agent"] = user_agent
|
37
|
+
end
|
38
|
+
|
39
|
+
def user_agent
|
40
|
+
@attributes["user_agent"]
|
41
|
+
end
|
42
|
+
|
43
|
+
def unread_messages
|
44
|
+
@attributes["unread_messages"]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'intercom/user_resource'
|
2
|
+
|
3
|
+
module Intercom
|
4
|
+
##
|
5
|
+
# object representing a conversation with a user
|
6
|
+
class MessageThread < UserResource
|
7
|
+
include UnixTimestampUnwrapper
|
8
|
+
|
9
|
+
##
|
10
|
+
# Finds a particular Message identified by thread_id
|
11
|
+
def self.find(params)
|
12
|
+
requires_parameters(params, %W(thread_id))
|
13
|
+
api_response = Intercom.get("users/message_threads", params)
|
14
|
+
MessageThread.from_api(api_response)
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Finds all Messages to show a particular user
|
19
|
+
def self.find_all(params)
|
20
|
+
response = Intercom.get("users/message_threads", params)
|
21
|
+
response.map { |message| MessageThread.from_api(message) }
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Either creates a new message from this user to your application admins, or a comment on an existing one
|
26
|
+
def self.create(params)
|
27
|
+
requires_parameters(params, %W(body))
|
28
|
+
MessageThread.new(params).save
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Marks a message (identified by thread_id) as read
|
33
|
+
def self.mark_as_read(params)
|
34
|
+
requires_parameters(params, %W(thread_id))
|
35
|
+
MessageThread.new({"read" => true}.merge(params)).save(:put)
|
36
|
+
end
|
37
|
+
|
38
|
+
def save(method=:post)
|
39
|
+
response = Intercom.send(method, "users/message_threads", to_hash)
|
40
|
+
self.update_from_api_response(response)
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Set the content of the message. Supports standard markdown syntax
|
45
|
+
def body=(body)
|
46
|
+
@attributes["body"] = body
|
47
|
+
end
|
48
|
+
|
49
|
+
def body
|
50
|
+
@attributes["body"]
|
51
|
+
end
|
52
|
+
|
53
|
+
def created_at
|
54
|
+
time_at("created_at")
|
55
|
+
end
|
56
|
+
|
57
|
+
def updated_at
|
58
|
+
time_at("updated_at")
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def thread_id=(thread_id)
|
63
|
+
@attributes["thread_id"] = thread_id
|
64
|
+
end
|
65
|
+
|
66
|
+
def thread_id
|
67
|
+
@attributes["thread_id"]
|
68
|
+
end
|
69
|
+
|
70
|
+
def read=(read)
|
71
|
+
@attributes["read"] = read
|
72
|
+
end
|
73
|
+
|
74
|
+
def read
|
75
|
+
@attributes["read"]
|
76
|
+
end
|
77
|
+
|
78
|
+
def messages
|
79
|
+
@attributes["messages"].map {|message_hash| Message.new(message_hash)}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class Message
|
84
|
+
include UnixTimestampUnwrapper
|
85
|
+
|
86
|
+
def initialize(params)
|
87
|
+
@attributes = params
|
88
|
+
end
|
89
|
+
|
90
|
+
def from
|
91
|
+
MessageAuthor.new(@attributes["from"])
|
92
|
+
end
|
93
|
+
|
94
|
+
def html
|
95
|
+
@attributes["html"]
|
96
|
+
end
|
97
|
+
|
98
|
+
def created_at
|
99
|
+
time_at("created_at")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class MessageAuthor
|
104
|
+
def initialize(params)
|
105
|
+
@attributes = params
|
106
|
+
end
|
107
|
+
|
108
|
+
def admin?
|
109
|
+
@attributes['is_admin']
|
110
|
+
end
|
111
|
+
|
112
|
+
def email
|
113
|
+
@attributes['email']
|
114
|
+
end
|
115
|
+
|
116
|
+
def user_id
|
117
|
+
@attributes['user_id']
|
118
|
+
end
|
119
|
+
|
120
|
+
def avatar_path_50
|
121
|
+
@attributes['avatar_path_50']
|
122
|
+
end
|
123
|
+
|
124
|
+
def name
|
125
|
+
@attributes['name']
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'intercom/user_resource'
|
2
|
+
|
3
|
+
module Intercom
|
4
|
+
##
|
5
|
+
# object representing a social profile for the User (see )http://docs.intercom.io/#SocialProfiles)
|
6
|
+
class SocialProfile < UserResource
|
7
|
+
def for_wire #:nodoc:
|
8
|
+
@attributes
|
9
|
+
end
|
10
|
+
|
11
|
+
def type
|
12
|
+
@attributes["type"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def type=(type)
|
16
|
+
@attributes["type"]=type
|
17
|
+
end
|
18
|
+
|
19
|
+
def id
|
20
|
+
@attributes["id"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def id=(id)
|
24
|
+
@attributes["id"]=id
|
25
|
+
end
|
26
|
+
|
27
|
+
def url
|
28
|
+
@attributes["url"]
|
29
|
+
end
|
30
|
+
|
31
|
+
def url=(url)
|
32
|
+
@attributes["url"]=url
|
33
|
+
end
|
34
|
+
|
35
|
+
def username
|
36
|
+
@attributes["username"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def username=(username)
|
40
|
+
@attributes["username"]=username
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Intercom
|
2
|
+
module UnixTimestampUnwrapper
|
3
|
+
def time_at(attribute_name)
|
4
|
+
Time.at(@attributes[attribute_name]) if @attributes[attribute_name]
|
5
|
+
end
|
6
|
+
|
7
|
+
def set_time_at(attribute_name, time)
|
8
|
+
@attributes[attribute_name.to_s] = time.to_i
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'intercom/user_resource'
|
2
|
+
require 'intercom/shallow_hash'
|
3
|
+
require 'intercom/social_profile'
|
4
|
+
|
5
|
+
module Intercom
|
6
|
+
##
|
7
|
+
# Represents a user of your application on Intercom.
|
8
|
+
class User < UserResource
|
9
|
+
##
|
10
|
+
# Fetches an Intercom::User from our API.
|
11
|
+
#
|
12
|
+
# Calls GET https://api.intercom.io/v1/users
|
13
|
+
#
|
14
|
+
# returns Intercom::User object representing the state on our servers.
|
15
|
+
#
|
16
|
+
def self.find(params)
|
17
|
+
response = Intercom.get("users", params)
|
18
|
+
User.from_api(response)
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Creates (or updates when a user already exists for that email/user_id) a user record on your application.
|
23
|
+
#
|
24
|
+
# Calls POST https://api.intercom.io/v1/users
|
25
|
+
#
|
26
|
+
# returns Intercom::User object representing the state on our servers.
|
27
|
+
#
|
28
|
+
# This operation is idempotent.
|
29
|
+
def self.create(params)
|
30
|
+
User.new(params).save
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# instance method alternative to #create
|
35
|
+
def save
|
36
|
+
response = Intercom.post("users", to_hash)
|
37
|
+
self.update_from_api_response(response)
|
38
|
+
end
|
39
|
+
|
40
|
+
def name
|
41
|
+
@attributes["name"]
|
42
|
+
end
|
43
|
+
|
44
|
+
def name=(name)
|
45
|
+
@attributes["name"]=name
|
46
|
+
end
|
47
|
+
|
48
|
+
def last_seen_ip
|
49
|
+
@attributes["last_seen_ip"]
|
50
|
+
end
|
51
|
+
|
52
|
+
def last_seen_ip=(last_seen_ip)
|
53
|
+
@attributes["last_seen_ip"]=last_seen_ip
|
54
|
+
end
|
55
|
+
|
56
|
+
def last_seen_user_agent
|
57
|
+
@attributes["last_seen_user_agent"]
|
58
|
+
end
|
59
|
+
|
60
|
+
def last_seen_user_agent=(last_seen_user_agent)
|
61
|
+
@attributes["last_seen_user_agent"]=last_seen_user_agent
|
62
|
+
end
|
63
|
+
|
64
|
+
def relationship_score
|
65
|
+
@attributes["relationship_score"]
|
66
|
+
end
|
67
|
+
|
68
|
+
def session_count
|
69
|
+
@attributes["session_count"]
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Get last time this User interacted with your application
|
74
|
+
def last_impression_at
|
75
|
+
time_at("last_impression_at")
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Get Time at which this User started using your application.
|
80
|
+
def created_at
|
81
|
+
time_at("created_at")
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Get Time at which this User started using your application.
|
86
|
+
def created_at=(time)
|
87
|
+
set_time_at("created_at", time)
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Get array of Intercom::SocialProfile objects attached to this Intercom::User
|
92
|
+
#
|
93
|
+
# See http://docs.intercom.io/#SocialProfiles for more information
|
94
|
+
def social_profiles
|
95
|
+
@social_profiles ||= [].freeze
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Get hash of location attributes associated with this Intercom::User
|
100
|
+
#
|
101
|
+
# Possible entries: city_name, continent_code, country_code, country_name, latitude, longitude, postal_code, region_name, timezone
|
102
|
+
#
|
103
|
+
# e.g.
|
104
|
+
#
|
105
|
+
# {"city_name"=>"Santiago", "continent_code"=>"SA", "country_code"=>"CHL", "country_name"=>"Chile",
|
106
|
+
# "latitude"=>-33.44999999999999, "longitude"=>-70.6667, "postal_code"=>"", "region_name"=>"12",
|
107
|
+
# "timezone"=>"Chile/Continental"}
|
108
|
+
def location_data
|
109
|
+
@location_data ||= {}.freeze
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Get hash of custom attributes stored for this Intercom::User
|
114
|
+
#
|
115
|
+
# See http://docs.intercom.io/#CustomData for more information
|
116
|
+
def custom_data
|
117
|
+
@attributes["custom_data"] ||= ShallowHash.new
|
118
|
+
end
|
119
|
+
|
120
|
+
protected
|
121
|
+
def social_profiles=(social_profiles) #:nodoc:
|
122
|
+
@social_profiles = social_profiles.map { |account| SocialProfile.new(account) }.freeze
|
123
|
+
end
|
124
|
+
|
125
|
+
def location_data=(hash) #:nodoc:
|
126
|
+
@location_data = hash.freeze
|
127
|
+
end
|
128
|
+
|
129
|
+
def custom_data=(custom_data) #:nodoc:
|
130
|
+
@attributes["custom_data"] = ShallowHash.new.merge(custom_data)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|