myjohndeere 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +52 -0
  3. data/Gemfile +16 -0
  4. data/Gemfile.lock +37 -0
  5. data/LICENSE +21 -0
  6. data/README.md +109 -0
  7. data/Rakefile +8 -0
  8. data/lib/myjohndeere.rb +132 -0
  9. data/lib/myjohndeere/access_token.rb +79 -0
  10. data/lib/myjohndeere/api_support_item.rb +27 -0
  11. data/lib/myjohndeere/boundary.rb +18 -0
  12. data/lib/myjohndeere/core_ext/string.rb +9 -0
  13. data/lib/myjohndeere/errors.rb +10 -0
  14. data/lib/myjohndeere/field.rb +28 -0
  15. data/lib/myjohndeere/file_resource.rb +61 -0
  16. data/lib/myjohndeere/hash_utils.rb +33 -0
  17. data/lib/myjohndeere/json_attributes.rb +39 -0
  18. data/lib/myjohndeere/list_object.rb +94 -0
  19. data/lib/myjohndeere/map_layer.rb +41 -0
  20. data/lib/myjohndeere/map_layer_summary.rb +40 -0
  21. data/lib/myjohndeere/map_legend_item.rb +10 -0
  22. data/lib/myjohndeere/metadata_item.rb +8 -0
  23. data/lib/myjohndeere/organization.rb +16 -0
  24. data/lib/myjohndeere/organization_owned_resource.rb +17 -0
  25. data/lib/myjohndeere/requestable.rb +36 -0
  26. data/lib/myjohndeere/response.rb +31 -0
  27. data/lib/myjohndeere/rest_methods.rb +64 -0
  28. data/lib/myjohndeere/single_resource.rb +13 -0
  29. data/lib/myjohndeere/util.rb +54 -0
  30. data/lib/myjohndeere/version.rb +3 -0
  31. data/myjohndeere.gemspec +23 -0
  32. data/spec/fixtures.json +778 -0
  33. data/test/api_fixtures.rb +29 -0
  34. data/test/test_access_token.rb +60 -0
  35. data/test/test_boundary.rb +37 -0
  36. data/test/test_field.rb +47 -0
  37. data/test/test_file_resource.rb +48 -0
  38. data/test/test_helper.rb +36 -0
  39. data/test/test_list_object.rb +74 -0
  40. data/test/test_map_layer.rb +52 -0
  41. data/test/test_map_layer_summary.rb +52 -0
  42. data/test/test_myjohndeere.rb +56 -0
  43. data/test/test_organization.rb +42 -0
  44. data/test/test_requestable.rb +15 -0
  45. data/test/test_rest_methods.rb +34 -0
  46. data/test/test_util.rb +86 -0
  47. metadata +118 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 69d83496b40f9f3572eb474f5b39dc257e6fd5ad
4
+ data.tar.gz: f2714c4b6ea7b99e9d82ce75a89c972c85456b4d
5
+ SHA512:
6
+ metadata.gz: a2ca3525d62c644406162c3f1fb1b9ee057443958d00ee2110848e5ba10b911dec04962f3b3cde41328284891a93de810acb1feda093d585f5c1b04d46693dbe
7
+ data.tar.gz: 967b2056c8c55902150d88407453580d48997cd30abdf71e6c9f8f480e6cff38d5a24c849491b4f5da22cbd15fa1a7e0b46ddf3cf56f4beca8b8dcda8ba7b631
data/.gitignore ADDED
@@ -0,0 +1,52 @@
1
+ *agribotix*
2
+ *.gem
3
+ *.rbc
4
+ *.byebug*
5
+ /.config
6
+ /coverage/
7
+ /InstalledFiles
8
+ /pkg/
9
+ /spec/reports/
10
+ /spec/examples.txt
11
+ /test/tmp/
12
+ /test/version_tmp/
13
+ /tmp/
14
+
15
+ # Used by dotenv library to load environment variables.
16
+ # .env
17
+
18
+ ## Specific to RubyMotion:
19
+ .dat*
20
+ .repl_history
21
+ build/
22
+ *.bridgesupport
23
+ build-iPhoneOS/
24
+ build-iPhoneSimulator/
25
+
26
+ ## Specific to RubyMotion (use of CocoaPods):
27
+ #
28
+ # We recommend against adding the Pods directory to your .gitignore. However
29
+ # you should judge for yourself, the pros and cons are mentioned at:
30
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
31
+ #
32
+ # vendor/Pods/
33
+
34
+ ## Documentation cache and generated files:
35
+ /.yardoc/
36
+ /_yardoc/
37
+ /doc/
38
+ /rdoc/
39
+
40
+ ## Environment normalization:
41
+ /.bundle/
42
+ /vendor/bundle
43
+ /lib/bundler/man/
44
+
45
+ # for a library or gem, you might want to ignore these files since the code is
46
+ # intended to run in multiple environments; otherwise, check them in:
47
+ # Gemfile.lock
48
+ # .ruby-version
49
+ # .ruby-gemset
50
+
51
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
52
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'minitest'
7
+ gem 'webmock'
8
+ gem 'rake'
9
+ platforms :mri do
10
+ # to avoid problems, bring Byebug in on just versions of Ruby under which
11
+ # it's known to work well
12
+ if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.0.0')
13
+ gem 'byebug'
14
+ end
15
+ end
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,37 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ myjohndeere (0.0.1)
5
+ oauth (>= 0.5.3)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ addressable (2.5.1)
11
+ public_suffix (~> 2.0, >= 2.0.2)
12
+ byebug (9.0.6)
13
+ crack (0.4.3)
14
+ safe_yaml (~> 1.0.0)
15
+ hashdiff (0.3.2)
16
+ minitest (5.8.4)
17
+ oauth (0.5.3)
18
+ public_suffix (2.0.5)
19
+ rake (11.3.0)
20
+ safe_yaml (1.0.4)
21
+ webmock (3.0.1)
22
+ addressable (>= 2.3.6)
23
+ crack (>= 0.3.2)
24
+ hashdiff
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ byebug
31
+ minitest
32
+ myjohndeere!
33
+ rake
34
+ webmock
35
+
36
+ BUNDLED WITH
37
+ 1.13.2
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Paul Susmarski
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.
data/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # MyJohnDeere API Library
2
+
3
+ The MyJohnDeere Ruby library provides convenient access to the MyJohnDeere API from applications written in the Ruby language. It includes a pre-defined set of classes for API resources that are available currently from the API. You will need to get access by going to the [JohnDeere Developer page](https://developer.deere.com/#!welcome). The interface utilizes OAUTH 1.0.
4
+
5
+ ## Usage
6
+
7
+ ### Configuration
8
+
9
+ The library needs to be configured with your MyJohnDeere account's shared secret & app id. These will be available on the developer page at JohnDeere.
10
+
11
+ ``` ruby
12
+ require "myjohndeere"
13
+
14
+ MyJohnDeere.configure do |config|
15
+ config.environment = :sandbox # :production is the other option
16
+ config.shared_secret = "...."
17
+ config.app_id = "johndeere-...."
18
+ # config.contribution_definition_id = "...." # not required for all requests
19
+ #config.log_level = :info
20
+ end
21
+
22
+ ```
23
+
24
+ The `contribution_definition_id` is used for a subset of requests, usually when you are adding resources to a map or otherwise. You can get this by contacting [JohnDeere Dev Support](APIDevSupport@johndeere.com) An error will be raised if this is missing for a certain request.
25
+
26
+ ### Get an Access Token
27
+
28
+ **NOTE:** These expire after one year
29
+
30
+ #### Access Token from Request Token
31
+ If you are beginning from scratch then you'll be starting with a request token and the request token secret. To do this:
32
+
33
+
34
+ ``` ruby
35
+
36
+ request_token = MyJohnDeere::AccessToken.get_request_token()
37
+ puts "Now visit the #{request_token.authorize_url}"
38
+ puts "Use the #{request_token.secret} and #{request_token.token} when creating the "
39
+ puts "access token along with the verifier code from the browser"
40
+
41
+ ```
42
+
43
+ Then later:
44
+ ``` ruby
45
+
46
+ access_token = MyJohnDeere::AccessToken.new(request_token_token: "....",
47
+ request_token_secret: "....",
48
+ verifier_code: "....")
49
+ # You'll now have the oauth access tokens
50
+ puts access_token.token
51
+ puts access_token.secret
52
+
53
+ ```
54
+
55
+ #### Access Token from Existing OAuth Token
56
+
57
+ If you've already gone through the effort to get your OAuth access token, then you can do:
58
+
59
+ ``` ruby
60
+ access_token = MyJohnDeere::AccessToken.new(
61
+ oauth_access_token_token: "....",
62
+ oauth_access_token_secret: "....",
63
+ )
64
+ ```
65
+ ### Getting Objects
66
+
67
+ Assuming you've created a MyJohnDeere::AccessToken using something from above, then you can do:
68
+
69
+ ``` ruby
70
+ organizations = MyJohnDeere::Organization.list(access_token)
71
+
72
+ organizations.each do |organization|
73
+ puts organization.fields.data
74
+ end
75
+
76
+ organizations.has_more?
77
+
78
+ ```
79
+
80
+ ## Listable Objects
81
+
82
+ MyJohnDeere returns either pages of objects that will automatically be iterated through 10 at a time *or* you'll receive the entirety of the resource if you specify an etag token. **The default behavior is for pagination.**
83
+
84
+ **If using the paginated approach**: Use `more_pages?` on the listable object to see if there are more pages to be acquired by using `next_page!`. This will modify the `.start` and `.count` values on the list object. These automatically increase with each `next_page`.
85
+
86
+ **If using the etag approach**: The entirety of the data set will be returned to you and on the list object you'll want to call `list.etag` and store this locally. You can then use this on future requests to see if anything has changed from the original request.
87
+
88
+ If you for some reason specify both, the etag will be the assumed behavior.
89
+
90
+ The raw data can be acquired by using `.data` on a listable object.
91
+
92
+
93
+ ## Development
94
+
95
+ Run all tests:
96
+
97
+ bundle exec rake
98
+
99
+ Run a single test suite:
100
+
101
+ bundle exec ruby -Ilib/ test/myjohndeere_test.rb
102
+
103
+ Run a single test:
104
+
105
+ bundle exec ruby -Ilib/ test/myjohndeere_test.rb -n /some_test/
106
+
107
+ ## Disclaimer
108
+
109
+ This Gem is in no way associated with JohnDeere, and they are in no way associated with it's support, maintenance, or updates.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.pattern = './test/**/test_*.rb'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
@@ -0,0 +1,132 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'rbconfig'
4
+ require 'base64'
5
+ require 'oauth'
6
+ require 'logger'
7
+
8
+ # Core extensions
9
+ require 'myjohndeere/core_ext/string'
10
+
11
+ # Errors
12
+ require 'myjohndeere/errors'
13
+
14
+ # Version
15
+ require 'myjohndeere/version'
16
+
17
+ # API Support Classes
18
+ require 'myjohndeere/rest_methods'
19
+ require 'myjohndeere/json_attributes'
20
+ require 'myjohndeere/requestable'
21
+ require 'myjohndeere/util'
22
+ require 'myjohndeere/hash_utils'
23
+ require 'myjohndeere/response'
24
+ require 'myjohndeere/access_token'
25
+ require 'myjohndeere/list_object'
26
+ require 'myjohndeere/single_resource'
27
+ require 'myjohndeere/organization_owned_resource'
28
+ require 'myjohndeere/api_support_item'
29
+
30
+ # API Sub-classes
31
+ require 'myjohndeere/map_legend_item'
32
+ require 'myjohndeere/metadata_item'
33
+
34
+ # API Objects
35
+ require 'myjohndeere/organization'
36
+ require 'myjohndeere/field'
37
+ require 'myjohndeere/boundary'
38
+ require 'myjohndeere/map_layer_summary'
39
+ require 'myjohndeere/map_layer'
40
+ require 'myjohndeere/file_resource'
41
+
42
+ module MyJohnDeere
43
+ class << self
44
+ attr_accessor :configuration
45
+ def set_logger()
46
+ @logger ||= Logger.new(STDOUT)
47
+ @logger.level = Logger.const_get(self.configuration.log_level.to_s.upcase)
48
+ end
49
+
50
+ def logger
51
+ if @logger.nil? then
52
+ set_logger()
53
+ end
54
+ @logger
55
+ end
56
+ end
57
+
58
+ JSON_CONTENT_HEADER_VALUE = 'application/vnd.deere.axiom.v3+json'
59
+ ENDPOINTS = {
60
+ sandbox: "https://sandboxapi.deere.com/platform",
61
+ production: "https://api.soa-proxy.deere.com/platform"
62
+ }.freeze
63
+ AUTHORIZE_URL = "https://my.deere.com/consentToUseOfData"
64
+ DEFAULT_REQUEST_HEADER = { 'accept'=> JSON_CONTENT_HEADER_VALUE }.freeze
65
+ DEFAULT_POST_HEADER = {
66
+ 'accept'=> JSON_CONTENT_HEADER_VALUE,
67
+ "Content-Type"=> JSON_CONTENT_HEADER_VALUE
68
+ }.freeze
69
+ ETAG_HEADER_KEY = "X-Deere-Signature"
70
+ REQUEST_METHODS_TO_PUT_PARAMS_IN_URL = [:get, :delete, :head]
71
+ SPECIAL_BODY_PARAMETERS = [:start, :count]
72
+
73
+ def self.configure
74
+ self.configuration ||= Configuration.new
75
+ yield(configuration)
76
+ set_logger()
77
+ end
78
+
79
+ class Configuration
80
+ attr_accessor :endpoint
81
+ attr_writer :shared_secret, :app_id, :contribution_definition_id
82
+ attr_reader :environment
83
+
84
+ def log_level=(val)
85
+ @log_level = val
86
+ end
87
+
88
+ def log_level
89
+ @log_level ||= :fatal
90
+ return @log_level
91
+ end
92
+
93
+ def environment=(val)
94
+ @environment = val.to_sym
95
+ @endpoint = ENDPOINTS[@environment]
96
+ if @endpoint.nil?
97
+ raise ConfigurationError.new('Invalid environment, you must use either :sandbox or :production. Sandbox is the default')
98
+ end
99
+ end
100
+
101
+ def initialize
102
+ # Assume the sandbox endpoint
103
+ self.environment = :sandbox
104
+ @shared_secret = nil
105
+ @app_id = nil
106
+ end
107
+
108
+ def contribution_definition_id
109
+ if @contribution_definition_id.nil? then
110
+ raise ConfigurationError.new('No contribution_definition_id provided in configuration. ' \
111
+ 'Please set this to make the request, you\'ll need to contact JohnDeere support to get this value.')
112
+ end
113
+ return @contribution_definition_id
114
+ end
115
+
116
+ def shared_secret
117
+ if @shared_secret.nil? then
118
+ raise ConfigurationError.new('No shared_secret provided in configuration. ' \
119
+ 'Please set this according to your Deere Developer app credentials.')
120
+ end
121
+ return @shared_secret
122
+ end
123
+
124
+ def app_id
125
+ if @app_id.nil? then
126
+ raise ConfigurationError.new('No app_id provided in configuration. ' \
127
+ 'Please set this according to your Deere Developer app credentials.')
128
+ end
129
+ return @app_id
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,79 @@
1
+ module MyJohnDeere
2
+ class AccessToken
3
+ attr_accessor :oauth_access_token
4
+
5
+ def self.oauth_consumer(options = {})
6
+ OAuth::Consumer.new(
7
+ MyJohnDeere.configuration.app_id,
8
+ MyJohnDeere.configuration.shared_secret,
9
+ options.merge(
10
+ site: MyJohnDeere.configuration.endpoint,
11
+ header: {Accept: MyJohnDeere::JSON_CONTENT_HEADER_VALUE}
12
+ ))
13
+ end
14
+
15
+ # Use this if you need to get the verifier code. You'll need to use this
16
+ # along with the request_token.authorize_url to have the user sign in and
17
+ # provide you with a verifier code. Makes a request to get the request_token.
18
+ def self.get_request_token()
19
+ consumer = self.oauth_consumer(
20
+ authorize_url: MyJohnDeere::AUTHORIZE_URL,
21
+ http_method: :get
22
+ )
23
+ return consumer.get_request_token({})
24
+ end
25
+
26
+ def initialize(options = {})
27
+ request_token_options = [:request_token_token, :request_token_secret, :verifier_code]
28
+ oauth_token_options = [:oauth_access_token_token, :oauth_access_token_secret]
29
+ if request_token_options.all? { |i| options.key?(i) } then
30
+ request_token = OAuth::RequestToken.from_hash(self.class.oauth_consumer, {
31
+ oauth_token: options[:token],
32
+ oauth_token_secret: options[:token_secret]
33
+ })
34
+ self.oauth_access_token = request_token.get_access_token(oauth_verifier: options[:verifier_code])
35
+ elsif oauth_token_options.all? { |i| options.key?(i) } then
36
+ self.oauth_access_token = OAuth::AccessToken.from_hash(
37
+ self.class.oauth_consumer,
38
+ {
39
+ oauth_token: options[:oauth_access_token_token],
40
+ oauth_token_secret: options[:oauth_access_token_secret]
41
+ }
42
+ )
43
+ else
44
+ raise ArgumentError.new("You must specify either request token options [#{request_token_options.join(',')}] or [#{oauth_token_options.join(',')}]")
45
+ end
46
+ end
47
+
48
+ def token
49
+ return oauth_access_token.nil? ? nil : oauth_access_token.token
50
+ end
51
+
52
+ def secret
53
+ return oauth_access_token.nil? ? nil : oauth_access_token.secret
54
+ end
55
+
56
+ def execute_request(method, path, options = {})
57
+ path, headers, body = Util.build_path_headers_and_body(method, path,
58
+ headers: options[:headers],
59
+ body: options[:body],
60
+ etag: options[:etag])
61
+ response = nil
62
+ if REQUEST_METHODS_TO_PUT_PARAMS_IN_URL.include?(method)
63
+ response = self.oauth_access_token.send(method, path, headers)
64
+ else
65
+ # permit the body through since it'll be in the
66
+ response = self.oauth_access_token.send(method, path, body, headers)
67
+ end
68
+ MyJohnDeere.logger.info("JohnDeere token response: #{response.body}")
69
+ # if response.code == "401"
70
+ # self.notify_on_destroy = true
71
+ # # we are no longer authorized
72
+ # self.destroy
73
+ # logger.info("JohnDeere token destroyed: #{self.persisted?}, errors: #{self.errors.full_messages}")
74
+ # end
75
+ # return response
76
+ return Response.new(response)
77
+ end
78
+ end
79
+ end