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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +51 -0
  6. data/LICENSE +22 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +125 -0
  9. data/Rakefile +16 -0
  10. data/lib/namely.rb +114 -0
  11. data/lib/namely/authenticator.rb +164 -0
  12. data/lib/namely/country.rb +9 -0
  13. data/lib/namely/currency_type.rb +9 -0
  14. data/lib/namely/event.rb +9 -0
  15. data/lib/namely/exceptions.rb +13 -0
  16. data/lib/namely/field.rb +9 -0
  17. data/lib/namely/job_tier.rb +9 -0
  18. data/lib/namely/profile.rb +13 -0
  19. data/lib/namely/report.rb +9 -0
  20. data/lib/namely/resource_gateway.rb +81 -0
  21. data/lib/namely/restful_model.rb +150 -0
  22. data/lib/namely/version.rb +3 -0
  23. data/namely.gemspec +30 -0
  24. data/spec/fixtures/vcr_cassettes/country_head.yml +51 -0
  25. data/spec/fixtures/vcr_cassettes/country_head_missing.yml +50 -0
  26. data/spec/fixtures/vcr_cassettes/country_index.yml +121 -0
  27. data/spec/fixtures/vcr_cassettes/country_show.yml +68 -0
  28. data/spec/fixtures/vcr_cassettes/country_show_missing.yml +54 -0
  29. data/spec/fixtures/vcr_cassettes/currencytype_index.yml +64 -0
  30. data/spec/fixtures/vcr_cassettes/event_head.yml +51 -0
  31. data/spec/fixtures/vcr_cassettes/event_head_missing.yml +50 -0
  32. data/spec/fixtures/vcr_cassettes/event_index.yml +88 -0
  33. data/spec/fixtures/vcr_cassettes/event_show.yml +62 -0
  34. data/spec/fixtures/vcr_cassettes/event_show_missing.yml +54 -0
  35. data/spec/fixtures/vcr_cassettes/field_index.yml +207 -0
  36. data/spec/fixtures/vcr_cassettes/jobtier_index.yml +103 -0
  37. data/spec/fixtures/vcr_cassettes/profile_create.yml +85 -0
  38. data/spec/fixtures/vcr_cassettes/profile_create_failed.yml +54 -0
  39. data/spec/fixtures/vcr_cassettes/profile_head.yml +51 -0
  40. data/spec/fixtures/vcr_cassettes/profile_head_missing.yml +50 -0
  41. data/spec/fixtures/vcr_cassettes/profile_index.yml +979 -0
  42. data/spec/fixtures/vcr_cassettes/profile_show.yml +91 -0
  43. data/spec/fixtures/vcr_cassettes/profile_show_missing.yml +54 -0
  44. data/spec/fixtures/vcr_cassettes/profile_show_updated.yml +91 -0
  45. data/spec/fixtures/vcr_cassettes/profile_update.yml +95 -0
  46. data/spec/fixtures/vcr_cassettes/profile_update_revert.yml +95 -0
  47. data/spec/fixtures/vcr_cassettes/report_head.yml +51 -0
  48. data/spec/fixtures/vcr_cassettes/report_head_missing.yml +50 -0
  49. data/spec/fixtures/vcr_cassettes/report_show.yml +185 -0
  50. data/spec/fixtures/vcr_cassettes/report_show_missing.yml +54 -0
  51. data/spec/fixtures/vcr_cassettes/token.yml +57 -0
  52. data/spec/fixtures/vcr_cassettes/token_refresh.yml +57 -0
  53. data/spec/namely/authenticator_spec.rb +143 -0
  54. data/spec/namely/configuration_spec.rb +33 -0
  55. data/spec/namely/country_spec.rb +11 -0
  56. data/spec/namely/currency_type_spec.rb +5 -0
  57. data/spec/namely/event_spec.rb +11 -0
  58. data/spec/namely/field_spec.rb +5 -0
  59. data/spec/namely/job_tier_spec.rb +5 -0
  60. data/spec/namely/profile_spec.rb +25 -0
  61. data/spec/namely/report_spec.rb +8 -0
  62. data/spec/namely/resource_gateway_spec.rb +93 -0
  63. data/spec/shared_examples/a_model_with_a_create_action.rb +24 -0
  64. data/spec/shared_examples/a_model_with_a_show_action.rb +38 -0
  65. data/spec/shared_examples/a_model_with_an_index_action.rb +17 -0
  66. data/spec/shared_examples/a_model_with_an_update_action.rb +37 -0
  67. data/spec/spec_helper.rb +49 -0
  68. metadata +280 -0
@@ -0,0 +1,50 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: head
5
+ uri: https://<TEST_SUBDOMAIN>.namely.com/api/v1/reports/this-is-almost-certainly-not-the-id-of-any-model?access_token=<TEST_ACCESS_TOKEN>
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 404
19
+ message: Not Found
20
+ headers:
21
+ Cache-Control:
22
+ - no-cache
23
+ Content-Encoding:
24
+ - gzip
25
+ Content-Type:
26
+ - application/json; charset=utf-8
27
+ Date:
28
+ - Tue, 04 Nov 2014 16:34:50 GMT
29
+ Server:
30
+ - nginx/1.6.2
31
+ Status:
32
+ - 404 Not Found
33
+ Strict-Transport-Security:
34
+ - max-age=31536000
35
+ Vary:
36
+ - Accept-Encoding
37
+ X-Rack-Cache:
38
+ - miss
39
+ X-Request-Id:
40
+ - d7d37c67-ed05-4344-a6ff-cdfdf35552cc
41
+ X-Runtime:
42
+ - '0.024991'
43
+ Connection:
44
+ - keep-alive
45
+ body:
46
+ encoding: UTF-8
47
+ string: ''
48
+ http_version:
49
+ recorded_at: Tue, 04 Nov 2014 16:34:50 GMT
50
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,185 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://<TEST_SUBDOMAIN>.namely.com/api/v1/reports/bbf089f6-90c5-473c-8928-058014a462c9?access_token=<TEST_ACCESS_TOKEN>
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Cache-Control:
22
+ - max-age=0, private, must-revalidate
23
+ Content-Encoding:
24
+ - gzip
25
+ Content-Type:
26
+ - application/json; charset=utf-8
27
+ Date:
28
+ - Tue, 04 Nov 2014 16:34:49 GMT
29
+ Server:
30
+ - nginx
31
+ Status:
32
+ - 200 OK
33
+ Strict-Transport-Security:
34
+ - max-age=31536000
35
+ - max-age=31536000; includeSubDomains;
36
+ Vary:
37
+ - Accept-Encoding
38
+ X-Rack-Cache:
39
+ - miss
40
+ X-Request-Id:
41
+ - 977b6e70-4437-4f03-b138-0dc56ceafea1
42
+ X-Runtime:
43
+ - '0.114426'
44
+ Content-Length:
45
+ - '5918'
46
+ Connection:
47
+ - keep-alive
48
+ body:
49
+ encoding: ASCII-8BIT
50
+ string: !binary |-
51
+ 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
182
+ U0igsPD3Bmz+hCAdb/kvtPocsn5oAAA=
183
+ http_version:
184
+ recorded_at: Tue, 04 Nov 2014 16:34:49 GMT
185
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,54 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://<TEST_SUBDOMAIN>.namely.com/api/v1/reports/this-is-almost-certainly-not-the-id-of-any-model?access_token=<TEST_ACCESS_TOKEN>
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 404
19
+ message: Not Found
20
+ headers:
21
+ Cache-Control:
22
+ - no-cache
23
+ Content-Encoding:
24
+ - gzip
25
+ Content-Type:
26
+ - application/json; charset=utf-8
27
+ Date:
28
+ - Tue, 04 Nov 2014 16:34:49 GMT
29
+ Server:
30
+ - nginx/1.6.2
31
+ Status:
32
+ - 404 Not Found
33
+ Strict-Transport-Security:
34
+ - max-age=31536000
35
+ Vary:
36
+ - Accept-Encoding
37
+ X-Rack-Cache:
38
+ - miss
39
+ X-Request-Id:
40
+ - 52e1e643-65de-487a-8b28-2be8291d2f1b
41
+ X-Runtime:
42
+ - '0.025837'
43
+ Content-Length:
44
+ - '64'
45
+ Connection:
46
+ - keep-alive
47
+ body:
48
+ encoding: ASCII-8BIT
49
+ string: !binary |-
50
+ H4sIAAAAAAAAA6tWyk0tLk5MT1WyUgpKLcgvKlHIyy9RSMsvzUtR0lFKLSrK
51
+ LypWssorzcmpBQBUHrxBLAAAAA==
52
+ http_version:
53
+ recorded_at: Tue, 04 Nov 2014 16:34:49 GMT
54
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,57 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://<TEST_SUBDOMAIN>.namely.com/api/v1/oauth2/token?redirect_uri=<CLIENT_REDIRECT_URI>
6
+ body:
7
+ encoding: US-ASCII
8
+ string: grant_type=authorization_code&client_id=<CLIENT_ID>&client_secret=<CLIENT_SECRET>&code=<AUTH_CODE>
9
+ headers:
10
+ Accept:
11
+ - "*/*; q=0.5, application/xml"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ Content-Length:
15
+ - '189'
16
+ Content-Type:
17
+ - application/x-www-form-urlencoded
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Cache-Control:
26
+ - no-store
27
+ Content-Type:
28
+ - application/json
29
+ Date:
30
+ - Tue, 04 Nov 2014 16:38:10 GMT
31
+ Etag:
32
+ - '"fc3490b779796351d40312ba491c69c2"'
33
+ Pragma:
34
+ - no-cache
35
+ Server:
36
+ - nginx
37
+ Status:
38
+ - 200 OK
39
+ Strict-Transport-Security:
40
+ - max-age=31536000
41
+ - max-age=31536000; includeSubDomains;
42
+ X-Rack-Cache:
43
+ - invalidate, pass
44
+ X-Request-Id:
45
+ - 386d8523-f838-4023-a096-f74bc6c6291e
46
+ X-Runtime:
47
+ - '0.059499'
48
+ Content-Length:
49
+ - '141'
50
+ Connection:
51
+ - keep-alive
52
+ body:
53
+ encoding: UTF-8
54
+ string: '{"access_token":"<%= access_token %>","refresh_token":"<%= refresh_token %>","token_type":"bearer","expires_in":899}'
55
+ http_version:
56
+ recorded_at: Tue, 04 Nov 2014 16:38:11 GMT
57
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,57 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://<TEST_SUBDOMAIN>.namely.com/api/v1/oauth2/token?redirect_uri=<CLIENT_REDIRECT_URI>
6
+ body:
7
+ encoding: US-ASCII
8
+ string: grant_type=refresh_token&client_id=<CLIENT_ID>&client_secret=<CLIENT_SECRET>&refresh_token=<TEST_REFRESH_TOKEN>
9
+ headers:
10
+ Accept:
11
+ - "*/*; q=0.5, application/xml"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ Content-Length:
15
+ - '193'
16
+ Content-Type:
17
+ - application/x-www-form-urlencoded
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Cache-Control:
26
+ - no-store
27
+ Content-Type:
28
+ - application/json
29
+ Date:
30
+ - Tue, 04 Nov 2014 17:06:29 GMT
31
+ Etag:
32
+ - '"c4566dc1eddea53969e88a3bc69cdfb3"'
33
+ Pragma:
34
+ - no-cache
35
+ Server:
36
+ - nginx/1.6.2
37
+ Status:
38
+ - 200 OK
39
+ Strict-Transport-Security:
40
+ - max-age=31536000
41
+ - max-age=31536000; includeSubDomains;
42
+ X-Rack-Cache:
43
+ - invalidate, pass
44
+ X-Request-Id:
45
+ - e2d5a360-d44d-4198-8528-ceb6ad91bd6c
46
+ X-Runtime:
47
+ - '0.045489'
48
+ Content-Length:
49
+ - '90'
50
+ Connection:
51
+ - keep-alive
52
+ body:
53
+ encoding: UTF-8
54
+ string: '{"access_token":"<%= access_token %>","token_type":"bearer","expires_in":899}'
55
+ http_version:
56
+ recorded_at: Tue, 04 Nov 2014 17:06:29 GMT
57
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,143 @@
1
+ require "spec_helper"
2
+ require "cgi"
3
+ require "uri"
4
+
5
+ describe Namely::Authenticator do
6
+ describe "#auth_code_url" do
7
+ it "returns a URL to begin the authorization code URL flow" do
8
+ authenticator = described_class.new(
9
+ client_id: "MY_CLIENT_ID",
10
+ client_secret: "MY_CLIENT_SECRET",
11
+ )
12
+
13
+ authorization_code_url = authenticator.authorization_code_url(
14
+ subdomain: "ellingsonmineral",
15
+ redirect_uri: "http://www.example.com/authenticated",
16
+ )
17
+
18
+ parsed_uri = URI(authorization_code_url)
19
+ parsed_query = CGI.parse(parsed_uri.query)
20
+ expect(parsed_uri.scheme).to eq "https"
21
+ expect(parsed_uri.host).to eq "ellingsonmineral.namely.com"
22
+ expect(parsed_uri.path).to eq "/api/v1/oauth2/authorize"
23
+ expect(parsed_query).to eq(
24
+ "response_type" => ["code"],
25
+ "approve" => ["true"],
26
+ "client_id" => ["MY_CLIENT_ID"],
27
+ "redirect_uri" => ["http://www.example.com/authenticated"],
28
+ )
29
+ end
30
+
31
+ it "allows the redirect_uri to be omitted" do
32
+ authenticator = described_class.new(
33
+ client_id: "MY_CLIENT_ID",
34
+ client_secret: "MY_CLIENT_SECRET",
35
+ )
36
+
37
+ authorization_code_url = authenticator.authorization_code_url(
38
+ subdomain: "ellingsonmineral",
39
+ )
40
+
41
+ parsed_uri = URI(authorization_code_url)
42
+ parsed_query = CGI.parse(parsed_uri.query)
43
+ expect(parsed_query).to eq(
44
+ "response_type" => ["code"],
45
+ "approve" => ["true"],
46
+ "client_id" => ["MY_CLIENT_ID"],
47
+ )
48
+ end
49
+
50
+ it "escapes reserved characters in query parameters" do
51
+ authenticator = described_class.new(
52
+ client_id: "MY_CLIENT_ID",
53
+ client_secret: "MY_CLIENT_SECRET",
54
+ )
55
+ redirect_uri = "http://example.com/?auth=true&provider=namely"
56
+
57
+ authorization_code_url = authenticator.authorization_code_url(
58
+ subdomain: "ellingsonmineral",
59
+ redirect_uri: redirect_uri,
60
+ )
61
+
62
+ parsed_uri = URI(authorization_code_url)
63
+ parsed_query = CGI.parse(parsed_uri.query)
64
+ expect(parsed_query["redirect_uri"]).to eq [redirect_uri]
65
+ end
66
+
67
+ it "allows the host and protocol to be overridden" do
68
+ authenticator = described_class.new(
69
+ client_id: "MY_CLIENT_ID",
70
+ client_secret: "MY_CLIENT_SECRET",
71
+ )
72
+
73
+ authorization_code_url = authenticator.authorization_code_url(
74
+ protocol: "http",
75
+ host: "testing.example.com",
76
+ )
77
+
78
+ parsed_uri = URI(authorization_code_url)
79
+ expect(parsed_uri.scheme).to eq "http"
80
+ expect(parsed_uri.host).to eq "testing.example.com"
81
+ end
82
+ end
83
+
84
+ describe "#retrieve_tokens" do
85
+ it "exchanges an authorization code for access and refresh tokens" do
86
+ erb_settings = {
87
+ erb: {
88
+ access_token: "MY_ACCESS_TOKEN",
89
+ refresh_token: "MY_REFRESH_TOKEN",
90
+ }
91
+ }
92
+
93
+ VCR.use_cassette("token", erb_settings) do
94
+ authenticator = described_class.new(
95
+ client_id: ENV.fetch("CLIENT_ID"),
96
+ client_secret: ENV.fetch("CLIENT_SECRET"),
97
+ )
98
+
99
+ tokens = authenticator.retrieve_tokens(
100
+ subdomain: ENV.fetch("TEST_SUBDOMAIN"),
101
+ code: ENV.fetch("AUTH_CODE"),
102
+ redirect_uri: ENV.fetch("CLIENT_REDIRECT_URI"),
103
+ )
104
+
105
+ expect(tokens).to eq(
106
+ "access_token" => "MY_ACCESS_TOKEN",
107
+ "refresh_token" => "MY_REFRESH_TOKEN",
108
+ "expires_in" => 899,
109
+ "token_type" => "bearer",
110
+ )
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "#refresh_access_token" do
116
+ it "uses a refresh token to retrieve a new access token" do
117
+ erb_settings = {
118
+ erb: {
119
+ access_token: "MY_ACCESS_TOKEN",
120
+ }
121
+ }
122
+
123
+ VCR.use_cassette("token_refresh", erb_settings) do
124
+ authenticator = described_class.new(
125
+ client_id: ENV.fetch("CLIENT_ID"),
126
+ client_secret: ENV.fetch("CLIENT_SECRET"),
127
+ )
128
+
129
+ tokens = authenticator.refresh_access_token(
130
+ subdomain: ENV.fetch("TEST_SUBDOMAIN"),
131
+ refresh_token: ENV.fetch("TEST_REFRESH_TOKEN"),
132
+ redirect_uri: ENV.fetch("CLIENT_REDIRECT_URI"),
133
+ )
134
+
135
+ expect(tokens).to eq(
136
+ "access_token" => "MY_ACCESS_TOKEN",
137
+ "expires_in" => 899,
138
+ "token_type" => "bearer",
139
+ )
140
+ end
141
+ end
142
+ end
143
+ end