namely 0.0.1
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 +7 -0
- data/.gitignore +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +22 -0
- data/LICENSE.txt +22 -0
- data/README.md +125 -0
- data/Rakefile +16 -0
- data/lib/namely.rb +114 -0
- data/lib/namely/authenticator.rb +164 -0
- data/lib/namely/country.rb +9 -0
- data/lib/namely/currency_type.rb +9 -0
- data/lib/namely/event.rb +9 -0
- data/lib/namely/exceptions.rb +13 -0
- data/lib/namely/field.rb +9 -0
- data/lib/namely/job_tier.rb +9 -0
- data/lib/namely/profile.rb +13 -0
- data/lib/namely/report.rb +9 -0
- data/lib/namely/resource_gateway.rb +81 -0
- data/lib/namely/restful_model.rb +150 -0
- data/lib/namely/version.rb +3 -0
- data/namely.gemspec +30 -0
- data/spec/fixtures/vcr_cassettes/country_head.yml +51 -0
- data/spec/fixtures/vcr_cassettes/country_head_missing.yml +50 -0
- data/spec/fixtures/vcr_cassettes/country_index.yml +121 -0
- data/spec/fixtures/vcr_cassettes/country_show.yml +68 -0
- data/spec/fixtures/vcr_cassettes/country_show_missing.yml +54 -0
- data/spec/fixtures/vcr_cassettes/currencytype_index.yml +64 -0
- data/spec/fixtures/vcr_cassettes/event_head.yml +51 -0
- data/spec/fixtures/vcr_cassettes/event_head_missing.yml +50 -0
- data/spec/fixtures/vcr_cassettes/event_index.yml +88 -0
- data/spec/fixtures/vcr_cassettes/event_show.yml +62 -0
- data/spec/fixtures/vcr_cassettes/event_show_missing.yml +54 -0
- data/spec/fixtures/vcr_cassettes/field_index.yml +207 -0
- data/spec/fixtures/vcr_cassettes/jobtier_index.yml +103 -0
- data/spec/fixtures/vcr_cassettes/profile_create.yml +85 -0
- data/spec/fixtures/vcr_cassettes/profile_create_failed.yml +54 -0
- data/spec/fixtures/vcr_cassettes/profile_head.yml +51 -0
- data/spec/fixtures/vcr_cassettes/profile_head_missing.yml +50 -0
- data/spec/fixtures/vcr_cassettes/profile_index.yml +979 -0
- data/spec/fixtures/vcr_cassettes/profile_show.yml +91 -0
- data/spec/fixtures/vcr_cassettes/profile_show_missing.yml +54 -0
- data/spec/fixtures/vcr_cassettes/profile_show_updated.yml +91 -0
- data/spec/fixtures/vcr_cassettes/profile_update.yml +95 -0
- data/spec/fixtures/vcr_cassettes/profile_update_revert.yml +95 -0
- data/spec/fixtures/vcr_cassettes/report_head.yml +51 -0
- data/spec/fixtures/vcr_cassettes/report_head_missing.yml +50 -0
- data/spec/fixtures/vcr_cassettes/report_show.yml +185 -0
- data/spec/fixtures/vcr_cassettes/report_show_missing.yml +54 -0
- data/spec/fixtures/vcr_cassettes/token.yml +57 -0
- data/spec/fixtures/vcr_cassettes/token_refresh.yml +57 -0
- data/spec/namely/authenticator_spec.rb +143 -0
- data/spec/namely/configuration_spec.rb +33 -0
- data/spec/namely/country_spec.rb +11 -0
- data/spec/namely/currency_type_spec.rb +5 -0
- data/spec/namely/event_spec.rb +11 -0
- data/spec/namely/field_spec.rb +5 -0
- data/spec/namely/job_tier_spec.rb +5 -0
- data/spec/namely/profile_spec.rb +25 -0
- data/spec/namely/report_spec.rb +8 -0
- data/spec/namely/resource_gateway_spec.rb +93 -0
- data/spec/shared_examples/a_model_with_a_create_action.rb +24 -0
- data/spec/shared_examples/a_model_with_a_show_action.rb +38 -0
- data/spec/shared_examples/a_model_with_an_index_action.rb +17 -0
- data/spec/shared_examples/a_model_with_an_update_action.rb +37 -0
- data/spec/spec_helper.rb +49 -0
- metadata +280 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c6c9e3f2c619a62f8ecf845c656d50ff12f025d9
|
4
|
+
data.tar.gz: e17424ee887917ba69dd1928557bb6cd5c64ab02
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2a9a3dc86ec13b62778feca282add92456013a154dfc8fa5e652a761a9f58350e35ee626184b5bf4aaf60cc47a9d58f56e6aeef156f6204ae16bc58ebdb11a0a
|
7
|
+
data.tar.gz: 5a025299aad278901b62a0fc0a24a4977cb4c56aaee28fcbc93f85c65811e70598c400366a487e872f8a78c2d8a19a4f65baecb577e4de15404d7375da07d297
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
namely (0.0.1)
|
5
|
+
backports
|
6
|
+
rest_client
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
addressable (2.3.6)
|
12
|
+
backports (3.6.3)
|
13
|
+
crack (0.4.2)
|
14
|
+
safe_yaml (~> 1.0.0)
|
15
|
+
diff-lcs (1.2.5)
|
16
|
+
dotenv (1.0.2)
|
17
|
+
netrc (0.7.9)
|
18
|
+
rake (10.3.2)
|
19
|
+
rest_client (1.8.1)
|
20
|
+
netrc (~> 0.7.7)
|
21
|
+
rspec (3.1.0)
|
22
|
+
rspec-core (~> 3.1.0)
|
23
|
+
rspec-expectations (~> 3.1.0)
|
24
|
+
rspec-mocks (~> 3.1.0)
|
25
|
+
rspec-core (3.1.7)
|
26
|
+
rspec-support (~> 3.1.0)
|
27
|
+
rspec-expectations (3.1.2)
|
28
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
29
|
+
rspec-support (~> 3.1.0)
|
30
|
+
rspec-mocks (3.1.3)
|
31
|
+
rspec-support (~> 3.1.0)
|
32
|
+
rspec-support (3.1.2)
|
33
|
+
safe_yaml (1.0.4)
|
34
|
+
vcr (2.9.3)
|
35
|
+
webmock (1.8.7)
|
36
|
+
addressable (>= 2.2.7)
|
37
|
+
crack (>= 0.1.7)
|
38
|
+
yard (0.8.7.6)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
bundler (~> 1.7)
|
45
|
+
dotenv
|
46
|
+
namely!
|
47
|
+
rake (~> 10.0)
|
48
|
+
rspec
|
49
|
+
vcr
|
50
|
+
webmock
|
51
|
+
yard
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014
|
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 all
|
13
|
+
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 THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Namely
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
# Namely
|
2
|
+
|
3
|
+
[](https://travis-ci.org/namely/ruby-client/builds)
|
4
|
+
[](https://codeclimate.com/github/namely/ruby-client)
|
5
|
+
|
6
|
+
TODO: Write a gem description
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem "namely"
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install namely
|
23
|
+
|
24
|
+
## Configuration
|
25
|
+
|
26
|
+
You'll need to configure the gem to use your Namely account. Do this
|
27
|
+
by setting the `access_token` and `subdomain` variables in a
|
28
|
+
configuration block:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
Namely.configure do |config|
|
32
|
+
config.access_token = "your_access_token"
|
33
|
+
config.subdomain = "your-organization"
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
An access token can be obtained through your organization's Namely
|
38
|
+
account.
|
39
|
+
|
40
|
+
Namely associates a subdomain with your
|
41
|
+
organization. organization. For example, if your account is at
|
42
|
+
`http://your-organization.namely.com/`, your subdomain would be
|
43
|
+
`"your-organization"`.
|
44
|
+
|
45
|
+
In a Rails application this configuration belongs in
|
46
|
+
`config/initializers/namely.rb`.
|
47
|
+
|
48
|
+
## Usage Examples
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
Namely::Country.all.each do |country|
|
52
|
+
puts "#{country.id} - #{country.name}"
|
53
|
+
end
|
54
|
+
# AF - Afghanistan
|
55
|
+
# AL - Albania
|
56
|
+
# DZ - Algeria
|
57
|
+
# AS - American Samoa
|
58
|
+
# ...
|
59
|
+
```
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
if Namely::Country.exists?("BE")
|
63
|
+
"Belgium exists!"
|
64
|
+
else
|
65
|
+
"Hmm."
|
66
|
+
end # => "Belgium exists!"
|
67
|
+
```
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
Namely::Country.find("BE")
|
71
|
+
# => <Namely::Country id="BE", name="Belgium", subdivision_type="Province", links={"subdivisions"=>[{"id"=>"BRU", "name"=>"Brussels"}, {"id"=>"VAN", "name"=>"Antwerpen (nl)"}, {"id"=>"VBR", "name"=>"Vlaams Brabant (nl)"}, {"id"=>"VLI", "name"=>"Limburg (nl)"}, {"id"=>"VOV", "name"=>"Oost-Vlaanderen (nl)"}, {"id"=>"VWV", "name"=>"West-Vlaanderen (nl)"}, {"id"=>"WBR", "name"=>"Brabant Wallon (fr)"}, {"id"=>"WHT", "name"=>"Hainaut (fr)"}, {"id"=>"WLG", "name"=>"Liège (fr)"}, {"id"=>"WLX", "name"=>"Luxembourg (fr)"}, {"id"=>"WNA", "name"=>"Namur (fr)"}]}>
|
72
|
+
```
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
foo_bar = Namely::Profile.create!(
|
76
|
+
first_name: "Metasyntactic",
|
77
|
+
last_name: "Variable",
|
78
|
+
email: "foo_bar@namely.com"
|
79
|
+
)
|
80
|
+
|
81
|
+
foo_bar.id # => "37c919e2-f1c8-4beb-b1d4-a9a36ccc830c"
|
82
|
+
```
|
83
|
+
|
84
|
+
## Contributing
|
85
|
+
|
86
|
+
Wanna help out? Great! Here are a few resources that might help you
|
87
|
+
started:
|
88
|
+
|
89
|
+
* Documentation on [Namely's HTTP API]
|
90
|
+
* Namely tries to stick to the [JSON API standard]. If we're seriously
|
91
|
+
deviating from it, that may well be a bug.
|
92
|
+
* For coding style, we like [thoughtbot's style guide]
|
93
|
+
|
94
|
+
### Setting up a development environment
|
95
|
+
|
96
|
+
The Namely gem uses [dotenv] to manage environment variables. To run
|
97
|
+
the tests you'll need to create a `.env` file in the project's root
|
98
|
+
directory and assign a few variables in it.
|
99
|
+
|
100
|
+
Just take this example `.env` file and plug in appropriate values:
|
101
|
+
|
102
|
+
```
|
103
|
+
TEST_ACCESS_TOKEN=my-sample-access-token
|
104
|
+
TEST_SUBDOMAIN=my-sample-subdomain
|
105
|
+
```
|
106
|
+
|
107
|
+
You'll need admin access to a Namely site to get tokens for these
|
108
|
+
variables. You can create application and permanent tokens on the API
|
109
|
+
page of the site.
|
110
|
+
|
111
|
+
### Submitting your changes
|
112
|
+
|
113
|
+
1. [Fork it!]
|
114
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
115
|
+
3. Commit your changes (`git commit -am "Add some feature"`). Be sure
|
116
|
+
to include tests!
|
117
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
118
|
+
5. Create a new pull request. We'll review it and leave feedback for
|
119
|
+
you ASAP.
|
120
|
+
|
121
|
+
[Namely's HTTP API]: http://namely.readme.io/v1/docs
|
122
|
+
[thoughtbot's style guide]: https://github.com/thoughtbot/guides/tree/master/style
|
123
|
+
[JSON API standard]: http://jsonapi.org/
|
124
|
+
[dotenv]: https://github.com/bkeepers/dotenv
|
125
|
+
[Fork it!]: https://github.com/namely/ruby-client/fork
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "rspec/core/rake_task"
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
5
|
+
task.rspec_opts = ["--color"]
|
6
|
+
end
|
7
|
+
|
8
|
+
task :console do
|
9
|
+
exec "irb -r namely -I ./lib"
|
10
|
+
end
|
11
|
+
|
12
|
+
task :documentation do
|
13
|
+
exec "yardoc --no-private"
|
14
|
+
end
|
15
|
+
|
16
|
+
task default: :spec
|
data/lib/namely.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
require "backports"
|
2
|
+
require "json"
|
3
|
+
require "ostruct"
|
4
|
+
require "rest_client"
|
5
|
+
|
6
|
+
require "namely/authenticator"
|
7
|
+
require "namely/exceptions"
|
8
|
+
require "namely/resource_gateway"
|
9
|
+
require "namely/restful_model"
|
10
|
+
|
11
|
+
require "namely/country"
|
12
|
+
require "namely/currency_type"
|
13
|
+
require "namely/event"
|
14
|
+
require "namely/field"
|
15
|
+
require "namely/job_tier"
|
16
|
+
require "namely/profile"
|
17
|
+
require "namely/report"
|
18
|
+
|
19
|
+
require "namely/version"
|
20
|
+
|
21
|
+
module Namely
|
22
|
+
class << self
|
23
|
+
attr_writer :configuration
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return the current configuration.
|
27
|
+
#
|
28
|
+
# @raise [ImproperlyConfiguredError] if the subdomain or access token
|
29
|
+
# haven't been configured.
|
30
|
+
#
|
31
|
+
# @return [Configuration]
|
32
|
+
def self.configuration
|
33
|
+
@configuration || raise(
|
34
|
+
ImproperlyConfiguredError,
|
35
|
+
"Before using the Namely gem, you'll need to configure it with `Namely.configure`."
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set the configuration variables (the subdomain and access token)
|
40
|
+
# that allow the Namely gem to access your account.
|
41
|
+
#
|
42
|
+
# @yieldparam [Configuration] configuration the Configuration
|
43
|
+
# object, the attributes of which can be set in the block.
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# Namely.configure do |config|
|
47
|
+
# config.access_token = "your_access_token"
|
48
|
+
# config.subdomain = "your-organization"
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# @return [void]
|
52
|
+
def self.configure
|
53
|
+
@configuration ||= Configuration.new
|
54
|
+
yield configuration
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return a resource gateway for interfacing with a given resource.
|
58
|
+
#
|
59
|
+
# @param [String] resource_name
|
60
|
+
# @param [String] endpoint
|
61
|
+
#
|
62
|
+
# @return [ResourceGateway]
|
63
|
+
def self.resource_gateway(resource_name, endpoint)
|
64
|
+
configuration.resource_gateway(resource_name, endpoint)
|
65
|
+
end
|
66
|
+
|
67
|
+
class Configuration
|
68
|
+
attr_writer :access_token, :subdomain
|
69
|
+
|
70
|
+
# Get the access token.
|
71
|
+
#
|
72
|
+
# @raise [ImproperlyConfiguredError] if the access token hasn't
|
73
|
+
# been configured.
|
74
|
+
#
|
75
|
+
# @return [String] the access token
|
76
|
+
def access_token
|
77
|
+
@access_token || raise_missing_variable_error(:access_token)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get the subdomain.
|
81
|
+
#
|
82
|
+
# @raise [ImproperlyConfiguredError] if the subdomain hasn't been
|
83
|
+
# configured.
|
84
|
+
#
|
85
|
+
# @return [String] the subdomain
|
86
|
+
def subdomain
|
87
|
+
@subdomain || raise_missing_variable_error(:subdomain)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Create a resource gateway for interfacing with a given resource.
|
91
|
+
#
|
92
|
+
# @param [String] resource_name
|
93
|
+
# @param [String] endpoint
|
94
|
+
#
|
95
|
+
# @return [ResourceGateway]
|
96
|
+
def resource_gateway(resource_name, endpoint)
|
97
|
+
Namely::ResourceGateway.new(
|
98
|
+
access_token: access_token,
|
99
|
+
endpoint: endpoint,
|
100
|
+
resource_name: resource_name,
|
101
|
+
subdomain: subdomain
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def raise_missing_variable_error(variable)
|
108
|
+
raise(
|
109
|
+
ImproperlyConfiguredError,
|
110
|
+
"The Namely `#{variable}` configuration variable hasn't been set... did you set it when you called `Namely.configure`?"
|
111
|
+
)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require "cgi"
|
2
|
+
|
3
|
+
module Namely
|
4
|
+
class Authenticator
|
5
|
+
# Return a new Authenticator instance.
|
6
|
+
#
|
7
|
+
# @param [Hash] options
|
8
|
+
# @option options [String] client_id
|
9
|
+
# @option options [String] client_secret
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# authenticator = Authenticator.new(
|
13
|
+
# client_id: "my-client-id",
|
14
|
+
# client_secret: "my-client-secret"
|
15
|
+
# )
|
16
|
+
#
|
17
|
+
# @return [Authenticator]
|
18
|
+
def initialize(options)
|
19
|
+
@client_id = options.fetch(:client_id)
|
20
|
+
@client_secret = options.fetch(:client_secret)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns a URL to begin the authorization code workflow. If you
|
24
|
+
# provide a redirect_uri you can receive the server's response.
|
25
|
+
#
|
26
|
+
# @param [Hash] options
|
27
|
+
# @option options [String] host (optional)
|
28
|
+
# @option options [String] protocol (optional, defaults to "https")
|
29
|
+
# @option options [String] subdomain (required)
|
30
|
+
# @option options [String] redirect_uri (optional)
|
31
|
+
#
|
32
|
+
# @return [String]
|
33
|
+
def authorization_code_url(options)
|
34
|
+
URL.new(options.merge(
|
35
|
+
path: "/api/v1/oauth2/authorize",
|
36
|
+
params: {
|
37
|
+
response_type: "code",
|
38
|
+
approve: "true",
|
39
|
+
client_id: client_id,
|
40
|
+
},
|
41
|
+
)).to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
# Request an access token and refresh token.
|
45
|
+
#
|
46
|
+
# @param [Hash] options
|
47
|
+
# @option options [String] code (required)
|
48
|
+
# @option options [String] redirect_uri (required)
|
49
|
+
# @option options [String] subdomain (required)
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# authenticator = Authenticator.new(
|
53
|
+
# client_id: "my-client-id",
|
54
|
+
# client_secret: "my-client-secret"
|
55
|
+
# )
|
56
|
+
#
|
57
|
+
# tokens = authenticator.retrieve_tokens(
|
58
|
+
# code: "my-code",
|
59
|
+
# subdomain: "my-subdomain",
|
60
|
+
# redirect_uri: "my-redirect-uri"
|
61
|
+
# )
|
62
|
+
#
|
63
|
+
# tokens["access_token"] # => "my-access-token"
|
64
|
+
# tokens["refresh_token"] # => "my-refresh-token"
|
65
|
+
# tokens["expires_in"] # => 1234
|
66
|
+
# tokens["token_type"] # => "bearer"
|
67
|
+
#
|
68
|
+
# @return [Hash]
|
69
|
+
def retrieve_tokens(options)
|
70
|
+
request_tokens(options, "authorization_code", options.fetch(:code))
|
71
|
+
end
|
72
|
+
|
73
|
+
# Get an updated access token using the refresh token.
|
74
|
+
#
|
75
|
+
# @param [Hash] options
|
76
|
+
# @option options [String] redirect_uri (required)
|
77
|
+
# @option options [String] refresh_token (required)
|
78
|
+
# @option options [String] subdomain (required)
|
79
|
+
#
|
80
|
+
# @example
|
81
|
+
# authenticator = Authenticator.new(
|
82
|
+
# client_id: "my-client-id",
|
83
|
+
# client_secret: "my-client-secret"
|
84
|
+
# )
|
85
|
+
#
|
86
|
+
# tokens = authenticator.refresh_access_token(
|
87
|
+
# redirect_uri: "my-redirect-uri",
|
88
|
+
# refresh_token: "my-refresh-token",
|
89
|
+
# subdomain: "my-subdomain"
|
90
|
+
# )
|
91
|
+
#
|
92
|
+
# tokens["access_token"] # => "my-access-token"
|
93
|
+
# tokens["expires_in"] # => 1234
|
94
|
+
# tokens["token_type"] # => "bearer"
|
95
|
+
#
|
96
|
+
# @return [Hash]
|
97
|
+
def refresh_access_token(options)
|
98
|
+
request_tokens(options, "refresh_token", options.fetch(:refresh_token))
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
attr_reader :client_id, :client_secret
|
104
|
+
|
105
|
+
def request_tokens(options, grant_type, token)
|
106
|
+
response = RestClient.post(
|
107
|
+
URL.new(options.merge(path: "/api/v1/oauth2/token")).to_s,
|
108
|
+
grant_type: grant_type,
|
109
|
+
client_id: client_id,
|
110
|
+
client_secret: client_secret,
|
111
|
+
refresh_token: token,
|
112
|
+
)
|
113
|
+
JSON.parse(response)
|
114
|
+
end
|
115
|
+
|
116
|
+
class URL
|
117
|
+
def initialize(options)
|
118
|
+
@options = options
|
119
|
+
end
|
120
|
+
|
121
|
+
def to_s
|
122
|
+
"#{protocol}://#{host}#{path}?#{query}"
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
attr_reader :options
|
128
|
+
|
129
|
+
def protocol
|
130
|
+
options.fetch(:protocol, "https")
|
131
|
+
end
|
132
|
+
|
133
|
+
def host
|
134
|
+
if options.has_key?(:subdomain)
|
135
|
+
"#{options[:subdomain]}.namely.com"
|
136
|
+
else
|
137
|
+
options.fetch(:host)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def path
|
142
|
+
options.fetch(:path)
|
143
|
+
end
|
144
|
+
|
145
|
+
def query
|
146
|
+
params.
|
147
|
+
map { |key, value| "#{CGI.escape(key.to_s)}=#{CGI.escape(value)}" }.
|
148
|
+
join("&")
|
149
|
+
end
|
150
|
+
|
151
|
+
def params
|
152
|
+
options.fetch(:params, {}).merge(redirect_uri_param)
|
153
|
+
end
|
154
|
+
|
155
|
+
def redirect_uri_param
|
156
|
+
if options.has_key?(:redirect_uri)
|
157
|
+
{ redirect_uri: options[:redirect_uri] }
|
158
|
+
else
|
159
|
+
{}
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|