filebound_client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|