pagopa-soap 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|