wrapi 0.1.0

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