hubspot-api-ruby 0.8.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.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +3 -0
  4. data/Guardfile +9 -0
  5. data/LICENSE.txt +18 -0
  6. data/README.md +295 -0
  7. data/RELEASING.md +6 -0
  8. data/Rakefile +32 -0
  9. data/hubspot-api-ruby.gemspec +42 -0
  10. data/lib/hubspot-api-ruby.rb +39 -0
  11. data/lib/hubspot/blog.rb +98 -0
  12. data/lib/hubspot/collection.rb +41 -0
  13. data/lib/hubspot/company.rb +160 -0
  14. data/lib/hubspot/company_properties.rb +59 -0
  15. data/lib/hubspot/config.rb +63 -0
  16. data/lib/hubspot/connection.rb +152 -0
  17. data/lib/hubspot/contact.rb +110 -0
  18. data/lib/hubspot/contact_list.rb +129 -0
  19. data/lib/hubspot/contact_properties.rb +59 -0
  20. data/lib/hubspot/deal.rb +173 -0
  21. data/lib/hubspot/deal_pipeline.rb +58 -0
  22. data/lib/hubspot/deal_properties.rb +59 -0
  23. data/lib/hubspot/deprecator.rb +7 -0
  24. data/lib/hubspot/engagement.rb +222 -0
  25. data/lib/hubspot/event.rb +21 -0
  26. data/lib/hubspot/exceptions.rb +18 -0
  27. data/lib/hubspot/file.rb +38 -0
  28. data/lib/hubspot/form.rb +95 -0
  29. data/lib/hubspot/oauth.rb +50 -0
  30. data/lib/hubspot/owner.rb +57 -0
  31. data/lib/hubspot/paged_collection.rb +35 -0
  32. data/lib/hubspot/properties.rb +123 -0
  33. data/lib/hubspot/railtie.rb +10 -0
  34. data/lib/hubspot/resource.rb +270 -0
  35. data/lib/hubspot/subscription.rb +37 -0
  36. data/lib/hubspot/topic.rb +37 -0
  37. data/lib/hubspot/utils.rb +127 -0
  38. data/lib/tasks/hubspot.rake +53 -0
  39. data/spec/factories/companies.rb +9 -0
  40. data/spec/factories/contacts.rb +10 -0
  41. data/spec/lib/hubspot-ruby_spec.rb +12 -0
  42. data/spec/lib/hubspot/blog_spec.rb +150 -0
  43. data/spec/lib/hubspot/company_properties_spec.rb +410 -0
  44. data/spec/lib/hubspot/company_spec.rb +340 -0
  45. data/spec/lib/hubspot/config_spec.rb +87 -0
  46. data/spec/lib/hubspot/connection_spec.rb +214 -0
  47. data/spec/lib/hubspot/contact_list_spec.rb +301 -0
  48. data/spec/lib/hubspot/contact_properties_spec.rb +245 -0
  49. data/spec/lib/hubspot/contact_spec.rb +223 -0
  50. data/spec/lib/hubspot/deal_pipeline_spec.rb +85 -0
  51. data/spec/lib/hubspot/deal_properties_spec.rb +262 -0
  52. data/spec/lib/hubspot/deal_spec.rb +185 -0
  53. data/spec/lib/hubspot/deprecator_spec.rb +15 -0
  54. data/spec/lib/hubspot/engagement_spec.rb +177 -0
  55. data/spec/lib/hubspot/event_spec.rb +33 -0
  56. data/spec/lib/hubspot/file_spec.rb +38 -0
  57. data/spec/lib/hubspot/form_spec.rb +189 -0
  58. data/spec/lib/hubspot/owner_spec.rb +56 -0
  59. data/spec/lib/hubspot/properties_spec.rb +45 -0
  60. data/spec/lib/hubspot/resource_spec.rb +54 -0
  61. data/spec/lib/hubspot/topic_spec.rb +23 -0
  62. data/spec/lib/hubspot/utils_spec.rb +164 -0
  63. data/spec/lib/tasks/hubspot_spec.rb +119 -0
  64. data/spec/shared_examples/saveable_resource.rb +45 -0
  65. data/spec/shared_examples/updateable_resource.rb +87 -0
  66. data/spec/spec_helper.rb +44 -0
  67. data/spec/support/capture_output.rb +21 -0
  68. data/spec/support/cassette_helper.rb +19 -0
  69. data/spec/support/hubspot_api_helpers.rb +13 -0
  70. data/spec/support/rake.rb +46 -0
  71. data/spec/support/tests_helper.rb +17 -0
  72. data/spec/support/vcr.rb +16 -0
  73. metadata +369 -0
@@ -0,0 +1,58 @@
1
+ require 'hubspot/utils'
2
+
3
+ module Hubspot
4
+ #
5
+ # HubSpot Deals API
6
+ #
7
+ # {http://developers.hubspot.com/docs/methods/deal-pipelines/overview}
8
+ #
9
+ class DealPipeline
10
+ PIPELINES_PATH = "/deals/v1/pipelines"
11
+ PIPELINE_PATH = "/deals/v1/pipelines/:pipeline_id"
12
+
13
+ attr_reader :active
14
+ attr_reader :display_order
15
+ attr_reader :label
16
+ attr_reader :pipeline_id
17
+ attr_reader :stages
18
+
19
+ def initialize(response_hash)
20
+ @active = response_hash["active"]
21
+ @display_order = response_hash["displayOrder"]
22
+ @label = response_hash["label"]
23
+ @pipeline_id = response_hash["pipelineId"]
24
+ @stages = response_hash["stages"]
25
+ end
26
+
27
+ class << self
28
+ def find(pipeline_id)
29
+ response = Hubspot::Connection.get_json(PIPELINE_PATH, { pipeline_id: pipeline_id })
30
+ new(response)
31
+ end
32
+
33
+ def all
34
+ response = Hubspot::Connection.get_json(PIPELINES_PATH, {})
35
+ response.map { |p| new(p) }
36
+ end
37
+
38
+ # Creates a DealPipeline
39
+ # {https://developers.hubspot.com/docs/methods/deal-pipelines/create-deal-pipeline}
40
+ # @return [Hubspot::PipeLine] Company record
41
+ def create!(post_data={})
42
+ response = Hubspot::Connection.post_json(PIPELINES_PATH, params: {}, body: post_data)
43
+ new(response)
44
+ end
45
+ end
46
+
47
+ # Destroys deal_pipeline
48
+ # {http://developers.hubspot.com/docs/methods/companies/delete_company}
49
+ # @return [TrueClass] true
50
+ def destroy!
51
+ Hubspot::Connection.delete_json(PIPELINE_PATH, pipeline_id: @pipeline_id)
52
+ end
53
+
54
+ def [](stage)
55
+ @stages[stage]
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,59 @@
1
+ module Hubspot
2
+ class DealProperties < Properties
3
+
4
+ ALL_PROPERTIES_PATH = '/deals/v1/properties'
5
+ ALL_GROUPS_PATH = '/deals/v1/groups'
6
+ CREATE_PROPERTY_PATH = '/deals/v1/properties/'
7
+ UPDATE_PROPERTY_PATH = '/deals/v1/properties/named/:property_name'
8
+ DELETE_PROPERTY_PATH = '/deals/v1/properties/named/:property_name'
9
+ CREATE_GROUP_PATH = '/deals/v1/groups/'
10
+ UPDATE_GROUP_PATH = '/deals/v1/groups/named/:group_name'
11
+ DELETE_GROUP_PATH = '/deals/v1/groups/named/:group_name'
12
+
13
+ class << self
14
+ def add_default_parameters(opts={})
15
+ superclass.add_default_parameters(opts)
16
+ end
17
+
18
+ def all(opts={}, filter={})
19
+ superclass.all(ALL_PROPERTIES_PATH, opts, filter)
20
+ end
21
+
22
+ def groups(opts={}, filter={})
23
+ superclass.groups(ALL_GROUPS_PATH, opts, filter)
24
+ end
25
+
26
+ def create!(params={})
27
+ superclass.create!(CREATE_PROPERTY_PATH, params)
28
+ end
29
+
30
+ def update!(property_name, params={})
31
+ superclass.update!(UPDATE_PROPERTY_PATH, property_name, params)
32
+ end
33
+
34
+ def delete!(property_name)
35
+ superclass.delete!(DELETE_PROPERTY_PATH, property_name)
36
+ end
37
+
38
+ def create_group!(params={})
39
+ superclass.create_group!(CREATE_GROUP_PATH, params)
40
+ end
41
+
42
+ def update_group!(group_name, params={})
43
+ superclass.update_group!(UPDATE_GROUP_PATH, group_name, params)
44
+ end
45
+
46
+ def delete_group!(group_name)
47
+ superclass.delete_group!(DELETE_GROUP_PATH, group_name)
48
+ end
49
+
50
+ def same?(src, dst)
51
+ superclass.same?(src, dst)
52
+ end
53
+
54
+ def valid_params(params)
55
+ superclass.valid_params(params)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,7 @@
1
+ module Hubspot
2
+ class Deprecator
3
+ def self.build(version: "1.0")
4
+ ActiveSupport::Deprecation.new(version, "hubspot-api-ruby")
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,222 @@
1
+ require 'hubspot/utils'
2
+
3
+ module Hubspot
4
+ #
5
+ # HubSpot Engagements API
6
+ #
7
+ # {http://developers.hubspot.com/docs/methods/engagements/create_engagement}
8
+ #
9
+ class Engagement
10
+ ALL_ENGAGEMENTS_PATH = '/engagements/v1/engagements/paged'
11
+ RECENT_ENGAGEMENT_PATH = '/engagements/v1/engagements/recent/modified'
12
+ CREATE_ENGAGMEMENT_PATH = '/engagements/v1/engagements'
13
+ ENGAGEMENT_PATH = '/engagements/v1/engagements/:engagement_id'
14
+ ASSOCIATE_ENGAGEMENT_PATH = '/engagements/v1/engagements/:engagement_id/associations/:object_type/:object_vid'
15
+ GET_ASSOCIATED_ENGAGEMENTS = '/engagements/v1/engagements/associated/:objectType/:objectId/paged'
16
+
17
+ attr_reader :id
18
+ attr_reader :engagement
19
+ attr_reader :associations
20
+ attr_reader :attachments
21
+ attr_reader :metadata
22
+
23
+ def initialize(response_hash)
24
+
25
+ @engagement = response_hash["engagement"]
26
+ @associations = response_hash["associations"]
27
+ @attachments = response_hash["attachments"]
28
+ @metadata = response_hash["metadata"]
29
+ @id = engagement["id"]
30
+ end
31
+
32
+ class << self
33
+ def create!(params={})
34
+ response = Hubspot::Connection.post_json(CREATE_ENGAGMEMENT_PATH, params: {}, body: params )
35
+ new(HashWithIndifferentAccess.new(response))
36
+ end
37
+
38
+ def find(engagement_id)
39
+ begin
40
+ response = Hubspot::Connection.get_json(ENGAGEMENT_PATH, { engagement_id: engagement_id })
41
+ response ? new(HashWithIndifferentAccess.new(response)) : nil
42
+ rescue Hubspot::RequestError => ex
43
+ if ex.response.code == 404
44
+ return nil
45
+ else
46
+ raise ex
47
+ end
48
+ end
49
+ end
50
+
51
+ def all(opts = {})
52
+ path = ALL_ENGAGEMENTS_PATH
53
+
54
+ response = Hubspot::Connection.get_json(path, opts)
55
+
56
+ result = {}
57
+ result['engagements'] = response['results'].map { |d| new(d) }
58
+ result['offset'] = response['offset']
59
+ result['hasMore'] = response['hasMore']
60
+ return result
61
+ end
62
+
63
+ def recent(opts = {})
64
+ path = RECENT_ENGAGEMENT_PATH
65
+
66
+ response = Hubspot::Connection.get_json(path, opts)
67
+
68
+ result = {}
69
+ result['engagements'] = response['results'].map { |d| new(d) }
70
+ result['offset'] = response['offset']
71
+ result['hasMore'] = response['hasMore']
72
+ result
73
+ end
74
+
75
+ def find_by_company(company_id)
76
+ find_by_association company_id, 'COMPANY'
77
+ end
78
+
79
+ def find_by_contact(contact_id)
80
+ find_by_association contact_id, 'CONTACT'
81
+ end
82
+
83
+ def find_by_association(association_id, association_type)
84
+ path = GET_ASSOCIATED_ENGAGEMENTS
85
+ params = { objectType: association_type, objectId: association_id }
86
+ raise Hubspot::InvalidParams, 'expecting Integer parameter' unless association_id.try(:is_a?, Integer)
87
+ raise Hubspot::InvalidParams, 'expecting String parameter' unless association_type.try(:is_a?, String)
88
+
89
+ engagements = []
90
+ begin
91
+ response = Hubspot::Connection.get_json(path, params)
92
+ engagements = response["results"].try(:map) { |engagement| new(engagement) }
93
+ rescue => e
94
+ raise e unless e.message =~ /not found/
95
+ end
96
+ engagements
97
+ end
98
+
99
+ # Associates an engagement with an object
100
+ # {https://developers.hubspot.com/docs/methods/engagements/associate_engagement}
101
+ # @param engagement_id [int] id of the engagement to associate
102
+ # @param object_type [string] one of contact, company, or deal
103
+ # @param object_vid [int] id of the contact, company, or deal to associate
104
+ def associate!(engagement_id, object_type, object_vid)
105
+ Hubspot::Connection.put_json(ASSOCIATE_ENGAGEMENT_PATH,
106
+ params: {
107
+ engagement_id: engagement_id,
108
+ object_type: object_type,
109
+ object_vid: object_vid
110
+ })
111
+ end
112
+ end
113
+
114
+ # Archives the engagement in hubspot
115
+ # {http://developers.hubspot.com/docs/methods/engagements/delete-engagement}
116
+ # @return [TrueClass] true
117
+ def destroy!
118
+ Hubspot::Connection.delete_json(ENGAGEMENT_PATH, {engagement_id: id})
119
+ @destroyed = true
120
+ end
121
+
122
+ def destroyed?
123
+ !!@destroyed
124
+ end
125
+
126
+ def [](property)
127
+ @properties[property]
128
+ end
129
+
130
+ # Updates the properties of an engagement
131
+ # {http://developers.hubspot.com/docs/methods/engagements/update_engagement}
132
+ # @param params [Hash] hash of properties to update
133
+ # @return [Hubspot::Engagement] self
134
+ def update!(params)
135
+ data = {
136
+ engagement: params[:engagement] || engagement,
137
+ associations: params[:associations] || associations,
138
+ attachments: params[:attachments] || attachments,
139
+ metadata: params[:metadata] || metadata
140
+ }
141
+
142
+ Hubspot::Connection.put_json(ENGAGEMENT_PATH, params: { engagement_id: id }, body: data)
143
+ self
144
+ end
145
+ end
146
+
147
+ class EngagementNote < Engagement
148
+ def body
149
+ metadata['body']
150
+ end
151
+
152
+ def contact_ids
153
+ associations['contactIds']
154
+ end
155
+
156
+ class << self
157
+ def create!(contact_id, note_body, owner_id = nil, deal_id = nil)
158
+ data = {
159
+ engagement: {
160
+ type: 'NOTE'
161
+ },
162
+ associations: {
163
+ contactIds: [contact_id]
164
+ },
165
+ metadata: {
166
+ body: note_body
167
+ }
168
+ }
169
+
170
+ # if the owner id has been provided, append it to the engagement
171
+ data[:engagement][:owner_id] = owner_id if owner_id
172
+ # if the deal id has been provided, associate the note with the deal
173
+ data[:associations][:dealIds] = [deal_id] if deal_id
174
+
175
+ super(data)
176
+ end
177
+ end
178
+ end
179
+
180
+ class EngagementCall < Engagement
181
+ def body
182
+ metadata['body']
183
+ end
184
+
185
+ def contact_ids
186
+ associations['contactIds']
187
+ end
188
+
189
+ def company_ids
190
+ associations['companyIds']
191
+ end
192
+
193
+ def deal_ids
194
+ associations['dealIds']
195
+ end
196
+
197
+ class << self
198
+ def create!(contact_vid, body, duration, owner_id = nil, deal_id = nil, status = 'COMPLETED', time = nil)
199
+ data = {
200
+ engagement: {
201
+ type: 'CALL'
202
+ },
203
+ associations: {
204
+ contactIds: [contact_vid],
205
+ dealIds: [deal_id],
206
+ ownerIds: [owner_id]
207
+ },
208
+ metadata: {
209
+ body: body,
210
+ status: status,
211
+ durationMilliseconds: duration
212
+ }
213
+ }
214
+
215
+ data[:engagement][:timestamp] = (time.to_i) * 1000 if time
216
+ data[:engagement][:owner_id] = owner_id if owner_id
217
+
218
+ super(data)
219
+ end
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,21 @@
1
+ require 'hubspot/utils'
2
+
3
+ module Hubspot
4
+ #
5
+ # HubSpot Events HTTP API
6
+ #
7
+ # {https://developers.hubspot.com/docs/methods/enterprise_events/http_api}
8
+ #
9
+ class Event
10
+ POST_EVENT_PATH = '/v1/event'
11
+
12
+ class << self
13
+ def trigger(event_id, email, options = {})
14
+ default_params = { _n: event_id, _a: Hubspot::Config.portal_id, email: email }
15
+ options[:params] = default_params.merge(options[:params] || {})
16
+
17
+ Hubspot::EventConnection.trigger(POST_EVENT_PATH, options).success?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module Hubspot
2
+ class RequestError < StandardError
3
+ attr_accessor :response
4
+
5
+ def initialize(response, message=nil)
6
+ message += "\n" if message
7
+ me = super("#{message}Response body: #{response.body}",)
8
+ me.response = response
9
+ return me
10
+ end
11
+ end
12
+
13
+ class ConfigurationError < StandardError; end
14
+ class MissingInterpolation < StandardError; end
15
+ class ContactExistsError < RequestError; end
16
+ class InvalidParams < StandardError; end
17
+ class ApiError < StandardError; end
18
+ end
@@ -0,0 +1,38 @@
1
+ require 'hubspot/utils'
2
+ require 'base64'
3
+ require 'pp'
4
+
5
+ module Hubspot
6
+ #
7
+ # HubSpot Files API
8
+ #
9
+ # {https://developers.hubspot.com/docs/methods/files/post_files}
10
+ #
11
+ class File
12
+ GET_FILE_PATH = "/filemanager/api/v2/files/:file_id"
13
+ DELETE_FILE_PATH = "/filemanager/api/v2/files/:file_id/full-delete"
14
+ LIST_FILE_PATH = "/filemanager/api/v2/files"
15
+
16
+ attr_reader :id
17
+ attr_reader :properties
18
+
19
+ def initialize(response_hash)
20
+ @id = response_hash["id"]
21
+ @properties = response_hash
22
+ end
23
+
24
+ class << self
25
+ def find_by_id(file_id)
26
+ response = Hubspot::Connection.get_json(GET_FILE_PATH, { file_id: file_id })
27
+ new(response)
28
+ end
29
+ end
30
+
31
+ # Permanently delete a file and all related data and thumbnails from file manager.
32
+ # {https://developers.hubspot.com/docs/methods/files/hard_delete_file_and_associated_objects}
33
+ def destroy!
34
+ Hubspot::Connection.post_json(DELETE_FILE_PATH, params: {file_id: id})
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,95 @@
1
+ module Hubspot
2
+ #
3
+ # HubSpot Form API
4
+ #
5
+ # {https://developers.hubspot.com/docs/methods/forms/forms_overview}
6
+ #
7
+ class Form
8
+ FORMS_PATH = '/forms/v2/forms' # '/contacts/v1/forms'
9
+ FORM_PATH = '/forms/v2/forms/:form_guid' # '/contacts/v1/forms/:form_guid'
10
+ FIELDS_PATH = '/forms/v2/fields/:form_guid' # '/contacts/v1/fields/:form_guid'
11
+ FIELD_PATH = FIELDS_PATH + '/:field_name'
12
+ SUBMIT_DATA_PATH = '/uploads/form/v2/:portal_id/:form_guid'
13
+
14
+ class << self
15
+ # {https://developers.hubspot.com/docs/methods/forms/create_form}
16
+ def create!(opts={})
17
+ response = Hubspot::Connection.post_json(FORMS_PATH, params: {}, body: opts)
18
+ new(response)
19
+ end
20
+
21
+ def all
22
+ response = Hubspot::Connection.get_json(FORMS_PATH, {})
23
+ response.map { |f| new(f) }
24
+ end
25
+
26
+ # {https://developers.hubspot.com/docs/methods/forms/get_form}
27
+ def find(guid)
28
+ response = Hubspot::Connection.get_json(FORM_PATH, { form_guid: guid })
29
+ new(response)
30
+ end
31
+ end
32
+
33
+ attr_reader :guid
34
+ attr_reader :fields
35
+ attr_reader :properties
36
+
37
+ def initialize(hash)
38
+ self.send(:assign_properties, hash)
39
+ end
40
+
41
+ # {https://developers.hubspot.com/docs/methods/forms/get_fields}
42
+ # {https://developers.hubspot.com/docs/methods/forms/get_field}
43
+ def fields(opts={})
44
+ bypass_cache = opts.delete(:bypass_cache) { false }
45
+ field_name = opts.delete(:only) { nil }
46
+
47
+ if field_name
48
+ field_name = field_name.to_s
49
+ if bypass_cache || @fields.nil? || @fields.empty?
50
+ response = Hubspot::Connection.get_json(FIELD_PATH, { form_guid: @guid, field_name: field_name })
51
+ response
52
+ else
53
+ @fields.detect { |f| f['name'] == field_name }
54
+ end
55
+ else
56
+ if bypass_cache || @fields.nil? || @fields.empty?
57
+ response = Hubspot::Connection.get_json(FIELDS_PATH, { form_guid: @guid })
58
+ @fields = response
59
+ end
60
+ @fields
61
+ end
62
+ end
63
+
64
+ # {https://developers.hubspot.com/docs/methods/forms/submit_form}
65
+ def submit(opts={})
66
+ response = Hubspot::FormsConnection.submit(SUBMIT_DATA_PATH, params: { form_guid: @guid }, body: opts)
67
+ [204, 302, 200].include?(response.code)
68
+ end
69
+
70
+ # {https://developers.hubspot.com/docs/methods/forms/update_form}
71
+ def update!(opts={})
72
+ response = Hubspot::Connection.post_json(FORM_PATH, params: { form_guid: @guid }, body: opts)
73
+ self.send(:assign_properties, response)
74
+ self
75
+ end
76
+
77
+ # {https://developers.hubspot.com/docs/methods/forms/delete_form}
78
+ def destroy!
79
+ response = Hubspot::Connection.delete_json(FORM_PATH, { form_guid: @guid })
80
+ @destroyed = (response.code == 204)
81
+ end
82
+
83
+ def destroyed?
84
+ !!@destroyed
85
+ end
86
+
87
+ private
88
+
89
+ def assign_properties(hash)
90
+ @guid = hash['guid']
91
+ @fields = (hash['formFieldGroups'] || []).inject([]) { |result, fg| result | fg['fields'] }
92
+ @properties = hash
93
+ end
94
+ end
95
+ end