hubspot-api-ruby 0.8.1 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5039b18c952923db03dbe7f0ae2f1ae676008179860804e34182298e6acbbcfb
4
- data.tar.gz: 13a047c2ff4858e64cd00c173513bf0643d79ba9dc9b815d6017c148af6bf2fb
3
+ metadata.gz: adea84341de555a5a7b9d83e03f8aa1013484015ad17d151f4876e9f2bd02293
4
+ data.tar.gz: 16380d38efaea5c290d2d3b969e76b7501f81beab80a2bec1b8dee6209c5bc57
5
5
  SHA512:
6
- metadata.gz: 17ac11777f8b4c3bb6e95f29a43ffb3ae6b1cba2ab1a27f37c423390fd6603bad8a9b140ebcaaca3df2a74995407dbcafadeceeb853a950fdb0fb8d5a0f289a3
7
- data.tar.gz: ae7cfcbbdf2a34c7cec6505f34144436f055f7902cb1d8497845d33fff0fc25f90376c6bd221c2c4fb9c59b8cf4dc44efdb75479a6a2322bcd6970bb3b76ff43
6
+ metadata.gz: 3ca148e0b2648da567d90d312cf979b1bcf8f840ed56393623d8c4cdb2aa0a7d1fe711721fd0828d5062837765280dc4f39719742cd124313bb9e15d31371e89
7
+ data.tar.gz: b3f6ac7fd1468a9caf227bd37f7cbe8316328ee88008e0305d891fa7c11478e9161425ababe9eb93416684284e39f2839f468e5667d6e9ce05e96c6c807b617c
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
@@ -141,15 +147,17 @@ By default, the VCR recording mode is set to `:none`, which allows recorded
141
147
  requests to be re-played but raises for any new request. This prevents the test
142
148
  suite from issuing unexpected HTTP requests.
143
149
 
144
- To add a new test or update a VCR recording, run the test with the `VCR_RECORD`
145
- environment variable:
150
+ Some requests require to be done on a live hubspot portal, you can set the `HUBSPOT_HAPI_KEY` environement variable, for example inside a `.env.test` file :
146
151
 
147
- ```sh
148
- VCR_RECORD=1 bundle exec rspec spec
152
+ ```
153
+ HUBSPOT_HAPI_KEY=xxxx
149
154
  ```
150
155
 
151
- [VCR]: https://github.com/vcr/vcr
156
+ To add a new test or update a VCR recording, run the test with the `VCR_RECORD_MODE`
157
+ environment variable, for instance:
152
158
 
153
- ## Disclaimer
159
+ ```sh
160
+ VCR_RECORD_MODE=new_episodes bundle exec rspec spec
161
+ ```
154
162
 
155
- This project and the code therein was not created by and is not supported by HubSpot, Inc or any of its affiliates.
163
+ [VCR]: https://github.com/vcr/vcr
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "hubspot-api-ruby"
3
- s.version = "0.8.1"
3
+ s.version = "0.9.0"
4
4
  s.require_paths = ["lib"]
5
5
  s.authors = ["Jonathan"]
6
6
  s.email = ["jonathan@hoggo.com"]
@@ -10,10 +10,10 @@ Gem::Specification.new do |s|
10
10
  s.files += Dir["lib/**/*.rb"]
11
11
  s.files += Dir["lib/**/*.rake"]
12
12
  s.files += Dir["spec/**/*.rb"]
13
- s.homepage = "http://github.com/lounna-sas/hubspot-api-ruby"
13
+ s.homepage = "https://github.com/captaincontrat/hubspot-api-ruby"
14
14
  s.summary = "hubspot-api-ruby is a wrapper for the HubSpot REST API"
15
15
  s.metadata = {
16
- "changelog_uri" => "https://github.com/lounna-sas/hubspot-api-ruby/blob/master/History.md"
16
+ "changelog_uri" => "https://github.com/captaincontrat/hubspot-api-ruby/blob/master/History.md"
17
17
  }
18
18
 
19
19
  s.required_ruby_version = ">= 2.3"
@@ -23,7 +23,6 @@ Gem::Specification.new do |s|
23
23
  s.add_runtime_dependency "httparty", ">= 0.10"
24
24
 
25
25
  # Add development-only dependencies here
26
- s.add_development_dependency("appraisal", "~> 2.2")
27
26
  s.add_development_dependency("dotenv")
28
27
  s.add_development_dependency("rake", "~> 11.0")
29
28
  s.add_development_dependency("rspec", "~> 3.8")
@@ -1,80 +1,106 @@
1
1
  class Hubspot::Association
2
- COMPANY_TO_CONTACT = 2
3
- DEAL_TO_CONTACT = 3
4
- CONTACT_TO_DEAL = 4
5
- DEAL_TO_COMPANY = 5
6
- COMPANY_TO_DEAL = 6
7
- DEFINITION_TARGET_TO_CLASS = {
8
- 2 => Hubspot::Contact,
9
- 3 => Hubspot::Contact,
10
- 4 => Hubspot::Deal,
11
- 5 => Hubspot::Company,
12
- 6 => Hubspot::Deal
2
+ OBJECT_TARGET_TO_CLASS = {
3
+ "Contact" => Hubspot::Contact,
4
+ "Deal" => Hubspot::Deal,
5
+ "Company" => Hubspot::Company
13
6
  }.freeze
14
7
 
15
- BATCH_CREATE_PATH = '/crm-associations/v1/associations/create-batch'
16
- BATCH_DELETE_PATH = '/crm-associations/v1/associations/delete-batch'
17
- ASSOCIATIONS_PATH = '/crm-associations/v1/associations/:resource_id/HUBSPOT_DEFINED/:definition_id'
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
18
22
 
19
23
  class << self
20
- def create(from_id, to_id, definition_id)
21
- batch_create([{ from_id: from_id, to_id: to_id, definition_id: definition_id }])
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}])
22
26
  end
23
27
 
24
28
  # Make multiple associations in a single API call
25
- # {https://developers.hubspot.com/docs/methods/crm-associations/batch-associate-objects}
29
+ # {https://developers.hubspot.com/docs/api/crm/associations}
26
30
  # usage:
27
- # Hubspot::Association.batch_create([{ from_id: 1, to_id: 2, definition_id: Hubspot::Association::COMPANY_TO_CONTACT }])
28
- def batch_create(associations)
29
- request = associations.map { |assocation| build_association_body(assocation) }
30
- Hubspot::Connection.put_json(BATCH_CREATE_PATH, params: { no_parse: true }, body: request).success?
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?
31
39
  end
32
40
 
33
- def delete(from_id, to_id, definition_id)
34
- batch_delete([{from_id: from_id, to_id: to_id, definition_id: definition_id}])
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}])
35
43
  end
36
44
 
37
45
  # Remove multiple associations in a single API call
38
- # {https://developers.hubspot.com/docs/methods/crm-associations/batch-delete-associations}
46
+ # {https://developers.hubspot.com/docs/api/crm/associations}
39
47
  # usage:
40
- # Hubspot::Association.batch_delete([{ from_id: 1, to_id: 2, definition_id: Hubspot::Association::COMPANY_TO_CONTACT }])
41
- def batch_delete(associations)
42
- request = associations.map { |assocation| build_association_body(assocation) }
43
- Hubspot::Connection.put_json(BATCH_DELETE_PATH, params: { no_parse: true }, body: request).success?
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?
44
52
  end
45
53
 
46
- # Retrieve all associated resources given a source (resource_id) and a kind (definition_id)
47
- # Example: if resource_id is a deal, using DEAL_TO_CONTACT will find every contact associated with the deal
48
- # {https://developers.hubspot.com/docs/methods/crm-associations/get-associations}
49
- # Warning: it will make N+M queries, where
50
- # N is the number of PagedCollection requests necessary to get all ids,
51
- # and M is the number of results, each resulting in a find
52
- # usage:
53
- # Hubspot::Association.all(42, Hubspot::Association::DEAL_TO_CONTACT)
54
- def all(resource_id, definition_id)
55
- opts = { resource_id: resource_id, definition_id: definition_id }
56
- klass = DEFINITION_TARGET_TO_CLASS[definition_id]
57
- raise(Hubspot::InvalidParams, 'Definition not supported') unless klass.present?
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?
58
61
 
59
- collection = Hubspot::PagedCollection.new(opts) do |options, offset, limit|
60
- params = options.merge(offset: offset, limit: limit)
61
- response = Hubspot::Connection.get_json(ASSOCIATIONS_PATH, params)
62
-
63
- resources = response['results'].map { |result| klass.find(result) }
64
- [resources, response['offset'], response['has-more']]
65
- end
66
- collection.resources
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"]) }
67
64
  end
68
65
 
69
66
  private
70
67
 
71
- def build_association_body(assocation)
68
+ def build_create_association_body(association, definition_id)
72
69
  {
73
- fromObjectId: assocation[:from_id],
74
- toObjectId: assocation[:to_id],
75
- category: 'HUBSPOT_DEFINED',
76
- definitionId: assocation[:definition_id]
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
+ ]
77
82
  }
78
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
79
105
  end
80
106
  end
@@ -78,11 +78,11 @@ class Hubspot::Company < Hubspot::Resource
78
78
  end
79
79
 
80
80
  def add_contact(id, contact_id)
81
- Hubspot::Association.create(id, contact_id, Hubspot::Association::COMPANY_TO_CONTACT)
81
+ Hubspot::Association.create("Company", id, "Contact", contact_id)
82
82
  end
83
83
 
84
84
  def remove_contact(id, contact_id)
85
- Hubspot::Association.delete(id, contact_id, Hubspot::Association::COMPANY_TO_CONTACT)
85
+ Hubspot::Association.delete("Company", id, "Contact", contact_id)
86
86
  end
87
87
 
88
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,16 +15,17 @@ 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")
@@ -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
data/lib/hubspot/deal.rb CHANGED
@@ -64,13 +64,23 @@ module Hubspot
64
64
  # Usage
65
65
  # Hubspot::Deal.associate!(45146940, [32], [52])
66
66
  def associate!(deal_id, company_ids=[], vids=[])
67
- associations = company_ids.map do |id|
68
- { from_id: deal_id, to_id: id, definition_id: Hubspot::Association::DEAL_TO_COMPANY }
67
+ company_associations = associations = company_ids.map do |id|
68
+ { from_id: deal_id, to_id: id }
69
69
  end
70
- associations += vids.map do |id|
71
- { from_id: deal_id, to_id: id, definition_id: Hubspot::Association::DEAL_TO_CONTACT }
70
+
71
+ contact_associations = vids.map do |id|
72
+ { from_id: deal_id, to_id: id}
73
+ end
74
+
75
+ results = []
76
+ if company_associations.any?
77
+ results << HubSpot::Association.batch_create("Deal", "Company", company_associations)
72
78
  end
73
- Hubspot::Association.batch_create(associations)
79
+ if contact_associations.any?
80
+ results << HubSpot::Association.batch_create("Deal", "Contact", contact_associations)
81
+ end
82
+
83
+ results.all?
74
84
  end
75
85
 
76
86
  # Didssociate a deal with a contact or company
@@ -78,13 +88,23 @@ module Hubspot
78
88
  # Usage
79
89
  # Hubspot::Deal.dissociate!(45146940, [32], [52])
80
90
  def dissociate!(deal_id, company_ids=[], vids=[])
81
- associations = company_ids.map do |id|
82
- { from_id: deal_id, to_id: id, definition_id: Hubspot::Association::DEAL_TO_COMPANY }
91
+ company_associations = company_ids.map do |id|
92
+ { from_id: deal_id, to_id: id }
83
93
  end
84
- associations += vids.map do |id|
85
- { from_id: deal_id, to_id: id, definition_id: Hubspot::Association::DEAL_TO_CONTACT }
94
+
95
+ contact_associations = vids.map do |id|
96
+ { from_id: deal_id, to_id: id }
97
+ end
98
+
99
+ results = []
100
+ if company_associations.any?
101
+ results << HubSpot::Association.batch_delete("Deal", "Company", company_associations)
86
102
  end
87
- Hubspot::Association.batch_delete(associations)
103
+ if contact_associations.any?
104
+ results << HubSpot::Association.batch_delete("Deal", "Contact", contact_associations)
105
+ end
106
+
107
+ results.all?
88
108
  end
89
109
 
90
110
  def find(deal_id)
@@ -134,12 +154,12 @@ module Hubspot
134
154
  # @param object [Hubspot::Contact || Hubspot::Company] a contact or company
135
155
  # @return [Array] Array of Hubspot::Deal records
136
156
  def find_by_association(object)
137
- definition = case object
138
- when Hubspot::Company then Hubspot::Association::COMPANY_TO_DEAL
139
- when Hubspot::Contact then Hubspot::Association::CONTACT_TO_DEAL
157
+ to_object_type = case object
158
+ when Hubspot::Company then "Company"
159
+ when Hubspot::Contact then "Contact"
140
160
  else raise(Hubspot::InvalidParams, 'Instance type not supported')
141
161
  end
142
- Hubspot::Association.all(object.id, definition)
162
+ Hubspot::Association.all(to_object_type, object.id, "Deal")
143
163
  end
144
164
  end
145
165
 
@@ -10,6 +10,8 @@ module Hubspot
10
10
  end
11
11
  end
12
12
 
13
+ class NotFoundError < RequestError; end
14
+
13
15
  class ConfigurationError < StandardError; end
14
16
  class MissingInterpolation < StandardError; end
15
17
  class ContactExistsError < RequestError; end
@@ -0,0 +1,44 @@
1
+ require 'hubspot/utils'
2
+
3
+ module Hubspot
4
+ class Meeting
5
+ #
6
+ # HubSpot Meeting API
7
+ #
8
+ # {https://developers.hubspot.com/docs/api/crm/meetings}
9
+ #
10
+ CREATE_MEETING_PATH = '/crm/v3/objects/meetings'
11
+ MEETING_PATH = '/crm/v3/objects/meetings/:meeting_id'
12
+ ASSOCIATE_MEETING_PATH = '/crm/v3/objects/meetings/:meeting_id/associations/Contact/:contact_id/meeting_event_to_contact'
13
+
14
+ class << self
15
+ def create!(owner_id, meeting_title, meeting_body, start_date_time, end_date_time)
16
+ body = {
17
+ properties: {
18
+ hs_timestamp: DateTime.now.strftime('%Q'),
19
+ hubspot_owner_id: owner_id,
20
+ hs_meeting_title: meeting_title,
21
+ hs_meeting_body: meeting_body,
22
+ hs_meeting_start_time: start_date_time.is_a?(DateTime) ? start_date_time.strftime('%Q') : start_date_time,
23
+ hs_meeting_end_time: end_date_time.is_a?(DateTime) ? end_date_time.strftime('%Q') : end_date_time,
24
+ hs_meeting_outcome: 'SCHEDULED'
25
+ }
26
+ }
27
+ response = Hubspot::Connection.post_json(CREATE_MEETING_PATH, params: {}, body: body)
28
+ HashWithIndifferentAccess.new(response)
29
+ end
30
+
31
+ def destroy!(meeting_id)
32
+ Hubspot::Connection.delete_json(MEETING_PATH, {meeting_id: meeting_id})
33
+ end
34
+
35
+ def associate!(meeting_id, contact_id)
36
+ Hubspot::Connection.put_json(ASSOCIATE_MEETING_PATH,
37
+ params: {
38
+ meeting_id: meeting_id,
39
+ contact_id: contact_id
40
+ })
41
+ end
42
+ end
43
+ end
44
+ end
@@ -97,7 +97,7 @@ module Hubspot
97
97
 
98
98
  def valid_group_params(params)
99
99
  return {} if params.blank?
100
- result = params.slice(*PROPERTY_SPECS[:group_field_names])
100
+ result = params.with_indifferent_access.slice(*PROPERTY_SPECS[:group_field_names])
101
101
  result['properties'] = valid_property_params(result['properties']) unless result['properties'].blank?
102
102
  result
103
103
  end
@@ -14,6 +14,7 @@ require 'hubspot/contact'
14
14
  require 'hubspot/contact_properties'
15
15
  require 'hubspot/contact_list'
16
16
  require 'hubspot/event'
17
+ require 'hubspot/custom_event'
17
18
  require 'hubspot/form'
18
19
  require 'hubspot/blog'
19
20
  require 'hubspot/topic'
@@ -27,6 +28,7 @@ require 'hubspot/engagement'
27
28
  require 'hubspot/subscription'
28
29
  require 'hubspot/oauth'
29
30
  require 'hubspot/file'
31
+ require 'hubspot/meeting'
30
32
 
31
33
  module Hubspot
32
34
  def self.configure(config={})