hubspot-api-ruby 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/Gemfile +3 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +18 -0
- data/README.md +295 -0
- data/RELEASING.md +6 -0
- data/Rakefile +32 -0
- data/hubspot-api-ruby.gemspec +42 -0
- data/lib/hubspot-api-ruby.rb +39 -0
- data/lib/hubspot/blog.rb +98 -0
- data/lib/hubspot/collection.rb +41 -0
- data/lib/hubspot/company.rb +160 -0
- data/lib/hubspot/company_properties.rb +59 -0
- data/lib/hubspot/config.rb +63 -0
- data/lib/hubspot/connection.rb +152 -0
- data/lib/hubspot/contact.rb +110 -0
- data/lib/hubspot/contact_list.rb +129 -0
- data/lib/hubspot/contact_properties.rb +59 -0
- data/lib/hubspot/deal.rb +173 -0
- data/lib/hubspot/deal_pipeline.rb +58 -0
- data/lib/hubspot/deal_properties.rb +59 -0
- data/lib/hubspot/deprecator.rb +7 -0
- data/lib/hubspot/engagement.rb +222 -0
- data/lib/hubspot/event.rb +21 -0
- data/lib/hubspot/exceptions.rb +18 -0
- data/lib/hubspot/file.rb +38 -0
- data/lib/hubspot/form.rb +95 -0
- data/lib/hubspot/oauth.rb +50 -0
- data/lib/hubspot/owner.rb +57 -0
- data/lib/hubspot/paged_collection.rb +35 -0
- data/lib/hubspot/properties.rb +123 -0
- data/lib/hubspot/railtie.rb +10 -0
- data/lib/hubspot/resource.rb +270 -0
- data/lib/hubspot/subscription.rb +37 -0
- data/lib/hubspot/topic.rb +37 -0
- data/lib/hubspot/utils.rb +127 -0
- data/lib/tasks/hubspot.rake +53 -0
- data/spec/factories/companies.rb +9 -0
- data/spec/factories/contacts.rb +10 -0
- data/spec/lib/hubspot-ruby_spec.rb +12 -0
- data/spec/lib/hubspot/blog_spec.rb +150 -0
- data/spec/lib/hubspot/company_properties_spec.rb +410 -0
- data/spec/lib/hubspot/company_spec.rb +340 -0
- data/spec/lib/hubspot/config_spec.rb +87 -0
- data/spec/lib/hubspot/connection_spec.rb +214 -0
- data/spec/lib/hubspot/contact_list_spec.rb +301 -0
- data/spec/lib/hubspot/contact_properties_spec.rb +245 -0
- data/spec/lib/hubspot/contact_spec.rb +223 -0
- data/spec/lib/hubspot/deal_pipeline_spec.rb +85 -0
- data/spec/lib/hubspot/deal_properties_spec.rb +262 -0
- data/spec/lib/hubspot/deal_spec.rb +185 -0
- data/spec/lib/hubspot/deprecator_spec.rb +15 -0
- data/spec/lib/hubspot/engagement_spec.rb +177 -0
- data/spec/lib/hubspot/event_spec.rb +33 -0
- data/spec/lib/hubspot/file_spec.rb +38 -0
- data/spec/lib/hubspot/form_spec.rb +189 -0
- data/spec/lib/hubspot/owner_spec.rb +56 -0
- data/spec/lib/hubspot/properties_spec.rb +45 -0
- data/spec/lib/hubspot/resource_spec.rb +54 -0
- data/spec/lib/hubspot/topic_spec.rb +23 -0
- data/spec/lib/hubspot/utils_spec.rb +164 -0
- data/spec/lib/tasks/hubspot_spec.rb +119 -0
- data/spec/shared_examples/saveable_resource.rb +45 -0
- data/spec/shared_examples/updateable_resource.rb +87 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/capture_output.rb +21 -0
- data/spec/support/cassette_helper.rb +19 -0
- data/spec/support/hubspot_api_helpers.rb +13 -0
- data/spec/support/rake.rb +46 -0
- data/spec/support/tests_helper.rb +17 -0
- data/spec/support/vcr.rb +16 -0
- metadata +369 -0
data/lib/hubspot/blog.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
module Hubspot
|
2
|
+
#
|
3
|
+
# HubSpot Contacts API
|
4
|
+
#
|
5
|
+
class Blog
|
6
|
+
BLOG_LIST_PATH = "/content/api/v2/blogs"
|
7
|
+
BLOG_POSTS_PATH = "/content/api/v2/blog-posts"
|
8
|
+
GET_BLOG_BY_ID_PATH = "/content/api/v2/blogs/:blog_id"
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Lists the blogs
|
12
|
+
# {https://developers.hubspot.com/docs/methods/blogv2/get_blogs}
|
13
|
+
# No param filtering is currently implemented
|
14
|
+
# @return [Hubspot::Blog] the first 20 blogs or empty_array
|
15
|
+
def list
|
16
|
+
response = Hubspot::Connection.get_json(BLOG_LIST_PATH, {})
|
17
|
+
response['objects'].map { |b| new(b) }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Finds a specific blog by its ID
|
21
|
+
# {https://developers.hubspot.com/docs/methods/blogv2/get_blogs_blog_id}
|
22
|
+
# @return Hubspot::Blog
|
23
|
+
def find_by_id(id)
|
24
|
+
response = Hubspot::Connection.get_json(GET_BLOG_BY_ID_PATH, { blog_id: id })
|
25
|
+
new(response)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :properties
|
30
|
+
|
31
|
+
def initialize(response_hash)
|
32
|
+
@properties = response_hash #no need to parse anything, we have properties
|
33
|
+
end
|
34
|
+
|
35
|
+
def [](property)
|
36
|
+
@properties[property]
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Returns the posts for this blog instance.
|
41
|
+
# defaults to returning the last 2 months worth of published blog posts
|
42
|
+
# in date descending order (i.e. most recent first)
|
43
|
+
# {https://developers.hubspot.com/docs/methods/blogv2/get_blog_posts}
|
44
|
+
# @return [Hubspot::BlogPost]
|
45
|
+
def posts(params = {})
|
46
|
+
default_params = {
|
47
|
+
content_group_id: self["id"],
|
48
|
+
order_by: '-created',
|
49
|
+
created__gt: Time.now - 2.month,
|
50
|
+
state: 'PUBLISHED'
|
51
|
+
}
|
52
|
+
raise Hubspot::InvalidParams.new('params must be passed as a hash') unless params.is_a?(Hash)
|
53
|
+
params = default_params.merge(params)
|
54
|
+
|
55
|
+
raise Hubspot::InvalidParams.new('State parameter was invalid') unless [false, 'PUBLISHED', 'DRAFT'].include?(params[:state])
|
56
|
+
params.each { |k, v| params.delete(k) if v == false }
|
57
|
+
|
58
|
+
response = Hubspot::Connection.get_json(BLOG_POSTS_PATH, params)
|
59
|
+
response['objects'].map { |p| BlogPost.new(p) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class BlogPost
|
64
|
+
GET_BLOG_POST_BY_ID_PATH = "/content/api/v2/blog-posts/:blog_post_id"
|
65
|
+
|
66
|
+
# Returns a specific blog post by ID
|
67
|
+
# {https://developers.hubspot.com/docs/methods/blogv2/get_blog_posts_blog_post_id}
|
68
|
+
# @return Hubspot::BlogPost
|
69
|
+
def self.find_by_blog_post_id(id)
|
70
|
+
response = Hubspot::Connection.get_json(GET_BLOG_POST_BY_ID_PATH, { blog_post_id: id })
|
71
|
+
new(response)
|
72
|
+
end
|
73
|
+
|
74
|
+
def initialize(response_hash)
|
75
|
+
@properties = response_hash #no need to parse anything, we have properties
|
76
|
+
end
|
77
|
+
|
78
|
+
def [](property)
|
79
|
+
@properties[property]
|
80
|
+
end
|
81
|
+
|
82
|
+
def created_at
|
83
|
+
Time.at(@properties['created'] / 1000)
|
84
|
+
end
|
85
|
+
|
86
|
+
def topics
|
87
|
+
@topics ||= begin
|
88
|
+
if @properties['topic_ids'].empty?
|
89
|
+
[]
|
90
|
+
else
|
91
|
+
@properties['topic_ids'].map do |topic_id|
|
92
|
+
Hubspot::Topic.find_by_topic_id(topic_id)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Hubspot::Collection
|
2
|
+
def initialize(opts = {}, &block)
|
3
|
+
@options = opts
|
4
|
+
@fetch_proc = block
|
5
|
+
fetch
|
6
|
+
end
|
7
|
+
|
8
|
+
def refresh
|
9
|
+
fetch
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def resources
|
14
|
+
@resources
|
15
|
+
end
|
16
|
+
|
17
|
+
def update_all(opts = {})
|
18
|
+
return true if empty?
|
19
|
+
|
20
|
+
# This assumes that all resources are the same type
|
21
|
+
resource_class = resources.first.class
|
22
|
+
unless resource_class.respond_to?(:batch_update)
|
23
|
+
raise "#{resource_class} does not support bulk update"
|
24
|
+
end
|
25
|
+
|
26
|
+
resource_class.batch_update(resources, opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
def fetch
|
31
|
+
@resources = @fetch_proc.call(@options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def respond_to_missing?(name, include_private = false)
|
35
|
+
@resources.respond_to?(name, include_private)
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing(method, *args, &block)
|
39
|
+
@resources.public_send(method, *args, &block)
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
class Hubspot::Company < Hubspot::Resource
|
2
|
+
self.id_field = "companyId"
|
3
|
+
self.property_name_field = "name"
|
4
|
+
|
5
|
+
ADD_CONTACT_PATH = '/companies/v2/companies/:id/contacts/:contact_id'
|
6
|
+
ALL_PATH = '/companies/v2/companies/paged'
|
7
|
+
BATCH_UPDATE_PATH = '/companies/v1/batch-async/update'
|
8
|
+
CONTACTS_PATH = '/companies/v2/companies/:id/contacts'
|
9
|
+
CONTACT_IDS_PATH = '/companies/v2/companies/:id/vids'
|
10
|
+
CREATE_PATH = '/companies/v2/companies/'
|
11
|
+
DELETE_PATH = '/companies/v2/companies/:id'
|
12
|
+
FIND_PATH = '/companies/v2/companies/:id'
|
13
|
+
RECENTLY_CREATED_PATH = '/companies/v2/companies/recent/created'
|
14
|
+
RECENTLY_MODIFIED_PATH = '/companies/v2/companies/recent/modified'
|
15
|
+
REMOVE_CONTACT_PATH = '/companies/v2/companies/:id/contacts/:contact_id'
|
16
|
+
SEARCH_DOMAIN_PATH = '/companies/v2/domains/:domain/companies'
|
17
|
+
UPDATE_PATH = '/companies/v2/companies/:id'
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def all(opts = {})
|
21
|
+
Hubspot::PagedCollection.new(opts) do |options, offset, limit|
|
22
|
+
response = Hubspot::Connection.get_json(
|
23
|
+
ALL_PATH,
|
24
|
+
options.merge(offset: offset, limit: limit)
|
25
|
+
)
|
26
|
+
|
27
|
+
companies = response["companies"].map { |result| from_result(result) }
|
28
|
+
|
29
|
+
[companies, response["offset"], response["has-more"]]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def search_domain(domain, opts = {})
|
34
|
+
Hubspot::PagedCollection.new(opts) do |options, offset, limit|
|
35
|
+
request = {
|
36
|
+
"limit" => limit,
|
37
|
+
"requestOptions" => options,
|
38
|
+
"offset" => {
|
39
|
+
"isPrimary" => true,
|
40
|
+
"companyId" => offset
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
response = Hubspot::Connection.post_json(
|
45
|
+
SEARCH_DOMAIN_PATH,
|
46
|
+
params: { domain: domain },
|
47
|
+
body: request
|
48
|
+
)
|
49
|
+
|
50
|
+
companies = response["results"].map { |result| from_result(result) }
|
51
|
+
|
52
|
+
[companies, response["offset"]["companyId"], response["hasMore"]]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def recently_created(opts = {})
|
57
|
+
Hubspot::PagedCollection.new(opts) do |options, offset, limit|
|
58
|
+
response = Hubspot::Connection.get_json(
|
59
|
+
RECENTLY_CREATED_PATH,
|
60
|
+
{offset: offset, count: limit}
|
61
|
+
)
|
62
|
+
|
63
|
+
companies = response["results"].map { |result| from_result(result) }
|
64
|
+
|
65
|
+
[companies, response["offset"], response["hasMore"]]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def recently_modified(opts = {})
|
70
|
+
Hubspot::PagedCollection.new(opts) do |options, offset, limit|
|
71
|
+
response = Hubspot::Connection.get_json(
|
72
|
+
RECENTLY_MODIFIED_PATH,
|
73
|
+
{offset: offset, count: limit}
|
74
|
+
)
|
75
|
+
|
76
|
+
companies = response["results"].map { |result| from_result(result) }
|
77
|
+
|
78
|
+
[companies, response["offset"], response["hasMore"]]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_contact(id, contact_id)
|
83
|
+
Hubspot::Connection.put_json(
|
84
|
+
ADD_CONTACT_PATH,
|
85
|
+
params: { id: id, contact_id: contact_id }
|
86
|
+
)
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
def remove_contact(id, contact_id)
|
91
|
+
Hubspot::Connection.delete_json(
|
92
|
+
REMOVE_CONTACT_PATH,
|
93
|
+
{ id: id, contact_id: contact_id }
|
94
|
+
)
|
95
|
+
|
96
|
+
true
|
97
|
+
end
|
98
|
+
|
99
|
+
def batch_update(companies, opts = {})
|
100
|
+
request = companies.map do |company|
|
101
|
+
# Use the specified options or update with the changes
|
102
|
+
changes = opts.empty? ? company.changes : opts
|
103
|
+
|
104
|
+
unless changes.empty?
|
105
|
+
{
|
106
|
+
"objectId" => company.id,
|
107
|
+
"properties" => changes.map { |k, v| { "name" => k, "value" => v } }
|
108
|
+
}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Remove any objects without changes and return if there is nothing to update
|
113
|
+
request.compact!
|
114
|
+
return true if request.empty?
|
115
|
+
|
116
|
+
Hubspot::Connection.post_json(
|
117
|
+
BATCH_UPDATE_PATH,
|
118
|
+
params: {},
|
119
|
+
body: request
|
120
|
+
)
|
121
|
+
|
122
|
+
true
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def contacts(opts = {})
|
127
|
+
Hubspot::PagedCollection.new(opts) do |options, offset, limit|
|
128
|
+
response = Hubspot::Connection.get_json(
|
129
|
+
CONTACTS_PATH,
|
130
|
+
{"id" => @id, "vidOffset" => offset, "count" => limit}
|
131
|
+
)
|
132
|
+
|
133
|
+
contacts = response["contacts"].map do |result|
|
134
|
+
result["properties"] = Hubspot::Utils.properties_array_to_hash(result["properties"])
|
135
|
+
Hubspot::Contact.from_result(result)
|
136
|
+
end
|
137
|
+
|
138
|
+
[contacts, response["vidOffset"], response["hasMore"]]
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def contact_ids(opts = {})
|
143
|
+
Hubspot::PagedCollection.new(opts) do |options, offset, limit|
|
144
|
+
response = Hubspot::Connection.get_json(
|
145
|
+
CONTACT_IDS_PATH,
|
146
|
+
{"id" => @id, "vidOffset" => offset, "count" => limit}
|
147
|
+
)
|
148
|
+
|
149
|
+
[response["vids"], response["vidOffset"], response["hasMore"]]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def add_contact(contact)
|
154
|
+
self.class.add_contact(@id, contact.to_i)
|
155
|
+
end
|
156
|
+
|
157
|
+
def remove_contact(contact)
|
158
|
+
self.class.remove_contact(@id, contact.to_i)
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Hubspot
|
2
|
+
class CompanyProperties < Properties
|
3
|
+
|
4
|
+
ALL_PROPERTIES_PATH = "/properties/v1/companies/properties"
|
5
|
+
ALL_GROUPS_PATH = "/properties/v1/companies/groups"
|
6
|
+
CREATE_PROPERTY_PATH = "/properties/v1/companies/properties"
|
7
|
+
UPDATE_PROPERTY_PATH = "/properties/v1/companies/properties/named/:property_name"
|
8
|
+
DELETE_PROPERTY_PATH = "/properties/v1/companies/properties/named/:property_name"
|
9
|
+
CREATE_GROUP_PATH = "/properties/v1/companies/groups"
|
10
|
+
UPDATE_GROUP_PATH = "/properties/v1/companies/groups/named/:group_name"
|
11
|
+
DELETE_GROUP_PATH = "/properties/v1/companies/groups/named/:group_name"
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def add_default_parameters(opts={})
|
15
|
+
superclass.add_default_parameters(opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def all(opts={}, filter={})
|
19
|
+
superclass.all(ALL_PROPERTIES_PATH, opts, filter)
|
20
|
+
end
|
21
|
+
|
22
|
+
def groups(opts={}, filter={})
|
23
|
+
superclass.groups(ALL_GROUPS_PATH, opts, filter)
|
24
|
+
end
|
25
|
+
|
26
|
+
def create!(params={})
|
27
|
+
superclass.create!(CREATE_PROPERTY_PATH, params)
|
28
|
+
end
|
29
|
+
|
30
|
+
def update!(property_name, params={})
|
31
|
+
superclass.update!(UPDATE_PROPERTY_PATH, property_name, params)
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete!(property_name)
|
35
|
+
superclass.delete!(DELETE_PROPERTY_PATH, property_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_group!(params={})
|
39
|
+
superclass.create_group!(CREATE_GROUP_PATH, params)
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_group!(group_name, params={})
|
43
|
+
superclass.update_group!(UPDATE_GROUP_PATH, group_name, params)
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete_group!(group_name)
|
47
|
+
superclass.delete_group!(DELETE_GROUP_PATH, group_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def same?(src, dst)
|
51
|
+
superclass.same?(src, dst)
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid_params(params)
|
55
|
+
superclass.valid_params(params)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'hubspot/connection'
|
3
|
+
|
4
|
+
module Hubspot
|
5
|
+
class Config
|
6
|
+
CONFIG_KEYS = [
|
7
|
+
:hapikey, :base_url, :portal_id, :logger, :access_token, :client_id,
|
8
|
+
:client_secret, :redirect_uri, :read_timeout, :open_timeout
|
9
|
+
]
|
10
|
+
DEFAULT_LOGGER = Logger.new(nil)
|
11
|
+
DEFAULT_BASE_URL = "https://api.hubapi.com".freeze
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor *CONFIG_KEYS
|
15
|
+
|
16
|
+
def configure(config)
|
17
|
+
config.stringify_keys!
|
18
|
+
@hapikey = config["hapikey"]
|
19
|
+
@base_url = config["base_url"] || DEFAULT_BASE_URL
|
20
|
+
@portal_id = config["portal_id"]
|
21
|
+
@logger = config["logger"] || DEFAULT_LOGGER
|
22
|
+
@access_token = config["access_token"]
|
23
|
+
@client_id = config["client_id"] if config["client_id"].present?
|
24
|
+
@client_secret = config["client_secret"] if config["client_secret"].present?
|
25
|
+
@redirect_uri = config["redirect_uri"] if config["redirect_uri"].present?
|
26
|
+
@read_timeout = config['read_timeout'] || config['timeout']
|
27
|
+
@open_timeout = config['open_timeout'] || config['timeout']
|
28
|
+
|
29
|
+
unless authentication_uncertain?
|
30
|
+
raise Hubspot::ConfigurationError.new("You must provide either an access_token or an hapikey")
|
31
|
+
end
|
32
|
+
|
33
|
+
if access_token.present?
|
34
|
+
Hubspot::Connection.headers("Authorization" => "Bearer #{access_token}")
|
35
|
+
end
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def reset!
|
40
|
+
@hapikey = nil
|
41
|
+
@base_url = DEFAULT_BASE_URL
|
42
|
+
@portal_id = nil
|
43
|
+
@logger = DEFAULT_LOGGER
|
44
|
+
@access_token = nil
|
45
|
+
Hubspot::Connection.headers({})
|
46
|
+
end
|
47
|
+
|
48
|
+
def ensure!(*params)
|
49
|
+
params.each do |p|
|
50
|
+
raise Hubspot::ConfigurationError.new("'#{p}' not configured") unless instance_variable_get "@#{p}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def authentication_uncertain?
|
57
|
+
access_token.present? ^ hapikey.present?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
reset!
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Hubspot
|
2
|
+
class Connection
|
3
|
+
include HTTParty
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def get_json(path, opts)
|
7
|
+
url = generate_url(path, opts)
|
8
|
+
response = get(url, format: :json, read_timeout: read_timeout(opts), open_timeout: open_timeout(opts))
|
9
|
+
log_request_and_response url, response
|
10
|
+
handle_response(response)
|
11
|
+
end
|
12
|
+
|
13
|
+
def post_json(path, opts)
|
14
|
+
no_parse = opts[:params].delete(:no_parse) { false }
|
15
|
+
|
16
|
+
url = generate_url(path, opts[:params])
|
17
|
+
response = post(
|
18
|
+
url,
|
19
|
+
body: opts[:body].to_json,
|
20
|
+
headers: { 'Content-Type' => 'application/json' },
|
21
|
+
format: :json,
|
22
|
+
read_timeout: read_timeout(opts),
|
23
|
+
open_timeout: open_timeout(opts)
|
24
|
+
)
|
25
|
+
|
26
|
+
log_request_and_response url, response, opts[:body]
|
27
|
+
raise(Hubspot::RequestError.new(response)) unless response.success?
|
28
|
+
|
29
|
+
no_parse ? response : response.parsed_response
|
30
|
+
end
|
31
|
+
|
32
|
+
def put_json(path, options)
|
33
|
+
no_parse = options[:params].delete(:no_parse) { false }
|
34
|
+
url = generate_url(path, options[:params])
|
35
|
+
|
36
|
+
response = put(
|
37
|
+
url,
|
38
|
+
body: options[:body].to_json,
|
39
|
+
headers: { "Content-Type" => "application/json" },
|
40
|
+
format: :json,
|
41
|
+
read_timeout: read_timeout(options),
|
42
|
+
open_timeout: open_timeout(options),
|
43
|
+
)
|
44
|
+
|
45
|
+
log_request_and_response(url, response, options[:body])
|
46
|
+
raise(Hubspot::RequestError.new(response)) unless response.success?
|
47
|
+
|
48
|
+
no_parse ? response : response.parsed_response
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete_json(path, opts)
|
52
|
+
url = generate_url(path, opts)
|
53
|
+
response = delete(url, format: :json, read_timeout: read_timeout(opts), open_timeout: open_timeout(opts))
|
54
|
+
log_request_and_response url, response, opts[:body]
|
55
|
+
raise(Hubspot::RequestError.new(response)) unless response.success?
|
56
|
+
response
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
def read_timeout(opts = {})
|
62
|
+
opts.delete(:read_timeout) || Hubspot::Config.read_timeout
|
63
|
+
end
|
64
|
+
|
65
|
+
def open_timeout(opts = {})
|
66
|
+
opts.delete(:open_timeout) || Hubspot::Config.open_timeout
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_response(response)
|
70
|
+
if response.success?
|
71
|
+
response.parsed_response
|
72
|
+
else
|
73
|
+
raise(Hubspot::RequestError.new(response))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def log_request_and_response(uri, response, body=nil)
|
78
|
+
Hubspot::Config.logger.info(<<~MSG)
|
79
|
+
Hubspot: #{uri}.
|
80
|
+
Body: #{body}.
|
81
|
+
Response: #{response.code} #{response.body}
|
82
|
+
MSG
|
83
|
+
end
|
84
|
+
|
85
|
+
def generate_url(path, params={}, options={})
|
86
|
+
if Hubspot::Config.access_token.present?
|
87
|
+
options[:hapikey] = false
|
88
|
+
else
|
89
|
+
Hubspot::Config.ensure! :hapikey
|
90
|
+
end
|
91
|
+
path = path.clone
|
92
|
+
params = params.clone
|
93
|
+
base_url = options[:base_url] || Hubspot::Config.base_url
|
94
|
+
params["hapikey"] = Hubspot::Config.hapikey unless options[:hapikey] == false
|
95
|
+
|
96
|
+
if path =~ /:portal_id/
|
97
|
+
Hubspot::Config.ensure! :portal_id
|
98
|
+
params["portal_id"] = Hubspot::Config.portal_id if path =~ /:portal_id/
|
99
|
+
end
|
100
|
+
|
101
|
+
params.each do |k,v|
|
102
|
+
if path.match(":#{k}")
|
103
|
+
path.gsub!(":#{k}", CGI.escape(v.to_s))
|
104
|
+
params.delete(k)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
raise(Hubspot::MissingInterpolation.new("Interpolation not resolved")) if path =~ /:/
|
108
|
+
|
109
|
+
query = params.map do |k,v|
|
110
|
+
v.is_a?(Array) ? v.map { |value| param_string(k,value) } : param_string(k,v)
|
111
|
+
end.join("&")
|
112
|
+
|
113
|
+
path += path.include?('?') ? '&' : "?" if query.present?
|
114
|
+
base_url + path + query
|
115
|
+
end
|
116
|
+
|
117
|
+
# convert into milliseconds since epoch
|
118
|
+
def converted_value(value)
|
119
|
+
value.is_a?(Time) ? (value.to_i * 1000) : CGI.escape(value.to_s)
|
120
|
+
end
|
121
|
+
|
122
|
+
def param_string(key,value)
|
123
|
+
case key
|
124
|
+
when /range/
|
125
|
+
raise "Value must be a range" unless value.is_a?(Range)
|
126
|
+
"#{key}=#{converted_value(value.begin)}&#{key}=#{converted_value(value.end)}"
|
127
|
+
when /^batch_(.*)$/
|
128
|
+
key = $1.gsub(/(_.)/) { |w| w.last.upcase }
|
129
|
+
"#{key}=#{converted_value(value)}"
|
130
|
+
else
|
131
|
+
"#{key}=#{converted_value(value)}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class FormsConnection < Connection
|
138
|
+
follow_redirects true
|
139
|
+
|
140
|
+
def self.submit(path, opts)
|
141
|
+
url = generate_url(path, opts[:params], { base_url: 'https://forms.hubspot.com', hapikey: false })
|
142
|
+
post(url, body: opts[:body], headers: { 'Content-Type' => 'application/x-www-form-urlencoded' })
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class EventConnection < Connection
|
147
|
+
def self.trigger(path, opts)
|
148
|
+
url = generate_url(path, opts[:params], { base_url: 'https://track.hubspot.com', hapikey: false })
|
149
|
+
get(url, body: opts[:body], headers: opts[:headers])
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|