hubspot-api-ruby 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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={})