pagopa-soap 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 +7 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +137 -0
- data/.travis.yml +14 -0
- data/CODE_OF_CONDUCT.md +75 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +29 -0
- data/README.md +229 -0
- data/Rakefile +13 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/diagrams/diagrammi-psp.jpg +0 -0
- data/diagrams/diagrammi-revoca.jpg +0 -0
- data/diagrams/diagrammi-wisp.jpg +0 -0
- data/lib/pago_pa.rb +14 -0
- data/lib/pago_pa/soap.rb +17 -0
- data/lib/pago_pa/soap/configurable.rb +38 -0
- data/lib/pago_pa/soap/message/domain.rb +31 -0
- data/lib/pago_pa/soap/message/institution.rb +42 -0
- data/lib/pago_pa/soap/message/payer.rb +42 -0
- data/lib/pago_pa/soap/message/payment.rb +61 -0
- data/lib/pago_pa/soap/message/rpt.rb +86 -0
- data/lib/pago_pa/soap/message/rt.rb +43 -0
- data/lib/pago_pa/soap/message/single_payment.rb +18 -0
- data/lib/pago_pa/soap/version.rb +8 -0
- data/lib/pago_pa/soap/wsdl_loader.rb +66 -0
- data/lib/soap.rb +126 -0
- data/lib/soap/parser.rb +74 -0
- data/lib/soap/parser/binding.rb +53 -0
- data/lib/soap/parser/message.rb +27 -0
- data/lib/soap/parser/port_type.rb +42 -0
- data/lib/soap/parser/service.rb +25 -0
- data/lib/soap/parser/types.rb +97 -0
- data/lib/soap/string.rb +33 -0
- data/lib/soap/webservice.rb +4 -0
- data/lib/soap/webservice/client.rb +37 -0
- data/lib/soap/webservice/error.rb +17 -0
- data/lib/soap/webservice/fault_error.rb +12 -0
- data/lib/soap/webservice/request.rb +118 -0
- data/lib/soap/webservice/response.rb +88 -0
- data/pagopa-soap.gemspec +45 -0
- data/resources/PaPerNodo.wsdl +214 -0
- data/resources/PaPerNodoChiediElencoAvvisiDigitali.wsdl +93 -0
- data/resources/PaPerNodoPagamentoPsp.wsdl +241 -0
- data/resources/PaPerNodoRichiestaAvvisi.wsdl +202 -0
- data/resources/pagopa_avvisi.wsdl +98 -0
- data/resources/pagopa_base.wsdl +869 -0
- metadata +245 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PagoPA; end
|
4
|
+
module PagoPA::SOAP; end
|
5
|
+
|
6
|
+
class PagoPA::SOAP::WSDLLoader
|
7
|
+
attr_reader :wsdl_base
|
8
|
+
attr_reader :wsdl_notify
|
9
|
+
attr_reader :namespace
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@wsdl_base = options[:wsdl_base] || PagoPA::SOAP.config.wsdl_base
|
13
|
+
@wsdl_notify = options[:wsdl_notify] || PagoPA::SOAP.config.wsdl_notify
|
14
|
+
@namespace = options[:namespace] || PagoPA::SOAP.config.namespace
|
15
|
+
|
16
|
+
validate_wsdl_base!
|
17
|
+
validate_wsdl_notify!
|
18
|
+
end
|
19
|
+
|
20
|
+
def build
|
21
|
+
soap_base.build
|
22
|
+
soap_notify.build
|
23
|
+
end
|
24
|
+
|
25
|
+
def requests
|
26
|
+
soap_base.request + soap_notify.request
|
27
|
+
end
|
28
|
+
|
29
|
+
def clients
|
30
|
+
soap_base.client + soap_notify.client
|
31
|
+
end
|
32
|
+
|
33
|
+
def responses
|
34
|
+
soap_base.response + soap_notify.response
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def soap_base
|
40
|
+
@soap_base ||=
|
41
|
+
Soap::Base.new(
|
42
|
+
wsdl: wsdl_base,
|
43
|
+
namespace: namespace,
|
44
|
+
endpoint: PagoPA::SOAP.config.endpoint_base
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def soap_notify
|
49
|
+
@soap_notify ||=
|
50
|
+
Soap::Base.new(
|
51
|
+
wsdl: wsdl_notify,
|
52
|
+
namespace: namespace,
|
53
|
+
endpoint: PagoPA::SOAP.config.endpoint_notify
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_wsdl_base!
|
58
|
+
raise "Error: WSDL is empty" if !@wsdl_base.instance_of?(String)
|
59
|
+
raise "Error: File not exists" if !File.exists?(@wsdl_base)
|
60
|
+
end
|
61
|
+
|
62
|
+
def validate_wsdl_notify!
|
63
|
+
raise "Error: WSDL is empty" if !@wsdl_notify.instance_of?(String)
|
64
|
+
raise "Error: File not exists" if !File.exists?(@wsdl_notify)
|
65
|
+
end
|
66
|
+
end
|
data/lib/soap.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nokogiri"
|
4
|
+
require "gyoku"
|
5
|
+
require "nori"
|
6
|
+
require "soap/string"
|
7
|
+
|
8
|
+
# Parser
|
9
|
+
require "soap/parser"
|
10
|
+
require "soap/parser/types"
|
11
|
+
require "soap/parser/port_type"
|
12
|
+
require "soap/parser/binding"
|
13
|
+
require "soap/parser/message"
|
14
|
+
require "soap/parser/service"
|
15
|
+
|
16
|
+
# WebService
|
17
|
+
require "soap/webservice/request"
|
18
|
+
require "soap/webservice/response"
|
19
|
+
require "soap/webservice/client"
|
20
|
+
require "soap/webservice/error"
|
21
|
+
require "soap/webservice/fault_error"
|
22
|
+
|
23
|
+
module Soap
|
24
|
+
class << self
|
25
|
+
def to_snakecase(str)
|
26
|
+
Soap::String.snakecase(str)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_camelcase(str)
|
30
|
+
Soap::String.camelcase(
|
31
|
+
Soap.to_snakecase(str)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_wsdl_camelcase(str)
|
36
|
+
Soap::String.wsdl_camelcase(
|
37
|
+
Soap.to_snakecase(str)
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Soap::Base
|
44
|
+
SUB_CLASSES = %i[request client response].freeze
|
45
|
+
attr_reader :wsdl
|
46
|
+
attr_reader :namespace
|
47
|
+
attr_reader :endpoint
|
48
|
+
|
49
|
+
def initialize(wsdl:, namespace:, endpoint: nil)
|
50
|
+
@wsdl = wsdl
|
51
|
+
@namespace = namespace
|
52
|
+
@endpoint = endpoint
|
53
|
+
end
|
54
|
+
|
55
|
+
def build
|
56
|
+
ns_module =
|
57
|
+
if Object.const_defined?(namespace)
|
58
|
+
Object.const_get(namespace)
|
59
|
+
else
|
60
|
+
Object.const_set(namespace, Module.new)
|
61
|
+
end
|
62
|
+
parser.soap_actions.each do |action|
|
63
|
+
build_klass(ns_module, action, parser.soap_action(action), endpoint)
|
64
|
+
end
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_klass(mod, name, action, endpoint)
|
69
|
+
service_name = parser.service[:base_endpoint]
|
70
|
+
k_mod = mod.const_set(Soap.to_camelcase(name), Module.new)
|
71
|
+
build_custom_klass(k_mod, "Request", action[:input])
|
72
|
+
build_custom_klass(k_mod, "Response", action[:output])
|
73
|
+
|
74
|
+
klass = Class.new(Soap::Webservice::Client) do
|
75
|
+
define_singleton_method :namespace do
|
76
|
+
if !endpoint.blank?
|
77
|
+
endpoint
|
78
|
+
else
|
79
|
+
service_name
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
define_singleton_method :action do
|
84
|
+
action[:input][:port_type][:name]
|
85
|
+
end
|
86
|
+
|
87
|
+
define_method :response do
|
88
|
+
@response ||= k_mod.const_get("Response")
|
89
|
+
end
|
90
|
+
|
91
|
+
# rubocop:disable all
|
92
|
+
private :response
|
93
|
+
# rubocop:enable all
|
94
|
+
end
|
95
|
+
k_mod.const_set("Client", klass)
|
96
|
+
end
|
97
|
+
|
98
|
+
def build_custom_klass(mod, type_klass, action_klass)
|
99
|
+
klass = Class.new(Object.const_get("Soap::Webservice::#{type_klass}")) do
|
100
|
+
define_singleton_method :body_attributes do
|
101
|
+
action_klass[:types][:body]
|
102
|
+
end
|
103
|
+
|
104
|
+
define_singleton_method :header_attributes do
|
105
|
+
action_klass[:types][:header]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
mod.const_set(type_klass.to_s, klass)
|
110
|
+
end
|
111
|
+
|
112
|
+
SUB_CLASSES.each do |sub_class|
|
113
|
+
define_method(sub_class) do
|
114
|
+
name = Soap.to_camelcase(sub_class.to_s)
|
115
|
+
parser.soap_actions.map do |action|
|
116
|
+
"#{namespace}::#{Soap.to_camelcase(action)}::#{name}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def parser
|
124
|
+
@parser ||= Soap::Parse.new(File.read(wsdl))
|
125
|
+
end
|
126
|
+
end
|
data/lib/soap/parser.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Soap; end
|
4
|
+
module Soap::Parser; end
|
5
|
+
|
6
|
+
class Soap::Parse
|
7
|
+
COMMON_ATTRIBUTES = %i[input output].freeze
|
8
|
+
DEFAULT_SECTIONS = %w[types message port_type binding service].freeze
|
9
|
+
attr_reader :document
|
10
|
+
|
11
|
+
def initialize(file)
|
12
|
+
@document = Nokogiri::XML(file)
|
13
|
+
end
|
14
|
+
|
15
|
+
def namespaces
|
16
|
+
@namespaces = @document.namespaces.inject({}) do |memo, (key, value)|
|
17
|
+
memo[key.sub("xmlns:", "")] = value
|
18
|
+
memo
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
DEFAULT_SECTIONS.each do |sec|
|
23
|
+
define_method(sec.to_sym) do
|
24
|
+
sec_klass = Object.const_get("Soap::Parser::#{Soap.to_camelcase(sec)}")
|
25
|
+
sec_result = sec_klass.new(namespaces, section(sec))
|
26
|
+
sec_result.parse
|
27
|
+
sec_result.hash
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def soap_actions
|
32
|
+
port_type.keys.map do |pt|
|
33
|
+
pt
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def soap_action(name)
|
38
|
+
Soap::Parse::COMMON_ATTRIBUTES.each.with_object({}) do |common, attrs|
|
39
|
+
attrs[common] = {
|
40
|
+
port_type: port_type[name][common],
|
41
|
+
binding: binding[:operations][name][common],
|
42
|
+
message: message[port_type[name][common][:message].split(":").last],
|
43
|
+
types: extract_types_attribute(name, common)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_types_attribute(name, io)
|
49
|
+
msg_name = port_type[name][io][:message].split(":").last
|
50
|
+
components = binding[:operations][name][io]
|
51
|
+
ext = {}
|
52
|
+
components.map do |k, v|
|
53
|
+
component = message[msg_name][:part]
|
54
|
+
if v[:part].nil? && v[:parts].nil?
|
55
|
+
namespace, params = component.values.first.split(":")
|
56
|
+
else
|
57
|
+
namespace, params = component[v[:part] || v[:parts]].split(":")
|
58
|
+
end
|
59
|
+
ext[k.to_sym] = types[namespace][params][:params]
|
60
|
+
end
|
61
|
+
ext
|
62
|
+
end
|
63
|
+
|
64
|
+
def section(section_name)
|
65
|
+
sections[section_name] || []
|
66
|
+
end
|
67
|
+
|
68
|
+
def sections
|
69
|
+
@sections ||=
|
70
|
+
@document.root.element_children.each.with_object({}) do |node, attrs|
|
71
|
+
(attrs[Soap.to_snakecase(node.name)] ||= []) << node
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Soap; end
|
4
|
+
module Soap::Parser; end
|
5
|
+
|
6
|
+
class Soap::Parser::Binding
|
7
|
+
COMPONENT_ATTRIBUTES = %i[part parts message].freeze
|
8
|
+
attr_accessor :hash
|
9
|
+
attr_reader :node
|
10
|
+
|
11
|
+
def initialize(_namespaces, node)
|
12
|
+
@node = node
|
13
|
+
@hash = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse
|
17
|
+
parse_binding
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_binding
|
21
|
+
return if @node.empty? && @node.first.nil?
|
22
|
+
binding_node = @node.first
|
23
|
+
|
24
|
+
@hash[:name] = binding_node["name"]
|
25
|
+
@hash[:type] = binding_node["type"]
|
26
|
+
operations = Hash[binding_node.xpath("./wsdl:operation").map do |operation|
|
27
|
+
[operation["name"], {
|
28
|
+
input: parse_input_output(operation, "input"),
|
29
|
+
output: parse_input_output(operation, "output")
|
30
|
+
}]
|
31
|
+
end]
|
32
|
+
@hash[:operations] = operations
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_input_output(node, type)
|
36
|
+
type_node = node.element_children.find { |ec| ec.name == type }
|
37
|
+
|
38
|
+
Hash[type_node.element_children.map do |elem|
|
39
|
+
[elem.name, parse_attribute(elem)]
|
40
|
+
end]
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_attribute(node)
|
44
|
+
attributes =
|
45
|
+
COMPONENT_ATTRIBUTES.each.with_object({}) do |attr, attrs|
|
46
|
+
value = node.attribute(attr.to_s)
|
47
|
+
attrs[attr] = value.to_s if value
|
48
|
+
end
|
49
|
+
attributes[:name] = node.parent["name"]
|
50
|
+
|
51
|
+
attributes
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Soap; end
|
4
|
+
module Soap::Parser; end
|
5
|
+
|
6
|
+
class Soap::Parser::Message
|
7
|
+
attr_accessor :hash
|
8
|
+
attr_reader :node
|
9
|
+
|
10
|
+
def initialize(_namespaces, node)
|
11
|
+
@node = node
|
12
|
+
@hash = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse
|
16
|
+
parse_message
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_message
|
20
|
+
@hash = Hash[@node.map do |node|
|
21
|
+
[node["name"], Hash[:part, Hash[node.element_children.map do |mec|
|
22
|
+
[mec["name"], mec.attribute("element").value]
|
23
|
+
end
|
24
|
+
]]]
|
25
|
+
end]
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Soap; end
|
4
|
+
module Soap::Parser; end
|
5
|
+
|
6
|
+
class Soap::Parser::PortType
|
7
|
+
attr_accessor :hash
|
8
|
+
attr_reader :node
|
9
|
+
|
10
|
+
def initialize(_namespaces, node)
|
11
|
+
@node = node
|
12
|
+
@hash = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse
|
16
|
+
parse_port_types
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_port_types
|
20
|
+
return if @node.empty? && @node.first.nil?
|
21
|
+
node_elements =
|
22
|
+
node.first.element_children.select do |op|
|
23
|
+
op.name == "operation"
|
24
|
+
end
|
25
|
+
|
26
|
+
@hash = Hash[node_elements.map do |operation|
|
27
|
+
[operation["name"], {
|
28
|
+
input: parse_input_or_output(operation, "input"),
|
29
|
+
output: parse_input_or_output(operation, "output")
|
30
|
+
}]
|
31
|
+
end]
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse_input_or_output(node, type)
|
35
|
+
node_type = node.element_children.find { |n| n.name == type }
|
36
|
+
{
|
37
|
+
name: node_type.attribute("message").to_s.split(":").last,
|
38
|
+
message: node_type.attribute("message").to_s,
|
39
|
+
action: node_type.attribute("Action").to_s
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Soap; end
|
4
|
+
module Soap::Parser; end
|
5
|
+
|
6
|
+
class Soap::Parser::Service
|
7
|
+
attr_accessor :hash
|
8
|
+
attr_reader :node
|
9
|
+
|
10
|
+
def initialize(_namespaces, node)
|
11
|
+
@node = node
|
12
|
+
@hash = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse
|
16
|
+
parse_service
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_service
|
20
|
+
address = node.first.at_xpath("./wsdl:port/soap:address")
|
21
|
+
@hash = {
|
22
|
+
base_endpoint: address["location"]
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Soap; end
|
4
|
+
module Soap::Parser; end
|
5
|
+
|
6
|
+
class Soap::Parser::Types
|
7
|
+
VALIDATION_ATTRIBUTES = %i[nillable default minOccurs maxOccurs].freeze
|
8
|
+
|
9
|
+
attr_accessor :hash
|
10
|
+
attr_reader :node
|
11
|
+
attr_reader :namespaces
|
12
|
+
|
13
|
+
def initialize(namespaces, node)
|
14
|
+
@namespaces = namespaces
|
15
|
+
@node = node
|
16
|
+
@hash = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse
|
20
|
+
parse_types
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_types
|
24
|
+
schemas.each do |schema|
|
25
|
+
namespace = @namespaces.key(schema["targetNamespace"])
|
26
|
+
@hash[namespace] = {}
|
27
|
+
schema.element_children.each do |node|
|
28
|
+
case node.name
|
29
|
+
when "element"
|
30
|
+
if !node.children.empty?
|
31
|
+
node_type = node.at_xpath("./xsd:complexType")
|
32
|
+
else
|
33
|
+
complex_type = node.attribute("type").to_s
|
34
|
+
node_type = schema.at_xpath(
|
35
|
+
"xsd:complexType[@name='#{complex_type.split(':').last}']"
|
36
|
+
)
|
37
|
+
end
|
38
|
+
@hash[namespace].merge!(parse_type(node_type, node["name"]))
|
39
|
+
when "complexType"
|
40
|
+
@hash[namespace].merge!(parse_type(node, node["name"]))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def simple_type
|
47
|
+
{ "base" => @node.at_xpath("./xs|xsd:restriction")["base"] }
|
48
|
+
end
|
49
|
+
|
50
|
+
# rubocop:disable all
|
51
|
+
def parse_type(node, name)
|
52
|
+
element = {}
|
53
|
+
element[name] ||= { params: [] }
|
54
|
+
node.xpath("./xsd:complexContent/xsd:extension/xsd:sequence/xsd:element").each do |inner|
|
55
|
+
elem_name = inner.attribute("name").to_s
|
56
|
+
elem_type = inner.attribute("type").to_s
|
57
|
+
elem_attributes =
|
58
|
+
VALIDATION_ATTRIBUTES.each.with_object({}) do |attr, attrs|
|
59
|
+
value = inner.attribute(attr.to_s)
|
60
|
+
attrs[attr] = value.to_s if value
|
61
|
+
end
|
62
|
+
|
63
|
+
element[name][:params] << {
|
64
|
+
name: elem_name,
|
65
|
+
type: elem_type,
|
66
|
+
attributes: elem_attributes
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
node.xpath("./xsd:sequence/xsd:element").each do |inner|
|
71
|
+
elem_name = inner.attribute("name").value
|
72
|
+
elem_type = inner.attribute("type").value
|
73
|
+
elem_attributes =
|
74
|
+
VALIDATION_ATTRIBUTES.each.with_object({}) do |attr, attrs|
|
75
|
+
value = inner.attribute(attr.to_s)
|
76
|
+
attrs[attr] = value.to_s if value
|
77
|
+
end
|
78
|
+
|
79
|
+
element[name][:params] << {
|
80
|
+
name: elem_name,
|
81
|
+
type: elem_type,
|
82
|
+
attributes: elem_attributes
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
element
|
87
|
+
end
|
88
|
+
# rubocop:enable all
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def schemas
|
93
|
+
return [] if @node.empty? && @node.first.nil?
|
94
|
+
types = @node.first
|
95
|
+
types ? types.element_children : []
|
96
|
+
end
|
97
|
+
end
|