setsuzoku 0.10.1
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/.gitattributes +2 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +82 -0
- data/LICENSE.txt +21 -0
- data/README.md +93 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/setsuzoku.rb +37 -0
- data/lib/setsuzoku/api_response.rb +11 -0
- data/lib/setsuzoku/api_strategy.rb +124 -0
- data/lib/setsuzoku/auth_strategy.rb +72 -0
- data/lib/setsuzoku/credential.rb +37 -0
- data/lib/setsuzoku/exception.rb +18 -0
- data/lib/setsuzoku/external_api_handler.rb +19 -0
- data/lib/setsuzoku/pluggable.rb +87 -0
- data/lib/setsuzoku/plugin.rb +128 -0
- data/lib/setsuzoku/rspec.rb +2 -0
- data/lib/setsuzoku/rspec/dynamic_spec_helper.rb +281 -0
- data/lib/setsuzoku/service.rb +70 -0
- data/lib/setsuzoku/service/web_service.rb +21 -0
- data/lib/setsuzoku/service/web_service/api_strategies/rest_api_request.rb +17 -0
- data/lib/setsuzoku/service/web_service/api_strategies/rest_strategy.rb +155 -0
- data/lib/setsuzoku/service/web_service/api_strategy.rb +169 -0
- data/lib/setsuzoku/service/web_service/auth_strategies/basic_auth_strategy.rb +50 -0
- data/lib/setsuzoku/service/web_service/auth_strategies/o_auth_strategy.rb +173 -0
- data/lib/setsuzoku/service/web_service/auth_strategy.rb +48 -0
- data/lib/setsuzoku/service/web_service/credentials/basic_auth_credential.rb +52 -0
- data/lib/setsuzoku/service/web_service/credentials/o_auth_credential.rb +83 -0
- data/lib/setsuzoku/service/web_service/service.rb +31 -0
- data/lib/setsuzoku/utilities.rb +7 -0
- data/lib/setsuzoku/version.rb +6 -0
- data/setsuzoku.gemspec +50 -0
- data/sorbet/config +2 -0
- data/sorbet/rbi/gems/activesupport.rbi +1125 -0
- data/sorbet/rbi/gems/addressable.rbi +199 -0
- data/sorbet/rbi/gems/concurrent-ruby.rbi +1586 -0
- data/sorbet/rbi/gems/crack.rbi +62 -0
- data/sorbet/rbi/gems/faraday.rbi +615 -0
- data/sorbet/rbi/gems/hashdiff.rbi +66 -0
- data/sorbet/rbi/gems/httparty.rbi +401 -0
- data/sorbet/rbi/gems/i18n.rbi +133 -0
- data/sorbet/rbi/gems/mime-types-data.rbi +17 -0
- data/sorbet/rbi/gems/mime-types.rbi +218 -0
- data/sorbet/rbi/gems/multi_xml.rbi +35 -0
- data/sorbet/rbi/gems/multipart-post.rbi +53 -0
- data/sorbet/rbi/gems/nokogiri.rbi +1011 -0
- data/sorbet/rbi/gems/public_suffix.rbi +104 -0
- data/sorbet/rbi/gems/rake.rbi +646 -0
- data/sorbet/rbi/gems/rspec-core.rbi +1893 -0
- data/sorbet/rbi/gems/rspec-expectations.rbi +1123 -0
- data/sorbet/rbi/gems/rspec-mocks.rbi +1090 -0
- data/sorbet/rbi/gems/rspec-support.rbi +280 -0
- data/sorbet/rbi/gems/rspec.rbi +15 -0
- data/sorbet/rbi/gems/safe_yaml.rbi +124 -0
- data/sorbet/rbi/gems/thread_safe.rbi +82 -0
- data/sorbet/rbi/gems/tzinfo.rbi +406 -0
- data/sorbet/rbi/gems/webmock.rbi +532 -0
- data/sorbet/rbi/hidden-definitions/hidden.rbi +13722 -0
- data/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +1431 -0
- data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +8684 -0
- data/sorbet/rbi/sorbet-typed/lib/httparty/all/httparty.rbi +427 -0
- data/sorbet/rbi/sorbet-typed/lib/minitest/all/minitest.rbi +108 -0
- data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +111 -0
- data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +543 -0
- data/sorbet/rbi/todo.rbi +11 -0
- metadata +255 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Setsuzoku
|
5
|
+
# Core service required for a web service plugin.
|
6
|
+
# It should be able to register all of its available api and auth strategies.
|
7
|
+
# It acts as the orchestration between a plugin, auth_strategy, and api_strategy.
|
8
|
+
module Service
|
9
|
+
autoload :WebService, 'setsuzoku/service/web_service'
|
10
|
+
|
11
|
+
extend Forwardable
|
12
|
+
extend T::Sig
|
13
|
+
extend T::Helpers
|
14
|
+
abstract!
|
15
|
+
|
16
|
+
attr_accessor :plugin
|
17
|
+
attr_accessor :auth_strategy
|
18
|
+
attr_accessor :api_strategy
|
19
|
+
attr_accessor :external_api_handler
|
20
|
+
def_delegators :@auth_strategy, :new_credential!
|
21
|
+
def_delegators :@api_strategy, :call_external_api, :request_class
|
22
|
+
|
23
|
+
def self.included(klass)
|
24
|
+
klass.extend(ClassMethods)
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
extend T::Sig
|
29
|
+
extend T::Helpers
|
30
|
+
abstract!
|
31
|
+
|
32
|
+
# The api and auth strategies available for the service.
|
33
|
+
# api: { simple_name: ApiModule }
|
34
|
+
#
|
35
|
+
# @return [Hash(Hash(Class))] the available_strategies object for the Service.
|
36
|
+
sig { abstract.returns(T::Hash[Symbol, T::Hash[Symbol, Class]]) }
|
37
|
+
def available_strategies; end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Initialize the plugin_service by setting its auth and api strategies.
|
41
|
+
#
|
42
|
+
# @param auth_strategy [AuthStrategy] the auth_strategy for the service to use.
|
43
|
+
# @param api_strategy [ApiStrategy] the api_strategy for the service to use.
|
44
|
+
#
|
45
|
+
# @return [Service] the new instance of service with its correct strategies.
|
46
|
+
sig(:final) do
|
47
|
+
params(
|
48
|
+
plugin: T.untyped,
|
49
|
+
strategies: T::Hash[Symbol, T.untyped],
|
50
|
+
args: T.untyped
|
51
|
+
).returns(T.any(Setsuzoku::Service::WebService::Service, T.untyped))
|
52
|
+
end
|
53
|
+
def initialize(plugin:, strategies:, **args)
|
54
|
+
#TODO: here we need to assign credentials etc, I think.
|
55
|
+
self.plugin = plugin
|
56
|
+
self.external_api_handler = Setsuzoku.external_api_handler.new
|
57
|
+
|
58
|
+
# iterate over all strategies this plugin's service uses and set their configuration
|
59
|
+
strategies.each do |strategy, attrs|
|
60
|
+
# get the strategy type from auth_strategy/api_strategy etc.
|
61
|
+
type = T.must(strategy.to_s.split("_strategy").first).to_sym
|
62
|
+
strat = attrs[:strategy]
|
63
|
+
# associate the strategy with the service
|
64
|
+
self.send("#{strategy}=", self.class.available_strategies[type][strat].new(service: self, credential: args[:credential], **attrs.except(:strategy)))
|
65
|
+
end
|
66
|
+
|
67
|
+
self
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'setsuzoku/service/web_service/api_strategy'
|
5
|
+
require 'setsuzoku/service/web_service/auth_strategy'
|
6
|
+
require 'setsuzoku/service/web_service/service'
|
7
|
+
require 'setsuzoku/service/web_service/api_strategies/rest_strategy'
|
8
|
+
require 'setsuzoku/service/web_service/api_strategies/rest_api_request'
|
9
|
+
require 'setsuzoku/service/web_service/auth_strategies/o_auth_strategy'
|
10
|
+
require 'setsuzoku/service/web_service/auth_strategies/basic_auth_strategy'
|
11
|
+
require 'setsuzoku/service/web_service/credentials/o_auth_credential'
|
12
|
+
require 'setsuzoku/service/web_service/credentials/basic_auth_credential'
|
13
|
+
|
14
|
+
module Setsuzoku
|
15
|
+
module Service
|
16
|
+
module WebService
|
17
|
+
# Core service required for a web service plugin.
|
18
|
+
# It should be able to register all of its available api and auth strategies.
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
# typed: false
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
module Setsuzoku
|
6
|
+
module Service
|
7
|
+
module WebService
|
8
|
+
module ApiStrategies
|
9
|
+
class RestAPIRequest < T::Struct
|
10
|
+
prop :action, Symbol, default: nil
|
11
|
+
prop :body, T::Hash[T.untyped, T.untyped], default: {}
|
12
|
+
prop :without_headers, T::Boolean, default: false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'active_support/json'
|
5
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
6
|
+
require 'active_support/core_ext/string/access'
|
7
|
+
|
8
|
+
module Setsuzoku
|
9
|
+
module Service
|
10
|
+
module WebService
|
11
|
+
module ApiStrategies
|
12
|
+
# Defines all necessary methods for handling interfacing with a REST API.
|
13
|
+
class RestStrategy < WebService::ApiStrategy
|
14
|
+
extend T::Sig
|
15
|
+
extend T::Helpers
|
16
|
+
|
17
|
+
def request_class
|
18
|
+
RestAPIRequest
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.required_instance_methods
|
22
|
+
[]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Make a REST API request.
|
26
|
+
# 1. Format the request and send it via the appropriate HTTP method.
|
27
|
+
# 2. Format the response and return it.
|
28
|
+
#
|
29
|
+
# @param request [RestAPIRequest] the constructed API request object.
|
30
|
+
# @param action_details [Hash] the action details for the action to execute.
|
31
|
+
# @param options [Any] additional options needed to pass to correctly perform the request.
|
32
|
+
# options are:
|
33
|
+
# media_type - 'json'
|
34
|
+
#
|
35
|
+
# @return [Hash] the parsed response object.
|
36
|
+
sig { override.params(request: T.untyped, action_details: T::Hash[T.untyped, T.untyped], options: T.untyped).returns(Faraday::Response) }
|
37
|
+
def perform_external_call(request:, action_details:, **options)
|
38
|
+
request_properties = self.get_request_properties(action_name: request.action, action_details: action_details, req_params: request.body)
|
39
|
+
request_options = self.request_options(request_properties[:request_format], action_details[:actions][request.action])
|
40
|
+
|
41
|
+
full_request = self.formulate_request(request_properties, request_options)
|
42
|
+
|
43
|
+
@faraday = Faraday.new(url: request_properties[:formatted_full_url]) do |faraday|
|
44
|
+
faraday.request(:multipart) if options[:attachments].present?
|
45
|
+
faraday.request(:url_encoded)
|
46
|
+
# faraday.basic_auth(request_options[:basic_auth][:username], request_options[:basic_auth][:password]) if request_options[:basic_auth]
|
47
|
+
faraday.request(:basic_auth, request_options[:basic_auth][:username], request_options[:basic_auth][:password]) if request_options[:basic_auth]
|
48
|
+
# faraday.response request_properties[:response_format] if request_properties[:response_format]
|
49
|
+
faraday.authorization(:Bearer, request_properties[:token]) if request_properties[:token]
|
50
|
+
# request_options[:headers][:Authorization].prepend('Bearer ') if request_options[:headers][:Authorization]
|
51
|
+
faraday.adapter Faraday.default_adapter
|
52
|
+
end
|
53
|
+
|
54
|
+
if options[:attachments].present?
|
55
|
+
resp = @faraday.post do |req|
|
56
|
+
io = StringIO.new(full_request)
|
57
|
+
payload = {}
|
58
|
+
payload[:json] = Faraday::UploadIO.new(io, 'application/json')
|
59
|
+
payload[:attachment] = options[:attachments].map{ |file| Faraday::UploadIO.new(file[0], file[1], file[2]) }
|
60
|
+
req.body = payload
|
61
|
+
end
|
62
|
+
else
|
63
|
+
@faraday.headers = request_options[:headers] if request_options[:headers]
|
64
|
+
resp = @faraday.send(request_properties[:request_method], request_properties[:formatted_full_url], full_request)
|
65
|
+
end
|
66
|
+
resp
|
67
|
+
end
|
68
|
+
|
69
|
+
sig do
|
70
|
+
params(
|
71
|
+
action_name: Symbol,
|
72
|
+
for_stub: T::Boolean,
|
73
|
+
req_params: T::Hash[T.untyped, T.untyped],
|
74
|
+
action_details: T::Hash[Symbol, T.untyped]
|
75
|
+
).returns(T::Hash[Symbol, T.untyped])
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_request_properties(action_name:, for_stub: false, req_params: {}, action_details: { actions: self.plugin.api_actions, url: self.plugin.api_base_url })
|
79
|
+
action = action_details[:actions][action_name]
|
80
|
+
request_method, endpoint = action.first
|
81
|
+
request_method = request_method.downcase.to_sym
|
82
|
+
request_format = action[:request_type]
|
83
|
+
response_format = action[:response_type]
|
84
|
+
token = action[:token]
|
85
|
+
stub_data = action[:stub_data] if for_stub
|
86
|
+
full_url = action_details[:url] + endpoint
|
87
|
+
formatted_full_url, req_params = self.replace_dynamic_vars(full_url: full_url, req_params: req_params)
|
88
|
+
{
|
89
|
+
request_method: request_method,
|
90
|
+
endpoint: endpoint,
|
91
|
+
request_format: request_format,
|
92
|
+
response_format: response_format,
|
93
|
+
formatted_full_url: formatted_full_url,
|
94
|
+
req_params: req_params,
|
95
|
+
stub_data: stub_data,
|
96
|
+
token: token
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
# Create the proper request body based on the request_properties and request_options passed
|
101
|
+
#
|
102
|
+
# @param request_properties [Hash] information pertaining to the body of the request
|
103
|
+
# @param request_options [Hash] information pertainint to the headers of the request
|
104
|
+
#
|
105
|
+
# @return full_request [Hash/String] returns the request body in the format required
|
106
|
+
def formulate_request(request_properties = {}, request_options = {})
|
107
|
+
request_format = request_properties.dig(:request_format).to_s
|
108
|
+
content_type = request_options.dig(:headers, :'Content-Type').to_s
|
109
|
+
|
110
|
+
if request_properties[:request_method] == :get || request_properties[:req_params].empty?
|
111
|
+
request_properties[:req_params]
|
112
|
+
else
|
113
|
+
# if the header or request format and request format include urlencoded return the body as a hash
|
114
|
+
if request_format.include?('urlencoded') && content_type.include?('urlencoded')
|
115
|
+
request_properties[:req_params]
|
116
|
+
else
|
117
|
+
# return either xml or json
|
118
|
+
if request_properties[:request_format] == :xml
|
119
|
+
convert_hash_to_xml(request_properties[:req_params])
|
120
|
+
else
|
121
|
+
request_properties[:req_params].to_json
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def request_options(request_format = nil, action_details = {})
|
128
|
+
request_options = self.auth_strategy.auth_headers.merge(self.plugin.api_headers).merge(action_details[:request_options] || {})
|
129
|
+
(request_options[:headers] ||= {})[:'Content-Type'] = "application/#{request_format || :json}"
|
130
|
+
request_options
|
131
|
+
end
|
132
|
+
|
133
|
+
def replace_dynamic_vars(full_url:, req_params: {})
|
134
|
+
# replace matching vars in the action with matching params.
|
135
|
+
# scans the string for variables like {{number_sid}} and replaces it with the matching key in params
|
136
|
+
# removes the params variable, as it's probably intended to be in the url only. If you encounter a need to have
|
137
|
+
# it in the body and the url, then you should put it in params twice with different names.
|
138
|
+
req_params = req_params.dup
|
139
|
+
full_url = full_url.dup
|
140
|
+
dynamic_vars = self.plugin.dynamic_url_params.merge(req_params).with_indifferent_access
|
141
|
+
full_url.scan(/({{.*?}})/).flatten.each do |var|
|
142
|
+
var_name = var.tr('{{ }}', '')
|
143
|
+
next unless dynamic_vars[var_name]
|
144
|
+
|
145
|
+
full_url.gsub!(var, dynamic_vars[var_name])
|
146
|
+
req_params.delete(var_name)
|
147
|
+
req_params.delete(var_name.to_sym)
|
148
|
+
end
|
149
|
+
[full_url, req_params]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Setsuzoku
|
5
|
+
module Service
|
6
|
+
# Defines all common methods for handling interfacing with a Web Service API.
|
7
|
+
module WebService
|
8
|
+
|
9
|
+
class ApiStrategy
|
10
|
+
include Setsuzoku::ApiStrategy
|
11
|
+
extend T::Sig
|
12
|
+
extend T::Helpers
|
13
|
+
|
14
|
+
# These are interface methods that a plugin that implements this strategy must implement.
|
15
|
+
module InterfaceMethods
|
16
|
+
extend T::Sig
|
17
|
+
extend T::Helpers
|
18
|
+
interface!
|
19
|
+
|
20
|
+
# The base Web Service API URL for the plugin.
|
21
|
+
#
|
22
|
+
# @return [String] the API base url.
|
23
|
+
sig { abstract.returns(String) }
|
24
|
+
def api_base_url; end
|
25
|
+
|
26
|
+
# the base webhook api url
|
27
|
+
#
|
28
|
+
# @return [String] the webhook base url
|
29
|
+
def webhook_base_url; end
|
30
|
+
|
31
|
+
# The collection of all implemented endpoints for the API.
|
32
|
+
# Formatted as: { api_action: { 'HTTP_VERB': 'api.com/endpoints' } }
|
33
|
+
#
|
34
|
+
# @return [Hash] all endpoint definitions for the API.
|
35
|
+
sig { abstract.returns(T::Hash[T.untyped, T.untyped]) }
|
36
|
+
def api_actions; end
|
37
|
+
|
38
|
+
# Any api request headers that this service needs to set.
|
39
|
+
#
|
40
|
+
# @return [Hash]
|
41
|
+
sig { abstract.returns(T::Hash[Symbol, T.untyped]) }
|
42
|
+
def api_headers; end
|
43
|
+
|
44
|
+
# All dynamic url parameters provided by the plugin.
|
45
|
+
#
|
46
|
+
# @return [Hash(String)] all parameters that need to be replaced dynamically for url requests.
|
47
|
+
sig { abstract.returns(T::Hash[Symbol, T.nilable(String)]) }
|
48
|
+
def dynamic_url_params; end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Perform the external call for the external API.
|
52
|
+
# Each WebService::ApiStrategy must define how this works.
|
53
|
+
#
|
54
|
+
# It should:
|
55
|
+
# 1. Make the external request
|
56
|
+
# 2. Parse the response
|
57
|
+
# 3. Handle any bad response
|
58
|
+
# 4. Format the response
|
59
|
+
#
|
60
|
+
# @param request [APIRequest] the request object to be used for the request. Each strategy defines its request structure.
|
61
|
+
# @param action_details [Hash] the action_details for the action to execute.
|
62
|
+
# @param options [Any] any additional options needed to pass to correctly perform the request.
|
63
|
+
#
|
64
|
+
# @return [Any] the formatted response object.
|
65
|
+
sig { override.params(request: T.untyped, action_details: T::Hash[T.untyped, T.untyped], options: T.untyped).returns(T.untyped) }
|
66
|
+
def perform_external_call(request:, action_details:, **options); end
|
67
|
+
|
68
|
+
# Parse the response from the API for the given request.
|
69
|
+
# This should just convert JSON strings/XML/SQL rows to a formatted response Hash.
|
70
|
+
#
|
71
|
+
# @param response [HTTParty::Response] the response from the HTTP request.
|
72
|
+
# @param options [Hash] the parsing options. Generally the response_type. e.g. :xml, :json
|
73
|
+
#
|
74
|
+
# @return [Hash] the parsed hash of the response object.
|
75
|
+
sig { override.params(response: Faraday::Response, options: T.untyped).returns(T::Hash[Symbol, T.untyped]) }
|
76
|
+
def parse_response(response:, **options)
|
77
|
+
case options[:response_type]
|
78
|
+
when :json
|
79
|
+
JSON.parse(response.body).deep_symbolize_keys
|
80
|
+
when :xml
|
81
|
+
convert_xml_to_hash(response.body)
|
82
|
+
else
|
83
|
+
JSON.parse(response.body).deep_symbolize_keys
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
sig { params(hash: T::Hash[Symbol, T.untyped], mutate_keys: T::Boolean).returns(String)}
|
90
|
+
def convert_hash_to_xml(hash, mutate_keys = true)
|
91
|
+
hash = hash.map do |k, v|
|
92
|
+
text = if v.is_a?(Hash)
|
93
|
+
convert_hash_to_xml(v)
|
94
|
+
elsif v.is_a?(Array)
|
95
|
+
v.map do |elem|
|
96
|
+
convert_hash_to_xml(elem)
|
97
|
+
end.join
|
98
|
+
else
|
99
|
+
v
|
100
|
+
end
|
101
|
+
k = k.to_s.camelize if mutate_keys
|
102
|
+
"<%s>%s</%s>" % [k, text, k]
|
103
|
+
end.join
|
104
|
+
hash
|
105
|
+
end
|
106
|
+
|
107
|
+
# Convert an XML string to a usable hash.
|
108
|
+
sig { params(xml: String).returns(T::Hash[Symbol, T.untyped])}
|
109
|
+
def convert_xml_to_hash(xml)
|
110
|
+
begin
|
111
|
+
result = Nokogiri::XML(xml)
|
112
|
+
return { result.root.name.underscore.to_sym => xml_node_to_hash(result.root)}
|
113
|
+
rescue Exception => e
|
114
|
+
{}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def xml_node_to_hash(node)
|
119
|
+
# If we are at the root of the document, start the hash
|
120
|
+
if node.element?
|
121
|
+
result_hash = {}
|
122
|
+
if node.attributes != {}
|
123
|
+
attributes = {}
|
124
|
+
node.attributes.keys.each do |key|
|
125
|
+
attributes[node.attributes[key].name.underscore.to_sym] = node.attributes[key].value
|
126
|
+
end
|
127
|
+
end
|
128
|
+
if node.children.size > 0
|
129
|
+
node.children.each do |child|
|
130
|
+
result = xml_node_to_hash(child)
|
131
|
+
|
132
|
+
if child.name == "text"
|
133
|
+
unless child.next_sibling || child.previous_sibling
|
134
|
+
return result unless attributes
|
135
|
+
result_hash[child.name.underscore.to_sym] = result
|
136
|
+
end
|
137
|
+
elsif result_hash[child.name.to_sym]
|
138
|
+
|
139
|
+
if result_hash[child.name.to_sym].is_a?(Array)
|
140
|
+
result_hash[child.name.underscore.to_sym] << result
|
141
|
+
else
|
142
|
+
result_hash[child.name.underscore.to_sym] = [result_hash[child.name.to_sym]] << result
|
143
|
+
end
|
144
|
+
else
|
145
|
+
stripped_children = node.children.reject{ |n| n.text.strip.blank? }
|
146
|
+
if stripped_children.length > 1 && stripped_children.combination(2).all? { |a,b| a.name == b.name }
|
147
|
+
return result_hash[node.name.underscore.to_sym] = stripped_children.map{|n| xml_node_to_hash(n) }
|
148
|
+
else
|
149
|
+
result_hash[child.name.underscore.to_sym] = result
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
if attributes
|
154
|
+
#add code to remove non-data attributes e.g. xml schema, namespace here
|
155
|
+
#if there is a collision then node content supersets attributes
|
156
|
+
result_hash = attributes.merge(result_hash)
|
157
|
+
end
|
158
|
+
return result_hash
|
159
|
+
else
|
160
|
+
return attributes
|
161
|
+
end
|
162
|
+
else
|
163
|
+
return node.content.to_s
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Setsuzoku
|
5
|
+
module Service
|
6
|
+
module WebService
|
7
|
+
module AuthStrategies
|
8
|
+
# The API OAuth Authentication Interface definition.
|
9
|
+
# Any Plugin that implements this must implement all methods required for OAuth.
|
10
|
+
#
|
11
|
+
# Defines all necessary methods for handling authentication for any authentication strategy.
|
12
|
+
class BasicAuthStrategy < WebService::AuthStrategy
|
13
|
+
extend T::Sig
|
14
|
+
extend T::Helpers
|
15
|
+
|
16
|
+
def self.required_instance_methods
|
17
|
+
[]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.credential_class
|
21
|
+
Setsuzoku::Service::WebService::Credentials::BasicAuthCredential
|
22
|
+
end
|
23
|
+
|
24
|
+
# OAuth API authentication headers.
|
25
|
+
#
|
26
|
+
# @return [Hash(String)] the formatted authorization headers for an OAuth request
|
27
|
+
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
28
|
+
def auth_headers
|
29
|
+
{
|
30
|
+
basic_auth: {
|
31
|
+
username: self.credential.username,
|
32
|
+
password: self.credential.password
|
33
|
+
}
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# if the auth credientials are valid
|
39
|
+
#
|
40
|
+
#
|
41
|
+
# sig { override.returns(T::Boolean) }
|
42
|
+
def auth_credential_valid?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|