procore 0.8.4 → 1.0.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 +4 -4
- data/.rubocop.yml +9 -5
- data/.travis.yml +2 -0
- data/CHANGELOG.md +84 -1
- data/README.md +134 -9
- data/lib/procore.rb +1 -0
- data/lib/procore/auth/client_credentials.rb +1 -1
- data/lib/procore/auth/stores/dalli.rb +38 -0
- data/lib/procore/client.rb +1 -1
- data/lib/procore/configuration.rb +23 -0
- data/lib/procore/defaults.rb +7 -0
- data/lib/procore/requestable.rb +119 -19
- data/lib/procore/response.rb +1 -1
- data/lib/procore/version.rb +1 -1
- data/procore.gemspec +3 -0
- metadata +46 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab6a771f9ecbd227e500591c59381e08e70b1ad3cea2f82e767b4de2d88664b3
|
4
|
+
data.tar.gz: 1159fa494f5d38ce2d0a0fbcbdb465bf6203e8989a96acf3bcceab915ea9dbac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1c9f942d9c8223df00bff8c67b366adc85be3224d2a6ef41ee4e345d40cba8cc0ca71fe0361ff094be1ba358d3ad7ead40fc99d36bba8e5edac0dfc19932c57
|
7
|
+
data.tar.gz: afb9275ad4ec9b1396f3f7bed77317eb39b8e6cacf5d82dc77b38e9a934491e439795fe7df432d27fdc337800b7343327f1cb9d7b70c072ed72244bcd41d6a0a
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rails
|
3
|
+
- rubocop-performance
|
4
|
+
|
1
5
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
6
|
+
TargetRubyVersion: 2.4
|
3
7
|
Include:
|
4
8
|
- '**/Rakefile'
|
5
9
|
- '**/config.ru'
|
@@ -305,7 +309,7 @@ Style/PerlBackrefs:
|
|
305
309
|
Naming/PredicateName:
|
306
310
|
Description: 'Check the names of predicate methods.'
|
307
311
|
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark'
|
308
|
-
|
312
|
+
ForbiddenPrefixes:
|
309
313
|
- is_
|
310
314
|
Exclude:
|
311
315
|
- spec/**/*
|
@@ -437,7 +441,7 @@ Style/RedundantBegin:
|
|
437
441
|
|
438
442
|
# Layout
|
439
443
|
|
440
|
-
Layout/
|
444
|
+
Layout/ParameterAlignment:
|
441
445
|
Description: 'Here we check if the parameters on a multi-line method call or definition are aligned.'
|
442
446
|
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-double-indent'
|
443
447
|
Enabled: false
|
@@ -505,7 +509,7 @@ Lint/DeprecatedClassMethods:
|
|
505
509
|
Description: 'Check for deprecated class method calls.'
|
506
510
|
Enabled: false
|
507
511
|
|
508
|
-
Lint/
|
512
|
+
Lint/DuplicateHashKey:
|
509
513
|
Description: 'Check for duplicate keys in hash literals.'
|
510
514
|
Enabled: false
|
511
515
|
|
@@ -521,7 +525,7 @@ Lint/FormatParameterMismatch:
|
|
521
525
|
Description: 'The number of parameters to format/sprint must match the fields.'
|
522
526
|
Enabled: false
|
523
527
|
|
524
|
-
Lint/
|
528
|
+
Lint/SuppressedException:
|
525
529
|
Description: "Don't suppress exception."
|
526
530
|
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions'
|
527
531
|
Enabled: false
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,87 @@
|
|
1
|
-
##
|
1
|
+
## 1.0.0 (January 5, 2021)
|
2
|
+
|
3
|
+
* Adds support for API versioning
|
4
|
+
|
5
|
+
*Nate Baer*
|
6
|
+
|
7
|
+
### Upgrading
|
8
|
+
|
9
|
+
As of v1.0.0, this gem now defaults to making requests against Procore's new
|
10
|
+
Rest v1.0 resources, instead of the now deprecated `/vapid` namespace. Example:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
# Previously makes a request to
|
14
|
+
client.get("me")
|
15
|
+
=> app.procore.com/vapid/me
|
16
|
+
|
17
|
+
# In 1.0.0
|
18
|
+
client.get("me")
|
19
|
+
=> app.procore.com/rest/v1.0/me
|
20
|
+
```
|
21
|
+
|
22
|
+
To keep the legacy behavior, set the new `default_version` configuration option.
|
23
|
+
Note, that Rest v1.0 is a superset of the Vapid Api - there are no breaking
|
24
|
+
changes. The Vapid API will be decommissioned in December 2021.
|
25
|
+
|
26
|
+
[Read more here](https://developers.procore.com/documentation/vapid-deprecation)
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
Procore.configure do |config|
|
30
|
+
...
|
31
|
+
# Defaults to "v1.0"
|
32
|
+
config.default_version = "vapid"
|
33
|
+
...
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
All the request methods (`get`, `post`, `patch`, `put`, `delete`, `sync`) now
|
38
|
+
accept an optional version parameter to specify the version at request time.
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
client.get("me")
|
42
|
+
=> https://app.procore.com/rest/v1.0/me
|
43
|
+
|
44
|
+
client.get("me", version: "v1.1")
|
45
|
+
=> https://app.procore.com/rest/v1.1/me
|
46
|
+
|
47
|
+
client.get("me", version: "vapid")
|
48
|
+
=> https://app.procore.com/vapid/me
|
49
|
+
```
|
50
|
+
|
51
|
+
## 0.8.8 (October 17, 2019)
|
52
|
+
|
53
|
+
* Expose #sync, a method that enables calling sync-actions
|
54
|
+
|
55
|
+
*Patrick Koperwas*
|
56
|
+
|
57
|
+
* Addition of contribution guidelines to README
|
58
|
+
|
59
|
+
*Megan O'Neill*
|
60
|
+
|
61
|
+
* Fix TravisCI failures
|
62
|
+
|
63
|
+
*Patrick Koperwas*
|
64
|
+
|
65
|
+
## 0.8.7 (April 18, 2019)
|
66
|
+
|
67
|
+
* Add api_version to allow calls to procore rest endpoints
|
68
|
+
|
69
|
+
*Shane Means*
|
70
|
+
|
71
|
+
## 0.8.6 (May 10, 2018)
|
72
|
+
|
73
|
+
* Dalli Store
|
74
|
+
|
75
|
+
*Patrick Koperwas*
|
76
|
+
|
77
|
+
* Fix Requestable paths to prevent double slash in URI
|
78
|
+
|
79
|
+
*Megan O'Neill*
|
80
|
+
|
81
|
+
## 0.8.5 (May 9, 2018)
|
82
|
+
* Rescue Errno::ECONNREFUSED errors and RestClient::ServerBrokeConnection
|
83
|
+
|
84
|
+
*Casey Ochs*
|
2
85
|
|
3
86
|
## 0.8.4 (May 8, 2018)
|
4
87
|
|
data/README.md
CHANGED
@@ -4,20 +4,24 @@
|
|
4
4
|
|
5
5
|
#### Table of Contents
|
6
6
|
- [Installation](#installation)
|
7
|
+
- [1.0.0 Release](#1.0.0-release)
|
7
8
|
- [Making Requests](#making-requests)
|
8
9
|
- [Usage](#usage)
|
9
10
|
- [Error Handling](#error-handling)
|
10
11
|
- [Pagination](#pagination)
|
11
12
|
- [Navigating Through Paginated Results](#navigating-through-paginated-results)
|
12
13
|
- [Change Number of Results](#change-number-of-results)
|
14
|
+
- [Sync Actions](#sync-actions)
|
13
15
|
- [Configuration](#configuration)
|
14
16
|
- [Stores](#stores)
|
15
17
|
- [Session Store](#session-store)
|
16
18
|
- [Redis Store](#redis-store)
|
19
|
+
- [Dalli Store](#dalli-store)
|
17
20
|
- [ActiveRecord Store](#activerecord-store)
|
18
21
|
- [File Store](#file-store)
|
19
22
|
- [Memory Store](#memory-store)
|
20
23
|
- [Full Example](#full-example)
|
24
|
+
- [Contributing](#contributing)
|
21
25
|
|
22
26
|
## Installation
|
23
27
|
|
@@ -27,6 +31,11 @@ Add this line to your application's Gemfile:
|
|
27
31
|
gem "procore"
|
28
32
|
```
|
29
33
|
|
34
|
+
## 1.0.0 Release
|
35
|
+
|
36
|
+
v1.0.0 was released on January 5, 2021, and adds support the new Rest v1.0 API.
|
37
|
+
See the CHANGELOG for upgrade instructions.
|
38
|
+
|
30
39
|
## Making Requests
|
31
40
|
|
32
41
|
At the core of the gem is the `Client` class. Clients are initialized with a
|
@@ -38,19 +47,27 @@ Stores automatically manage tokens for you - refreshing, revoking and storage
|
|
38
47
|
are abstracted away to make your code as simple as possible. There are several
|
39
48
|
different [types of stores](#stores) available to you.
|
40
49
|
|
41
|
-
The Client class exposes `#get`, `#post`, `#put`, `#patch
|
42
|
-
to you.
|
50
|
+
The Client class exposes `#get`, `#post`, `#put`, `#patch`, `#sync` and
|
51
|
+
`#delete` methods to you.
|
43
52
|
|
44
53
|
```ruby
|
45
|
-
get(path, query: {})
|
46
|
-
post(path, body: {}, options: {})
|
47
|
-
put(path, body: {}, options: {})
|
48
|
-
patch(path, body: {}, options: {})
|
49
|
-
delete(path, query: {})
|
54
|
+
get(path, version: "", query: {})
|
55
|
+
post(path, version: "", body: {}, options: {})
|
56
|
+
put(path, version: "", body: {}, options: {})
|
57
|
+
patch(path, version: "", body: {}, options: {})
|
58
|
+
delete(path, version: "", query: {})
|
59
|
+
sync(path, version: "", body: {}, options: {})
|
50
60
|
```
|
51
61
|
|
52
|
-
All paths are relative
|
53
|
-
`
|
62
|
+
All paths are relative, the gem will handle expanding them. An API version may
|
63
|
+
be specified in the `version:` argument, or the default version is used. The
|
64
|
+
default version is `v1.0` unless otherwise configured.
|
65
|
+
|
66
|
+
| Example | Requested URL |
|
67
|
+
| --- | --- |
|
68
|
+
| `client.get("me")` | `https://app.procore.com/rest/v1.0/me` |
|
69
|
+
| `client.get("me", version: "v1.1")` | `https://app.procore.com/rest/v1.1/me` |
|
70
|
+
| `client.get("me", version: "vapid")` | `https://app.procore.com/vapid/me` |
|
54
71
|
|
55
72
|
Example Usage:
|
56
73
|
|
@@ -68,6 +85,19 @@ companies = client.get("companies")
|
|
68
85
|
companies.first[:name] #=> "Procore Company 1"
|
69
86
|
```
|
70
87
|
|
88
|
+
To use Procore's older API Vapid by default, the default version can be set in
|
89
|
+
either the Gem's [configuration](https://github.com/procore/ruby-sdk#configuration)
|
90
|
+
or the client's `options` hash:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
client = Procore::Client.new(
|
94
|
+
...
|
95
|
+
options {
|
96
|
+
default_version: "vapid"
|
97
|
+
}
|
98
|
+
)
|
99
|
+
```
|
100
|
+
|
71
101
|
## Usage
|
72
102
|
|
73
103
|
The first step is to place the user's token into the store. For this example,
|
@@ -258,6 +288,49 @@ puts first_page.pagination
|
|
258
288
|
Notice that because `per_page` has been set to 250, there are only two pages of
|
259
289
|
results (500 resources / 250 page size = 2 pages).
|
260
290
|
|
291
|
+
## Sync Actions
|
292
|
+
The Sync action enables batch creation or updates to resources using a single
|
293
|
+
call. When using a Sync action, the resources to be created or updated can be
|
294
|
+
specified by supplying either an `id` or an `origin_id` in the request body.
|
295
|
+
Utilizing the `origin_id` attribute for batch operations is often preferable as
|
296
|
+
it allows you to easily link to external systems by maintaining your own list of
|
297
|
+
unique resource identifiers outside of Procore.
|
298
|
+
|
299
|
+
The caller provides an array of hashes, each hash containing the attributes for
|
300
|
+
a single resource. The attribute names in each hash match those used by the
|
301
|
+
Create and Update actions for the resource. Attributes for a maximum of 1000
|
302
|
+
resources within a collection may be passed with each call. The API will always
|
303
|
+
return an HTTP status of 200.
|
304
|
+
|
305
|
+
The response body contains two attributes - `entities` and `errors`. The
|
306
|
+
attributes for each successfully created or updated resource will appear in the
|
307
|
+
entities list. The attributes for each resource will match those returned by the
|
308
|
+
Show action. For each resource which could not be created or updated, the
|
309
|
+
attributes supplied by the caller are present in the errors list, along with an
|
310
|
+
additional errors attribute which provides reasons for the failure.
|
311
|
+
|
312
|
+
[Continue reading
|
313
|
+
here.](https://developers.procore.com/documentation/using-sync-actions)
|
314
|
+
|
315
|
+
Example Usage:
|
316
|
+
|
317
|
+
```ruby
|
318
|
+
client.sync(
|
319
|
+
"projects/sync",
|
320
|
+
body: {
|
321
|
+
updates: [
|
322
|
+
{ id: 1, name: "Update 1" },
|
323
|
+
{ id: 2, name: "Update 2" },
|
324
|
+
{ id: 3, name: "Update 3" },
|
325
|
+
...
|
326
|
+
...
|
327
|
+
{ id: 5055, name: "Update 5055" },
|
328
|
+
]
|
329
|
+
},
|
330
|
+
options: { batch_size: 500, company_id: 1 },
|
331
|
+
)
|
332
|
+
```
|
333
|
+
|
261
334
|
## Configuration
|
262
335
|
|
263
336
|
The Procore Gem exposes a configuration with several options.
|
@@ -272,6 +345,15 @@ Procore.configure do |config|
|
|
272
345
|
# instead of production.
|
273
346
|
config.host = ENV.fetch("PROCORE_BASE_API_PATH", "https://app.procore.com")
|
274
347
|
|
348
|
+
# When using #sync action, sets the default batch size to use for chunking
|
349
|
+
# up a request body. Example: if the size is set to 500, and 2,000 updates
|
350
|
+
# are desired, 4 requests will be made. Note, the maximum size is 1000.
|
351
|
+
config.default_batch_size = 500
|
352
|
+
|
353
|
+
# The default API version to use if none is specified in the request.
|
354
|
+
# Should be either "v1.0" (recommended) or "vapid" (legacy).
|
355
|
+
config.default_version = "v1.0"
|
356
|
+
|
275
357
|
# Integer: Number of times to retry a failed API call. Reasons an API call
|
276
358
|
# could potentially fail:
|
277
359
|
# 1. Service is briefly down or unreachable
|
@@ -313,6 +395,14 @@ Options: `session`: Instance of a Rails session
|
|
313
395
|
|
314
396
|
For applications that want to keep access tokens in the user's session.
|
315
397
|
|
398
|
+
:warning:
|
399
|
+
We strongly discourage using the session as a token store since the rails
|
400
|
+
session is often logged by default to external apps such as bugsnag etc. Be sure
|
401
|
+
you are not logging tokens. There is also the possibility that the rails session
|
402
|
+
is using a cookie store which, depending on application settings, could be
|
403
|
+
unencrypted. Tokens should not be stored client-side if it can be avoided.
|
404
|
+
:warning:
|
405
|
+
|
316
406
|
```ruby
|
317
407
|
store = Procore::Auth::Stores::Session.new(session: session)
|
318
408
|
```
|
@@ -331,6 +421,20 @@ The key will usually be the id of the current user.
|
|
331
421
|
store = Procore::Auth::Stores::Redis.new(redis: Redis.new, key: current_user.id)
|
332
422
|
```
|
333
423
|
|
424
|
+
### Dalli Store
|
425
|
+
|
426
|
+
Options: `dalli`: Instance of Dalli
|
427
|
+
Options: `key`: Unique identifier to an access token
|
428
|
+
|
429
|
+
For applications which want to store access tokens in memcached using Dalli.
|
430
|
+
There's two required options, `dalli` which is an instance of a Dalli client,
|
431
|
+
and `key` which is a unique key which will be used to save / retrieve an access
|
432
|
+
token. The key will usually be the id of the current user.
|
433
|
+
|
434
|
+
```ruby
|
435
|
+
store = Procore::Auth::Stores::Dalli.new(dalli: Dalli.new, key: current_user.id)
|
436
|
+
```
|
437
|
+
|
334
438
|
### ActiveRecord Store
|
335
439
|
|
336
440
|
Options: `object`: Instance of an ActiveRecord model.
|
@@ -410,6 +514,27 @@ class ProjectsController
|
|
410
514
|
end
|
411
515
|
end
|
412
516
|
```
|
517
|
+
## Contributing
|
518
|
+
|
519
|
+
To contribute to the gem, please clone the repo and cut a new branch. In the PR update the changelog with a short explanation of what you've changed, and your name under the "Unreleased" section. Example changelog update:
|
520
|
+
|
521
|
+
```markdown
|
522
|
+
## Unreleased
|
523
|
+
|
524
|
+
* Short sentence of what has changed
|
525
|
+
|
526
|
+
*Your Name*
|
527
|
+
```
|
528
|
+
|
529
|
+
Please **do not** bump the gem version in your PR. This will be done in a follow up PR by the gem maintainers.
|
530
|
+
|
531
|
+
### Tests
|
532
|
+
|
533
|
+
To run the specs run the following command:
|
534
|
+
```bash
|
535
|
+
$ bundle exec rake test
|
536
|
+
```
|
537
|
+
|
413
538
|
|
414
539
|
## License
|
415
540
|
|
data/lib/procore.rb
CHANGED
@@ -7,6 +7,7 @@ require "json"
|
|
7
7
|
require "procore/auth/access_token_credentials"
|
8
8
|
require "procore/auth/client_credentials"
|
9
9
|
require "procore/auth/stores/active_record"
|
10
|
+
require "procore/auth/stores/dalli"
|
10
11
|
require "procore/auth/stores/file"
|
11
12
|
require "procore/auth/stores/memory"
|
12
13
|
require "procore/auth/stores/redis"
|
@@ -29,7 +29,7 @@ module Procore
|
|
29
29
|
raise OAuthError.new(e.description, response: e.response)
|
30
30
|
rescue Faraday::ConnectionFailed => e
|
31
31
|
raise APIConnectionError.new("Connection Error: #{e.message}")
|
32
|
-
rescue URI::BadURIError
|
32
|
+
rescue URI::BadURIError, URI::InvalidURIError
|
33
33
|
raise OAuthError.new(
|
34
34
|
"Host is not a valid URI. Check your host option to make sure it " \
|
35
35
|
"is a properly formed url",
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Procore
|
2
|
+
module Auth
|
3
|
+
module Stores
|
4
|
+
class Dalli
|
5
|
+
attr_reader :key, :dalli
|
6
|
+
def initialize(key:, dalli:)
|
7
|
+
@key = key
|
8
|
+
@dalli = dalli
|
9
|
+
end
|
10
|
+
|
11
|
+
def save(token)
|
12
|
+
dalli.set(dalli_key, token.to_json)
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch
|
16
|
+
return unless dalli.get(dalli_key)
|
17
|
+
|
18
|
+
token = JSON.parse(dalli.get(dalli_key))
|
19
|
+
Procore::Auth::Token.new(
|
20
|
+
access_token: token["access_token"],
|
21
|
+
refresh_token: token["refresh_token"],
|
22
|
+
expires_at: token["expires_at"],
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete
|
27
|
+
dalli.delete(dalli_key)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def dalli_key
|
33
|
+
"procore-dalli-#{key}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/procore/client.rb
CHANGED
@@ -32,6 +32,15 @@ module Procore
|
|
32
32
|
# @return [String]
|
33
33
|
attr_accessor :host
|
34
34
|
|
35
|
+
# @!attribute [rw] default_version
|
36
|
+
# @note defaults to Defaults::DEFAULT_VERSION
|
37
|
+
#
|
38
|
+
# The default API version to use if none is specified in the request.
|
39
|
+
# Should be either "v1.0" (recommended) or "vapid" (legacy).
|
40
|
+
#
|
41
|
+
# @return [String]
|
42
|
+
attr_accessor :default_version
|
43
|
+
|
35
44
|
# @!attribute [rw] logger
|
36
45
|
# @note defaults to nil
|
37
46
|
#
|
@@ -77,12 +86,26 @@ module Procore
|
|
77
86
|
# @return [String]
|
78
87
|
attr_accessor :user_agent
|
79
88
|
|
89
|
+
# @!attribute [rw] default_batch_size
|
90
|
+
# @note defaults to Defaults::BATCH_SIZE
|
91
|
+
#
|
92
|
+
# When using #sync action, sets the default batch size to use for chunking
|
93
|
+
# up a request body. Example, if the size is set to 500 and 2,000 updates
|
94
|
+
# are desired, 4 requests will be made.
|
95
|
+
#
|
96
|
+
# Note: The maximum size is 1,000
|
97
|
+
#
|
98
|
+
# @return [Integer]
|
99
|
+
attr_accessor :default_batch_size
|
100
|
+
|
80
101
|
def initialize
|
102
|
+
@default_batch_size = Procore::Defaults::BATCH_SIZE
|
81
103
|
@host = Procore::Defaults::API_ENDPOINT
|
82
104
|
@logger = nil
|
83
105
|
@max_retries = 1
|
84
106
|
@timeout = 1.0
|
85
107
|
@user_agent = Procore::Defaults::USER_AGENT
|
108
|
+
@default_version = Procore::Defaults::DEFAULT_VERSION
|
86
109
|
end
|
87
110
|
end
|
88
111
|
end
|
data/lib/procore/defaults.rb
CHANGED
@@ -9,10 +9,17 @@ module Procore
|
|
9
9
|
# Default User Agent header string
|
10
10
|
USER_AGENT = "Procore Ruby Gem #{Procore::VERSION}".freeze
|
11
11
|
|
12
|
+
# Default size to use for batch requests
|
13
|
+
BATCH_SIZE = 500
|
14
|
+
|
15
|
+
# Default API version to use
|
16
|
+
DEFAULT_VERSION = "v1.0"
|
17
|
+
|
12
18
|
def self.client_options
|
13
19
|
{
|
14
20
|
host: Procore.configuration.host,
|
15
21
|
user_agent: Procore.configuration.user_agent,
|
22
|
+
default_version: Procore.configuration.default_version,
|
16
23
|
}
|
17
24
|
end
|
18
25
|
end
|
data/lib/procore/requestable.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "rest-client"
|
2
|
+
require "procore/errors"
|
2
3
|
|
3
4
|
module Procore
|
4
5
|
# Module which defines HTTP verbs GET, POST, PUT, PATCH and DELETE. Is
|
@@ -10,7 +11,15 @@ module Procore
|
|
10
11
|
# @example Using #post:
|
11
12
|
# client.post("projects", name: "New Project")
|
12
13
|
module Requestable
|
14
|
+
HTTP_EXCEPTIONS = [
|
15
|
+
Errno::ECONNREFUSED,
|
16
|
+
Errno::ECONNRESET,
|
17
|
+
Procore::OAuthError,
|
18
|
+
RestClient::Exceptions::Timeout,
|
19
|
+
RestClient::ServerBrokeConnection,
|
20
|
+
].freeze
|
13
21
|
# @param path [String] URL path
|
22
|
+
# @param version [String] API version
|
14
23
|
# @param query [Hash] Query options to pass along with the request
|
15
24
|
# @option options [Hash] :company_id
|
16
25
|
#
|
@@ -18,10 +27,12 @@ module Procore
|
|
18
27
|
# client.get("my_open_items", query: { per_page: 5, filter: {} })
|
19
28
|
#
|
20
29
|
# @return [Response]
|
21
|
-
def get(path, query: {}, options: {})
|
30
|
+
def get(path, version: nil, query: {}, options: {})
|
31
|
+
full_path = full_path(path, version)
|
32
|
+
|
22
33
|
Util.log_info(
|
23
34
|
"API Request Initiated",
|
24
|
-
path:
|
35
|
+
path: full_path,
|
25
36
|
method: "GET",
|
26
37
|
query: query.to_s,
|
27
38
|
)
|
@@ -29,7 +40,7 @@ module Procore
|
|
29
40
|
with_response_handling do
|
30
41
|
RestClient::Request.execute(
|
31
42
|
method: :get,
|
32
|
-
url:
|
43
|
+
url: full_path,
|
33
44
|
headers: headers(options).merge(params: query),
|
34
45
|
timeout: Procore.configuration.timeout,
|
35
46
|
)
|
@@ -37,8 +48,9 @@ module Procore
|
|
37
48
|
end
|
38
49
|
|
39
50
|
# @param path [String] URL path
|
51
|
+
# @param version [String] API version
|
40
52
|
# @param body [Hash] Body parameters to send with the request
|
41
|
-
# @param options [Hash
|
53
|
+
# @param options [Hash] Extra request options
|
42
54
|
# @option options [String] :idempotency_token | :company_id
|
43
55
|
#
|
44
56
|
# @example Usage
|
@@ -49,10 +61,12 @@ module Procore
|
|
49
61
|
# )
|
50
62
|
#
|
51
63
|
# @return [Response]
|
52
|
-
def post(path, body: {}, options: {})
|
64
|
+
def post(path, version: nil, body: {}, options: {})
|
65
|
+
full_path = full_path(path, version)
|
66
|
+
|
53
67
|
Util.log_info(
|
54
68
|
"API Request Initiated",
|
55
|
-
path:
|
69
|
+
path: full_path,
|
56
70
|
method: "POST",
|
57
71
|
body: body.to_s,
|
58
72
|
)
|
@@ -60,7 +74,7 @@ module Procore
|
|
60
74
|
with_response_handling(request_body: body) do
|
61
75
|
RestClient::Request.execute(
|
62
76
|
method: :post,
|
63
|
-
url:
|
77
|
+
url: full_path,
|
64
78
|
payload: payload(body),
|
65
79
|
headers: headers(options),
|
66
80
|
timeout: Procore.configuration.timeout,
|
@@ -69,18 +83,21 @@ module Procore
|
|
69
83
|
end
|
70
84
|
|
71
85
|
# @param path [String] URL path
|
86
|
+
# @param version [String] API version
|
72
87
|
# @param body [Hash] Body parameters to send with the request
|
73
|
-
# @param options [Hash
|
88
|
+
# @param options [Hash] Extra request options
|
74
89
|
# @option options [String] :idempotency_token | :company_id
|
75
90
|
#
|
76
91
|
# @example Usage
|
77
92
|
# client.put("dashboards/1/users", body: [1,2,3], options: { company_id: 1 })
|
78
93
|
#
|
79
94
|
# @return [Response]
|
80
|
-
def put(path, body: {}, options: {})
|
95
|
+
def put(path, version: nil, body: {}, options: {})
|
96
|
+
full_path = full_path(path, version)
|
97
|
+
|
81
98
|
Util.log_info(
|
82
99
|
"API Request Initiated",
|
83
|
-
path:
|
100
|
+
path: full_path,
|
84
101
|
method: "PUT",
|
85
102
|
body: body.to_s,
|
86
103
|
)
|
@@ -88,7 +105,7 @@ module Procore
|
|
88
105
|
with_response_handling(request_body: body) do
|
89
106
|
RestClient::Request.execute(
|
90
107
|
method: :put,
|
91
|
-
url:
|
108
|
+
url: full_path,
|
92
109
|
payload: payload(body),
|
93
110
|
headers: headers(options),
|
94
111
|
timeout: Procore.configuration.timeout,
|
@@ -97,8 +114,9 @@ module Procore
|
|
97
114
|
end
|
98
115
|
|
99
116
|
# @param path [String] URL path
|
117
|
+
# @param version [String] API version
|
100
118
|
# @param body [Hash] Body parameters to send with the request
|
101
|
-
# @param options [Hash
|
119
|
+
# @param options [Hash] Extra request options
|
102
120
|
# @option options [String] :idempotency_token | :company_id
|
103
121
|
#
|
104
122
|
# @example Usage
|
@@ -109,10 +127,12 @@ module Procore
|
|
109
127
|
# )
|
110
128
|
#
|
111
129
|
# @return [Response]
|
112
|
-
def patch(path, body: {}, options: {})
|
130
|
+
def patch(path, version: nil, body: {}, options: {})
|
131
|
+
full_path = full_path(path, version)
|
132
|
+
|
113
133
|
Util.log_info(
|
114
134
|
"API Request Initiated",
|
115
|
-
path:
|
135
|
+
path: full_path,
|
116
136
|
method: "PATCH",
|
117
137
|
body: body.to_s,
|
118
138
|
)
|
@@ -120,7 +140,7 @@ module Procore
|
|
120
140
|
with_response_handling(request_body: body) do
|
121
141
|
RestClient::Request.execute(
|
122
142
|
method: :patch,
|
123
|
-
url:
|
143
|
+
url: full_path,
|
124
144
|
payload: payload(body),
|
125
145
|
headers: headers(options),
|
126
146
|
timeout: Procore.configuration.timeout,
|
@@ -129,6 +149,73 @@ module Procore
|
|
129
149
|
end
|
130
150
|
|
131
151
|
# @param path [String] URL path
|
152
|
+
# @param version [String] API version
|
153
|
+
# @param body [Hash] Body parameters to send with the request
|
154
|
+
# @param options [Hash] Extra request options
|
155
|
+
# @option options [String | Integer] :company_id | :batch_size
|
156
|
+
#
|
157
|
+
# @example Usage
|
158
|
+
# client.sync(
|
159
|
+
# "projects/sync",
|
160
|
+
# body: {
|
161
|
+
# updates: [
|
162
|
+
# { id: 1, name: "Update 1" },
|
163
|
+
# { id: 2, name: "Update 2" },
|
164
|
+
# { id: 3, name: "Update 3" },
|
165
|
+
# ...
|
166
|
+
# ...
|
167
|
+
# { id: 5055, name: "Update 5055" },
|
168
|
+
# ]
|
169
|
+
# },
|
170
|
+
# options: { batch_size: 500, company_id: 1 },
|
171
|
+
# )
|
172
|
+
#
|
173
|
+
# @return [Response]
|
174
|
+
def sync(path, version: nil, body: {}, options: {})
|
175
|
+
full_path = full_path(path, version)
|
176
|
+
|
177
|
+
batch_size = options[:batch_size] ||
|
178
|
+
Procore.configuration.default_batch_size
|
179
|
+
|
180
|
+
if batch_size > 1000
|
181
|
+
batch_size = 1000
|
182
|
+
end
|
183
|
+
|
184
|
+
Util.log_info(
|
185
|
+
"API Request Initiated",
|
186
|
+
path: full_path,
|
187
|
+
method: "SYNC",
|
188
|
+
batch_size: batch_size,
|
189
|
+
)
|
190
|
+
|
191
|
+
groups = body[:updates].each_slice(batch_size).to_a
|
192
|
+
|
193
|
+
responses = groups.map do |group|
|
194
|
+
batched_body = body.merge(updates: group)
|
195
|
+
with_response_handling(request_body: batched_body) do
|
196
|
+
RestClient::Request.execute(
|
197
|
+
method: :patch,
|
198
|
+
url: full_path,
|
199
|
+
payload: payload(batched_body),
|
200
|
+
headers: headers(options),
|
201
|
+
timeout: Procore.configuration.timeout,
|
202
|
+
)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
Procore::Response.new(
|
207
|
+
body: responses.reduce({}) do |combined, response|
|
208
|
+
combined.deep_merge(response.body) { |_, v1, v2| v1 + v2 }
|
209
|
+
end.to_json,
|
210
|
+
headers: responses.map(&:headers).inject({}, &:deep_merge),
|
211
|
+
code: 200,
|
212
|
+
request: responses.last&.request,
|
213
|
+
request_body: body,
|
214
|
+
)
|
215
|
+
end
|
216
|
+
|
217
|
+
# @param path [String] URL path
|
218
|
+
# @param version [String] API version
|
132
219
|
# @param query [Hash] Query options to pass along with the request
|
133
220
|
# @option options [String] :company_id
|
134
221
|
#
|
@@ -136,10 +223,12 @@ module Procore
|
|
136
223
|
# client.delete("users/1", query: {}, options: {})
|
137
224
|
#
|
138
225
|
# @return [Response]
|
139
|
-
def delete(path, query: {}, options: {})
|
226
|
+
def delete(path, version: nil, query: {}, options: {})
|
227
|
+
full_path = full_path(path, version)
|
228
|
+
|
140
229
|
Util.log_info(
|
141
230
|
"API Request Initiated",
|
142
|
-
path:
|
231
|
+
path: full_path,
|
143
232
|
method: "DELETE",
|
144
233
|
headers: headers(options),
|
145
234
|
query: query.to_s,
|
@@ -148,7 +237,7 @@ module Procore
|
|
148
237
|
with_response_handling do
|
149
238
|
RestClient::Request.execute(
|
150
239
|
method: :delete,
|
151
|
-
url:
|
240
|
+
url: full_path,
|
152
241
|
headers: headers.merge(params: query),
|
153
242
|
timeout: Procore.configuration.timeout,
|
154
243
|
)
|
@@ -163,7 +252,7 @@ module Procore
|
|
163
252
|
|
164
253
|
begin
|
165
254
|
result = yield
|
166
|
-
rescue
|
255
|
+
rescue *HTTP_EXCEPTIONS => e
|
167
256
|
if retries <= Procore.configuration.max_retries
|
168
257
|
retries += 1
|
169
258
|
sleep 1.5**retries
|
@@ -277,5 +366,16 @@ module Procore
|
|
277
366
|
def multipart?(body)
|
278
367
|
RestClient::Payload::has_file?(body)
|
279
368
|
end
|
369
|
+
|
370
|
+
def full_path(path, version)
|
371
|
+
version ||= options[:default_version]
|
372
|
+
if version == "vapid"
|
373
|
+
File.join(base_api_path, "vapid", path)
|
374
|
+
elsif /\Av\d+\.\d+\z/.match?(version)
|
375
|
+
File.join(base_api_path, "rest", version, path)
|
376
|
+
else
|
377
|
+
raise ArgumentError.new "'#{version}' is an invalid Procore API version"
|
378
|
+
end
|
379
|
+
end
|
280
380
|
end
|
281
381
|
end
|
data/lib/procore/response.rb
CHANGED
@@ -72,7 +72,7 @@ module Procore
|
|
72
72
|
|
73
73
|
def parse_pagination
|
74
74
|
headers[:link].to_s.split(", ").map(&:strip).reduce({}) do |links, link|
|
75
|
-
url, name = link.match(/vapid\/(.*?)>; rel="(\w+)"/).captures
|
75
|
+
url, name = link.match(/(?:vapid|rest\/.*?)\/(.*?)>; rel="(\w+)"/).captures
|
76
76
|
links.merge!(name.to_sym => url)
|
77
77
|
end
|
78
78
|
end
|
data/lib/procore/version.rb
CHANGED
data/procore.gemspec
CHANGED
@@ -25,12 +25,15 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency "actionpack"
|
26
26
|
spec.add_development_dependency "activerecord"
|
27
27
|
spec.add_development_dependency "bundler"
|
28
|
+
spec.add_development_dependency "dalli"
|
28
29
|
spec.add_development_dependency "fakefs"
|
29
30
|
spec.add_development_dependency "minitest"
|
30
31
|
spec.add_development_dependency "pry"
|
31
32
|
spec.add_development_dependency "rake"
|
32
33
|
spec.add_development_dependency "redis"
|
33
34
|
spec.add_development_dependency "rubocop"
|
35
|
+
spec.add_development_dependency "rubocop-performance"
|
36
|
+
spec.add_development_dependency "rubocop-rails"
|
34
37
|
spec.add_development_dependency "sqlite3"
|
35
38
|
spec.add_development_dependency "webmock"
|
36
39
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: procore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Procore Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: dalli
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: fakefs
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +150,34 @@ dependencies:
|
|
136
150
|
- - ">="
|
137
151
|
- !ruby/object:Gem::Version
|
138
152
|
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubocop-performance
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: rubocop-rails
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
139
181
|
- !ruby/object:Gem::Dependency
|
140
182
|
name: sqlite3
|
141
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -227,6 +269,7 @@ files:
|
|
227
269
|
- lib/procore/auth/access_token_credentials.rb
|
228
270
|
- lib/procore/auth/client_credentials.rb
|
229
271
|
- lib/procore/auth/stores/active_record.rb
|
272
|
+
- lib/procore/auth/stores/dalli.rb
|
230
273
|
- lib/procore/auth/stores/file.rb
|
231
274
|
- lib/procore/auth/stores/memory.rb
|
232
275
|
- lib/procore/auth/stores/redis.rb
|
@@ -260,8 +303,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
260
303
|
- !ruby/object:Gem::Version
|
261
304
|
version: '0'
|
262
305
|
requirements: []
|
263
|
-
|
264
|
-
rubygems_version: 2.7.6
|
306
|
+
rubygems_version: 3.1.4
|
265
307
|
signing_key:
|
266
308
|
specification_version: 4
|
267
309
|
summary: Procore Ruby Gem
|