hubspot-api-ruby 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -154
  3. data/Rakefile +0 -2
  4. data/hubspot-api-ruby.gemspec +5 -7
  5. data/lib/hubspot/association.rb +106 -0
  6. data/lib/hubspot/company.rb +2 -13
  7. data/lib/hubspot/config.rb +14 -9
  8. data/lib/hubspot/connection.rb +20 -14
  9. data/lib/hubspot/contact.rb +5 -1
  10. data/lib/hubspot/contact_list.rb +0 -7
  11. data/lib/hubspot/custom_event.rb +25 -0
  12. data/lib/hubspot/deal.rb +53 -32
  13. data/lib/hubspot/engagement.rb +0 -1
  14. data/lib/hubspot/exceptions.rb +2 -0
  15. data/lib/hubspot/file.rb +2 -2
  16. data/lib/hubspot/meeting.rb +44 -0
  17. data/lib/hubspot/properties.rb +1 -1
  18. data/lib/hubspot/railtie.rb +0 -4
  19. data/lib/hubspot/resource.rb +4 -4
  20. data/lib/hubspot/utils.rb +0 -30
  21. data/lib/hubspot-api-ruby.rb +3 -0
  22. data/spec/lib/hubspot/association_spec.rb +165 -0
  23. data/spec/lib/hubspot/blog_spec.rb +10 -21
  24. data/spec/lib/hubspot/company_properties_spec.rb +8 -11
  25. data/spec/lib/hubspot/company_spec.rb +18 -36
  26. data/spec/lib/hubspot/config_spec.rb +24 -14
  27. data/spec/lib/hubspot/connection_spec.rb +44 -55
  28. data/spec/lib/hubspot/contact_list_spec.rb +82 -71
  29. data/spec/lib/hubspot/contact_properties_spec.rb +5 -34
  30. data/spec/lib/hubspot/contact_spec.rb +2 -4
  31. data/spec/lib/hubspot/custom_event_spec.rb +28 -0
  32. data/spec/lib/hubspot/deal_pipeline_spec.rb +4 -15
  33. data/spec/lib/hubspot/deal_properties_spec.rb +11 -58
  34. data/spec/lib/hubspot/deal_spec.rb +46 -47
  35. data/spec/lib/hubspot/engagement_spec.rb +21 -40
  36. data/spec/lib/hubspot/event_spec.rb +3 -2
  37. data/spec/lib/hubspot/file_spec.rb +16 -30
  38. data/spec/lib/hubspot/form_spec.rb +34 -34
  39. data/spec/lib/hubspot/meeting_spec.rb +81 -0
  40. data/spec/lib/hubspot/owner_spec.rb +2 -3
  41. data/spec/lib/hubspot/resource_spec.rb +41 -1
  42. data/spec/lib/hubspot/utils_spec.rb +6 -39
  43. data/spec/lib/hubspot-ruby_spec.rb +1 -1
  44. data/spec/spec_helper.rb +13 -4
  45. data/spec/support/vcr.rb +4 -6
  46. metadata +11 -27
  47. data/lib/tasks/hubspot.rake +0 -53
  48. data/spec/lib/hubspot/topic_spec.rb +0 -23
  49. data/spec/lib/tasks/hubspot_spec.rb +0 -119
  50. data/spec/support/capture_output.rb +0 -21
  51. data/spec/support/rake.rb +0 -46
  52. data/spec/support/tests_helper.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8c321bf08699c556e265ef8bb24a6f66ad0993ed284a66adb4dacbcc5263748
4
- data.tar.gz: 9a9fd7fccb6ac668affde2373ed824a3f5ac95fc7ed1ca6afc90e7e523dcd83e
3
+ metadata.gz: 4aa748bc77ade29ff96016950aa3f3d8d9bbb309167b200319798d9edf8664bc
4
+ data.tar.gz: f09d8a29a3dbbcaa18071670e46d4c10c6727731409bbf4a7eee5099d6fd15e2
5
5
  SHA512:
6
- metadata.gz: 872f7fc25b8acfd21ca29fa0223f36506993581ced761f90838adcb5425bad857bec190f5b804f9c466f1919988d76e80b5834004228e722ca920216b2b92406
7
- data.tar.gz: f9608077e1a5346205baf9216259fbfdee3e6d49f1abac18ac05e5226b3c05db86b61c0ed6d0e266510c2b9cd898e899da66e12335bdf8a4b2796677bac788ff
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
- hapikey: <HAPIKEY>,
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 an API key
53
+ ## Authentication with a private app access token
48
54
 
49
- To set the HubSpot API key, aka `hapikey`, run the following:
55
+ To set the HubSpot access token, run the following:
50
56
  ```ruby
51
- Hubspot.configure(hapikey: "YOUR_API_KEY")
57
+ Hubspot.configure(access_token: 'YOUR_ACCESS_TOKEN')
52
58
  ```
53
59
 
54
- If you have a HubSpot account, you can find your API key by logging in and
55
- visiting: https://app.hubspot.com/keys/get
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
- ## Usage
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
- To make working with API endpoints that return multiple resources easier, the returned instances will be wrapped in a collection instance. Just like in Rails, the collection instance provides helper methods for limiting the number of returned resources, paging through the results, and handles passing the options each time a new API call is made. The collection exposes all Ruby Array methods so you can use things like `size()`, `first()`, `last()`, and `map()`.
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
- irb(main):001:0> contacts = Hubspot::Contact.all
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
- For Hubspot resources that support batch updates for updating multiple resources, the collection provides an `update_all()` method:
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
- irb(main):004:0> companies.refresh
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
- ### Deleting a resource
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
- ```ruby
249
- irb(main):001:0> contact = Hubspot::Contact.find(9324874)
250
- => #<Hubspot::Contact:0x000055a87c87aee0 ...snip... >
135
+ ### Example
251
136
 
252
- irb(main):002:0> contact.delete
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
- To add a new test or update a VCR recording, run the test with the `VCR_RECORD`
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
- ```sh
288
- VCR_RECORD=1 bundle exec rspec spec
169
+ ```
170
+ HUBSPOT_ACCESS_TOKEN=xxxx
171
+ HUBSPOT_PORTAL_ID=yyyy
289
172
  ```
290
173
 
291
- [VCR]: https://github.com/vcr/vcr
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
- ## Disclaimer
177
+ ```sh
178
+ VCR_RECORD_MODE=new_episodes bundle exec rspec spec
179
+ ```
294
180
 
295
- This project and the code therein was not created by and is not supported by HubSpot, Inc or any of its affiliates.
181
+ [VCR]: https://github.com/vcr/vcr
data/Rakefile CHANGED
@@ -28,5 +28,3 @@ Rake::RDocTask.new do |rdoc|
28
28
  rdoc.rdoc_files.include('README*')
29
29
  rdoc.rdoc_files.include('lib/**/*.rb')
30
30
  end
31
-
32
- Dir.glob('lib/tasks/*.rake').each { |r| load r }
@@ -1,19 +1,18 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "hubspot-api-ruby"
3
- s.version = "0.8.0"
3
+ s.version = "0.10.0"
4
4
  s.require_paths = ["lib"]
5
- s.authors = ["Jonathan", "Juliette"]
6
- s.email = ["jonathan@hoggo.com", "juliette@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 = "http://github.com/lounna-sas/hubspot-api-ruby"
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/lounna-sas/hubspot-api-ruby/blob/master/History.md"
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
@@ -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::Connection.put_json(
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::Connection.delete_json(
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 = {})
@@ -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["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?
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
@@ -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
- raise(Hubspot::RequestError.new(response)) unless response.success?
28
-
29
- no_parse ? response : response.parsed_response
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
- raise(Hubspot::RequestError.new(response)) unless response.success?
47
-
48
- no_parse ? response : response.parsed_response
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
- raise(Hubspot::RequestError.new(response)) unless response.success?
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
- response.parsed_response
72
- else
73
- raise(Hubspot::RequestError.new(response))
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
@@ -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)
@@ -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