pagopa-soap 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +137 -0
  4. data/.travis.yml +14 -0
  5. data/CODE_OF_CONDUCT.md +75 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE.txt +29 -0
  8. data/README.md +229 -0
  9. data/Rakefile +13 -0
  10. data/bin/console +15 -0
  11. data/bin/setup +8 -0
  12. data/diagrams/diagrammi-psp.jpg +0 -0
  13. data/diagrams/diagrammi-revoca.jpg +0 -0
  14. data/diagrams/diagrammi-wisp.jpg +0 -0
  15. data/lib/pago_pa.rb +14 -0
  16. data/lib/pago_pa/soap.rb +17 -0
  17. data/lib/pago_pa/soap/configurable.rb +38 -0
  18. data/lib/pago_pa/soap/message/domain.rb +31 -0
  19. data/lib/pago_pa/soap/message/institution.rb +42 -0
  20. data/lib/pago_pa/soap/message/payer.rb +42 -0
  21. data/lib/pago_pa/soap/message/payment.rb +61 -0
  22. data/lib/pago_pa/soap/message/rpt.rb +86 -0
  23. data/lib/pago_pa/soap/message/rt.rb +43 -0
  24. data/lib/pago_pa/soap/message/single_payment.rb +18 -0
  25. data/lib/pago_pa/soap/version.rb +8 -0
  26. data/lib/pago_pa/soap/wsdl_loader.rb +66 -0
  27. data/lib/soap.rb +126 -0
  28. data/lib/soap/parser.rb +74 -0
  29. data/lib/soap/parser/binding.rb +53 -0
  30. data/lib/soap/parser/message.rb +27 -0
  31. data/lib/soap/parser/port_type.rb +42 -0
  32. data/lib/soap/parser/service.rb +25 -0
  33. data/lib/soap/parser/types.rb +97 -0
  34. data/lib/soap/string.rb +33 -0
  35. data/lib/soap/webservice.rb +4 -0
  36. data/lib/soap/webservice/client.rb +37 -0
  37. data/lib/soap/webservice/error.rb +17 -0
  38. data/lib/soap/webservice/fault_error.rb +12 -0
  39. data/lib/soap/webservice/request.rb +118 -0
  40. data/lib/soap/webservice/response.rb +88 -0
  41. data/pagopa-soap.gemspec +45 -0
  42. data/resources/PaPerNodo.wsdl +214 -0
  43. data/resources/PaPerNodoChiediElencoAvvisiDigitali.wsdl +93 -0
  44. data/resources/PaPerNodoPagamentoPsp.wsdl +241 -0
  45. data/resources/PaPerNodoRichiestaAvvisi.wsdl +202 -0
  46. data/resources/pagopa_avvisi.wsdl +98 -0
  47. data/resources/pagopa_base.wsdl +869 -0
  48. metadata +245 -0
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PagoPA; end
4
+ module PagoPA::SOAP; end
5
+
6
+ module PagoPA::SOAP
7
+ VERSION = "0.1.0"
8
+ end
@@ -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
@@ -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
@@ -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