treezor_connect 0.4.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: 79d1afed0a07f69cc928b97408ab1fd6db6be70e4126e0a3c24f42875bba8b51
4
+ data.tar.gz: 8e17befe9c24c48c48ac2e996faa1a41c2ac0d70ba5242c79382cc5755549a0a
5
+ SHA512:
6
+ metadata.gz: fdf5b0b8f6551420d2b9dd3e9a284773e55f7c74a2ad82a3ab12d03db520d03fba3bc93188c0a0042ed0b004b7d375e35651b65b4b467f5eb5bd89de1c1a3540
7
+ data.tar.gz: f29ed8b8d1e63677a6a04fdb89b4099c4b7671142881d435df078939bec7bceb53060626c8b4a065d94847004ceb130b9568998e3360c45d6546aacd3813d33d
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ module ApiOperations
5
+ module Create
6
+ def create(params = {})
7
+ treezor_response = request(:post, resource_url, body: params)
8
+ data = defined?(self::OBJECT_KEY) ? treezor_response.data.fetch(self::OBJECT_KEY)[0] : treezor_response.data
9
+ Util.convert_to_treezor_object(data, { object_class: self::OBJECT_NAME })
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ module ApiOperations
5
+ module Fetch
6
+ def fetch(id)
7
+ url = [resource_url, id].join('/')
8
+ treezor_response = request(:get, url)
9
+ data = treezor_response.data.fetch(self::OBJECT_KEY)[0]
10
+ Util.convert_to_treezor_object(data, { object_class: self::OBJECT_NAME })
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ module ApiOperations
5
+ module List
6
+ def list(filters = {})
7
+ treezor_response = request(:get, resource_url, { query: filters })
8
+ data = treezor_response.data.fetch(self::OBJECT_KEY)
9
+ Util.convert_to_treezor_object(data, { object_class: self::OBJECT_NAME })
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ module ApiOperations
5
+ module Request
6
+ module ClassMethods
7
+ def request(method, url, params = {}, headers = {})
8
+ params = Util.normalize_params(params)
9
+ client = TreezorConnect::Client.active_client
10
+ response = client.execute_request(
11
+ method, url,
12
+ headers:,
13
+ params:
14
+ )
15
+ TreezorResponse.from_http_response(response)
16
+ end
17
+ end
18
+
19
+ def self.included(base)
20
+ base.extend(ClassMethods)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApiResource
4
+ include TreezorConnect::ApiOperations::Request
5
+
6
+ def self.resource_url
7
+ raise NotImplementedError,
8
+ 'APIResource is an abstract class. You should perform actions ' \
9
+ 'on its subclasses (Payin, Payout, Transfer ...)'
10
+ end
11
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ class Client
5
+ attr_accessor :conn, :oauth_client
6
+
7
+ def initialize(conn = nil)
8
+ self.conn = conn || self.class.default_conn
9
+ self.oauth_client ||= OAuth2::Client.new(
10
+ TreezorConnect.client_id,
11
+ TreezorConnect.client_secret,
12
+ site: TreezorConnect.api_base_url
13
+ )
14
+ end
15
+
16
+ def self.active_client
17
+ Thread.current[:treezor_connect_client] ||= default_client
18
+ end
19
+
20
+ def self.default_client
21
+ Thread.current[:treezor_connect_client_default_client] ||=
22
+ TreezorConnect::Client.new(default_conn)
23
+ end
24
+
25
+ def self.default_conn
26
+ Thread.current[:treezor_connect_client_default_conn] ||= build_default_conn
27
+ end
28
+
29
+ def execute_request(method, path, headers: {}, params: {})
30
+ headers['Authorization'] = "Bearer #{access_token}"
31
+ response = conn.public_send(method, path, params: params[:query], form: params[:form], json: params[:body],
32
+ headers:)
33
+ http_body = JSON.parse(response.to_s)
34
+ http_status = response.status
35
+ raise_api_error(http_status:, http_body:) unless http_status.success?
36
+
37
+ response
38
+ end
39
+
40
+ def self.build_default_conn
41
+ http = HTTP.persistent(TreezorConnect.api_base_url)
42
+ return http.use(logging: { logger: Logger.new($stdout) }) unless ENV['ENABLE_HTTP_LOGGING'].nil?
43
+
44
+ http
45
+ end
46
+
47
+ private
48
+
49
+ def access_token
50
+ oauth_client.client_credentials.get_token.token
51
+ end
52
+
53
+ def raise_api_error(http_status:, http_body:)
54
+ raise ApiError, "API request failed: #{http_body.inspect} (HTTP response code was #{http_status})"
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApiError < StandardError; end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ class Payin < ApiResource
5
+ extend TreezorConnect::ApiOperations::Fetch
6
+ extend TreezorConnect::ApiOperations::List
7
+ extend TreezorConnect::ApiOperations::Create
8
+
9
+ OBJECT_NAME = 'payin'
10
+ OBJECT_KEY = 'payins'
11
+ OBJECT_PRIMARY_KEY = 'payinId'
12
+
13
+ def self.resource_url
14
+ '/v1/payins'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ module SctInst
5
+ class Payin < ApiResource
6
+ extend TreezorConnect::ApiOperations::Create
7
+ OBJECT_PRIMARY_KEY = 'sctInstID'
8
+ OBJECT_NAME = 'sct_inst/payin'
9
+
10
+ def self.resource_url
11
+ '/simulation/sct-inst/payin'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ module SctInst
5
+ class Recall < ApiResource
6
+ extend TreezorConnect::ApiOperations::Create
7
+
8
+ def self.resource_url
9
+ '/simulation/sct-inst/recall'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'treezor_connect/resources/payin'
4
+ require 'treezor_connect/resources/sct_inst/payin'
5
+ require 'treezor_connect/resources/sct_inst/recall'
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ class TreezorObject
5
+ def initialize
6
+ @attributes = {}
7
+ end
8
+
9
+ def self.construct_from(data, opts = {})
10
+ object_class = constantize_object_class(opts[:object_class])
11
+ id = extract_id(data, object_class)
12
+ instance = create_instance(object_class, id)
13
+ set_attributes(instance, data)
14
+ define_readers(instance)
15
+ instance
16
+ end
17
+
18
+ def self.constantize_object_class(object_class)
19
+ object_class_path = object_class.split('/').map { |value| Util.camelize(value) }.join('::')
20
+ Module.const_get("TreezorConnect::#{object_class_path}")
21
+ end
22
+
23
+ def self.extract_id(data, object_class)
24
+ primary_key = object_class::OBJECT_PRIMARY_KEY
25
+ data.delete(primary_key)
26
+ end
27
+
28
+ def self.create_instance(object_class, id)
29
+ instance = object_class.new
30
+ instance.instance_variable_set(:@attributes, { 'id' => id })
31
+ instance
32
+ end
33
+
34
+ def self.set_attributes(instance, data)
35
+ snake_cased_data = data.transform_keys { |key| Util.snake_case(key) }
36
+ instance.instance_variable_get(:@attributes).merge!(snake_cased_data)
37
+ end
38
+
39
+ def self.define_readers(instance)
40
+ @attributes = instance.instance_variable_get(:@attributes)
41
+ @attributes.each_key do |key|
42
+ instance.define_singleton_method(key) do
43
+ @attributes[key]
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreezorConnect
4
+ class TreezorResponse
5
+ attr_accessor :data, :http_body, :http_headers, :http_status
6
+
7
+ def self.from_http_response(http_resp)
8
+ resp = TreezorResponse.new
9
+ resp.data = JSON.parse(http_resp.body)
10
+ resp.http_body = http_resp.body
11
+ resp.http_headers = http_resp.headers
12
+ resp.http_status = http_resp.status
13
+ resp
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+
5
+ module TreezorConnect
6
+ module Util
7
+ def self.normalize_params(params)
8
+ Util.deep_transform_keys(params) do |key|
9
+ Util.camelize(key.to_s, uppercase_first_letter: false).to_sym
10
+ end
11
+ end
12
+
13
+ def self.deep_transform_keys(hash, &)
14
+ hash.each_with_object({}) do |(key, value), new_hash|
15
+ new_key = yield(key)
16
+
17
+ new_hash[new_key] = if value.is_a?(Hash)
18
+ deep_transform_keys(value, &)
19
+ else
20
+ value
21
+ end
22
+ end
23
+ end
24
+
25
+ def self.camelize(string, uppercase_first_letter: true)
26
+ string = if uppercase_first_letter
27
+ string.sub(/^[a-z\d]*/, &:capitalize)
28
+ else
29
+ string.sub(/^(?:(?=\b|[A-Z_])|\w)/, &:downcase)
30
+ end
31
+ string.gsub(%r{(?:_|(/))([a-z\d]*)}) do
32
+ "#{::Regexp.last_match(1)}#{::Regexp.last_match(2).capitalize}"
33
+ end.gsub('/', '::')
34
+ end
35
+
36
+ def self.snake_case(string)
37
+ string.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
38
+ end
39
+
40
+ def self.convert_to_treezor_object(data, opts = {})
41
+ case data
42
+ when Array
43
+ data.map { |record| convert_to_treezor_object(record, opts) }
44
+ when Hash
45
+ TreezorObject.construct_from(data, opts)
46
+ else
47
+ data
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'http'
4
+ require 'oauth2'
5
+ require 'logger'
6
+ require 'pry'
7
+
8
+ # Utils
9
+ require 'treezor_connect/util'
10
+ require 'treezor_connect/treezor_response'
11
+ require 'treezor_connect/treezor_object'
12
+
13
+ # API client
14
+ require 'treezor_connect/client'
15
+
16
+ # Errors
17
+ require 'treezor_connect/errors'
18
+
19
+ # API operations
20
+ require 'treezor_connect/api_operations/fetch'
21
+ require 'treezor_connect/api_operations/list'
22
+ require 'treezor_connect/api_operations/create'
23
+ require 'treezor_connect/api_operations/request'
24
+
25
+ # API resources
26
+ require 'treezor_connect/api_resource'
27
+ require 'treezor_connect/resources'
28
+
29
+ module TreezorConnect
30
+ class << self
31
+ attr_accessor :api_base_url, :api_version, :client_id, :client_secret
32
+ end
33
+
34
+ def self.configure
35
+ yield self
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: treezor_connect
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - stefakins
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-10-26 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A gem for making HTTP calls to Treezor Connect.
14
+ email: stefan.atkinson69@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/treezor_connect.rb
20
+ - lib/treezor_connect/api_operations/create.rb
21
+ - lib/treezor_connect/api_operations/fetch.rb
22
+ - lib/treezor_connect/api_operations/list.rb
23
+ - lib/treezor_connect/api_operations/request.rb
24
+ - lib/treezor_connect/api_resource.rb
25
+ - lib/treezor_connect/client.rb
26
+ - lib/treezor_connect/errors.rb
27
+ - lib/treezor_connect/resources.rb
28
+ - lib/treezor_connect/resources/payin.rb
29
+ - lib/treezor_connect/resources/sct_inst/payin.rb
30
+ - lib/treezor_connect/resources/sct_inst/recall.rb
31
+ - lib/treezor_connect/treezor_object.rb
32
+ - lib/treezor_connect/treezor_response.rb
33
+ - lib/treezor_connect/util.rb
34
+ homepage: https://github.com/leclan/treezor_connect
35
+ licenses:
36
+ - MIT
37
+ metadata:
38
+ rubygems_mfa_required: 'true'
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 3.1.4
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 3.4.10
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: A gem for making HTTP calls to Treezor Connect.
58
+ test_files: []