itglue 0.1.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 +12 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +104 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/itglue.gemspec +30 -0
- data/lib/itglue.rb +29 -0
- data/lib/itglue/asset.rb +8 -0
- data/lib/itglue/asset/base.rb +180 -0
- data/lib/itglue/asset/base/attributes.rb +44 -0
- data/lib/itglue/asset/base/relatable.rb +37 -0
- data/lib/itglue/asset/configuration.rb +6 -0
- data/lib/itglue/asset/configuration_interface.rb +6 -0
- data/lib/itglue/asset/configuration_status.rb +4 -0
- data/lib/itglue/asset/configuration_type.rb +4 -0
- data/lib/itglue/asset/organization.rb +4 -0
- data/lib/itglue/client.rb +119 -0
- data/lib/itglue/client/mapper.rb +41 -0
- data/lib/itglue/client/path_processor.rb +56 -0
- data/lib/itglue/version.rb +3 -0
- metadata +150 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 577a952aa71445a0982220ba9519ef3e8ff30abb
|
4
|
+
data.tar.gz: e00b1ce90a9bcd6a9b56935b72ad3953b85dcde0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 430a99fea58b66419afbefa28449d4bc3cedf0b3e457c9e61bce8e3b6b131c6585d94b0dacb39e8b22bb5acd5019c3993dc7d5b0012cb0711d06c6f4ac049285
|
7
|
+
data.tar.gz: 1ca0c09f3127a634d5dd087a38666ed8bbbb9a8cd6007569bfa86a6d539dd3a1e9c23409777e767c63ecf8191ef49f811cda42538b2f1db47f086806120f9ae7
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Ben Silva
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# ITGlue
|
2
|
+
|
3
|
+
A wrapper for the [ITGlue API](https://api.itglue.com/developer/).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'itglue'
|
9
|
+
```
|
10
|
+
|
11
|
+
## Requirements
|
12
|
+
|
13
|
+
* Ruby 2.0.0 or higher
|
14
|
+
|
15
|
+
## Setup
|
16
|
+
|
17
|
+
### Authentication
|
18
|
+
|
19
|
+
For now this gem only supports API Key authentication.
|
20
|
+
|
21
|
+
### Configuration
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'itglue'
|
25
|
+
|
26
|
+
ITGlue.configure do |config|
|
27
|
+
config.itglue_api_key = 'ITG.b94e901420fe7cb163a364b451f172d9.P3nMIV9EDp1Xb7h4-sO7WDU0S2R5DgC-fu2DsTxBkW7eZHRp0y4ODRQ51se1c24m' config.itglue_api_base_uri = 'https://api.itglue.com'
|
28
|
+
config.logger = ::Logger.new(STDOUT)
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
### Basics
|
35
|
+
|
36
|
+
Get all organizations
|
37
|
+
```ruby
|
38
|
+
organizations = ITGlue::Organization.get
|
39
|
+
#=> [#<ITGlue::Organization id: 123 name: "Happy Frog", description: nil, ...>, <ITGlue::Organization id: 124 name: "Vancity Superstars", description: nil, ...>, ...]
|
40
|
+
```
|
41
|
+
Get organizations with a filter
|
42
|
+
```ruby
|
43
|
+
organizations = ITGlue::Organization.filter(name: 'Happy Frog')
|
44
|
+
#=> [#<ITGlue::Organization id: 123 name: "Happy Frog", description: nil, ...>]
|
45
|
+
```
|
46
|
+
Get organization by id
|
47
|
+
```ruby
|
48
|
+
organization = ITGlue::Organization.find(123)
|
49
|
+
#=> #<ITGlue::Organization id: 123 name: "Ben's Gem Test", description: nil, ...>]
|
50
|
+
```
|
51
|
+
Get configurations for a specific organization
|
52
|
+
```ruby
|
53
|
+
configuration = ITGlue::Organization.get_nested(organization)
|
54
|
+
```
|
55
|
+
|
56
|
+
### Client
|
57
|
+
|
58
|
+
You can also directly instantiate a client and handle the data and response directly.
|
59
|
+
```ruby
|
60
|
+
client = ITGlue::Client.new
|
61
|
+
#=> #<ITGlue::Client:0x007fd7eb032d00 ...>
|
62
|
+
query = { filter: { name: 'HP' } }
|
63
|
+
client.get(:configurations, { parent: organization }, { query: query })
|
64
|
+
# => [
|
65
|
+
# {
|
66
|
+
# id: 456,
|
67
|
+
# type: "configurations",
|
68
|
+
# attributes: {
|
69
|
+
# organization_id: 123,
|
70
|
+
# organization_name: "Happy Frog",
|
71
|
+
# ...
|
72
|
+
# }
|
73
|
+
# },
|
74
|
+
# ...
|
75
|
+
# ]
|
76
|
+
```
|
77
|
+
A get request such as the one above will handle generating the route and pagination. If you want to handle these yourself, you can use 'execute'
|
78
|
+
```ruby
|
79
|
+
client.execute(:get, '/organizations/31131/relationships/configurations', nil, {query: {filter: {name: 'HP'}}})
|
80
|
+
# => {
|
81
|
+
# "data"=> [
|
82
|
+
# {
|
83
|
+
# "id"=>"23943",
|
84
|
+
# "type"=>"configurations",
|
85
|
+
# "attributes"=> {
|
86
|
+
# "organization-id"=>31131,
|
87
|
+
# "organization-name"=>"Ben's Gem Test",
|
88
|
+
# ...
|
89
|
+
# }
|
90
|
+
# },
|
91
|
+
# ...
|
92
|
+
# ],
|
93
|
+
# "links"=>{},
|
94
|
+
# "meta"=>{"current-page"=>1, "next-page"=>nil, "prev-page"=>nil, "total-pages"=>1, "total-count"=>1, "filters"=>{}}
|
95
|
+
# }
|
96
|
+
```
|
97
|
+
|
98
|
+
## Contributing
|
99
|
+
|
100
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/b-loyola/itglue.
|
101
|
+
|
102
|
+
## License
|
103
|
+
|
104
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "itglue"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/itglue.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "itglue/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "itglue"
|
8
|
+
spec.version = ITGlue::VERSION
|
9
|
+
spec.authors = ["Ben Silva"]
|
10
|
+
spec.email = ["berna.loyola@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A simple wrapper for the IT Glue API}
|
13
|
+
spec.description = %q{This gem provides a client for interactiong with the IT Glue API}
|
14
|
+
spec.homepage = "https://github.com/b-loyola/itglue"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
|
28
|
+
spec.add_dependency "httparty", "~> 0.16", ">= 0.15.7"
|
29
|
+
spec.add_dependency "activesupport", "~> 5.2", ">= 3.0.0"
|
30
|
+
end
|
data/lib/itglue.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module ITGlue
|
2
|
+
class ITGlueError < StandardError; end
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_writer :config
|
6
|
+
|
7
|
+
def config
|
8
|
+
@config ||= Config.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def configure
|
12
|
+
yield(config)
|
13
|
+
config
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Config
|
18
|
+
DEFAULT_PAGE_SIZE = 500
|
19
|
+
attr_accessor :itglue_api_key, :itglue_api_base_uri, :logger, :default_page_size
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@default_page_size = DEFAULT_PAGE_SIZE
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'itglue/version'
|
28
|
+
require 'itglue/client'
|
29
|
+
require 'itglue/asset'
|
data/lib/itglue/asset.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
require 'itglue/asset/base/relatable'
|
3
|
+
require 'itglue/asset/base/attributes'
|
4
|
+
|
5
|
+
module ITGlue
|
6
|
+
module Asset
|
7
|
+
class Base
|
8
|
+
extend Relatable
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Override in subclasses if required
|
12
|
+
def asset_type
|
13
|
+
raise ITGlueAssetError.new('no asset_type for base') if self == Base
|
14
|
+
self.name.demodulize.pluralize.underscore.to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
# Instantiates a record from data payload
|
18
|
+
# @param data [Hash] the data payload
|
19
|
+
# E.g.: { id: 1, type: 'organizations', attributes: {name: 'Happy Frog', ...} }
|
20
|
+
# @return [ITGlue::Asset] the record instance
|
21
|
+
def new_from_payload(data)
|
22
|
+
raise_method_not_available(__method__, 'not available for Base') if self == Base
|
23
|
+
asset = self.new(data[:attributes])
|
24
|
+
asset.id = data[:id]
|
25
|
+
asset.type = data[:type]
|
26
|
+
asset
|
27
|
+
end
|
28
|
+
|
29
|
+
# Executes a get request through the top-level path
|
30
|
+
# E.g. GET '/configurations'
|
31
|
+
# @return [Array<ITGlue::Asset>] an array of asset instances
|
32
|
+
def get
|
33
|
+
raise_method_not_available(__method__, 'is nested asset') if nested_asset?
|
34
|
+
assets = client.get(asset_type)
|
35
|
+
assets.map { |data| self.new_from_payload(data) }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Executes a get request through the nested asset path
|
39
|
+
# E.g. GET 'organizations/:organization_id/relationships/configurations'
|
40
|
+
# @param parent [ITGlue::Asset] the parent asset
|
41
|
+
# @return [Array<ITGlue::Asset>] an array of asset instances
|
42
|
+
def get_nested(parent)
|
43
|
+
raise_method_not_available(__method__, 'is top-level asset') unless parent_type
|
44
|
+
path_options = { parent: parent }
|
45
|
+
assets = client.get(asset_type, path_options)
|
46
|
+
assets.map { |data| self.new_from_payload(data) }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Executes a get request through the top-level path, with a filter query
|
50
|
+
# E.g. GET '/configurations?filter[name]=HP-01'
|
51
|
+
# @param filter [Hash|String] the parameters to filter by
|
52
|
+
# @return [Array<ITGlue::Asset>] an array of asset instances
|
53
|
+
def filter(filter)
|
54
|
+
raise_method_not_available(__method__, 'is nested asset') if nested_asset?
|
55
|
+
assets = client.get(asset_type, {}, { query: { filter: filter } })
|
56
|
+
assets.map { |data| self.new_from_payload(data) }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Executes a get request through the top-level path for a specific asset
|
60
|
+
# E.g. GET '/configurations/1'
|
61
|
+
# @param id [Integer] the id of the asset
|
62
|
+
# @return [ITGlue::Asset] the asset instance
|
63
|
+
def find(id)
|
64
|
+
data = client.get(asset_type, id: id )
|
65
|
+
self.new_from_payload(data)
|
66
|
+
end
|
67
|
+
|
68
|
+
def client
|
69
|
+
@@client ||= Client.new
|
70
|
+
end
|
71
|
+
|
72
|
+
protected
|
73
|
+
|
74
|
+
def raise_method_not_available(method_name, reason)
|
75
|
+
error_msg = "method '#{method_name}' is not available for #{asset_type}: #{reason}"
|
76
|
+
raise MethodNotAvailable.new(error_msg)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
attr_accessor :id, :type, :attributes
|
81
|
+
|
82
|
+
def initialize(attributes = {})
|
83
|
+
raise ITGlueAssetError.new('cannot instantiate base') if self == Base
|
84
|
+
@attributes = Attributes.new(attributes)
|
85
|
+
end
|
86
|
+
|
87
|
+
def asset_type
|
88
|
+
self.class.asset_type
|
89
|
+
end
|
90
|
+
|
91
|
+
def inspect
|
92
|
+
string = "#<#{self.class.name} id: #{self.id || 'nil'} "
|
93
|
+
fields = @attributes.keys.map { |field| "#{field}: #{@attributes.inspect_field(field)}" }
|
94
|
+
string << fields.join(", ") << ">"
|
95
|
+
end
|
96
|
+
|
97
|
+
def dup
|
98
|
+
dup = self.class.new(self.attributes)
|
99
|
+
dup.type = self.type
|
100
|
+
dup
|
101
|
+
end
|
102
|
+
|
103
|
+
def assign_attributes(attributes)
|
104
|
+
raise ArgumentError.new('attributtes must be a Hash') unless attributes.is_a?(Hash)
|
105
|
+
attributes.each do |attribute, value|
|
106
|
+
@attributes[attribute] = value
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def changed_attributes
|
111
|
+
@attributes.changes
|
112
|
+
end
|
113
|
+
|
114
|
+
def remove_attribute(key)
|
115
|
+
@attributes.remove_attribute(key)
|
116
|
+
end
|
117
|
+
|
118
|
+
def new_asset?
|
119
|
+
!self.id
|
120
|
+
end
|
121
|
+
|
122
|
+
def save
|
123
|
+
new_asset? ? create : update
|
124
|
+
end
|
125
|
+
|
126
|
+
def changed?
|
127
|
+
!changed_attributes.empty?
|
128
|
+
end
|
129
|
+
|
130
|
+
def [](attribute)
|
131
|
+
@attributes[attribute]
|
132
|
+
end
|
133
|
+
|
134
|
+
def []=(attribute, value)
|
135
|
+
@attributes.assign_attribute(attribute, value)
|
136
|
+
end
|
137
|
+
|
138
|
+
def method_missing(method, *args)
|
139
|
+
method_name = method.to_s
|
140
|
+
arg_count = args.length
|
141
|
+
if method_name.chomp!('=')
|
142
|
+
raise ArgumentError.new("wrong number of arguments (#{arg_count} for 1)") if arg_count != 1
|
143
|
+
@attributes.assign_attribute(method_name, args[0])
|
144
|
+
elsif arg_count == 0
|
145
|
+
@attributes[method]
|
146
|
+
else
|
147
|
+
super
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def create
|
154
|
+
data = self.class.client.post(asset_type, payload)
|
155
|
+
reload_from_data(data)
|
156
|
+
end
|
157
|
+
|
158
|
+
def update
|
159
|
+
data = self.class.client.patch(asset_type, payload, id: id )
|
160
|
+
reload_from_data(data)
|
161
|
+
end
|
162
|
+
|
163
|
+
def payload
|
164
|
+
{
|
165
|
+
data: {
|
166
|
+
type: asset_type,
|
167
|
+
attributes: attributes.attributes_hash
|
168
|
+
}
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
def reload_from_data(data)
|
173
|
+
@attributes = Attributes.new(data[:attributes])
|
174
|
+
self.type = data[:type]
|
175
|
+
self.id = data[:id]
|
176
|
+
self
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ITGlue
|
2
|
+
module Asset
|
3
|
+
class Attributes < OpenStruct
|
4
|
+
def initialize(*args)
|
5
|
+
@changed_attribute_keys = []
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def assign_attribute(key, value)
|
10
|
+
@changed_attribute_keys << key.to_sym
|
11
|
+
self[key] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def remove_attribute(key)
|
15
|
+
@changed_attribute_keys.delete(key)
|
16
|
+
self.delete_field(key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def keys
|
20
|
+
self.to_h.keys
|
21
|
+
end
|
22
|
+
|
23
|
+
def attributes_hash
|
24
|
+
self.to_h
|
25
|
+
end
|
26
|
+
|
27
|
+
def inspect_field(field)
|
28
|
+
value = self[field]
|
29
|
+
if value.is_a?(String)
|
30
|
+
value.length > 100 ? "\"#{value[0..100]}...\"" : "\"#{value}\""
|
31
|
+
else
|
32
|
+
value.inspect
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def changes
|
37
|
+
attributes_hash = self.attributes_hash
|
38
|
+
@changed_attribute_keys.each_with_object({}) do |key, changes|
|
39
|
+
changes[key] = attributes_hash[key]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ITGlue
|
2
|
+
module Asset
|
3
|
+
module Relatable
|
4
|
+
def parent(parent_type, options = {})
|
5
|
+
@parent_type = parent_type.to_s.pluralize
|
6
|
+
unless options[:no_association]
|
7
|
+
define_method parent_type do
|
8
|
+
parent_id = self.send("#{parent_type}_id")
|
9
|
+
"ITGlue::#{parent_type.to_s.classify}".constantize.find(parent_id)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def children(*child_types)
|
15
|
+
child_types.each do |child_type|
|
16
|
+
define_method child_type do |options = {}|
|
17
|
+
"ITGlue::#{child_type.to_s.classify}".constantize.get_nested(self, options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def nested_asset
|
25
|
+
@nested_asset = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def nested_asset?
|
29
|
+
!!@nested_asset
|
30
|
+
end
|
31
|
+
|
32
|
+
def parent_type
|
33
|
+
@parent_type
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'itglue/client/mapper'
|
3
|
+
require 'itglue/client/path_processor'
|
4
|
+
|
5
|
+
module ITGlue
|
6
|
+
class ClientError < ITGlueError; end
|
7
|
+
class AssetNotFoundError < ClientError; end
|
8
|
+
class ServerError < ClientError; end
|
9
|
+
class UnexpectedResponseError < ClientError; end
|
10
|
+
|
11
|
+
class Client
|
12
|
+
include HTTParty
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
raise ClientError.new('itglue_api_key not configured') unless ITGlue.config.itglue_api_key
|
16
|
+
raise ClientError.new('itglue_api_base_uri not configured') unless ITGlue.config.itglue_api_base_uri
|
17
|
+
@itglue_api_key = ITGlue.config.itglue_api_key
|
18
|
+
@default_page_size = ITGlue.config.default_page_size
|
19
|
+
self.class.base_uri ITGlue.config.itglue_api_base_uri
|
20
|
+
self.class.logger ITGlue.config.logger
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute(http_method, path, payload = nil, options = {})
|
24
|
+
process_request(http_method, path, payload, options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get(asset_type, path_options = {}, options = {})
|
28
|
+
response = process_request(:get, process_path(asset_type, path_options), nil, options)
|
29
|
+
data = get_remaining_data(response, options)
|
30
|
+
prepare_data(data)
|
31
|
+
end
|
32
|
+
|
33
|
+
def patch(asset_type, payload, path_options = {}, options = {})
|
34
|
+
response = process_request(:patch, process_path(asset_type, path_options), payload, options)
|
35
|
+
prepare_data(response['data'])
|
36
|
+
end
|
37
|
+
|
38
|
+
def post(asset_type, payload, path_options = {}, options = {})
|
39
|
+
response = process_request(:post, process_path(asset_type, path_options), payload, options)
|
40
|
+
prepare_data(response['data'])
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def get_remaining_data(response, options)
|
46
|
+
return response['data'] unless response['data'].is_a?(Array)
|
47
|
+
data = response['data']
|
48
|
+
loop do
|
49
|
+
break if response['meta'] && response['meta']['next-page'].nil?
|
50
|
+
response = process_request(:get, response['links']['next'], nil, options)
|
51
|
+
data += response['data']
|
52
|
+
end
|
53
|
+
data
|
54
|
+
end
|
55
|
+
|
56
|
+
def default_headers
|
57
|
+
@default_headers ||= {
|
58
|
+
'Content-Type' => 'application/vnd.api+json',
|
59
|
+
'x-api-key' => @itglue_api_key
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def process_path(asset_type, path_options)
|
64
|
+
PathProcessor.process(asset_type, path_options)
|
65
|
+
end
|
66
|
+
|
67
|
+
def prepare_data(data)
|
68
|
+
Mapper.map(data)
|
69
|
+
end
|
70
|
+
|
71
|
+
def process_request(http_method, path, payload, options)
|
72
|
+
options = process_options(options, payload)
|
73
|
+
response = self.class.send(http_method, path, options)
|
74
|
+
response.success? ? response : handle_response_errors(response)
|
75
|
+
end
|
76
|
+
|
77
|
+
def process_options(options, payload)
|
78
|
+
options.merge!(body: payload.to_json) if payload
|
79
|
+
options[:headers] = process_header_options(options[:headers])
|
80
|
+
options[:query] = process_query_options(options[:query])
|
81
|
+
options
|
82
|
+
end
|
83
|
+
|
84
|
+
def process_header_options(header_options)
|
85
|
+
return default_headers unless header_options
|
86
|
+
raise ClientError.new('header option must be a Hash') unless header_options.is_a?(Hash)
|
87
|
+
default_headers.merge(header_options)
|
88
|
+
end
|
89
|
+
|
90
|
+
def process_query_options(query_options)
|
91
|
+
return { page: { size: @default_page_size } } unless query_options
|
92
|
+
raise ClientError.new('query option must be a Hash') unless query_options.is_a?(Hash)
|
93
|
+
if query_options[:page]
|
94
|
+
raise ClientError.new('query page option must be a Hash') unless query_options[:page].is_a?(Hash)
|
95
|
+
query_options[:page][:size] ||= @default_page_size
|
96
|
+
else
|
97
|
+
query_options[:page] = { size: @default_page_size }
|
98
|
+
end
|
99
|
+
query_options
|
100
|
+
end
|
101
|
+
|
102
|
+
def handle_response_errors(response)
|
103
|
+
if response.not_found?
|
104
|
+
raise AssetNotFoundError.new(error_message(response))
|
105
|
+
elsif response.client_error?
|
106
|
+
raise ClientError.new(error_message(response))
|
107
|
+
elsif response.server_error?
|
108
|
+
raise ServerError.new(error_message(response))
|
109
|
+
else
|
110
|
+
raise UnexpectedResponseError.new(error_message(response))
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def error_message(response)
|
115
|
+
message = "Request failed with error code #{response.code}"
|
116
|
+
response.nil? ? message : "#{message} and body: #{response.parsed_response}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
|
3
|
+
module ITGlue
|
4
|
+
class Client
|
5
|
+
class Mapper
|
6
|
+
def self.map(raw_data)
|
7
|
+
self.new(raw_data).format
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(raw_data)
|
11
|
+
@raw_data = raw_data
|
12
|
+
end
|
13
|
+
|
14
|
+
def format
|
15
|
+
collection? ? format_collection(@raw_data) : format_object(@raw_data)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def collection?
|
21
|
+
@raw_data.is_a?(Array)
|
22
|
+
end
|
23
|
+
|
24
|
+
def format_collection(data)
|
25
|
+
data.map { |d| format_object(d) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def format_object(data)
|
29
|
+
{
|
30
|
+
id: data['id'].to_i,
|
31
|
+
type: data['type'],
|
32
|
+
attributes: transform_keys(data['attributes'])
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def transform_keys(attributes)
|
37
|
+
attributes.map { |key, value| [key.underscore.to_sym, value] }.to_h
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ITGlue
|
2
|
+
class Client
|
3
|
+
class PathProcessor
|
4
|
+
def self.process(asset_type, options = {})
|
5
|
+
self.new(asset_type, options).path
|
6
|
+
end
|
7
|
+
|
8
|
+
# @param asset_type [Symbol|String] the pluralized asset type name
|
9
|
+
# @param options [Hash] valid options:
|
10
|
+
# parent [ITGlue::Asset] the parent instance
|
11
|
+
# id [Integer] the asset id
|
12
|
+
def initialize(asset_type, options = {})
|
13
|
+
@asset_type = asset_type
|
14
|
+
@options = options
|
15
|
+
@path_array = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def path
|
19
|
+
@path ||= path_array.unshift('').join('/')
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def parent
|
25
|
+
@options[:parent]
|
26
|
+
end
|
27
|
+
|
28
|
+
def id
|
29
|
+
@options[:id]
|
30
|
+
end
|
31
|
+
|
32
|
+
def path_array
|
33
|
+
return @path_array if @processed
|
34
|
+
append_parent if parent
|
35
|
+
append_asset_type
|
36
|
+
append_id if id
|
37
|
+
@processed = true
|
38
|
+
@path_array
|
39
|
+
end
|
40
|
+
|
41
|
+
def append_parent
|
42
|
+
@path_array << parent.asset_type
|
43
|
+
@path_array << parent.id
|
44
|
+
@path_array << :relationships
|
45
|
+
end
|
46
|
+
|
47
|
+
def append_asset_type
|
48
|
+
@path_array << @asset_type
|
49
|
+
end
|
50
|
+
|
51
|
+
def append_id
|
52
|
+
@path_array << id
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: itglue
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Silva
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-05-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: httparty
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.16'
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: 0.15.7
|
65
|
+
type: :runtime
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - "~>"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0.16'
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 0.15.7
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: activesupport
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '5.2'
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 3.0.0
|
85
|
+
type: :runtime
|
86
|
+
prerelease: false
|
87
|
+
version_requirements: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - "~>"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '5.2'
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 3.0.0
|
95
|
+
description: This gem provides a client for interactiong with the IT Glue API
|
96
|
+
email:
|
97
|
+
- berna.loyola@gmail.com
|
98
|
+
executables: []
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- ".gitignore"
|
103
|
+
- ".rspec"
|
104
|
+
- ".travis.yml"
|
105
|
+
- Gemfile
|
106
|
+
- LICENSE.txt
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- bin/console
|
110
|
+
- bin/setup
|
111
|
+
- itglue.gemspec
|
112
|
+
- lib/itglue.rb
|
113
|
+
- lib/itglue/asset.rb
|
114
|
+
- lib/itglue/asset/base.rb
|
115
|
+
- lib/itglue/asset/base/attributes.rb
|
116
|
+
- lib/itglue/asset/base/relatable.rb
|
117
|
+
- lib/itglue/asset/configuration.rb
|
118
|
+
- lib/itglue/asset/configuration_interface.rb
|
119
|
+
- lib/itglue/asset/configuration_status.rb
|
120
|
+
- lib/itglue/asset/configuration_type.rb
|
121
|
+
- lib/itglue/asset/organization.rb
|
122
|
+
- lib/itglue/client.rb
|
123
|
+
- lib/itglue/client/mapper.rb
|
124
|
+
- lib/itglue/client/path_processor.rb
|
125
|
+
- lib/itglue/version.rb
|
126
|
+
homepage: https://github.com/b-loyola/itglue
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
metadata: {}
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubyforge_project:
|
146
|
+
rubygems_version: 2.5.1
|
147
|
+
signing_key:
|
148
|
+
specification_version: 4
|
149
|
+
summary: A simple wrapper for the IT Glue API
|
150
|
+
test_files: []
|