myjohndeere 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 (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