wrapi 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7c98bc6c2eee387f249deb88ca115e68379a7b1e6fee7931440a3b0cecb5fcf0
4
+ data.tar.gz: d2a971caf861d8ab974ff2a4b29b886926021ac1297aea12b932336458daf9ee
5
+ SHA512:
6
+ metadata.gz: a03c3c4c9c2ef461c5b2ab83ec791baaceb753569b87a1df32b42120b719c49b7f89b01fb98f80077fbb5a4a99f9824b4c7f156a81bcc5c721f53f471965458b
7
+ data.tar.gz: 19bdac9d4e22f1d9cbeda68e32146b6535ec49ee30f0684a5e250394aefd3fca03dbc0d2537708fee79ef556728b0e7ed0cd621dbcfec24941927d83762e86ba
data/.gitignore ADDED
@@ -0,0 +1,44 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+ /data/
13
+ *.log
14
+ *.txt
15
+ *.json
16
+ *.yml
17
+
18
+ # Used by dotenv library to load environment variables.
19
+ .env
20
+
21
+
22
+ ## Documentation cache and generated files:
23
+ /.yardoc/
24
+ /_yardoc/
25
+ /doc/
26
+ /rdoc/
27
+
28
+ ## Environment normalization:
29
+ /.bundle/
30
+ /vendor/bundle
31
+ /lib/bundler/man/
32
+
33
+ # for a library or gem, you might want to ignore these files since the code is
34
+ # intended to run in multiple environments; otherwise, check them in:
35
+ # Gemfile.lock
36
+ # .ruby-version
37
+ # .ruby-gemset
38
+
39
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
40
+ .rvmrc
41
+
42
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
43
+ # .rubocop-https?--*
44
+ Gemfile.lock
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-02-2
4
+ - Initial release extracted from CloudAlly gem
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in cloudally.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rubocop', "~> 1.7'
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # Wrapper API
2
+
3
+ Some generic cody extracted from by a number of api wrapper gems. Internal used only.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'wrapi'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install wrapi
20
+
21
+ ## Usage
22
+
23
+ See usage in integra365 gem https://github.com/jancotanis/integra365
24
+
25
+
26
+ ## Contributing
27
+
28
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jancotanis/wrapi.
29
+
30
+ ## License
31
+
32
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ end
11
+
12
+ require 'rubocop/rake_task'
13
+ RuboCop::RakeTask.new
14
+ task default: %i[test rubocop]
data/lib/wrapi/api.rb ADDED
@@ -0,0 +1,32 @@
1
+ require File.expand_path('configuration', __dir__)
2
+ require File.expand_path('connection', __dir__)
3
+ require File.expand_path('request', __dir__)
4
+ require File.expand_path('authentication', __dir__)
5
+
6
+ module WrAPI
7
+ # @private
8
+ class API
9
+ # @private
10
+ attr_accessor *WrAPI::Configuration::VALID_OPTIONS_KEYS
11
+
12
+ # Creates a new API and copies settings from singleton
13
+ def initialize(options = {})
14
+ options = WrAPI.options.merge(options)
15
+ WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
16
+ send("#{key}=", options[key])
17
+ end
18
+ end
19
+
20
+ def config
21
+ conf = {}
22
+ WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
23
+ conf[key] = send key
24
+ end
25
+ conf
26
+ end
27
+
28
+ include WrAPI::Connection
29
+ include WrAPI::Request
30
+ include WrAPI::Authentication
31
+ end
32
+ end
@@ -0,0 +1,48 @@
1
+ module WrAPI
2
+ # Deals with authentication flow and stores it within global configuration
3
+ # following attributes should be available:
4
+ # username
5
+ # password
6
+ # access_token
7
+ # token_type
8
+ # refresh_token
9
+ # token_expires
10
+
11
+ module Authentication
12
+ # Authorize to the portal and return access_token
13
+ def api_auth(path, options = {})
14
+ params = api_access_token_params.merge(options)
15
+ response = post(path, params)
16
+ # return access_token
17
+ api_process_token(response.body)
18
+ end
19
+
20
+ # Return an access token from authorization
21
+ def api_refresh(path, token)
22
+ params = { refreshToken: token }
23
+
24
+ response = post(path, params)
25
+ # return access_token
26
+ api_process_token(response.body)
27
+ end
28
+
29
+ private
30
+
31
+ def api_access_token_params
32
+ {
33
+ username: username,
34
+ password: password
35
+ }
36
+ end
37
+
38
+ def api_process_token(response)
39
+ at = self.access_token = response['accessToken']
40
+ self.token_type = response['tokenType']
41
+ self.refresh_token = response['refreshToken']
42
+ self.token_expires = response['expiresIn']
43
+ raise StandardError.new 'Could not find valid accessToken; response ' + response.to_s if at.nil? || at.empty?
44
+
45
+ at
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,84 @@
1
+ require_relative './version'
2
+ module WrAPI
3
+ # Defines constants and methods related to configuration
4
+ module Configuration
5
+ # An array of valid keys in the options hash when configuring a {Integra365::API}
6
+
7
+ VALID_OPTIONS_KEYS = [
8
+ :access_token,
9
+ :token_type,
10
+ :refresh_token,
11
+ :token_expires,
12
+ :client_id,
13
+ :client_secret,
14
+ :connection_options,
15
+ :username,
16
+ :password,
17
+ :endpoint,
18
+ :logger,
19
+ :format,
20
+ :page_size,
21
+ :user_agent
22
+ ].freeze
23
+
24
+ # By default, don't set any connection options
25
+ DEFAULT_CONNECTION_OPTIONS = {}
26
+
27
+ # The endpoint that will be used to connect if none is set
28
+ #
29
+ # @note There is no reason to use any other endpoint at this time
30
+ DEFAULT_ENDPOINT = 'https://api.com'.freeze
31
+
32
+ # The response format appended to the path and sent in the 'Accept' header if none is set
33
+ #
34
+ # @note JSON is the only available format at this time
35
+ DEFAULT_FORMAT = :json
36
+
37
+ # The page size for paged rest responses
38
+ #
39
+ # @note default JSON is the only available format at this time
40
+ DEFAULT_PAGE_SIZE = 500
41
+
42
+ # The user agent that will be sent to the API endpoint if none is set
43
+ DEFAULT_USER_AGENT = "Ruby API wrapper #{WrAPI::VERSION}".freeze
44
+
45
+ # @private
46
+ attr_accessor *VALID_OPTIONS_KEYS
47
+
48
+ # When this module is extended, set all configuration options to their default values
49
+ def self.extended(base)
50
+ base.reset
51
+ end
52
+
53
+ # Convenience method to allow configuration options to be set in a block
54
+ def configure
55
+ yield self
56
+ end
57
+
58
+ # Create a hash of options and their values
59
+ def options
60
+ VALID_OPTIONS_KEYS.inject({}) do |option, key|
61
+ option.merge!(key => send(key))
62
+ end
63
+ end
64
+
65
+ # Reset all configuration options to defaults
66
+ def reset
67
+ self.access_token = nil
68
+ self.token_type = nil
69
+ self.refresh_token = nil
70
+ self.token_expires = nil
71
+ self.client_id = nil
72
+ self.client_secret = nil
73
+ self.username = nil
74
+ self.password = nil
75
+
76
+ self.logger = nil
77
+ self.connection_options = DEFAULT_CONNECTION_OPTIONS
78
+ self.endpoint = DEFAULT_ENDPOINT
79
+ self.format = DEFAULT_FORMAT
80
+ self.page_size = DEFAULT_PAGE_SIZE
81
+ self.user_agent = DEFAULT_USER_AGENT
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,61 @@
1
+ require 'faraday'
2
+
3
+ module WrAPI
4
+ # Create connection including authorization parameters with default Accept format and User-Agent
5
+ # By default
6
+ # - Bearer authorization is access_token is not nil override with @setup_authorization
7
+ # - Headers setup for client-id and client-secret when client_id and client_secret are not nil @setup_headers
8
+ # @private
9
+ module Connection
10
+ private
11
+
12
+ def connection
13
+ options = setup_options
14
+
15
+ Faraday::Connection.new(options) do |connection|
16
+ connection.use Faraday::Response::RaiseError
17
+ connection.adapter Faraday.default_adapter
18
+ setup_authorization(connection)
19
+ setup_headers(connection)
20
+ connection.response :json, content_type: /\bjson$/
21
+ connection.use Faraday::Request::UrlEncoded
22
+
23
+ setup_logger_filtering(connection, logger) if logger
24
+ end
25
+ end
26
+
27
+ # callback method to setup api authorization
28
+ def setup_options()
29
+ {
30
+ headers: {
31
+ 'Accept': "application/#{format}; charset=utf-8",
32
+ 'User-Agent': user_agent
33
+ },
34
+ url: endpoint
35
+ }.merge(connection_options)
36
+ end
37
+
38
+ # callback method to setup api authorization
39
+ def setup_authorization(connection)
40
+ connection.authorization :Bearer, access_token if access_token
41
+ end
42
+
43
+ # callback method to setup api headers
44
+ def setup_headers(connection)
45
+ connection.headers['client-id'] = client_id if client_id
46
+ connection.headers['client-secret'] = client_secret if client_secret
47
+ end
48
+
49
+ # callback method to setup logger
50
+ def setup_logger_filtering(connection, logger)
51
+ connection.response :logger, logger, { headers: true, bodies: true } do |l|
52
+ # filter json content
53
+ l.filter(/("password":")(.+?)(".*)/, '\1[REMOVED]\3')
54
+ l.filter(/("accessToken":")(.+?)(".*)/, '\1[REMOVED]\3')
55
+ # filter header content
56
+ l.filter(/(client-secret:.)([^&]+)/, '\1[REMOVED]')
57
+ l.filter(/(Authorization:.)([^&]+)/, '\1[REMOVED]')
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,66 @@
1
+ require 'json'
2
+
3
+ module WrAPI
4
+ # Defines HTTP request methods
5
+ module Request
6
+ class Entity
7
+ attr_reader :attributes
8
+
9
+ def initialize(attributes)
10
+ @_raw = attributes
11
+
12
+ case attributes
13
+ when Hash
14
+ @attributes = attributes.clone.transform_keys(&:to_s)
15
+ when Array
16
+ # make deep copy
17
+ @attributes = entify(attributes)
18
+ else
19
+ @attributes = attributes.clone
20
+ end
21
+ end
22
+
23
+ def method_missing(method_sym, *arguments, &block)
24
+ len = arguments.length
25
+ # assignment
26
+ if (method = method_sym[/.*(?==\z)/m])
27
+ raise! ArgumentError, "wrong number of arguments (given #{len}, expected 1)", caller(1) unless len == 1
28
+
29
+ @attributes[method] = arguments[0]
30
+ elsif @attributes.include? method_sym.to_s
31
+ r = @attributes[method_sym.to_s]
32
+ case r
33
+ when Hash
34
+ @attributes[method_sym.to_s] = self.class.new(r)
35
+ when Array
36
+ # make deep copy
37
+ @attributes[method_sym.to_s] = r = entify(r)
38
+ r
39
+ else
40
+ r
41
+ end
42
+ else
43
+ @attributes.send(method_sym, *arguments, &block)
44
+ end
45
+ end
46
+
47
+ def respond_to?(method_sym, include_private = false)
48
+ if @attributes.include? method_sym.to_s
49
+ true
50
+ else
51
+ @attributes.respond_to?(method_sym, include_private)
52
+ end
53
+ end
54
+
55
+ def to_json(options = {})
56
+ @_raw.to_json
57
+ end
58
+
59
+ def entify(a)
60
+ a.map do |item|
61
+ item.is_a?(Hash) ? self.class.new(item) : item
62
+ end if !a.empty? && a[0].is_a?(Hash)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,83 @@
1
+ require 'uri'
2
+ require 'json'
3
+ require File.expand_path('entity', __dir__)
4
+
5
+ module WrAPI
6
+ # Defines HTTP request methods
7
+ # required attributes format
8
+ module Request
9
+
10
+ # Perform an HTTP GET request and return entity incase format is :json
11
+ def get(path, options = {})
12
+ response = request(:get, path, options)
13
+ :json.eql?(format) ? Entity.new(response.body) : response.body
14
+ end
15
+
16
+ # Perform an HTTP GET request for paged date sets response ind to
17
+ # Name Description
18
+ # pageSize The number of records to display per page
19
+ # page The page number
20
+ # nextPageToken Next page token
21
+ #
22
+ # response format { "page": 0, "totalPages": 0, "total": 0, "nextPageToken": "string", "data": [] }
23
+ def get_paged(path, options = {}, &block)
24
+ raise! ArgumentError,
25
+ "Pages requests should be json formatted (given format '#{format}')" unless :json.eql? format
26
+
27
+ result = []
28
+ page = 1
29
+ total = page + 1
30
+ next_page = ''
31
+ while page <= total
32
+ following_page = { pageSize: page_size }
33
+ following_page.merge!({ page: page, nextPageToken: next_page }) unless next_page.empty?
34
+
35
+ response = request(:get, path, options.merge(following_page))
36
+ data = response.body
37
+ d = data['data'].map { |e| Entity.new(e) }
38
+ if block_given?
39
+ yield(d)
40
+ else
41
+ result += d
42
+ end
43
+ page += 1
44
+ total = data['totalPages'].to_i
45
+ next_page = data['nextPageToken']
46
+ end
47
+ result unless block_given?
48
+ end
49
+
50
+ # Perform an HTTP POST request
51
+ def post(path, options = {})
52
+ request(:post, path, options)
53
+ end
54
+
55
+ # Perform an HTTP PUT request
56
+ def put(path, options = {})
57
+ request(:put, path, options)
58
+ end
59
+
60
+ # Perform an HTTP DELETE request
61
+ def delete(path, options = {})
62
+ request(:delete, path, options)
63
+ end
64
+
65
+ private
66
+
67
+ # Perform an HTTP request
68
+ def request(method, path, options)
69
+ response = connection.send(method) do |request|
70
+ uri = URI::Parser.new
71
+ case method
72
+ when :get, :delete
73
+ request.url(uri.escape(path), options)
74
+ when :post, :put
75
+ request.headers['Content-Type'] = "application/#{format}"
76
+ request.path = uri.escape(path)
77
+ request.body = options.to_json unless options.empty?
78
+ end
79
+ end
80
+ response
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,16 @@
1
+
2
+ module WrAPI
3
+ module RespondTo
4
+
5
+ # Delegate to Integra365::Client
6
+ def self.method_missing(method, *args, &block)
7
+ return super unless client.respond_to?(method)
8
+ client.send(method, *args, &block)
9
+ end
10
+
11
+ # Delegate to Integra365::Client
12
+ def self.respond_to?(method, include_all = false)
13
+ client.respond_to?(method, include_all) || super
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WrAPI
4
+ VERSION = '0.1.0'
5
+ end
data/lib/wrapi.rb ADDED
@@ -0,0 +1,26 @@
1
+ require File.expand_path('wrapi/authentication', __dir__)
2
+ require File.expand_path('wrapi/connection', __dir__)
3
+ require File.expand_path('wrapi/configuration', __dir__)
4
+ require File.expand_path('wrapi/api', __dir__)
5
+ require File.expand_path('wrapi/request', __dir__)
6
+ require File.expand_path('wrapi/entity', __dir__)
7
+ require File.expand_path('wrapi/respond_to', __dir__)
8
+ require File.expand_path('wrapi/version', __dir__)
9
+
10
+ module WrAPI
11
+ extend RespondTo
12
+ extend Configuration
13
+
14
+ # Abstract method should be overridden
15
+ #
16
+ # @return client
17
+ def self.client(options = {})
18
+ raise NotImplementedError, 'Abstract method self.client must implemented when including ResponTo'
19
+ end
20
+
21
+ # set/override defaults
22
+ def self.reset
23
+ super
24
+ self.user_agent = "Ruby API wrapper #{WrAPI::VERSION}".freeze
25
+ end
26
+ end
data/wrapi.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/wrapi/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'wrapi'
7
+ s.version = WrAPI::VERSION
8
+ s.authors = ['Janco Tanis']
9
+ s.email = 'gems@jancology.com'
10
+ s.license = 'MIT'
11
+
12
+ s.summary = 'A Ruby api wrapper code extracted from real world api clients'
13
+ s.homepage = 'https://rubygems.org/gems/wrapi'
14
+
15
+ s.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
16
+
17
+ s.metadata['homepage_uri'] = s.homepage
18
+ s.metadata['source_code_uri'] = 'https://github.com/jancotanis/wrapi'
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ s.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
24
+ end
25
+ s.bindir = 'exe'
26
+ s.executables = s.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
+ s.require_paths = ['lib']
28
+
29
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+ s.platform = Gem::Platform::RUBY
31
+ s.add_runtime_dependency 'faraday'
32
+ s.add_development_dependency 'minitest'
33
+ s.add_development_dependency 'rubocop'
34
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wrapi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Janco Tanis
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-02-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email: gems@jancology.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".gitignore"
62
+ - CHANGELOG.md
63
+ - Gemfile
64
+ - README.md
65
+ - Rakefile
66
+ - lib/wrapi.rb
67
+ - lib/wrapi/api.rb
68
+ - lib/wrapi/authentication.rb
69
+ - lib/wrapi/configuration.rb
70
+ - lib/wrapi/connection.rb
71
+ - lib/wrapi/entity.rb
72
+ - lib/wrapi/request.rb
73
+ - lib/wrapi/respond_to.rb
74
+ - lib/wrapi/version.rb
75
+ - wrapi.gemspec
76
+ homepage: https://rubygems.org/gems/wrapi
77
+ licenses:
78
+ - MIT
79
+ metadata:
80
+ homepage_uri: https://rubygems.org/gems/wrapi
81
+ source_code_uri: https://github.com/jancotanis/wrapi
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 2.4.0
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubygems_version: 3.2.12
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: A Ruby api wrapper code extracted from real world api clients
101
+ test_files: []