hubspot-api-ruby 0.8.0 → 0.10.0
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 +4 -4
- data/README.md +40 -154
- data/Rakefile +0 -2
- data/hubspot-api-ruby.gemspec +5 -7
- data/lib/hubspot/association.rb +106 -0
- data/lib/hubspot/company.rb +2 -13
- data/lib/hubspot/config.rb +14 -9
- data/lib/hubspot/connection.rb +20 -14
- data/lib/hubspot/contact.rb +5 -1
- data/lib/hubspot/contact_list.rb +0 -7
- data/lib/hubspot/custom_event.rb +25 -0
- data/lib/hubspot/deal.rb +53 -32
- data/lib/hubspot/engagement.rb +0 -1
- data/lib/hubspot/exceptions.rb +2 -0
- data/lib/hubspot/file.rb +2 -2
- data/lib/hubspot/meeting.rb +44 -0
- data/lib/hubspot/properties.rb +1 -1
- data/lib/hubspot/railtie.rb +0 -4
- data/lib/hubspot/resource.rb +4 -4
- data/lib/hubspot/utils.rb +0 -30
- data/lib/hubspot-api-ruby.rb +3 -0
- data/spec/lib/hubspot/association_spec.rb +165 -0
- data/spec/lib/hubspot/blog_spec.rb +10 -21
- data/spec/lib/hubspot/company_properties_spec.rb +8 -11
- data/spec/lib/hubspot/company_spec.rb +18 -36
- data/spec/lib/hubspot/config_spec.rb +24 -14
- data/spec/lib/hubspot/connection_spec.rb +44 -55
- data/spec/lib/hubspot/contact_list_spec.rb +82 -71
- data/spec/lib/hubspot/contact_properties_spec.rb +5 -34
- data/spec/lib/hubspot/contact_spec.rb +2 -4
- data/spec/lib/hubspot/custom_event_spec.rb +28 -0
- data/spec/lib/hubspot/deal_pipeline_spec.rb +4 -15
- data/spec/lib/hubspot/deal_properties_spec.rb +11 -58
- data/spec/lib/hubspot/deal_spec.rb +46 -47
- data/spec/lib/hubspot/engagement_spec.rb +21 -40
- data/spec/lib/hubspot/event_spec.rb +3 -2
- data/spec/lib/hubspot/file_spec.rb +16 -30
- data/spec/lib/hubspot/form_spec.rb +34 -34
- data/spec/lib/hubspot/meeting_spec.rb +81 -0
- data/spec/lib/hubspot/owner_spec.rb +2 -3
- data/spec/lib/hubspot/resource_spec.rb +41 -1
- data/spec/lib/hubspot/utils_spec.rb +6 -39
- data/spec/lib/hubspot-ruby_spec.rb +1 -1
- data/spec/spec_helper.rb +13 -4
- data/spec/support/vcr.rb +4 -6
- metadata +11 -27
- data/lib/tasks/hubspot.rake +0 -53
- data/spec/lib/hubspot/topic_spec.rb +0 -23
- data/spec/lib/tasks/hubspot_spec.rb +0 -119
- data/spec/support/capture_output.rb +0 -21
- data/spec/support/rake.rb +0 -46
- data/spec/support/tests_helper.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4aa748bc77ade29ff96016950aa3f3d8d9bbb309167b200319798d9edf8664bc
|
4
|
+
data.tar.gz: f09d8a29a3dbbcaa18071670e46d4c10c6727731409bbf4a7eee5099d6fd15e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac1c6faae15a4569c92d8061a270f7b55aad7c64eaf2f16bc057b31312204164771600a5ebb511a0d7e0977123baf65b22125f69832dc6b2af63637bb4689814
|
7
|
+
data.tar.gz: 37b874280272f531177bf348d038b5b6e935f2a4edefeef1c1c7d4e5e68c2613047a75ea782daa412053fb8f50c312d6a27d5f264509f758cd6eb82abf1afe8d
|
data/README.md
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
# HubSpot REST API wrappers for ruby
|
2
2
|
|
3
|
-
**This is the master branch and contains unreleased and potentially breaking changes. If you are looking for the most recent stable release you want the [v0-stable branch](https://github.com/adimichele/hubspot-ruby/tree/v0-stable).**
|
4
|
-
|
5
3
|
Wraps the HubSpot REST API for convenient access from ruby applications.
|
6
4
|
|
7
5
|
Documentation for the HubSpot REST API can be found here: https://developers.hubspot.com/docs/endpoints
|
8
6
|
|
7
|
+
## Disclaimer
|
8
|
+
|
9
|
+
This gem is a fork of the unofficial [hubspot-ruby](https://github.com/HubspotCommunity/hubspot-ruby) gem which is unfortunately not maintained anymore.
|
10
|
+
|
11
|
+
The API has evolved quite a bit and while this is not a drop-in replacement you should feel familiar if you come from `hubspot-ruby`.
|
12
|
+
|
13
|
+
This project and the code therein was not created by and is not supported by HubSpot, Inc or any of its affiliates.
|
14
|
+
|
9
15
|
## Setup
|
10
16
|
|
11
17
|
gem install hubspot-api-ruby
|
@@ -24,16 +30,16 @@ Authentication docs].
|
|
24
30
|
Below is a complete list of configuration options with the default values:
|
25
31
|
```ruby
|
26
32
|
Hubspot.configure({
|
27
|
-
|
33
|
+
access_token: <ACCESS_TOKEN>,
|
28
34
|
base_url: "https://api.hubapi.com",
|
29
35
|
portal_id: <PORTAL_ID>,
|
30
36
|
logger: Logger.new(nil),
|
31
|
-
access_token: <ACCESS_TOKEN>,
|
32
37
|
client_id: <CLIENT_ID>,
|
33
38
|
client_secret: <CLIENT_SECRET>,
|
34
39
|
redirect_uri: <REDIRECT_URI>,
|
35
40
|
read_timeout: nil, # or :timeout to set read_timeout and open_timeout
|
36
41
|
open_timeout: nil,
|
42
|
+
hapikey: <HAPIKEY>,
|
37
43
|
})
|
38
44
|
```
|
39
45
|
|
@@ -44,15 +50,20 @@ environment.
|
|
44
50
|
[HubSpot API Authentication Docs]: https://developers.hubspot.com/docs/methods/auth/oauth-overview
|
45
51
|
[HubSpot Developer Tools]: https://developers.hubspot.com/docs/devtools
|
46
52
|
|
47
|
-
## Authentication with
|
53
|
+
## Authentication with a private app access token
|
48
54
|
|
49
|
-
To set the HubSpot
|
55
|
+
To set the HubSpot access token, run the following:
|
50
56
|
```ruby
|
51
|
-
Hubspot.configure(
|
57
|
+
Hubspot.configure(access_token: 'YOUR_ACCESS_TOKEN')
|
52
58
|
```
|
53
59
|
|
54
|
-
|
55
|
-
|
60
|
+
Note: some APIs require the portal ID to be set.
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
Hubspot.configure(access_token: 'YOUR_ACCESS_TOKEN', portal_id: 'YOUR_PORTAL_ID')
|
64
|
+
```
|
65
|
+
|
66
|
+
[To learn how to create and manage private apps and access tokens, click here.](https://developers.hubspot.com/docs/api/private-apps)
|
56
67
|
|
57
68
|
## Authentication with OAuth 2.0
|
58
69
|
|
@@ -105,153 +116,25 @@ Hubspot::OAuth.refresh(refresh_token)
|
|
105
116
|
|
106
117
|
At this time, OAuth tokens are configured globally rather than on a per-connection basis.
|
107
118
|
|
108
|
-
##
|
109
|
-
|
110
|
-
Classes have been created that map to Hubspot resource types and attempt to abstract away as much of the API specific details as possible. These classes generally follow the [ActiveRecord](https://en.wikipedia.org/wiki/Active_record_pattern) pattern and general Ruby conventions. Anyone familiar with [Ruby On Rails](https://rubyonrails.org/) should find this API closely maps with familiar concepts.
|
111
|
-
|
112
|
-
|
113
|
-
### Creating a new resource
|
114
|
-
|
115
|
-
```ruby
|
116
|
-
irb(main):001:0> company = Hubspot::Company.new(name: "My Company LLC.")
|
117
|
-
=> #<Hubspot::Company:0x000055b9219cc068 @changes={"name"=>"My Company LLC."}, @properties={}, @id=nil, @persisted=false, @deleted=false>
|
118
|
-
|
119
|
-
irb(main):002:0> company.persisted?
|
120
|
-
=> false
|
121
|
-
|
122
|
-
irb(main):003:0> company.save
|
123
|
-
=> true
|
124
|
-
|
125
|
-
irb(main):004:0> company.persisted?
|
126
|
-
=> true
|
127
|
-
```
|
128
|
-
|
129
|
-
```ruby
|
130
|
-
irb(main):001:0> company = Hubspot::Company.create(name: "Second Financial LLC.")
|
131
|
-
=> #<Hubspot::Company:0x0000557ea7119fb0 @changes={}, @properties={"hs_lastmodifieddate"=>{"value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"CALCULATED", "sourceId"=>nil, "versions"=>[{"name"=>"hs_lastmodifieddate", "value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"CALCULATED", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}]}, "name"=>{"value"=>"Second Financial LLC.", "timestamp"=>1552234087467, "source"=>"API", "sourceId"=>nil, "versions"=>[{"name"=>"name", "value"=>"Second Financial LLC.", "timestamp"=>1552234087467, "source"=>"API", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}]}, "createdate"=>{"value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"API", "sourceId"=>nil, "versions"=>[{"name"=>"createdate", "value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"API", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}, {"name"=>"createdate", "value"=>"1552234087467", "timestamp"=>1552234087467, "sourceId"=>"API", "source"=>"API", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}]}}, @id=1726317857, @persisted=true, @deleted=false, @metadata={"portalId"=>62515, "companyId"=>1726317857, "isDeleted"=>false, "additionalDomains"=>[], "stateChanges"=>[], "mergeAudits"=>[]}>
|
132
|
-
|
133
|
-
irb(main):002:0> company.persisted?
|
134
|
-
=> true
|
135
|
-
```
|
136
|
-
|
137
|
-
|
138
|
-
### Find an existing resource
|
139
|
-
|
140
|
-
**Note:** Hubspot uses a combination of different names for the "ID" property of a resource based on what type of resource it is (eg. vid for Contact). This library attempts to abstract that away and generalizes an `id` property for all resources
|
141
|
-
|
142
|
-
```ruby
|
143
|
-
irb(main):001:0> company = Hubspot::Company.find(1726317857)
|
144
|
-
=> #<Hubspot::Company:0x0000562e4988c9a8 @changes={}, @properties={"hs_lastmodifieddate"=>{"value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"CALCULATED", "sourceId"=>nil, "versions"=>[{"name"=>"hs_lastmodifieddate", "value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"CALCULATED", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}]}, "name"=>{"value"=>"Second Financial LLC.", "timestamp"=>1552234087467, "source"=>"API", "sourceId"=>nil, "versions"=>[{"name"=>"name", "value"=>"Second Financial LLC.", "timestamp"=>1552234087467, "source"=>"API", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}]}, "createdate"=>{"value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"API", "sourceId"=>nil, "versions"=>[{"name"=>"createdate", "value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"API", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}]}}, @id=1726317857, @persisted=true, @deleted=false, @metadata={"portalId"=>62515, "companyId"=>1726317857, "isDeleted"=>false, "additionalDomains"=>[], "stateChanges"=>[], "mergeAudits"=>[]}>
|
145
|
-
|
146
|
-
irb(main):002:0> company = Hubspot::Company.find(1)
|
147
|
-
Traceback (most recent call last):
|
148
|
-
6: from ./hubspot-api-ruby/bin/console:20:in `<main>'
|
149
|
-
5: from (irb):2
|
150
|
-
4: from ./hubspot-api-ruby/lib/hubspot/resource.rb:17:in `find'
|
151
|
-
3: from ./hubspot-api-ruby/lib/hubspot/resource.rb:81:in `reload'
|
152
|
-
2: from ./hubspot-api-ruby/lib/hubspot/connection.rb:10:in `get_json'
|
153
|
-
1: from ./hubspot-api-ruby/lib/hubspot/connection.rb:52:in `handle_response'
|
154
|
-
Hubspot::RequestError (Response body: {"status":"error","message":"resource not found","correlationId":"7c8ba50e-16a4-4a52-a304-ff249175a8f1","requestId":"b4898274bf8992924082b4a460b90cbe"})
|
155
|
-
```
|
156
|
-
|
157
|
-
|
158
|
-
### Updating resource properties
|
159
|
-
|
160
|
-
```ruby
|
161
|
-
irb(main):001:0> company = Hubspot::Company.find(1726317857)
|
162
|
-
=> #<Hubspot::Company:0x0000563b9f3ee230 @changes={}, @properties={"hs_lastmodifieddate"=>{"value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"CALCULATED", "sourceId"=>nil, "versions"=>[{"name"=>"hs_lastmodifieddate", "value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"CALCULATED", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}]}, "name"=>{"value"=>"Second Financial LLC.", "timestamp"=>1552234087467, "source"=>"API", "sourceId"=>nil, "versions"=>[{"name"=>"name", "value"=>"Second Financial LLC.", "timestamp"=>1552234087467, "source"=>"API", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}]}, "createdate"=>{"value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"API", "sourceId"=>nil, "versions"=>[{"name"=>"createdate", "value"=>"1552234087467", "timestamp"=>1552234087467, "source"=>"API", "sourceVid"=>[], "requestId"=>"fd45773b-30d0-4d9d-b3b8-a85e01534e46"}]}}, @id=1726317857, @persisted=true, @deleted=false, @metadata={"portalId"=>62515, "companyId"=>1726317857, "isDeleted"=>false, "additionalDomains"=>[], "stateChanges"=>[], "mergeAudits"=>[]}>
|
163
|
-
|
164
|
-
irb(main):002:0> company.name
|
165
|
-
=> "Second Financial LLC."
|
166
|
-
|
167
|
-
irb(main):003:0> company.name = "Third Financial LLC."
|
168
|
-
=> "Third Financial LLC."
|
169
|
-
|
170
|
-
irb(main):004:0> company.changed?
|
171
|
-
=> true
|
172
|
-
|
173
|
-
irb(main):005:0> company.changes
|
174
|
-
=> {:name=>"Third Financial LLC."}
|
175
|
-
|
176
|
-
irb(main):006:0> company.save
|
177
|
-
=> true
|
178
|
-
|
179
|
-
irb(main):007:0> company.changed?
|
180
|
-
=> false
|
181
|
-
|
182
|
-
irb(main):008:0> company.changes
|
183
|
-
=> {}
|
184
|
-
```
|
185
|
-
|
186
|
-
**Note:** Unlike ActiveRecord in Rails, in some cases not all properties of a resource are known. If these properties are not returned by the API then they will not have a getter method defined for them until they've been set first. This may change in the future to improve the user experience and different methods are being tested.
|
187
|
-
|
188
|
-
```ruby
|
189
|
-
irb(main):001:0> company = Hubspot::Company.new
|
190
|
-
=> #<Hubspot::Company:0x0000561d0a8bdff8 @changes={}, @properties={}, @id=nil, @persisted=false, @deleted=false>
|
191
|
-
|
192
|
-
irb(main):002:0> company.name
|
193
|
-
Traceback (most recent call last):
|
194
|
-
3: from ./hubspot-api-ruby/bin/console:20:in `<main>'
|
195
|
-
2: from (irb):2
|
196
|
-
1: from ./hubspot-api-ruby/lib/hubspot/resource.rb:215:in `method_missing'
|
197
|
-
NoMethodError (undefined method `name' for #<Hubspot::Company:0x0000561d0a8bdff8>)
|
198
|
-
|
199
|
-
irb(main):003:0> company.name = "Foobar"
|
200
|
-
=> "Foobar"
|
201
|
-
|
202
|
-
irb(main):004:0> company.name
|
203
|
-
=> "Foobar"
|
204
|
-
```
|
205
|
-
|
206
|
-
### Collections
|
119
|
+
## Authentication with an API key
|
207
120
|
|
208
|
-
|
121
|
+
NOTE: API keys are deprecated. [Read more here](https://developers.hubspot.com/changelog/upcoming-api-key-sunset) and [find out how to migrate to private apps there](https://developers.hubspot.com/docs/api/migrate-an-api-key-integration-to-a-private-app).
|
209
122
|
|
123
|
+
To set the HubSpot API key, aka `hapikey`, run the following:
|
210
124
|
```ruby
|
211
|
-
|
212
|
-
=> #<Hubspot::PagedCollection:0x000055ba3c2b55d8 @limit_param="limit", @limit=25, @offset_param="offset", @offset=nil, @options={}, @fetch_proc=#<Proc:0x000055ba3c2b5538@./hubspot-api-ruby/lib/hubspot/contact.rb:18>, @resources=[...snip...], @next_offset=9242374, @has_more=true>
|
213
|
-
|
214
|
-
irb(main):002:0> contacts.more?
|
215
|
-
=> true
|
216
|
-
|
217
|
-
irb(main):003:0> contacts.next_offset
|
218
|
-
=> 9242374
|
219
|
-
|
220
|
-
irb(main):004:0> contacts.size
|
221
|
-
=> 25
|
222
|
-
|
223
|
-
irb(main):005:0> contacts.first
|
224
|
-
=> #<Hubspot::Contact:0x000055ba3c29bac0 @changes={}, @properties={"firstname"=>{"value"=>"My Street X 1551971239 => My Street X 1551971267 => My Street X 1551971279"}, "lastmodifieddate"=>{"value"=>"1551971286841"}, "company"=>{"value"=>"MadKudu"}, "lastname"=>{"value"=>"Test0830181615"}}, @id=9153674, @persisted=true, @deleted=false, @metadata={"addedAt"=>1535664601481, "vid"=>9153674, "canonical-vid"=>9153674, "merged-vids"=>[], "portal-id"=>62515, "is-contact"=>true, "profile-token"=>"AO_T-mPNHk6O7jh8u8D2IlrhZn7GO91w-weZrC93_UaJvdB0U4o6Uc_PkPJ3DOpf15sUplrxMzG9weiTTpPI05Nr04zxnaNYBVcWHOlMbVlJ2Avq1KGoCBVbIoQucOy_YmCBIfOXRtcc", "profile-url"=>"https://app.hubspot.com/contacts/62515/contact/9153674", "form-submissions"=>[], "identity-profiles"=>[{"vid"=>9153674, "saved-at-timestamp"=>1535664601272, "deleted-changed-timestamp"=>0, "identities"=>[{"type"=>"EMAIL", "value"=>"test.0830181615@test.com", "timestamp"=>1535664601151, "is-primary"=>true}, {"type"=>"LEAD_GUID", "value"=>"01a107c4-3872-44e0-ab2e-47061507ffa1", "timestamp"=>1535664601259}]}], "merge-audits"=>[]}>
|
225
|
-
|
226
|
-
irb(main):006:0> contacts.next_page
|
227
|
-
=> #<Hubspot::PagedCollection:0x000055ba3c2b55d8 @limit_param="limit", @limit=25, @offset_param="offset", @offset=9242374, @options={}, @fetch_proc=#<Proc:0x000055ba3c2b5538@./hubspot-api-ruby/lib/hubspot/contact.rb:18>, @resources=[...snip...], @next_offset=9324874, @has_more=true>
|
125
|
+
Hubspot.configure(hapikey: "YOUR_API_KEY")
|
228
126
|
```
|
229
127
|
|
230
|
-
|
231
|
-
|
232
|
-
```ruby
|
233
|
-
irb(main):001:0> companies = Hubspot::Company.all(limit: 5)
|
234
|
-
=> #<Hubspot::PagedCollection:0x000055d5314fe0c8 @limit_param="limit", @limit=5, @offset_param="offset", @offset=nil, @options={}, @fetch_proc=#<Proc:0x000055d5314fe028@./hubspot-api-ruby/lib/hubspot/company.rb:21>, @resources=[...snip...], @next_offset=116011506, @has_more=true>
|
235
|
-
|
236
|
-
irb(main):002:0> companies.size
|
237
|
-
=> 5
|
238
|
-
|
239
|
-
irb(main):003:0> companies.update_all(lifecyclestage: "opportunity")
|
240
|
-
=> true
|
128
|
+
If you have a HubSpot account, you can find your API key by logging in and
|
129
|
+
visiting: https://app.hubspot.com/keys/get
|
241
130
|
|
242
|
-
|
243
|
-
=> #<Hubspot::PagedCollection:0x000055d5314fe0c8 @limit_param="limit", @limit=5, @offset_param="offset", @offset=nil, @options={}, @fetch_proc=#<Proc:0x000055d5314fe028@./hubspot-api-ruby/lib/hubspot/company.rb:21>, @resources=[...snip...], @next_offset=116011506, @has_more=true>
|
244
|
-
```
|
131
|
+
## Usage
|
245
132
|
|
246
|
-
|
133
|
+
Classes have been created that map to Hubspot resource types and attempt to abstract away as much of the API specific details as possible. These classes generally follow the [ActiveRecord](https://en.wikipedia.org/wiki/Active_record_pattern) pattern and general Ruby conventions. Anyone familiar with [Ruby On Rails](https://rubyonrails.org/) should find this API closely maps with familiar concepts.
|
247
134
|
|
248
|
-
|
249
|
-
irb(main):001:0> contact = Hubspot::Contact.find(9324874)
|
250
|
-
=> #<Hubspot::Contact:0x000055a87c87aee0 ...snip... >
|
135
|
+
### Example
|
251
136
|
|
252
|
-
|
253
|
-
=> true
|
254
|
-
```
|
137
|
+
https://github.com/lounna-sas/hubspot-api-ruby/wiki
|
255
138
|
|
256
139
|
## Resource types
|
257
140
|
|
@@ -281,15 +164,18 @@ By default, the VCR recording mode is set to `:none`, which allows recorded
|
|
281
164
|
requests to be re-played but raises for any new request. This prevents the test
|
282
165
|
suite from issuing unexpected HTTP requests.
|
283
166
|
|
284
|
-
|
285
|
-
environment variable:
|
167
|
+
Some requests require to be done on a live hubspot portal, you can set the `HUBSPOT_ACCESS_TOKEN` and `HUBSPOT_PORTAL_ID` environement variables, for example inside a `.env.test` file :
|
286
168
|
|
287
|
-
```
|
288
|
-
|
169
|
+
```
|
170
|
+
HUBSPOT_ACCESS_TOKEN=xxxx
|
171
|
+
HUBSPOT_PORTAL_ID=yyyy
|
289
172
|
```
|
290
173
|
|
291
|
-
|
174
|
+
To add a new test or update a VCR recording, run the test with the `VCR_RECORD_MODE`
|
175
|
+
environment variable, for instance:
|
292
176
|
|
293
|
-
|
177
|
+
```sh
|
178
|
+
VCR_RECORD_MODE=new_episodes bundle exec rspec spec
|
179
|
+
```
|
294
180
|
|
295
|
-
|
181
|
+
[VCR]: https://github.com/vcr/vcr
|
data/Rakefile
CHANGED
data/hubspot-api-ruby.gemspec
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "hubspot-api-ruby"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.10.0"
|
4
4
|
s.require_paths = ["lib"]
|
5
|
-
s.authors = ["Jonathan"
|
6
|
-
s.email = ["jonathan@hoggo.com"
|
5
|
+
s.authors = ["Jonathan"]
|
6
|
+
s.email = ["jonathan@hoggo.com"]
|
7
7
|
s.description = "hubspot-api-ruby is a wrapper for the HubSpot REST API"
|
8
8
|
s.licenses = ["MIT"]
|
9
9
|
s.files = [".rspec", "Gemfile", "Guardfile", "LICENSE.txt", "README.md", "RELEASING.md", "Rakefile", "hubspot-api-ruby.gemspec"]
|
10
10
|
s.files += Dir["lib/**/*.rb"]
|
11
|
-
s.files += Dir["lib/**/*.rake"]
|
12
11
|
s.files += Dir["spec/**/*.rb"]
|
13
|
-
s.homepage = "
|
12
|
+
s.homepage = "https://github.com/captaincontrat/hubspot-api-ruby"
|
14
13
|
s.summary = "hubspot-api-ruby is a wrapper for the HubSpot REST API"
|
15
14
|
s.metadata = {
|
16
|
-
"changelog_uri" => "https://github.com/
|
15
|
+
"changelog_uri" => "https://github.com/captaincontrat/hubspot-api-ruby/blob/master/History.md"
|
17
16
|
}
|
18
17
|
|
19
18
|
s.required_ruby_version = ">= 2.3"
|
@@ -23,7 +22,6 @@ Gem::Specification.new do |s|
|
|
23
22
|
s.add_runtime_dependency "httparty", ">= 0.10"
|
24
23
|
|
25
24
|
# Add development-only dependencies here
|
26
|
-
s.add_development_dependency("appraisal", "~> 2.2")
|
27
25
|
s.add_development_dependency("dotenv")
|
28
26
|
s.add_development_dependency("rake", "~> 11.0")
|
29
27
|
s.add_development_dependency("rspec", "~> 3.8")
|
@@ -0,0 +1,106 @@
|
|
1
|
+
class Hubspot::Association
|
2
|
+
OBJECT_TARGET_TO_CLASS = {
|
3
|
+
"Contact" => Hubspot::Contact,
|
4
|
+
"Deal" => Hubspot::Deal,
|
5
|
+
"Company" => Hubspot::Company
|
6
|
+
}.freeze
|
7
|
+
|
8
|
+
ASSOCIATION_DEFINITIONS = {
|
9
|
+
"Company" => {
|
10
|
+
"Contact" => 2,
|
11
|
+
"Deal" => 6,
|
12
|
+
"Company" => 13
|
13
|
+
},
|
14
|
+
"Deal" => {
|
15
|
+
"Company" => 5,
|
16
|
+
"Contact" => 3
|
17
|
+
},
|
18
|
+
"Contact" => {
|
19
|
+
"Deal" => 4
|
20
|
+
}
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def create(object_type, object_id, to_object_type, to_object_id)
|
25
|
+
batch_create(object_type, to_object_type, [{from_id: object_id, to_id: to_object_id}])
|
26
|
+
end
|
27
|
+
|
28
|
+
# Make multiple associations in a single API call
|
29
|
+
# {https://developers.hubspot.com/docs/api/crm/associations}
|
30
|
+
# usage:
|
31
|
+
# Hubspot::Association.batch_create("Company", "Contact", [{from_id: 1, to_id: 2}]])
|
32
|
+
def batch_create(from_object_type, to_object_type, associations)
|
33
|
+
definition_id = ASSOCIATION_DEFINITIONS.dig(from_object_type, to_object_type)
|
34
|
+
request = { inputs: associations.map { |assocation| build_create_association_body(assocation, definition_id) } }
|
35
|
+
response = Hubspot::Connection.post_json("/crm/v4/associations/#{from_object_type}/#{to_object_type}/batch/create", params: { no_parse: true }, body: request)
|
36
|
+
return false if response.parsed_response["errors"].present?
|
37
|
+
|
38
|
+
response.success?
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(object_type, object_id, to_object_type, to_object_id)
|
42
|
+
batch_delete(object_type, to_object_type, [{from_id: object_id, to_id: to_object_id}])
|
43
|
+
end
|
44
|
+
|
45
|
+
# Remove multiple associations in a single API call
|
46
|
+
# {https://developers.hubspot.com/docs/api/crm/associations}
|
47
|
+
# usage:
|
48
|
+
# Hubspot::Association.batch_delete("Company", "Contact", [{ from_id: 1, to_id: 2}])
|
49
|
+
def batch_delete(from_object_type, to_object_type, associations)
|
50
|
+
request = { inputs: build_delete_associations_body(associations) }
|
51
|
+
Hubspot::Connection.post_json("/crm/v4/associations/#{from_object_type}/#{to_object_type}/batch/archive", params: { no_parse: true }, body: request).success?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Retrieve all associated resources given a source (object_type and object_id) and a relation type (to_object_type)
|
55
|
+
# {https://developers.hubspot.com/docs/api/crm/associations}
|
56
|
+
# Warning: it will return at most 1000 objects and make up to 1001 queries
|
57
|
+
# Hubspot::Association.all("Company", 42, "Contact")
|
58
|
+
def all(object_type, object_id, to_object_type)
|
59
|
+
klass = OBJECT_TARGET_TO_CLASS[to_object_type]
|
60
|
+
raise(Hubspot::InvalidParams, 'Object type not supported') unless klass.present?
|
61
|
+
|
62
|
+
response = Hubspot::Connection.get_json("/crm/v4/objects/#{object_type}/#{object_id}/associations/#{to_object_type}", {})
|
63
|
+
response['results'].map { |result| klass.find(result["toObjectId"]) }
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def build_create_association_body(association, definition_id)
|
69
|
+
{
|
70
|
+
from: {
|
71
|
+
id: association[:from_id]
|
72
|
+
},
|
73
|
+
to: {
|
74
|
+
id: association[:to_id]
|
75
|
+
},
|
76
|
+
types: [
|
77
|
+
{
|
78
|
+
associationCategory: "HUBSPOT_DEFINED",
|
79
|
+
associationTypeId: definition_id
|
80
|
+
}
|
81
|
+
]
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_delete_associations_body(associations)
|
86
|
+
normalized_associations = associations.inject({}) do |memo, association|
|
87
|
+
memo[association[:from_id]] ||= []
|
88
|
+
memo[association[:from_id]] << association[:to_id]
|
89
|
+
memo
|
90
|
+
end
|
91
|
+
|
92
|
+
normalized_associations.map do |from_id, to_ids|
|
93
|
+
{
|
94
|
+
from: {
|
95
|
+
id: from_id
|
96
|
+
},
|
97
|
+
to: to_ids.map do |to_id|
|
98
|
+
{
|
99
|
+
id: to_id
|
100
|
+
}
|
101
|
+
end
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/hubspot/company.rb
CHANGED
@@ -2,7 +2,6 @@ class Hubspot::Company < Hubspot::Resource
|
|
2
2
|
self.id_field = "companyId"
|
3
3
|
self.property_name_field = "name"
|
4
4
|
|
5
|
-
ADD_CONTACT_PATH = '/companies/v2/companies/:id/contacts/:contact_id'
|
6
5
|
ALL_PATH = '/companies/v2/companies/paged'
|
7
6
|
BATCH_UPDATE_PATH = '/companies/v1/batch-async/update'
|
8
7
|
CONTACTS_PATH = '/companies/v2/companies/:id/contacts'
|
@@ -12,7 +11,6 @@ class Hubspot::Company < Hubspot::Resource
|
|
12
11
|
FIND_PATH = '/companies/v2/companies/:id'
|
13
12
|
RECENTLY_CREATED_PATH = '/companies/v2/companies/recent/created'
|
14
13
|
RECENTLY_MODIFIED_PATH = '/companies/v2/companies/recent/modified'
|
15
|
-
REMOVE_CONTACT_PATH = '/companies/v2/companies/:id/contacts/:contact_id'
|
16
14
|
SEARCH_DOMAIN_PATH = '/companies/v2/domains/:domain/companies'
|
17
15
|
UPDATE_PATH = '/companies/v2/companies/:id'
|
18
16
|
|
@@ -80,20 +78,11 @@ class Hubspot::Company < Hubspot::Resource
|
|
80
78
|
end
|
81
79
|
|
82
80
|
def add_contact(id, contact_id)
|
83
|
-
Hubspot::
|
84
|
-
ADD_CONTACT_PATH,
|
85
|
-
params: { id: id, contact_id: contact_id }
|
86
|
-
)
|
87
|
-
true
|
81
|
+
Hubspot::Association.create("Company", id, "Contact", contact_id)
|
88
82
|
end
|
89
83
|
|
90
84
|
def remove_contact(id, contact_id)
|
91
|
-
Hubspot::
|
92
|
-
REMOVE_CONTACT_PATH,
|
93
|
-
{ id: id, contact_id: contact_id }
|
94
|
-
)
|
95
|
-
|
96
|
-
true
|
85
|
+
Hubspot::Association.delete("Company", id, "Contact", contact_id)
|
97
86
|
end
|
98
87
|
|
99
88
|
def batch_update(companies, opts = {})
|
data/lib/hubspot/config.rb
CHANGED
@@ -5,7 +5,7 @@ module Hubspot
|
|
5
5
|
class Config
|
6
6
|
CONFIG_KEYS = [
|
7
7
|
:hapikey, :base_url, :portal_id, :logger, :access_token, :client_id,
|
8
|
-
:client_secret, :redirect_uri, :read_timeout, :open_timeout
|
8
|
+
:client_secret, :redirect_uri, :read_timeout, :open_timeout, :custom_event_prefix
|
9
9
|
]
|
10
10
|
DEFAULT_LOGGER = Logger.new(nil)
|
11
11
|
DEFAULT_BASE_URL = "https://api.hubapi.com".freeze
|
@@ -15,21 +15,26 @@ module Hubspot
|
|
15
15
|
|
16
16
|
def configure(config)
|
17
17
|
config.stringify_keys!
|
18
|
-
@hapikey = config[
|
19
|
-
@base_url = config[
|
20
|
-
@portal_id = config[
|
21
|
-
@logger = config[
|
22
|
-
@access_token = config[
|
23
|
-
@client_id = config[
|
24
|
-
@client_secret = config[
|
25
|
-
@redirect_uri = config[
|
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
26
|
@read_timeout = config['read_timeout'] || config['timeout']
|
27
27
|
@open_timeout = config['open_timeout'] || config['timeout']
|
28
|
+
@custom_event_prefix = config['custom_event_prefix']
|
28
29
|
|
29
30
|
unless authentication_uncertain?
|
30
31
|
raise Hubspot::ConfigurationError.new("You must provide either an access_token or an hapikey")
|
31
32
|
end
|
32
33
|
|
34
|
+
if hapikey.present?
|
35
|
+
Hubspot::Deprecator.build.deprecation_warning("hapikey", "please use access_token instead. See https://developers.hubspot.com/docs/api/migrate-an-api-key-integration-to-a-private-app")
|
36
|
+
end
|
37
|
+
|
33
38
|
if access_token.present?
|
34
39
|
Hubspot::Connection.headers("Authorization" => "Bearer #{access_token}")
|
35
40
|
end
|
data/lib/hubspot/connection.rb
CHANGED
@@ -7,7 +7,7 @@ module Hubspot
|
|
7
7
|
url = generate_url(path, opts)
|
8
8
|
response = get(url, format: :json, read_timeout: read_timeout(opts), open_timeout: open_timeout(opts))
|
9
9
|
log_request_and_response url, response
|
10
|
-
handle_response(response)
|
10
|
+
handle_response(response).parsed_response
|
11
11
|
end
|
12
12
|
|
13
13
|
def post_json(path, opts)
|
@@ -24,9 +24,9 @@ module Hubspot
|
|
24
24
|
)
|
25
25
|
|
26
26
|
log_request_and_response url, response, opts[:body]
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
handle_response(response).yield_self do |r|
|
28
|
+
no_parse ? r : r.parsed_response
|
29
|
+
end
|
30
30
|
end
|
31
31
|
|
32
32
|
def put_json(path, options)
|
@@ -43,17 +43,16 @@ module Hubspot
|
|
43
43
|
)
|
44
44
|
|
45
45
|
log_request_and_response(url, response, options[:body])
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
handle_response(response).yield_self do |r|
|
47
|
+
no_parse ? r : r.parsed_response
|
48
|
+
end
|
49
49
|
end
|
50
50
|
|
51
51
|
def delete_json(path, opts)
|
52
52
|
url = generate_url(path, opts)
|
53
53
|
response = delete(url, format: :json, read_timeout: read_timeout(opts), open_timeout: open_timeout(opts))
|
54
54
|
log_request_and_response url, response, opts[:body]
|
55
|
-
|
56
|
-
response
|
55
|
+
handle_response(response)
|
57
56
|
end
|
58
57
|
|
59
58
|
protected
|
@@ -67,11 +66,10 @@ module Hubspot
|
|
67
66
|
end
|
68
67
|
|
69
68
|
def handle_response(response)
|
70
|
-
if response.success?
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
69
|
+
return response if response.success?
|
70
|
+
|
71
|
+
raise(Hubspot::NotFoundError.new(response)) if response.not_found?
|
72
|
+
raise(Hubspot::RequestError.new(response))
|
75
73
|
end
|
76
74
|
|
77
75
|
def log_request_and_response(uri, response, body=nil)
|
@@ -149,4 +147,12 @@ module Hubspot
|
|
149
147
|
get(url, body: opts[:body], headers: opts[:headers])
|
150
148
|
end
|
151
149
|
end
|
150
|
+
|
151
|
+
class CustomEventConnection < Connection
|
152
|
+
def self.trigger(path, opts)
|
153
|
+
url = generate_url(path, opts[:params], { hapikey: true })
|
154
|
+
headers = (opts[:headers] || {}).merge('content-type': 'application/json')
|
155
|
+
post(url, body: opts[:body].to_json, headers: headers)
|
156
|
+
end
|
157
|
+
end
|
152
158
|
end
|
data/lib/hubspot/contact.rb
CHANGED
@@ -12,7 +12,6 @@ class Hubspot::Contact < Hubspot::Resource
|
|
12
12
|
MERGE_PATH = '/contacts/v1/contact/merge-vids/:id/'
|
13
13
|
SEARCH_PATH = '/contacts/v1/search/query'
|
14
14
|
UPDATE_PATH = '/contacts/v1/contact/vid/:id/profile'
|
15
|
-
UPDATE_PATH = '/contacts/v1/contact/vid/:id/profile'
|
16
15
|
BATCH_UPDATE_PATH = '/contacts/v1/contact/batch'
|
17
16
|
|
18
17
|
class << self
|
@@ -28,6 +27,11 @@ class Hubspot::Contact < Hubspot::Resource
|
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
30
|
+
def find_by_vid(vid)
|
31
|
+
response = Hubspot::Connection.get_json(FIND_PATH, id: vid)
|
32
|
+
from_result(response)
|
33
|
+
end
|
34
|
+
|
31
35
|
def find_by_email(email)
|
32
36
|
response = Hubspot::Connection.get_json(FIND_BY_EMAIL_PATH, email: email)
|
33
37
|
from_result(response)
|
data/lib/hubspot/contact_list.rb
CHANGED
@@ -10,7 +10,6 @@ module Hubspot
|
|
10
10
|
RECENT_CONTACTS_PATH = LIST_PATH + '/contacts/recent'
|
11
11
|
ADD_CONTACT_PATH = LIST_PATH + '/add'
|
12
12
|
REMOVE_CONTACT_PATH = LIST_PATH + '/remove'
|
13
|
-
REFRESH_PATH = LIST_PATH + '/refresh'
|
14
13
|
|
15
14
|
class << self
|
16
15
|
# {http://developers.hubspot.com/docs/methods/lists/create_list}
|
@@ -92,12 +91,6 @@ module Hubspot
|
|
92
91
|
end
|
93
92
|
end
|
94
93
|
|
95
|
-
# {http://developers.hubspot.com/docs/methods/lists/refresh_list}
|
96
|
-
def refresh
|
97
|
-
response = Hubspot::Connection.post_json(REFRESH_PATH, params: { list_id: @id, no_parse: true }, body: {})
|
98
|
-
response.code == 204
|
99
|
-
end
|
100
|
-
|
101
94
|
# {http://developers.hubspot.com/docs/methods/lists/add_contact_to_list}
|
102
95
|
def add(contacts)
|
103
96
|
contact_ids = [contacts].flatten.uniq.compact.map(&:id)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'hubspot/utils'
|
2
|
+
|
3
|
+
module Hubspot
|
4
|
+
#
|
5
|
+
# HubSpot Custom Behavioral Events HTTP API
|
6
|
+
#
|
7
|
+
# {https://developers.hubspot.com/docs/api/analytics/events}
|
8
|
+
#
|
9
|
+
class CustomEvent
|
10
|
+
POST_EVENT_PATH = '/events/v3/send'
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def trigger(event_name, email, properties, options = {})
|
14
|
+
options[:params] ||= {}
|
15
|
+
options[:body] ||= {}
|
16
|
+
options[:body].merge!(
|
17
|
+
eventName: "#{Hubspot::Config.custom_event_prefix}_#{event_name}",
|
18
|
+
email: email,
|
19
|
+
properties: properties
|
20
|
+
)
|
21
|
+
Hubspot::CustomEventConnection.trigger(POST_EVENT_PATH, options).success?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|