sis_ruby 1.0.0
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 +41 -0
- data/Gemfile +3 -0
- data/LICENSE +28 -0
- data/README.md +188 -0
- data/RELEASE_NOTES.md +3 -0
- data/Rakefile +35 -0
- data/lib/sis_ruby/client.rb +85 -0
- data/lib/sis_ruby/common.rb +5 -0
- data/lib/sis_ruby/endpoint.rb +108 -0
- data/lib/sis_ruby/exceptions/bad_response_error.rb +35 -0
- data/lib/sis_ruby/exceptions/missing_id_error.rb +12 -0
- data/lib/sis_ruby/get_helper.rb +41 -0
- data/lib/sis_ruby/hash_builder.rb +31 -0
- data/lib/sis_ruby/params.rb +117 -0
- data/lib/sis_ruby/result_enumerable.rb +86 -0
- data/lib/sis_ruby/version.rb +3 -0
- data/lib/sis_ruby.rb +8 -0
- data/samples/sample-1.rb +26 -0
- data/samples/sample-2.rb +33 -0
- data/sis_ruby.gemspec +22 -0
- data/spec/client_spec.rb +57 -0
- data/spec/endpoint_spec.rb +54 -0
- data/spec/hash_builder_spec.rb +83 -0
- data/spec/params_spec.rb +75 -0
- data/spec/setup/drop-db.js +4 -0
- data/spec/setup/recreate-db.sh +14 -0
- data/spec/setup/test-user.json +6 -0
- data/spec/spec_helper.rb +1 -0
- data/spec-writing/entity.json +50 -0
- data/spec-writing/hiera.json +58 -0
- data/spec-writing/hook.json +64 -0
- data/spec-writing/schema.json +131 -0
- data/spec-writing/write_spec.rb +105 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 584c4065727e96b0b4c0172fe31b6ab7d8a1d39a
|
4
|
+
data.tar.gz: 99dd517363e6e832f3e2c910f2b7a36ecb925a9e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 001f9546fc5f481bb3b4677071f9d4dd924975810ab34ee25c83f3e749fb7ecfe367d5d74104bf04f76852fa05fb605f37c56c1e371ce9d3b7f063b623b75f91
|
7
|
+
data.tar.gz: 08a35bf1b678a39e0cb5b0826ee5c2c391c97fdec62df27e7c5833a61830ce3924fcb76f47228ff3757f9d0d7d1c71ab796104301e2885f6c041e4ff5d997e6f
|
data/.gitignore
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
### Ruby template
|
2
|
+
*.gem
|
3
|
+
*.rbc
|
4
|
+
/.config
|
5
|
+
/coverage/
|
6
|
+
/InstalledFiles
|
7
|
+
/pkg/
|
8
|
+
/spec/reports/
|
9
|
+
/spec/examples.txt
|
10
|
+
/test/tmp/
|
11
|
+
/test/version_tmp/
|
12
|
+
/tmp/
|
13
|
+
|
14
|
+
## Specific to RubyMotion:
|
15
|
+
.dat*
|
16
|
+
.repl_history
|
17
|
+
build/
|
18
|
+
|
19
|
+
## Documentation cache and generated files:
|
20
|
+
/.yardoc/
|
21
|
+
/_yardoc/
|
22
|
+
/doc/
|
23
|
+
/rdoc/
|
24
|
+
|
25
|
+
## Environment normalisation:
|
26
|
+
/.bundle/
|
27
|
+
/vendor/bundle
|
28
|
+
/lib/bundler/man/
|
29
|
+
|
30
|
+
# for a library or gem, you might want to ignore these files since the code is
|
31
|
+
# intended to run in multiple environments; otherwise, check them in:
|
32
|
+
# Gemfile.lock
|
33
|
+
# .ruby-version
|
34
|
+
# .ruby-gemset
|
35
|
+
|
36
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
37
|
+
.rvmrc
|
38
|
+
|
39
|
+
# Created by .ignore support plugin (hsz.mobi)
|
40
|
+
|
41
|
+
.idea/
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
This software is licensed under the BSD 3-Clause license.
|
2
|
+
|
3
|
+
Copyright (c) 2016, Verisign, Inc. All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
are permitted provided that the following conditions are met:
|
7
|
+
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
list of conditions and the following disclaimer.
|
10
|
+
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
this list of conditions and the following disclaimer in the documentation and/or
|
13
|
+
other materials provided with the distribution.
|
14
|
+
|
15
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
16
|
+
may be used to endorse or promote products derived from this software without
|
17
|
+
specific prior written permission.
|
18
|
+
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
23
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
24
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
25
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
26
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
28
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# sis_ruby
|
2
|
+
|
3
|
+
A Ruby client to talk to a SIS server (https://github.com/sis-cmdb/sis-api).
|
4
|
+
|
5
|
+
Currently only the v1.1 API is supported.
|
6
|
+
|
7
|
+
Initial commit represents work by Neel Goyal, formerly at Verisign,
|
8
|
+
and Keith Bennett, currently at Verisign (http://www.verisign.com/).
|
9
|
+
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
Example code:
|
14
|
+
|
15
|
+
```
|
16
|
+
require 'sis_ruby'
|
17
|
+
|
18
|
+
# Create a client
|
19
|
+
client = SisRuby::Client.new(sis_server_url)
|
20
|
+
|
21
|
+
# Get the host information endpoint
|
22
|
+
hosts = client.entities('host')
|
23
|
+
|
24
|
+
# Use all possible Params options to list records of a given entity:
|
25
|
+
params = SisRuby::Params.new.sort('hostname').offset(9000).limit(2).fields('hostname', 'environment')
|
26
|
+
records = hosts.list(params)
|
27
|
+
|
28
|
+
# Get record counts:
|
29
|
+
puts "Total host count is #{hosts.count}"
|
30
|
+
puts "Total qa host count is #{hosts.count('environment' => 'qa')}"
|
31
|
+
|
32
|
+
# Get up to 10 hooks
|
33
|
+
hook_list = client.hooks.list(SisRuby::Params.new.limit(10))
|
34
|
+
|
35
|
+
# Get 1 schema
|
36
|
+
schema_list = client.schemas.list(SisRuby::Params.new.limit(1)).first
|
37
|
+
|
38
|
+
# Hiera Entry Creation
|
39
|
+
hiera_entry = client.hiera.create({ 'name' => 'entry', 'hieradata' => { 'key1' => 'value1' }});
|
40
|
+
|
41
|
+
# Entity Deletion: Delete the entity of type 'entity_name' with id 'foo':
|
42
|
+
was_deleted = client.entities('entity_name').delete('foo');
|
43
|
+
```
|
44
|
+
|
45
|
+
## Client Initialization
|
46
|
+
|
47
|
+
The client constructor takes the following parameters:
|
48
|
+
|
49
|
+
* (required) a URL indicating the base URL of the SIS endpoints
|
50
|
+
* (optional) a hash containing neither, one, or both of:
|
51
|
+
* **:auth_token** - an authorization token field to be sent in the `x-auth-token` header
|
52
|
+
* **:api_version** - a version string to use in the request URL's instead of the default API version
|
53
|
+
|
54
|
+
```
|
55
|
+
client = SisRuby::Client.new(sis_server_url)
|
56
|
+
client = SisRuby::Client.new(sis_server_url, auth_token: auth_token)
|
57
|
+
```
|
58
|
+
|
59
|
+
## Client Authentication
|
60
|
+
|
61
|
+
The client may also acquire and use a temporary token to use against the SIS endpoint
|
62
|
+
via the `authenticate` method. Below are examples:
|
63
|
+
|
64
|
+
```
|
65
|
+
# This method will raise an SisRuby::Client::AuthenticationError if authentication fails.
|
66
|
+
token = client.authenticate(userid, password)
|
67
|
+
|
68
|
+
# You can also combine the client creation and authentication into a single expression
|
69
|
+
# since the authenticate method returns the client:
|
70
|
+
client = SisRuby::Client.new(sis_server_url).authenticate(userid, password)
|
71
|
+
```
|
72
|
+
|
73
|
+
Although `authenticate` returns the token, there is no need to save it;
|
74
|
+
it is stored in the client instance for subsequent requests.
|
75
|
+
|
76
|
+
## Entity, Hook, Schema, and Hiera Methods
|
77
|
+
|
78
|
+
The object returned by `client.hooks`, `client.schemas`, `client.hiera`, and
|
79
|
+
`client.entities(entity_name)` all interact with the appropriate endpoints
|
80
|
+
and expose the following interface:
|
81
|
+
|
82
|
+
|
83
|
+
### list(query)
|
84
|
+
|
85
|
+
This maps to a GET `/` request against the appropriate endpoint for the default or specified API version.
|
86
|
+
|
87
|
+
List parameters can be specified in the form of any object responding to
|
88
|
+
`to_hash` and returning a hash (including, of course, a `Hash`).
|
89
|
+
|
90
|
+
Values in the hash can contain:
|
91
|
+
|
92
|
+
* **sort** - field name(s) on which to sort the records, precede fieldname with `-` for descending
|
93
|
+
* **limit** - limit the result set size to the specified number of records
|
94
|
+
* **fields** - only return the fields passed to this method; however:
|
95
|
+
* currently there is a bug that results in array type fields being returned even if they
|
96
|
+
are not included in the field list
|
97
|
+
* the _id field will always be returned even if it is not specified
|
98
|
+
* **offset** - the offset into the sorted results at which to start adding records to the result set
|
99
|
+
(Note: offset is not reliable unless a sort order is specified; there is no default sort order
|
100
|
+
and the random order may change from call to call.
|
101
|
+
|
102
|
+
For your convenience, a `Params` class has been provided with chainable methods (see code example).
|
103
|
+
|
104
|
+
Also, there is a `count` method that will return the total record count. If passed a filter, it will
|
105
|
+
return the count of records that meet the filter criteria.
|
106
|
+
|
107
|
+
An array of hashes is returned on success. For your convenience, there is also a
|
108
|
+
`list_as_openstructs` method that returns each record as an `OpenStruct` instance for easier access.
|
109
|
+
OpenStruct instances allow you to call methods whose names correspond to the original hash's keys,
|
110
|
+
e.g. `host.site` instead of `host['site']`.
|
111
|
+
This approach is not recommended for large numbers of records, as it requires more memory and processing.
|
112
|
+
|
113
|
+
|
114
|
+
### get(id)
|
115
|
+
|
116
|
+
This maps to a GET `/id` request against the approprivate endpoint for the default or specified API version.
|
117
|
+
|
118
|
+
* id : a string representing the ID of the object to receive. For schemas, hooks, and hiera, this is the `name`.
|
119
|
+
For entities, it is the `_id`.
|
120
|
+
|
121
|
+
A single hash representing the object is returned on success.
|
122
|
+
|
123
|
+
|
124
|
+
### create(obj)
|
125
|
+
|
126
|
+
This maps to a POST `/` request against the appropriate endpoint for the default or specified API version.
|
127
|
+
|
128
|
+
* obj : a valid Hash conforming to the endpoint specification
|
129
|
+
|
130
|
+
The created object as a hash is returned on success.
|
131
|
+
|
132
|
+
|
133
|
+
### update(obj)
|
134
|
+
|
135
|
+
This maps to a PUT '/' request against the appropriate endpoint for the default or specified API version.
|
136
|
+
|
137
|
+
* obj : a valid hash conforming to the endpoint specification. Typically retrieved from `list` or `get`.
|
138
|
+
|
139
|
+
The updated hash representing the object is returned on success.
|
140
|
+
|
141
|
+
|
142
|
+
### delete(obj)
|
143
|
+
|
144
|
+
This maps to a DELETE '/id' request against the appropriate endpoint for the default or specified API version.
|
145
|
+
|
146
|
+
* obj : either a string id or an object retrieved from `list` or `get`
|
147
|
+
|
148
|
+
The boolean `true` is returned on success.
|
149
|
+
|
150
|
+
|
151
|
+
## Error handling
|
152
|
+
|
153
|
+
An instance of `SisRuby::Client` will raise an exception if an HTTP request returns a status code above and including 400.
|
154
|
+
|
155
|
+
|
156
|
+
## Running the Tests
|
157
|
+
|
158
|
+
Test code is divided into different top-level directories:
|
159
|
+
|
160
|
+
### `spec`
|
161
|
+
|
162
|
+
These are tests not requiring a SIS server.
|
163
|
+
|
164
|
+
### `spec_reading`
|
165
|
+
|
166
|
+
These are tests requiring a SIS server containing a 'host' entity populated with records
|
167
|
+
|
168
|
+
### `spec_writing`
|
169
|
+
|
170
|
+
These are tests requiring a SIS server that can be used for writing; for these
|
171
|
+
you'll probably want to set up a local server. Instructions for this are at
|
172
|
+
https://github.com/sis-cmdb/sis-api#building-and-testing.
|
173
|
+
|
174
|
+
If the tests should ever fail and the data base is not correctly restored to
|
175
|
+
its original empty state, you can delete the Mongo data
|
176
|
+
by running the Mongo shell ('mongo') and issuing the following commands:
|
177
|
+
|
178
|
+
```
|
179
|
+
use test
|
180
|
+
db.dropDatabase();
|
181
|
+
```
|
182
|
+
|
183
|
+
To verify the user id and password, you can issue the following command, replacing 'test' and
|
184
|
+
'abc123' with the real user id and password:
|
185
|
+
|
186
|
+
```
|
187
|
+
curl -D- -u test:abc123 -X POST -H "Content-Type: application/json" http://localhost:3000/api/v1.1/users/auth_token
|
188
|
+
```
|
data/RELEASE_NOTES.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# From https://github.com/goncalossilva/gem_template
|
2
|
+
begin
|
3
|
+
require "bundler"
|
4
|
+
Bundler.setup
|
5
|
+
rescue LoadError
|
6
|
+
$stderr.puts "You need to have Bundler installed to be able build this gem."
|
7
|
+
end
|
8
|
+
|
9
|
+
gemspec = eval(File.read('sis_ruby.gemspec'))
|
10
|
+
|
11
|
+
desc "Validate the gemspec"
|
12
|
+
task :gemspec do
|
13
|
+
gemspec.validate
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Build gem locally"
|
17
|
+
task :build => :gemspec do
|
18
|
+
system "gem build #{gemspec.name}.gemspec"
|
19
|
+
FileUtils.mkdir_p "pkg"
|
20
|
+
FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "pkg"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Install gem locally"
|
24
|
+
task :install => :build do
|
25
|
+
system "gem install pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Clean automatically generated files"
|
29
|
+
task :clean do
|
30
|
+
FileUtils.rm_rf "pkg"
|
31
|
+
end
|
32
|
+
|
33
|
+
require 'rspec/core/rake_task'
|
34
|
+
|
35
|
+
RSpec::Core::RakeTask.new('spec')
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative 'common'
|
2
|
+
require 'sis_ruby/endpoint'
|
3
|
+
require 'typhoeus'
|
4
|
+
|
5
|
+
module SisRuby
|
6
|
+
|
7
|
+
class Client
|
8
|
+
|
9
|
+
attr_reader :api_version, :auth_token, :base_url, :entity_endpoints, :hiera, :hooks, :hosts, :schemas
|
10
|
+
|
11
|
+
DEFAULT_API_VERSION = '1.1'
|
12
|
+
|
13
|
+
# @param url the base URL of the service (excluding ''/api/v...'')
|
14
|
+
# @param options (can include :version, :auth_token)
|
15
|
+
def initialize(url, options = {})
|
16
|
+
@base_url = url
|
17
|
+
@api_version = options[:api_version] || DEFAULT_API_VERSION
|
18
|
+
@auth_token = options[:auth_token]
|
19
|
+
|
20
|
+
@entity_endpoints = {}
|
21
|
+
@hooks = create_endpoint('hooks', 'name')
|
22
|
+
@schemas = create_endpoint('schemas', 'name')
|
23
|
+
@hiera = create_endpoint('hiera', 'name')
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def create_endpoint(endpoint_suffix, id_fieldname = :default)
|
28
|
+
Endpoint.new(self, endpoint_suffix, id_fieldname)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def entities(name, id_fieldname = DEFAULT_ID_FIELDNAME)
|
33
|
+
@entity_endpoints[name] ||= create_endpoint("entities/#{name}", id_fieldname)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def tokens(username)
|
38
|
+
create_endpoint("users/#{username}/tokens", 'name')
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# Returns the schema for the specified collection_name, or nil if it's not found.
|
43
|
+
def schema_for(collection_name)
|
44
|
+
params = Params.new.limit(1).filter('name' => collection_name)
|
45
|
+
schemas.list(params).first
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Authenticates the username and password. Get the token by calling client.auth_token.
|
50
|
+
# @return self for chaining this method after the constructor
|
51
|
+
def authenticate(username, password)
|
52
|
+
dest = "#{base_url}/api/v#{api_version}/users/auth_token"
|
53
|
+
options = {
|
54
|
+
userpwd: username + ':' + password,
|
55
|
+
headers: { 'Accept' => 'application/json', 'Content-Type' => 'application/json' }
|
56
|
+
}
|
57
|
+
response = Typhoeus.post(dest, options)
|
58
|
+
unless response.options[:response_code] == 201
|
59
|
+
raise AuthenticationError.new(response)
|
60
|
+
end
|
61
|
+
|
62
|
+
@auth_token = JSON.parse(response.response_body)['name']
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def to_s
|
68
|
+
self.class.name + ": base_url = #{@base_url}"
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
class AuthenticationError < Exception
|
74
|
+
|
75
|
+
def initialize(response)
|
76
|
+
@response = response
|
77
|
+
end
|
78
|
+
|
79
|
+
def to_s
|
80
|
+
@response.options[:response_headers].split("\r\n").first
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'typhoeus'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require_relative 'client'
|
5
|
+
require_relative 'common'
|
6
|
+
require_relative 'get_helper'
|
7
|
+
require_relative 'result_enumerable'
|
8
|
+
require_relative 'exceptions/missing_id_error'
|
9
|
+
|
10
|
+
module SisRuby
|
11
|
+
|
12
|
+
class Endpoint
|
13
|
+
|
14
|
+
include GetHelper
|
15
|
+
|
16
|
+
attr_reader :client, :id_field, :url
|
17
|
+
|
18
|
+
|
19
|
+
def initialize(client, endpoint_name, id_field = DEFAULT_ID_FIELDNAME)
|
20
|
+
@client = client
|
21
|
+
@url = "#{client.base_url}/api/v#{client.api_version}/#{endpoint_name}"
|
22
|
+
@id_field = id_field
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# This method is used to allow callers to pass either the id itself,
|
27
|
+
# or the record including an id key/value pair.
|
28
|
+
def id_from_param(object)
|
29
|
+
id = object.is_a?(Hash) ? object[@id_field] : object
|
30
|
+
id ? id : raise(MissingIdError.new("Missing required id field #{@id_field}}"))
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def create_enumerable(params = {}, chunk_size = ResultEnumerable::DEFAULT_CHUNK_RECORD_COUNT)
|
35
|
+
ResultEnumerable.new(self, params, chunk_size)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Gets the total count of records, with optional filter
|
40
|
+
def count(filter = {})
|
41
|
+
params = Params.new.filter(filter).limit(1).to_hash
|
42
|
+
response = Typhoeus::Request.new(@url, params: params, headers: create_headers(true)).run
|
43
|
+
response.headers['x-total-count'].to_i
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# Anything implementing a to_hash method can be passed as the query.
|
48
|
+
# This enables the passing in of SisParams objects.
|
49
|
+
def list(params = {})
|
50
|
+
create_enumerable(params).each.to_a
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Anything implementing a to_hash method can be passed as the query.
|
55
|
+
# This enables the passing in of SisParams objects.
|
56
|
+
def list_as_openstructs(query = {})
|
57
|
+
list(query).map { |h| OpenStruct.new(h) }
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def get(id)
|
62
|
+
request = Typhoeus::Request.new("#{url}/#{id}", headers: create_headers(true))
|
63
|
+
response = request.run
|
64
|
+
validate_response_success(response)
|
65
|
+
JSON.parse(response.body)
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def create(obj)
|
70
|
+
http_response = Typhoeus.post(@url, { body: obj.to_json, headers: get_headers(true) } )
|
71
|
+
validate_response_success(http_response)
|
72
|
+
JSON.parse(http_response.body)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def delete(id)
|
77
|
+
id = id_from_param(id)
|
78
|
+
http_response = Typhoeus.delete("#{@url}/#{id}", headers: get_headers(false))
|
79
|
+
validate_response_success(http_response)
|
80
|
+
JSON.parse(http_response.body)
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def update(obj)
|
85
|
+
id = id_from_param(obj)
|
86
|
+
http_response = self.class.put("#{@url}/#{id}", {body: obj.to_json, headers: get_headers(true) })
|
87
|
+
validate_response_success(http_response)
|
88
|
+
JSON.parse(http_response.body)
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
def to_s
|
93
|
+
self.class.name + ": endpoint = #{@url}, client = #{@client}"
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def ==(other)
|
98
|
+
client.equal?(other.client) && url == other.url && id_field == other.id_field
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def get_headers(specify_content_type)
|
104
|
+
create_headers(specify_content_type, @client.auth_token)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module SisRuby
|
2
|
+
|
3
|
+
class BadResponseError < RuntimeError
|
4
|
+
|
5
|
+
attr_reader :response
|
6
|
+
|
7
|
+
def initialize(response)
|
8
|
+
@response = response
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
|
14
|
+
first_header_line = if response && response.options[:response_headers]
|
15
|
+
header_lines = response.options[:response_headers].split("\r\n")
|
16
|
+
header_lines.any? ? header_lines.first : nil
|
17
|
+
else
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
body = if response && response.options[:response_body]
|
22
|
+
response.options[:response_body].rstrip
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
code = response.code
|
28
|
+
|
29
|
+
string = "#{self.class.name}: #{code}"
|
30
|
+
string << ": #{body}" if body
|
31
|
+
string << (first_header_line ? " (#{first_header_line})" : '')
|
32
|
+
string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative 'exceptions/bad_response_error'
|
2
|
+
|
3
|
+
|
4
|
+
# Methods for helping get data from SIS.
|
5
|
+
module SisRuby
|
6
|
+
module GetHelper
|
7
|
+
|
8
|
+
# Creates the header for a request.
|
9
|
+
def create_headers(specify_content_type, auth_token = nil)
|
10
|
+
headers = {
|
11
|
+
'Accept' => 'application/json'
|
12
|
+
}
|
13
|
+
|
14
|
+
if auth_token
|
15
|
+
headers['x-auth-token'] = auth_token
|
16
|
+
end
|
17
|
+
|
18
|
+
if specify_content_type
|
19
|
+
headers['Content-Type'] = 'application/json'
|
20
|
+
end
|
21
|
+
|
22
|
+
headers
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Raises an error on response failure.
|
27
|
+
def validate_response_success(response)
|
28
|
+
unless response.code.between?(200, 299)
|
29
|
+
raise BadResponseError.new(response)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Returns a Typhoeus response.
|
35
|
+
def typhoeus_get(query)
|
36
|
+
# TODO: Simplify w/Typhoeus.get ?
|
37
|
+
Typhoeus::Request.new(url, params: query, headers: get_headers(true) ).run
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
# Takes methods and builds an internal hash where the method calls
|
3
|
+
# are keys, and their parameter is the value.
|
4
|
+
class HashBuilder
|
5
|
+
|
6
|
+
attr_reader :key_type
|
7
|
+
|
8
|
+
def initialize(key_type = String)
|
9
|
+
raise ArgumentError.new("Invalid key type '#{key_type}'") unless [String, Symbol].include?(key_type)
|
10
|
+
@key_type = key_type
|
11
|
+
@data = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def method_missing(method_name, *args)
|
16
|
+
value = args.first
|
17
|
+
key = (@key_type == String) ? method_name.to_s : method_name.to_sym
|
18
|
+
@data[key] = value
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def respond_to_missing?(method_name, include_private)
|
24
|
+
true # TODO: exclude ancestor methods?
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def to_h
|
29
|
+
@data
|
30
|
+
end
|
31
|
+
end
|