filebound_client 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/.rubocop.yml +2 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +14 -0
- data/CODE_OF_CONDUCT.md +73 -0
- data/CONTRIBUTING.md +58 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +57 -0
- data/LICENSE.txt +21 -0
- data/README.md +200 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/example_test.yml +9 -0
- data/filebound_client.gemspec +29 -0
- data/lib/ext/hash.rb +8 -0
- data/lib/ext/object.rb +19 -0
- data/lib/filebound_client.rb +102 -0
- data/lib/filebound_client/config.rb +33 -0
- data/lib/filebound_client/configuration.rb +6 -0
- data/lib/filebound_client/connection.rb +183 -0
- data/lib/filebound_client/endpoints.rb +52 -0
- data/lib/filebound_client/endpoints/assignments.rb +21 -0
- data/lib/filebound_client/endpoints/dividers.rb +14 -0
- data/lib/filebound_client/endpoints/document_binary_data.rb +53 -0
- data/lib/filebound_client/endpoints/documents.rb +102 -0
- data/lib/filebound_client/endpoints/eform_data.rb +14 -0
- data/lib/filebound_client/endpoints/eform_detail.rb +14 -0
- data/lib/filebound_client/endpoints/files.rb +69 -0
- data/lib/filebound_client/endpoints/projects.rb +160 -0
- data/lib/filebound_client/endpoints/separators.rb +14 -0
- data/lib/filebound_client/endpoints/version.rb +12 -0
- data/lib/filebound_client/version.rb +4 -0
- data/test.txt +1 -0
- metadata +135 -0
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'filebound_client'
|
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/example_test.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'filebound_client/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'filebound_client'
|
7
|
+
spec.version = FileboundClient::VERSION
|
8
|
+
spec.authors = ['Bryan Richardson']
|
9
|
+
spec.email = ['brichardson@heiskell.com']
|
10
|
+
|
11
|
+
spec.summary = '%q{Provides connection to FileBound API}'
|
12
|
+
spec.homepage = 'https://github.com/JDHeiskell/filebound_client'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
# Specify which files should be added to the gem when it is released.
|
16
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
17
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
18
|
+
`git ls-files -z`.split("\x0").reject { |f| 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.0'
|
25
|
+
spec.add_development_dependency 'rake', '~> 12.3.0'
|
26
|
+
spec.add_development_dependency 'yard', '~> 0.9.0'
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'ruby-ntlm', '~> 0.0.4'
|
29
|
+
end
|
data/lib/ext/hash.rb
ADDED
data/lib/ext/object.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Extends Object with additional helper methods
|
2
|
+
class Object
|
3
|
+
# Adds blank? method to any object
|
4
|
+
# Lifted from: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/object/blank.rb
|
5
|
+
# @return [true, false]
|
6
|
+
def blank?
|
7
|
+
# rubocop:disable Style/DoubleNegation
|
8
|
+
respond_to?(:empty?) ? !!empty? : !self
|
9
|
+
# rubocop:enable Style/DoubleNegation
|
10
|
+
end
|
11
|
+
|
12
|
+
# Checks where object is greater than zero
|
13
|
+
# Returns false of object is nil
|
14
|
+
# @return [true, false]
|
15
|
+
def greater_than_zero?
|
16
|
+
return false if nil?
|
17
|
+
to_i > 0
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'ext/object'
|
2
|
+
require 'ext/hash'
|
3
|
+
require 'filebound_client/version'
|
4
|
+
require 'filebound_client/configuration'
|
5
|
+
require 'filebound_client/config'
|
6
|
+
require 'filebound_client/connection'
|
7
|
+
require 'filebound_client/endpoints'
|
8
|
+
require 'logger'
|
9
|
+
|
10
|
+
# This is the core module
|
11
|
+
module FileboundClient
|
12
|
+
# This encapsulates all client/server communications
|
13
|
+
class Client
|
14
|
+
include FileboundClient::Endpoints
|
15
|
+
|
16
|
+
# General client exception class
|
17
|
+
class FileboundClientException < StandardError
|
18
|
+
attr_reader :result
|
19
|
+
def initialize(message, result)
|
20
|
+
super(message)
|
21
|
+
@result = result
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Creates, initialize and logs into the Filebound API
|
26
|
+
# @param [Hash] config a hash of configuration values
|
27
|
+
# @return [FileboundClient::Client] an instance of FileboundClient::Client
|
28
|
+
def self.connect(config)
|
29
|
+
connection = FileboundClient::Connection.build_connection(config)
|
30
|
+
raise FileboundClientException.new('Failed to login', 401) unless connection.login
|
31
|
+
new(connection)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Initializes the client with the supplied Connection
|
35
|
+
# @param [Connection] connection the logged in Connection
|
36
|
+
# @return [FileboundClient::Client] an instance of FileboundClient::Client
|
37
|
+
def initialize(connection)
|
38
|
+
@connection = connection
|
39
|
+
end
|
40
|
+
|
41
|
+
# Executes a GET request on the current Filebound client session expecting JSON in the body of the response
|
42
|
+
# @param [String] url the resource url to request
|
43
|
+
# @param [Hash] query_params the optional query parameters to pass to the GET request
|
44
|
+
# @return [Hash] the JSON parsed hash of the response body
|
45
|
+
def get(url, query_params = nil)
|
46
|
+
JSON.parse(perform('get', url, query: query_params), symbolize_names: true)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Executes a GET request on the current Filebound client session expecting binary in the body of the response
|
50
|
+
# @param [String] url the resource url to request
|
51
|
+
# @param [Hash] query_params the optional query parameters to pass to the GET request
|
52
|
+
# @return [String] Base64 encoded binary string
|
53
|
+
def get_binary(url, query_params = nil)
|
54
|
+
perform('get', url, query: query_params)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Executes a PUT request on the current Filebound client session expecting JSON in the body of the request/response
|
58
|
+
# @param [String] url the resource url to request
|
59
|
+
# @param [Hash] query_params the optional query parameters to pass to the PUT request
|
60
|
+
# @param [Hash] body the hash that will be converted to JSON when inserted in the body of the request
|
61
|
+
# @return [Hash] the JSON parsed hash of the response body
|
62
|
+
def put(url, query_params = nil, body = nil)
|
63
|
+
params = { headers: { 'Content-Type' => 'application/json' }, query: query_params, body: body }
|
64
|
+
JSON.parse(perform('put', url, params), symbolize_names: true)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Executes a POST request on the current Filebound client session expecting JSON in the body of the request/response
|
68
|
+
# @param [String] url the resource url to request
|
69
|
+
# @param [Hash] query_params the optional query parameters to pass to the POST request
|
70
|
+
# @param [Hash] body the hash that will be converted to JSON when inserted in the body of the request
|
71
|
+
# @return [Hash] the JSON parsed hash of the response body
|
72
|
+
def post(url, query_params = nil, body = nil)
|
73
|
+
params = { headers: { 'Content-Type' => 'application/json' }, query: query_params, body: body }
|
74
|
+
JSON.parse(perform('post', url, params), symbolize_names: true)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Executes a DELETE request on the current Filebound client session
|
78
|
+
# @param [String] url the resource url to request
|
79
|
+
# @param [Hash] query_params the optional query parameters to pass to the DELETE request
|
80
|
+
# @return [true, false] true if resource was deleted successfully
|
81
|
+
def delete(url, query_params = nil)
|
82
|
+
perform('delete', url, query: query_params)
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
# The connection representing the currently logged on session with the Filebound API
|
87
|
+
# @return [FileboundClient::Connection] the security token used in all requests made to the Filebound server
|
88
|
+
attr_reader :connection
|
89
|
+
|
90
|
+
private_class_method :new
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def perform(action, url, params)
|
95
|
+
response = connection.send(action, url, params)
|
96
|
+
# rubocop:disable Metrics/LineLength
|
97
|
+
raise FileboundClientException.new("#{action.upcase} request failed: #{response.code}", response.code) unless response.code == '200'
|
98
|
+
# rubocop:enable Metrics/LineLength
|
99
|
+
response.body
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module FileboundClient
|
2
|
+
# Config module
|
3
|
+
module Config
|
4
|
+
# Retrive the current configuration
|
5
|
+
# @return [FileboundClient::Configuration]
|
6
|
+
def configuration
|
7
|
+
@configuration
|
8
|
+
end
|
9
|
+
|
10
|
+
# Retrieve the default logger
|
11
|
+
# @return [Logger] the default logger
|
12
|
+
def default_logger
|
13
|
+
logger ||= Logger.new(STDOUT)
|
14
|
+
logger.level = Logger::DEBUG
|
15
|
+
logger
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates a new Configuration object and yields to the caller
|
19
|
+
# Also sets the logger
|
20
|
+
def configure
|
21
|
+
@configuration ||= Configuration.new
|
22
|
+
yield @configuration
|
23
|
+
|
24
|
+
@configuration.logger ||= default_logger
|
25
|
+
end
|
26
|
+
|
27
|
+
# Simple logger plugin for debugging
|
28
|
+
def logger(message)
|
29
|
+
return unless configuration.logger
|
30
|
+
configuration.logger.debug(message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'ntlm/http'
|
2
|
+
require 'filebound_client/config'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module FileboundClient
|
6
|
+
# Encapsulates low level logic to talk to Filebound server
|
7
|
+
class Connection
|
8
|
+
include Config
|
9
|
+
|
10
|
+
# The token returned from the Filebound server on successfully logging in
|
11
|
+
# @return [Guid] the security token used in all requests made to the Filebound server
|
12
|
+
attr_reader :token
|
13
|
+
|
14
|
+
# Creates a new connection using the supplied configuration
|
15
|
+
# @param [Configuration] config the Configuration to use for the connection
|
16
|
+
# @return [Connection] the newly created and initialized Connection
|
17
|
+
def self.build_connection(config)
|
18
|
+
new(config)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Initialize a new connection with the supplied configuration
|
22
|
+
# @param [Configuration] config the Configuration to use for the connection
|
23
|
+
# @return [Connection] the newly created and initialized Connection
|
24
|
+
def initialize(config)
|
25
|
+
configure do |c|
|
26
|
+
c.host = config[:host]
|
27
|
+
c.api_base_uri = config[:api_base_uri]
|
28
|
+
c.username = config[:username]
|
29
|
+
c.password = config[:password]
|
30
|
+
# rubocop:disable Metrics/LineLength
|
31
|
+
c.ntlm_auth = { user: config[:ntlm_user], password: config[:ntlm_password], domain: config[:ntlm_domain] } if config[:use_ntlm]
|
32
|
+
# rubocop:enable Metrics/LineLength
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private_class_method :new
|
37
|
+
|
38
|
+
# The Filebound server hostname and protocol
|
39
|
+
# @return [String] the Filebound server URL
|
40
|
+
# @example
|
41
|
+
# "http://localhost"
|
42
|
+
def host
|
43
|
+
configuration.host
|
44
|
+
end
|
45
|
+
|
46
|
+
# The base path to the API on the Filebound server
|
47
|
+
# @return [String] the base path to the API
|
48
|
+
# @example
|
49
|
+
# "/api"
|
50
|
+
def api_base_uri
|
51
|
+
configuration.api_base_uri
|
52
|
+
end
|
53
|
+
|
54
|
+
# The username to log on to the Filebound server with
|
55
|
+
# @return [String] the username
|
56
|
+
# @example
|
57
|
+
# "username"
|
58
|
+
def username
|
59
|
+
configuration.username
|
60
|
+
end
|
61
|
+
|
62
|
+
# The password to log on to the Filebound server with
|
63
|
+
# @return [String] the password
|
64
|
+
# @example
|
65
|
+
# "password"
|
66
|
+
def password
|
67
|
+
configuration.password
|
68
|
+
end
|
69
|
+
|
70
|
+
# The NTLM username to use for NTLM Authentication
|
71
|
+
# @return [String] the NTLM username
|
72
|
+
# @example
|
73
|
+
# "ntlm_user"
|
74
|
+
def ntlm_user
|
75
|
+
configuration.ntlm_auth[:user] if configuration.ntlm_auth
|
76
|
+
end
|
77
|
+
|
78
|
+
# The NTLM password to use for NTLM Authentication
|
79
|
+
# @return [String] the NTLM password
|
80
|
+
# @example
|
81
|
+
# "ntlm_password"
|
82
|
+
def ntlm_password
|
83
|
+
configuration.ntlm_auth[:password] if configuration.ntlm_auth
|
84
|
+
end
|
85
|
+
|
86
|
+
# The NTLM domain to use for NTLM Authentication
|
87
|
+
# @return [String] the NTLM domain
|
88
|
+
# @example
|
89
|
+
# "ntlm_domain"
|
90
|
+
def ntlm_domain
|
91
|
+
configuration.ntlm_auth[:domain] if configuration.ntlm_auth
|
92
|
+
end
|
93
|
+
|
94
|
+
# The authentication query parameters required by all requests to the API
|
95
|
+
# @return [Hash] the query parameters hash
|
96
|
+
def auth_params
|
97
|
+
{ query: { guid: token } }
|
98
|
+
end
|
99
|
+
|
100
|
+
# Sends a GET request to the supplied resource using the supplied params hash
|
101
|
+
# @param [String] url the url that represents the resource
|
102
|
+
# @param [Hash] params the params Hash that will be sent in the request (keys: query, headers, body)
|
103
|
+
# @return [Net::HTTPResponse] the response from the GET request
|
104
|
+
def get(url, params)
|
105
|
+
request = Net::HTTP::Get.new(resource_url(url, query_params(params[:query])))
|
106
|
+
execute_request(request, params)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Sends a PUT request to the supplied resource using the supplied params hash
|
110
|
+
# @param [String] url the url that represents the resource
|
111
|
+
# @param [Hash] params the params Hash that will be sent in the request (keys: query, headers, body)
|
112
|
+
# @return [Net::HTTPResponse] the response from the PUT request
|
113
|
+
def put(url, params)
|
114
|
+
request = Net::HTTP::Put.new(resource_url(url, query_params(params[:query])))
|
115
|
+
request.body = params[:body].to_json
|
116
|
+
execute_request(request, params)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Sends a POST request to the supplied resource using the supplied params hash
|
120
|
+
# @param [String] url the url that represents the resource
|
121
|
+
# @param [Hash] params the params Hash that will be sent in the request (keys: query, headers, body)
|
122
|
+
# @return [Net::HTTPResponse] the response from the POST request
|
123
|
+
def post(url, params)
|
124
|
+
request = Net::HTTP::Post.new(resource_url(url, query_params(params[:query])))
|
125
|
+
request.body = params[:body].to_json
|
126
|
+
execute_request(request, params)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Sends a DELETE request to the supplied resource using the supplied params hash
|
130
|
+
# @param [String] url the url that represents the resource
|
131
|
+
# @param [Hash] params the params Hash that will be sent in the request (keys: query, headers, body)
|
132
|
+
# @return [Net::HTTPResponse] the response from the DELETE request
|
133
|
+
def delete(url, params)
|
134
|
+
request = Net::HTTP::Delete.new(resource_url(url, query_params(params[:query])))
|
135
|
+
execute_request(request, params)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Sends a POST request to the Filebound API's login endpoint to request a new security token
|
139
|
+
# @return [true, false] returns true if the login was successful and the token was set
|
140
|
+
def login
|
141
|
+
response = post('/login', body: { username: configuration.username, password: configuration.password },
|
142
|
+
headers: { 'Content-Type' => 'application/json' })
|
143
|
+
if response.is_a?(Net::HTTPSuccess)
|
144
|
+
@token = JSON.parse(response.body, symbolize_names: true)
|
145
|
+
true
|
146
|
+
else
|
147
|
+
false
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def resource_url(url, query)
|
154
|
+
return "#{api_base_uri}/#{url.reverse.chomp('/').reverse}" unless query
|
155
|
+
query_string = query.map { |k, v| "#{k}=#{v}" }.join('&')
|
156
|
+
"#{api_base_uri}/#{url.reverse.chomp('/').reverse}?#{query_string}"
|
157
|
+
end
|
158
|
+
|
159
|
+
def query_params(params)
|
160
|
+
if params
|
161
|
+
auth_params[:query].merge!(params)
|
162
|
+
else
|
163
|
+
auth_params[:query]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def set_headers(request, headers)
|
168
|
+
if headers.respond_to?(:to_hash)
|
169
|
+
headers.each do |k, v|
|
170
|
+
request[k.to_s] = v.to_s
|
171
|
+
end
|
172
|
+
end
|
173
|
+
request
|
174
|
+
end
|
175
|
+
|
176
|
+
def execute_request(request, params)
|
177
|
+
http = Net::HTTP.new(configuration.host)
|
178
|
+
request = set_headers(request, params[:headers])
|
179
|
+
request.ntlm_auth(ntlm_user, ntlm_domain, ntlm_password) if configuration.ntlm_auth
|
180
|
+
http.request(request)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'filebound_client/endpoints/projects'
|
2
|
+
require 'filebound_client/endpoints/files'
|
3
|
+
require 'filebound_client/endpoints/documents'
|
4
|
+
require 'filebound_client/endpoints/version'
|
5
|
+
require 'filebound_client/endpoints/assignments'
|
6
|
+
require 'filebound_client/endpoints/dividers'
|
7
|
+
require 'filebound_client/endpoints/document_binary_data'
|
8
|
+
require 'filebound_client/endpoints/eform_data'
|
9
|
+
require 'filebound_client/endpoints/separators'
|
10
|
+
|
11
|
+
module FileboundClient
|
12
|
+
# Module for resource endpoints
|
13
|
+
module Endpoints
|
14
|
+
# Sets up macros for use by endpoints and includes all endpoints
|
15
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
16
|
+
def self.included(klass)
|
17
|
+
klass.instance_eval do
|
18
|
+
# @!macro [attach] fb.allow_new
|
19
|
+
# Returns a new empty resource with defaulted values
|
20
|
+
# @return [Hash] a new hash of $1
|
21
|
+
def self.allow_new(name)
|
22
|
+
define_method("#{name}_new") do
|
23
|
+
get('/empty', template: name.to_s)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @!macro [attach] fb.allow_all
|
28
|
+
# Returns an array $1 hashes
|
29
|
+
# @param [Hash] query_params params to pass to the request
|
30
|
+
# @return [Array] an array of $1 hashes
|
31
|
+
def self.allow_all(name)
|
32
|
+
define_method(name.to_s) do |query_params = nil|
|
33
|
+
get("/#{name}", query_params)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
klass.class_eval do
|
39
|
+
include FileboundClient::Endpoints::Projects
|
40
|
+
include FileboundClient::Endpoints::Files
|
41
|
+
include FileboundClient::Endpoints::Documents
|
42
|
+
include FileboundClient::Endpoints::Version
|
43
|
+
include FileboundClient::Endpoints::Assignments
|
44
|
+
include FileboundClient::Endpoints::Dividers
|
45
|
+
include FileboundClient::Endpoints::DocumentBinaryData
|
46
|
+
include FileboundClient::Endpoints::EFormData
|
47
|
+
include FileboundClient::Endpoints::Separators
|
48
|
+
end
|
49
|
+
end
|
50
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
51
|
+
end
|
52
|
+
end
|