procore 0.6.7

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 318aae4eb7a76a5bad258a57d2614bde20e5b35b56f2e0d05a5d8d4ea2dc1aa6
4
+ data.tar.gz: 3546d5ca61534836b1ef63d10bf95e5f26db586a8873be3466a87e82824c02d9
5
+ SHA512:
6
+ metadata.gz: 0b5460652ebaf4c1b73925333d58345ba1483d7e5fd92403ac9c756209430918c4f73d819ee02328be314e91e030e48df13dfce913c3ce01eb6eb15a780ba248
7
+ data.tar.gz: 6d9340c15d1d28018e88019b60bccf5e2211a1a976294d1c293738330d1b853794daf08463d6842c96b2a1ef0b88d7f8704d1ef5842c7d84f6f48005f3c3d65e
@@ -0,0 +1,11 @@
1
+ .yardopts
2
+
3
+ /.bundle/
4
+ /.yardoc
5
+ /Gemfile.lock
6
+ /_yardoc/
7
+ /coverage/
8
+ /doc/
9
+ /pkg/
10
+ /spec/reports/
11
+ /tmp/
@@ -0,0 +1,27 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3
4
+ - 2.4
5
+ - 2.5
6
+
7
+ services:
8
+ - redis-server
9
+
10
+ before_install:
11
+ - gem update --system
12
+
13
+ cache: bundler
14
+
15
+ script: bundle exec rake
16
+
17
+ deploy:
18
+ provider: rubygems
19
+ api_key:
20
+ secure: GYH7nTi2D9ZwbCP+JYSgHceDUvZT9RQSP6yXFndwSyxdiSmB6wfq6EtoH4Wpznd6ALT6IxrtbR4aftTI9DO6HPq+PVO6NdxjkdlbdxxAqRQJBAwFwFATT8jCuuDjGPLf8PF0ouzcMvAIdIgHypwmLdevWdEMomWdRWlm1UFP/0C3RDjY1v04XDrRb+fEagPNnzMDCcO352nyFm06jnCq/ezjCRXBvNtHTZeqd7t9pbNw7gtYebZ3b9hfd4IIa68budeh+URygiPnNNWr6TCjO95IuHIeMDele3tir0KzqVBNsVAqEb7WpB26rf1JgneAoYZwVMFh+hk09cs68EbIELD4MX6/PzEUz2Ws20dIMjs1pcDtlw35ixoEpwC/vz2qVJyMRYXg8af5rpsZkKXRl7QP2LrX+xSEt4LiRnylj4PaRZWu1gvhC7fsCHXEM3mW3WlXFUmb9W4Jv8VooqOJtGhpD9Qs9pYtTOgJoEmYqttbuCaiYKaiPutBY4+t+t2ZmyCopv41nkjv/UCWXfo11ew1qK0rxDJVE2/JYTUDZ+zuHypTf2lHCWjyP65vGwBnmdixLnEMCUOkzKUmqFR4kAE6jRMEhtki4fTlFSIHJGM5oIXeRXDR43NIh7xWNvhl7lHkwWoRA0BfSITtvO8k0SefGnFwhNfOglQ/GKfyAaY=
21
+ gem: procore
22
+ on:
23
+ tags: true
24
+ repo: procore/ruby-sdk
25
+
26
+ notifications:
27
+ email: false
@@ -0,0 +1,46 @@
1
+ ## Unreleased
2
+
3
+ ## 0.6.7 (January 04, 2018)
4
+
5
+ * Allow gem to be pushed to RubyGems
6
+
7
+ ## 0.6.6 (January 04, 2018)
8
+
9
+ * Move to using TravisCI
10
+ * Publish to RubyGems
11
+
12
+ ## 0.6.5 (January 04, 2018)
13
+
14
+ * Add response to `OAuthError`
15
+
16
+ ## 0.6.4 (December 15, 2017)
17
+
18
+ * Fix issue with passing request into `Procore::Response`.
19
+
20
+ *Michael Stock*
21
+
22
+ ## 0.6.3 (December 11, 2017)
23
+
24
+ * Fix issue with client credentials by forcing the usage of request body
25
+ for sending `client_id` and `client_secret`
26
+
27
+ *Michael Stock*
28
+
29
+ ## 0.6.2 (December 6, 2017)
30
+
31
+ * Fix session store not saving off the optional key attribute
32
+
33
+ PR #2 - https://github.com/procore/ruby-sdk/pull/2
34
+
35
+ *Patrick Koperwas*
36
+
37
+ ## 0.6.1 (December 6, 2017)
38
+
39
+ * Change error class for 404s.
40
+
41
+ Previously a 404 would raise a Procore::InvalidRequestError. Now, a 404 will
42
+ raise a Procore::NotFoundError,
43
+
44
+ PR #1 - https://github.com/procore/ruby-sdk/pull/1
45
+
46
+ *Patrick Koperwas*
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in procore.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Patrick Koperwas
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.
@@ -0,0 +1,407 @@
1
+ # Procore Gem
2
+
3
+ [![Build Status](https://travis-ci.org/procore/ruby-sdk.svg?branch=move-to-travis)](https://travis-ci.org/procore/ruby-sdk)
4
+
5
+ ## Installation & Usage
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "procore"
11
+ ```
12
+
13
+ ## Making Requests
14
+
15
+ At the core of the gem is the `Client` class. Clients are initialized with a
16
+ `client_id` and `client_secret` which can be obtained by signing up for
17
+ Procore's [Developer Program](https://developers.procore.com/).
18
+
19
+ A client requires a store. A store manages a particular user's access token.
20
+ Stores automatically manage tokens for you - refreshing, revoking and storage
21
+ are abstracted away to make your code as simple as possible. There are several
22
+ different [types of stores](#stores) available to you.
23
+
24
+ The client class exposes `#get`, `#post`, `#patch` and `#delete` methods to you.
25
+
26
+ ```ruby
27
+ get(path, query = {})
28
+ post(path, body = {}, options = {})
29
+ patch(path, body = {}, options = {})
30
+ delete(path, query = {})
31
+ ```
32
+
33
+ All paths are relative - the gem will handle expanding `client.get("me")` to
34
+ `https://app.procore.com/vapid/me`.
35
+
36
+ Example Usage:
37
+
38
+ ```ruby
39
+ store = Procore::Auth::Stores::Session.new(session: session)
40
+ client = Procore::Client.new(
41
+ client_id: "client id",
42
+ client_secret: "client secret",
43
+ store: store
44
+ )
45
+
46
+ # Get the current user's companies
47
+ companies = client.get("companies")
48
+
49
+ companies.first[:name] #=> "Procore Company 1"
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ The first step is to place the user's token into the store. For this example,
55
+ the tokens will be stored in the Rails session. In the controller action that
56
+ handles the end of the [OAuth 2.0
57
+ Flow](https://developers.procore.com/documentation/oauth-introduction) add the
58
+ following code:
59
+
60
+ ```ruby
61
+ def handle_callback
62
+ if auth_hash.blank?
63
+ redirect_to '/auth/procore'
64
+ else
65
+ auth_hash = request.env['omniauth.auth']
66
+
67
+ # Create a new token to save into a store
68
+ token = Procore::Auth::Token.new(
69
+ access_token: auth_hash["credentials"]["token"]
70
+ refresh_token: auth_hash["credentials"]["refresh_token"],
71
+ expires_at: auth_hash["credentials"]["expires_at"]
72
+ )
73
+
74
+ store = Procore::Auth::Stores::Session.new(session: session)
75
+ store.save(token)
76
+
77
+ redirect_to root_path
78
+ end
79
+ end
80
+ ```
81
+
82
+ With the user's token stored, requests can be made from anywhere in the
83
+ application that has access to the Rails session.
84
+
85
+ ```ruby
86
+ client = Procore::Client.new(
87
+ client_id: Rails.application.secrets.procore_app_id,
88
+ client_secret: Rails.application.secrets.procore_app_secret,
89
+ store: Procore::Auth::Stores::Session.new(session: session)
90
+ )
91
+
92
+ client.get("me")
93
+ ```
94
+
95
+ ## Error Handling
96
+
97
+ The Procore Gem raises errors whenever a request returns a non `2xx` response.
98
+ Errors return both a message detailing the error and an instance of a
99
+ `Response`.
100
+
101
+ ```ruby
102
+ begin
103
+ # Use Procore Gem to make requests
104
+ client.get("projects")
105
+
106
+ rescue Procore::RateLimitError => e
107
+ # Raised when a token reaches it's request limit for the current time period.
108
+ # If you are receiving this error then you are making too many requests
109
+ # against the Procore API.
110
+
111
+ rescue Procore::NotFoundError => e
112
+ # Raised when the request 404's
113
+
114
+ rescue Procore::InvalidRequestError => e
115
+ # Raised when the request is incorrectly formated. Possible causes: missing
116
+ # required parameters or sending a request to access a non-existent resource.
117
+
118
+ rescue Procore::OAuthError => e
119
+ # Raised whenever there is a problem with OAuth. Possible causes: required
120
+ # credentials are missing or an access token failed to refresh.
121
+
122
+ rescue Procore::AuthorizationError => e
123
+ # Raised when the request is attempting to access a resource the token's
124
+ # owner does not have access to.
125
+
126
+ rescue Procore::APIConnectionError => e
127
+ # Raised when the gem cannot connect to the Procore API. Possible causes:
128
+ # Procore is down or the network is doing something funny.
129
+
130
+ rescue Procore::ServerError => e
131
+ # Raised when a Procore endpoint returns a 500x resonse code.
132
+
133
+ rescue Procore::Error => e
134
+ # Generic catch all error.
135
+
136
+ rescue => e
137
+ # Something unrelated to Procore errored.
138
+ end
139
+ ```
140
+
141
+ Note that all errors inherit from `Procore::Error`, so if you do not need to
142
+ handle each error uniquely you can just rescue from this base class to catch all
143
+ errors generated by this gem.
144
+
145
+ ```ruby
146
+ begin
147
+ client.get("projects")
148
+ rescue Procore:Error => e
149
+ # Something went wrong.
150
+
151
+ # Print the error class
152
+ puts e.class
153
+
154
+ # Print the error message
155
+ puts e.message
156
+
157
+ # Print the HTTP code
158
+ puts e.response.code
159
+
160
+ # Print the json error response
161
+ puts e.response.errors
162
+
163
+ # Print the headers
164
+ puts e.response.headers
165
+ end
166
+ ```
167
+
168
+ ## Pagination
169
+ Endpoints which return multiple objects (a collection) will include pagination
170
+ information. The `Response` object has a `#pagination` method that will return
171
+ a hash which may conditionally contain the following keys:
172
+
173
+ ```
174
+ :next URL for the immediate next page of results.
175
+ :last URL for the last page of results.
176
+ :first URL for the first page of results.
177
+ :prev URL for the immediate previous page of results.
178
+ ```
179
+
180
+ For example, on the first page of results the `#pagination` method will look
181
+ like:
182
+
183
+ ```ruby
184
+ response.pagination
185
+
186
+ {
187
+ next: "projects?per_page=100&page=2",
188
+ last: "projects?per_page=100&page=5"
189
+ }
190
+ ```
191
+
192
+ The `next` value will return the second page of results - which is expected as
193
+ all paginated responses start on page 1. The `last` value ends on page 5, so
194
+ there are another 4 pages to consume in order to get all the possible results.
195
+
196
+ ### Navigating Through Paginated Results
197
+
198
+ To get the next page of results, just pass the url into `client#get`. You may
199
+ want to guard against the next page being potentially empty.
200
+
201
+ ```ruby
202
+ first_page = client.get("projects")
203
+
204
+ if first_page.pagination[:next]
205
+ next_page = client.get(first_page.pagination[:next])
206
+ end
207
+
208
+ puts next_page.pagination
209
+
210
+ {
211
+ first: "projects?per_page=100&page=1",
212
+ next: "projects?per_page=100&page=3",
213
+ prev: "projects?per_page=100&page=1",
214
+ last: "projects?per_page=100&page=5"
215
+ }
216
+ ```
217
+
218
+ ### Change Number of Results
219
+
220
+ You can pass a `per_page` query parameter in your request to change the page
221
+ size. The pagination links will update to reflect that change.
222
+
223
+ ```
224
+ first_page = client.get("projects", per_page: 250)
225
+
226
+ puts first_page.pagination
227
+ {
228
+ next: "projects?per_page=250&page=2",
229
+ last: "projects?per_page=250&page=2"
230
+ }
231
+ ```
232
+
233
+ Notice that because `per_page` has been set to 250, there are only two pages of
234
+ results (500 resources / 250 page size = 2 pages).
235
+
236
+ ## Configuration
237
+
238
+ The Procore Gem exposes a configuration with several options.
239
+
240
+ ```ruby
241
+ # config/initializes/procore.rb
242
+
243
+ require "procore"
244
+ Procore.configure do |config|
245
+ # Base API host name. Alter this depending on your environment - in a
246
+ # staging or test environment you may want to point this at a sandbox
247
+ # instead of production.
248
+ config.host = ENV.fetch("PROCORE_BASE_API_PATH", "https://app.procore.com")
249
+
250
+ # Integer: Number of times to retry a failed API call. Reasons an API call
251
+ # could potentially fail:
252
+ # 1. Service is briefly down or unreachable
253
+ # 2. Timeout hit - service is experiencing immense load or mid restart
254
+ # 3. Because computers
255
+ #
256
+ # Defaults to 1 retry. Would recommend 3-5 for production use.
257
+ # Has exponential backoff - first request waits a 1.5s after a failure,
258
+ # next one 2.25s, next one 3.375s, 5.0, etc.
259
+ config.max_retries = 3
260
+
261
+ # Float: Threshold for canceling an API request. If a request takes longer
262
+ # than this value it will automatically cancel.
263
+ config.timeout = 5.0
264
+
265
+ # Instance of a Logger. This gem will log information about requests,
266
+ # responses and other things it might be doing. In a Rails application it
267
+ # should be set to Rails.logger
268
+ config.logger = Rails.logger
269
+
270
+ # String: User Agent sent with each API request. API requests must have a user
271
+ # agent set. It is recomended to set the user agent to the name of your
272
+ # application.
273
+ config.user_agent = "MyAppName"
274
+ end
275
+ ```
276
+
277
+ ## Stores
278
+
279
+ Stores contain logic for accessing, storing, and managing access tokens. The
280
+ Procore API uses expiring tokens - this gem abstracts away the need to manually
281
+ refresh tokens.
282
+
283
+ Available stores:
284
+
285
+ ### Session Store
286
+
287
+ Options: `session`: Instance of a Rails session
288
+
289
+ For applications that want to keep access tokens in the user's session.
290
+
291
+ ```ruby
292
+ store = Procore::Auth::Stores::Session.new(session: session)
293
+ ```
294
+
295
+ ### Redis Store
296
+
297
+ Options: `redis`: Instance of Redis
298
+ Options: `key`: Unique identifier to an access token
299
+
300
+ For applications which want to store access tokens in Redis. There's two
301
+ required options, `redis` which is an instance of a Redis connection, and `key`
302
+ which is a unique key which will be used to save / retrieve an access token.
303
+ They key will usually be the id of the current user.
304
+
305
+ ```ruby
306
+ store = Procore::Auth::Stores::Redis.new(redis: Redis.new, key: current_user.id)
307
+ ```
308
+
309
+ ### ActiveRecord Store
310
+
311
+ Options: `object`: Instance of an ActiveRecord model.
312
+
313
+ For applications that store access token information on some user object.
314
+
315
+ The following columns **must** exist on the model you pass in:
316
+ `access_token`, `refresh_token` and `expires_at`.
317
+
318
+ ```ruby
319
+ store = Procore::Auth::Stores::ActiveRecord.new(object: current_user)
320
+ ```
321
+
322
+ ### File Store
323
+
324
+ Options: `path`: Path to a file to store access tokens
325
+ Options: `key`: Unique identifier to an access token
326
+
327
+ Intended for command line applications, the File Store saves access token
328
+ information to disk. This way a user can run a CLI without needing to
329
+ authenticate every single command.
330
+
331
+ ```ruby
332
+ store = Procore::Auth::Stores::File.new(path: "./tokens.yml", key: current_user.id)
333
+ ```
334
+
335
+ ### Memory Store
336
+
337
+ Options: `key`: Unique identifier to an access token
338
+
339
+ The most basic store - a token is kept in memory for the duration of a request.
340
+ This store type is not recommended for application usage - it is meant to be
341
+ used in tests.
342
+
343
+ ```ruby
344
+ store = Procore::Auth::Stores::Memory.new(key: current_user.id)
345
+ ```
346
+
347
+ ## Full Example
348
+
349
+ ```ruby
350
+ # In controller, callback from oauth
351
+ def handle_callback
352
+ if auth_hash.blank?
353
+ redirect_to '/auth/procore'
354
+ else
355
+ auth_hash = request.env['omniauth.auth']
356
+
357
+ # Create a new token to save into a store
358
+ token = Procore::Auth::Token.new(
359
+ access_token: auth_hash["token"]
360
+ refresh_token: auth_hash["refresh_token"],
361
+ expires_at: auth_hash["expires_at"]
362
+ )
363
+
364
+ store = Procore::Auth::Stores::Session.new(session: session)
365
+ store.save(token)
366
+
367
+ redirect_to root_path
368
+ end
369
+ end
370
+
371
+ # Somewhere else in the application
372
+ class ProjectsController
373
+ def index
374
+ @projects = client.get("projects", company_id: params[:company_id])
375
+ end
376
+
377
+ private
378
+
379
+ def client
380
+ @client ||= Procore::Client.new(
381
+ client_id: Rails.application.secrets.procore_client_id,
382
+ client_secret: Rails.application.secrets.procore_client_secret,
383
+ store: Procore::Auth::Stores::Session.new(session: session)
384
+ )
385
+ end
386
+ end
387
+ ```
388
+
389
+ ## License
390
+
391
+ The gem is available as open source under the terms of the [MIT
392
+ License](http://opensource.org/licenses/MIT).
393
+
394
+ ## About Procore
395
+
396
+ <img
397
+ src="https://www.procore.com/images/procore_logo.png"
398
+ alt="Procore Logo"
399
+ width="250px"
400
+ />
401
+
402
+ The Procore Gem is maintained by Procore Technologies.
403
+
404
+ Procore - building the software that builds the world.
405
+
406
+ Learn more about the #1 most widely used construction management software at
407
+ [procore.com](https://www.procore.com/)