procore 0.6.7

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