ruby_hubspot_api 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.env.sample +40 -0
- data/.gitignore +8 -0
- data/.rspec +3 -0
- data/.rubocop.yml +6 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +43 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +78 -0
- data/LICENSE.txt +21 -0
- data/README.md +225 -0
- data/Rakefile +8 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/lib/hubspot/api_client.rb +77 -0
- data/lib/hubspot/company.rb +6 -0
- data/lib/hubspot/config.rb +59 -0
- data/lib/hubspot/contact.rb +6 -0
- data/lib/hubspot/exceptions.rb +36 -0
- data/lib/hubspot/paged_collection.rb +102 -0
- data/lib/hubspot/property.rb +15 -0
- data/lib/hubspot/resource.rb +289 -0
- data/lib/hubspot/user.rb +8 -0
- data/lib/hubspot/version.rb +5 -0
- data/lib/hubspot.rb +35 -0
- data/lib/ruby_hubspot_api.rb +23 -0
- data/ruby_hubspot_api.gemspec +55 -0
- metadata +271 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a9081936b5a9201fa61faff7d03946af84e7a655bc8fb4b87216fe904ed8a147
|
4
|
+
data.tar.gz: 7e33a98b6224c769b90327ac2702dbe3752d8ae7d15b7032f1ad195021db7ae8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3bf538ac27be73eb2a4dbe97e65d6449aa304b40628779836f482014009361586e129a2b363697d1c3b06264b22cbd295233af961f8d18eeef94146c7c46e3d1
|
7
|
+
data.tar.gz: 82fb453482303e5fc8ff09404fc3b0e7f1aae13614e6fba98c700b781272c731b03f7f461213a8949bb2220d11c1637db68df1a71215523329352f6d39b2eadc
|
data/.env.sample
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Sample .env file
|
2
|
+
# If you want to run the tests and re-record the cassettes you will need
|
3
|
+
# a private app in hubspot with the correct scopes and you will need to
|
4
|
+
# grab the access token and the client secret and portal_id
|
5
|
+
# see https://developers.hubspot.com/docs/api/private-apps
|
6
|
+
|
7
|
+
export HUBSPOT_ACCESS_TOKEN=your_private_app_access_token
|
8
|
+
export HUBSPOT_CLIENT_SECRET=your_client_secret
|
9
|
+
export HUBSPOT_PORTAL_ID=portal_id
|
10
|
+
|
11
|
+
# VCR configuration
|
12
|
+
# record mode can be none, once, newepisodes or all (default none)
|
13
|
+
# see https://andrewmcodes.gitbook.io/vcr/record_modes
|
14
|
+
export VCR_RECORD_MODE=once
|
15
|
+
# to allow new request set to true
|
16
|
+
export VCR_ALLOW_REQUESTS=false
|
17
|
+
|
18
|
+
# Used in specs....
|
19
|
+
# The values of the following are the defaults if the env var is not set
|
20
|
+
|
21
|
+
# Company id used to test find and update (should be real)
|
22
|
+
export HUBSPOT_TEST_COMPANY_ID=1
|
23
|
+
|
24
|
+
# Company name to test create company
|
25
|
+
export HUBSPOT_TEST_COMPANY_NAME="Numenor Capital"
|
26
|
+
|
27
|
+
# Company id to test deleting (hint: make a dummy one first!)
|
28
|
+
export HUBSPOT_TEST_COMPANY_ID_DELETE=666
|
29
|
+
|
30
|
+
# Contact if to test find and update
|
31
|
+
export HUBSPOT_TEST_CONTACT_ID=1
|
32
|
+
|
33
|
+
# domain name to test the search by email contains
|
34
|
+
export HUBSPOT_SEARCH_TEST_DOMAIN=hubspot.com
|
35
|
+
|
36
|
+
# maximum number of records to fetch when testing lists
|
37
|
+
export HUBSPOT_SEARCH_LIMIT=5
|
38
|
+
|
39
|
+
# email address for search on email = <email>
|
40
|
+
export HUBSPOT_TEST_CONTACT_EMAIL=test@hubspot.com
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.5.3
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
## v0.1.0
|
2
|
+
|
3
|
+
- initial setup
|
4
|
+
- Setup the configuration block
|
5
|
+
- Adds spec for config
|
6
|
+
- Set the auth headers when access_token configured
|
7
|
+
- Version spec
|
8
|
+
- don't test for client id
|
9
|
+
- Load api client and add exception handler
|
10
|
+
- Initial bases class Resource for api crud
|
11
|
+
- Contact class with spec
|
12
|
+
- Cassettes for contact spec
|
13
|
+
- company model and spec with cassettes
|
14
|
+
- Adds PagedCollection for paged results (list / search)
|
15
|
+
- Adds Hubspot configuration to tests
|
16
|
+
- Update required files
|
17
|
+
- Adds list method to return PagedCollection
|
18
|
+
- Add interface for search
|
19
|
+
- VCR configuration
|
20
|
+
- Contact/search cassette
|
21
|
+
- Sample ENV file for developers
|
22
|
+
- console with configuration if env vars set
|
23
|
+
- Readme file
|
24
|
+
- MIT license
|
25
|
+
- allow connections if vcr_record_mode is on
|
26
|
+
- Fix rubocop config
|
27
|
+
- Update Readme
|
28
|
+
- Log api requests and add interface to set logging
|
29
|
+
- Update exception handing logic and add more exception classes
|
30
|
+
- Test all parts of the config code
|
31
|
+
- Adds user model (aliased to Owner) and specs
|
32
|
+
- Add a configured? method to Hubspot module
|
33
|
+
- Adds a dummy Hubspot::Property class
|
34
|
+
- Update Paged request handling based on method
|
35
|
+
- Adds a find_by mechanism for resources
|
36
|
+
- Use the Hubspot::Property class to return properties for a given resource object
|
37
|
+
- Update the specs for 100% coverage
|
38
|
+
- Update the sample .env file
|
39
|
+
- Reorder and clarify Readme
|
40
|
+
- When we use limit(1) we should only return the object not an array
|
41
|
+
- Test that we only get the properties we ask for or the defaults
|
42
|
+
- Flatten the properties array into a comma separated list
|
43
|
+
- Improve the intialiser
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ruby_hubspot_api (0.1.0)
|
5
|
+
bundler (~> 2.3, < 3.0)
|
6
|
+
dotenv (~> 2.8, < 3.0)
|
7
|
+
httparty (~> 0.21, < 1.0)
|
8
|
+
pry (~> 0.13, < 1.0)
|
9
|
+
pry-byebug (~> 3.9, < 4.0)
|
10
|
+
rspec (~> 3.13, < 4.0)
|
11
|
+
simplecov (~> 0.22, < 1.0)
|
12
|
+
vcr (~> 6.0, < 7.0)
|
13
|
+
webmock (~> 3.23, < 4.0)
|
14
|
+
|
15
|
+
GEM
|
16
|
+
remote: https://rubygems.org/
|
17
|
+
specs:
|
18
|
+
addressable (2.8.7)
|
19
|
+
public_suffix (>= 2.0.2, < 7.0)
|
20
|
+
bigdecimal (3.1.8)
|
21
|
+
byebug (11.1.3)
|
22
|
+
coderay (1.1.3)
|
23
|
+
crack (1.0.0)
|
24
|
+
bigdecimal
|
25
|
+
rexml
|
26
|
+
diff-lcs (1.5.1)
|
27
|
+
docile (1.4.1)
|
28
|
+
dotenv (2.8.1)
|
29
|
+
hashdiff (1.1.1)
|
30
|
+
httparty (0.21.0)
|
31
|
+
mini_mime (>= 1.0.0)
|
32
|
+
multi_xml (>= 0.5.2)
|
33
|
+
method_source (1.1.0)
|
34
|
+
mini_mime (1.1.2)
|
35
|
+
multi_xml (0.6.0)
|
36
|
+
pry (0.13.1)
|
37
|
+
coderay (~> 1.1)
|
38
|
+
method_source (~> 1.0)
|
39
|
+
pry-byebug (3.9.0)
|
40
|
+
byebug (~> 11.0)
|
41
|
+
pry (~> 0.13.0)
|
42
|
+
public_suffix (4.0.7)
|
43
|
+
rake (13.2.1)
|
44
|
+
rexml (3.3.7)
|
45
|
+
rspec (3.13.0)
|
46
|
+
rspec-core (~> 3.13.0)
|
47
|
+
rspec-expectations (~> 3.13.0)
|
48
|
+
rspec-mocks (~> 3.13.0)
|
49
|
+
rspec-core (3.13.1)
|
50
|
+
rspec-support (~> 3.13.0)
|
51
|
+
rspec-expectations (3.13.3)
|
52
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
53
|
+
rspec-support (~> 3.13.0)
|
54
|
+
rspec-mocks (3.13.1)
|
55
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
56
|
+
rspec-support (~> 3.13.0)
|
57
|
+
rspec-support (3.13.1)
|
58
|
+
simplecov (0.22.0)
|
59
|
+
docile (~> 1.1)
|
60
|
+
simplecov-html (~> 0.11)
|
61
|
+
simplecov_json_formatter (~> 0.1)
|
62
|
+
simplecov-html (0.13.1)
|
63
|
+
simplecov_json_formatter (0.1.4)
|
64
|
+
vcr (6.0.0)
|
65
|
+
webmock (3.23.1)
|
66
|
+
addressable (>= 2.8.0)
|
67
|
+
crack (>= 0.3.2)
|
68
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
69
|
+
|
70
|
+
PLATFORMS
|
71
|
+
x86_64-darwin-18
|
72
|
+
|
73
|
+
DEPENDENCIES
|
74
|
+
rake (>= 11.0, < 14.0)
|
75
|
+
ruby_hubspot_api!
|
76
|
+
|
77
|
+
BUNDLED WITH
|
78
|
+
2.3.26
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Simon Brook
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
# Ruby HubSpot API Gem
|
2
|
+
|
3
|
+
This gem was largely inspired by [hubspot-api-ruby](https://github.com/captaincontrat/hubspot-api-ruby) which, in turn, was inspired by the [hubspot-ruby](https://github.com/HubspotCommunity/hubspot-ruby) community gem. I wanted to use version 3 of the api and simplify some parts of the interface
|
4
|
+
|
5
|
+
The Ruby HubSpot API gem is a starting point for building an ORM-like interface to HubSpot's API.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'ruby_hubspot_api'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
```bash
|
18
|
+
$ bundle install
|
19
|
+
```
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
```bash
|
24
|
+
$ gem install ruby_hubspot_api
|
25
|
+
```
|
26
|
+
|
27
|
+
## Configuration
|
28
|
+
|
29
|
+
To authenticate API requests, you need a HubSpot access token. First you will need to add a [private app in hubspot](https://developers.hubspot.com/docs/api/private-apps) When that is setup you can go to the "Auth" tab of your private app page and grab the access token from there
|
30
|
+
|
31
|
+
You can configure the gem by adding this code to your initializer (for Rails) or to your startup configuration (in any other environment):
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
Hubspot.configure do |config|
|
35
|
+
config.access_token = 'your_access_token'
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
This configuration ensures that your API requests are authenticated using your HubSpot access token.
|
40
|
+
|
41
|
+
## Working with Objects
|
42
|
+
|
43
|
+
This gem allows you to interact with HubSpot objects such as contacts and companies. You can perform operations on individual instances (e.g., creating or updating records) as well as on collections (e.g., listing or searching).
|
44
|
+
|
45
|
+
### Instance Methods
|
46
|
+
|
47
|
+
#### Creating and Saving an Object
|
48
|
+
|
49
|
+
You can instantiate a new resource (such as a contact) by passing a hash of properties when creating the object. After setting the properties, calling `save` will persist the object to the HubSpot API.
|
50
|
+
|
51
|
+
Example:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
new_contact = Hubspot::Contact.new(firstname: 'John', lastname: 'Doe', email: 'john.doe@example.com')
|
55
|
+
|
56
|
+
# Save the contact to HubSpot
|
57
|
+
new_contact.save
|
58
|
+
|
59
|
+
# After saving, the contact will be assigned an ID by the API
|
60
|
+
puts "New contact ID: #{new_contact.id}"
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Updating an Existing Object
|
64
|
+
|
65
|
+
To update an existing object, you can either modify the object and call `save`, or use the `update` method specifying the properties you want to update
|
66
|
+
|
67
|
+
Example using `save`:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
contact = Hubspot::Contact.find(1)
|
71
|
+
contact.lastname = 'DoeUpdated'
|
72
|
+
contact.save # true
|
73
|
+
```
|
74
|
+
|
75
|
+
Example using `update`:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
contact = Hubspot::Contact.find(1)
|
79
|
+
contact.update(lastname: 'DoeUpdated') # true
|
80
|
+
```
|
81
|
+
|
82
|
+
### Class Methods
|
83
|
+
|
84
|
+
#### Listing Objects
|
85
|
+
|
86
|
+
You can list all objects (such as contacts) using the `list` method, which returns a `PagedCollection`. This collection handles paginated results and responds to methods like `each_page`, `each`, and `all`. You can also pass the `page_size` parameter to control the number of records returned per page.
|
87
|
+
|
88
|
+
Example:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
contacts = Hubspot::Contact.list(page_size: 10)
|
92
|
+
|
93
|
+
# Using each_page to iterate over pages
|
94
|
+
contacts.each_page do |page|
|
95
|
+
page.each do |contact|
|
96
|
+
puts "Contact: #{contact.firstname} #{contact.lastname}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Or iterate over all contacts without worrying about pagination
|
101
|
+
contacts.each do |contact|
|
102
|
+
puts "Contact: #{contact.firstname} #{contact.lastname}"
|
103
|
+
end
|
104
|
+
|
105
|
+
# Get all contacts at once (use with caution for large datasets)
|
106
|
+
all_contacts = contacts.all
|
107
|
+
```
|
108
|
+
|
109
|
+
#### Retrieving the first n items
|
110
|
+
|
111
|
+
You can use the `first` method to retrieve the first item or a specified number of items:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
contacts = Hubspot::Contact.list(page_size: 10)
|
115
|
+
|
116
|
+
# Retrieve the first contact
|
117
|
+
first_contact = contacts.first
|
118
|
+
|
119
|
+
# Retrieve the first 5 contacts
|
120
|
+
first_five_contacts = contacts.first(5)
|
121
|
+
```
|
122
|
+
|
123
|
+
This will automatically set the limits and handle paging for the most efficient API calls while honouring the maximum page count for hubspot resources
|
124
|
+
|
125
|
+
#### Searching
|
126
|
+
|
127
|
+
You can search for objects by passing query parameters to the `search` method. HubSpot supports several operators such as `eq`, `gte`, `lt`, and `IN` for filtering.
|
128
|
+
|
129
|
+
Example:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
# Search for contacts with email containing "hubspot.com"
|
133
|
+
contacts = Hubspot::Contact.search(query: { email_contains: 'hubspot.com' })
|
134
|
+
|
135
|
+
contacts.each do |contact|
|
136
|
+
puts "Found: #{contact.email}"
|
137
|
+
end
|
138
|
+
|
139
|
+
# Search for companies with number of employees greater than or equal to 100
|
140
|
+
companies = Hubspot::Company.search(number_of_employees_gte: 100)
|
141
|
+
|
142
|
+
companies.each do |company|
|
143
|
+
puts "Found: #{company.name}, Employees: #{company.number_of_employees}"
|
144
|
+
end
|
145
|
+
|
146
|
+
# Search for contacts with email in a specific list (IN operator)
|
147
|
+
contacts = Hubspot::Contact.search(email_in: ['user1@example.com', 'user2@example.com'])
|
148
|
+
|
149
|
+
contacts.each do |contact|
|
150
|
+
puts "Found: #{contact.email}"
|
151
|
+
end
|
152
|
+
```
|
153
|
+
|
154
|
+
### Available Search Operators:
|
155
|
+
- **eq**: Equal to.
|
156
|
+
- **neq**: Not equal to.
|
157
|
+
- **gte**: Greater than or equal to.
|
158
|
+
- **lte**: Less than or equal to.
|
159
|
+
- **IN**: Matches any of the values in an array.
|
160
|
+
|
161
|
+
#### Specifying Properties in Search
|
162
|
+
|
163
|
+
When performing a search, you can also specify which properties to return. If you specify any properties, you will only get those properties back, and the default HubSpot properties will not be included automatically.
|
164
|
+
|
165
|
+
Example:
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
# Search for contacts with email containing "hubspot.com" and only return specific properties
|
169
|
+
contacts = Hubspot::Contact.search(
|
170
|
+
query: { email_contains: 'hubspot.com' },
|
171
|
+
properties: ['firstname', 'lastname', 'email', 'mobile', 'custom_property_1']
|
172
|
+
)
|
173
|
+
|
174
|
+
contacts.each do |contact|
|
175
|
+
puts "Name: #{contact.firstname} #{contact.lastname}, Email: #{contact.email}, Mobile: #{contact.mobile}"
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
## Contributing
|
180
|
+
|
181
|
+
There is much to do (including writing a TODO list, or at least adding issues in github!) but this should provide a solid start
|
182
|
+
|
183
|
+
If you're interested in contributing to the gem, follow the instructions below.
|
184
|
+
|
185
|
+
### Developer Setup
|
186
|
+
|
187
|
+
A `.env.sample` file is provided with all the environment variables needed for development, including testing credentials. To set up your environment:
|
188
|
+
|
189
|
+
1. Copy the `.env.sample` file to `.env`.
|
190
|
+
2. Update the values with your own credentials (e.g., your `HUBSPOT_ACCESS_TOKEN`).
|
191
|
+
|
192
|
+
The `.env` file will be used to configure your access to the HubSpot API and ensure that environment variables are properly loaded during development.
|
193
|
+
|
194
|
+
### Using VCR for Testing
|
195
|
+
|
196
|
+
We use VCR for recording and replaying HTTP requests during testing. You can control the VCR recording mode by setting the `VCR_RECORD_MODE` environment variable as a string. The following modes are supported:
|
197
|
+
|
198
|
+
- `none` (default): No new requests are recorded; only replay from existing cassettes.
|
199
|
+
- `all`: Records all requests, overwriting existing cassettes.
|
200
|
+
- `new_episodes`: Records new requests, but keeps existing cassettes unchanged.
|
201
|
+
- `once`: Records the first time tests are run, and replays on subsequent runs.
|
202
|
+
|
203
|
+
You can specify the `VCR_RECORD_MODE` either via the command line or in the `.env` file (see the `.env.sample` file for examples).
|
204
|
+
|
205
|
+
To change the record mode on the command line, use:
|
206
|
+
|
207
|
+
```bash
|
208
|
+
$ export VCR_RECORD_MODE=all
|
209
|
+
```
|
210
|
+
|
211
|
+
For more information on how VCR modes work, refer to the [VCR documentation](https://andrewmcodes.gitbook.io/vcr/record_modes).
|
212
|
+
|
213
|
+
### Running Tests
|
214
|
+
|
215
|
+
To run the tests, simply execute:
|
216
|
+
|
217
|
+
```bash
|
218
|
+
$ rspec
|
219
|
+
```
|
220
|
+
|
221
|
+
Ensure you have your `.env` file configured with a valid `HUBSPOT_ACCESS_TOKEN` for API integration tests if you want to rerecord your interactions.
|
222
|
+
|
223
|
+
## License
|
224
|
+
|
225
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'dotenv/load'
|
6
|
+
require 'pry'
|
7
|
+
require 'ruby_hubspot_api'
|
8
|
+
require 'openssl'
|
9
|
+
|
10
|
+
Hubspot.configure do |config|
|
11
|
+
config.access_token = ENV['HUBSPOT_ACCESS_TOKEN']
|
12
|
+
config.portal_id = ENV['HUBSPOT_PORTAL_ID']
|
13
|
+
config.client_secret = ENV['HUBSPOT_CLIENT_SECRET']
|
14
|
+
end
|
15
|
+
|
16
|
+
Pry.start
|
data/bin/setup
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hubspot
|
4
|
+
# All interations with the Hubspot API happen here...
|
5
|
+
class ApiClient
|
6
|
+
include HTTParty
|
7
|
+
base_uri 'https://api.hubapi.com'
|
8
|
+
|
9
|
+
headers 'Content-Type' => 'application/json'
|
10
|
+
|
11
|
+
def handle_response(response)
|
12
|
+
self.class.handle_response(response)
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def get(url, options = {})
|
17
|
+
ensure_configuration!
|
18
|
+
|
19
|
+
if options[:query] && options[:query][:properties].is_a?(Array)
|
20
|
+
options[:query][:properties] = options[:query][:properties].join(',')
|
21
|
+
end
|
22
|
+
|
23
|
+
start_time = Time.now
|
24
|
+
response = super(url, options)
|
25
|
+
|
26
|
+
request = HTTParty::Request.new(Net::HTTP::Get, url, options)
|
27
|
+
log_request(:get, request.uri.to_s, response, start_time)
|
28
|
+
response
|
29
|
+
end
|
30
|
+
|
31
|
+
def post(url, options = {})
|
32
|
+
ensure_configuration!
|
33
|
+
start_time = Time.now
|
34
|
+
response = super(url, options)
|
35
|
+
log_request(:post, url, response, start_time)
|
36
|
+
response
|
37
|
+
end
|
38
|
+
|
39
|
+
def patch(url, options = {})
|
40
|
+
ensure_configuration!
|
41
|
+
start_time = Time.now
|
42
|
+
response = super(url, options)
|
43
|
+
log_request(:patch, url, response, start_time)
|
44
|
+
response
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete(url, options = {})
|
48
|
+
ensure_configuration!
|
49
|
+
start_time = Time.now
|
50
|
+
response = super(url, options)
|
51
|
+
log_request(:delete, url, response, start_time)
|
52
|
+
response
|
53
|
+
end
|
54
|
+
|
55
|
+
def log_request(http_method, url, response, start_time)
|
56
|
+
d = Time.now - start_time
|
57
|
+
Hubspot.logger.info("#{http_method.to_s.upcase} #{url} took #{d.round(2)}s with status #{response.code}")
|
58
|
+
Hubspot.logger.debug("Response body: #{response.body}") if Hubspot.logger.debug?
|
59
|
+
end
|
60
|
+
|
61
|
+
def handle_response(response)
|
62
|
+
if response.success?
|
63
|
+
response.parsed_response
|
64
|
+
else
|
65
|
+
Hubspot.logger.error("API Error: #{response.code} - #{response.body}")
|
66
|
+
raise Hubspot.error_from_response(response)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def ensure_configuration!
|
73
|
+
raise NotConfiguredError, 'Hubspot API not configured' unless Hubspot.configured?
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hubspot
|
4
|
+
# To hold Hubspot configuration
|
5
|
+
class Config
|
6
|
+
attr_accessor :access_token, :portal_id, :client_secret, :logger, :log_level
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@access_token = nil
|
10
|
+
@portal_id = nil
|
11
|
+
@client_secret = nil
|
12
|
+
@logger = initialize_logger
|
13
|
+
@log_level = determine_log_level
|
14
|
+
apply_log_level
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Initialize the default logger
|
20
|
+
def initialize_logger
|
21
|
+
Logger.new($stdout)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Map string values from environment variables to Logger constants
|
25
|
+
# rubocop:disable Metrics/MethodLength
|
26
|
+
def determine_log_level
|
27
|
+
env_log_level = ENV['HUBSPOT_LOG_LEVEL'] || default_log_level
|
28
|
+
case env_log_level.to_s.upcase
|
29
|
+
when 'DEBUG'
|
30
|
+
Logger::DEBUG
|
31
|
+
when 'INFO'
|
32
|
+
Logger::INFO
|
33
|
+
when 'WARN'
|
34
|
+
Logger::WARN
|
35
|
+
when 'ERROR'
|
36
|
+
Logger::ERROR
|
37
|
+
when 'FATAL'
|
38
|
+
Logger::FATAL
|
39
|
+
else
|
40
|
+
Logger::INFO # Default to INFO if unrecognized
|
41
|
+
end
|
42
|
+
end
|
43
|
+
# rubocop:enable Metrics/MethodLength
|
44
|
+
|
45
|
+
# Apply the log level to the logger
|
46
|
+
def apply_log_level
|
47
|
+
@logger.level = @log_level
|
48
|
+
end
|
49
|
+
|
50
|
+
# Set the default log level based on environment
|
51
|
+
def default_log_level
|
52
|
+
if defined?(Rails) && Rails.env.test?
|
53
|
+
'FATAL' # Default to FATAL in test environments
|
54
|
+
else
|
55
|
+
'INFO' # Default to INFO in normal usage
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The main hubspot module
|
4
|
+
module Hubspot
|
5
|
+
# define the Hubspot specific error classes
|
6
|
+
class RequestError < StandardError
|
7
|
+
attr_accessor :response
|
8
|
+
|
9
|
+
def initialize(response, message = nil)
|
10
|
+
message = response.parsed_response['message'] if !message && response.respond_to?(:parsed_response)
|
11
|
+
message += "\n" if message
|
12
|
+
me = super("#{message}Response body: #{response.body}",)
|
13
|
+
me.response = response
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class NotFoundError < RequestError; end
|
18
|
+
class OauthScopeError < RequestError; end
|
19
|
+
class RateLimitExceededError < RequestError; end
|
20
|
+
class NotConfiguredError < StandardError; end
|
21
|
+
class ArgumentError < StandardError; end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def error_from_response(response)
|
25
|
+
return NotFoundError.new(response) if response.not_found?
|
26
|
+
return RateLimitExceededError.new(response) if response.code == 429
|
27
|
+
|
28
|
+
case response.body
|
29
|
+
when /MISSING_SCOPES/, /You do not have permissions/i
|
30
|
+
OauthScopeError.new(response, 'Private app missing required scopes')
|
31
|
+
else
|
32
|
+
RequestError.new(response)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|