From c969a2db8153943df16053219a5f50c205c5ca6c Mon Sep 17 00:00:00 2001 From: John Adamson Date: Sat, 11 Mar 2017 16:03:09 -0700 Subject: [PATCH 1/2] Changes to the way Savon handles attributes As per https://github.com/savonrb/savon/issues/518, changes to Savon causes the gem to break in version of Savon beyond 2.2. This is a first pass at moving all the attribute parsing to the new behavior. --- lib/marketingcloudsdk/objects.rb | 2 +- lib/marketingcloudsdk/soap.rb | 30 +++++++++-------- lib/new.rb | 57 ++++++++++++++------------------ marketingcloudsdk.gemspec | 2 +- spec/soap_spec.rb | 39 ++++++++++++---------- 5 files changed, 66 insertions(+), 64 deletions(-) diff --git a/lib/marketingcloudsdk/objects.rb b/lib/marketingcloudsdk/objects.rb index 6e5ea15..5df686f 100644 --- a/lib/marketingcloudsdk/objects.rb +++ b/lib/marketingcloudsdk/objects.rb @@ -303,7 +303,7 @@ def cleanProps # If the ID property is specified for the destination then it must be a list import if properties.has_key?('DestinationObject') then if properties['DestinationObject'].has_key?('ID') then - properties[:attributes!] = { 'DestinationObject' => { 'xsi:type' => 'tns:List'}} + properties['DesintationObject'][:'@xsi:type'] = 'tns:List' end end end diff --git a/lib/marketingcloudsdk/soap.rb b/lib/marketingcloudsdk/soap.rb index cecc0b7..8652c2a 100644 --- a/lib/marketingcloudsdk/soap.rb +++ b/lib/marketingcloudsdk/soap.rb @@ -121,8 +121,10 @@ module Soap def header raise 'Require legacy token for soap header' unless internal_token { - 'oAuth' => {'oAuthToken' => internal_token}, - :attributes! => { 'oAuth' => { 'xmlns' => 'http://exacttarget.com' }} + 'oAuth' => { + :'@xmlns' => 'http://exacttarget.com', + 'oAuthToken' => internal_token + } } end @@ -163,7 +165,7 @@ def soap_perform object_type, action, properties message = {} message['Action'] = action message['Definitions'] = {'Definition' => properties} - message['Definitions'][:attributes!] = { 'Definition' => { 'xsi:type' => ('tns:' + object_type) }} + message['Definitions'][:'@xsi:type'] = 'tns:' + object_type soap_request :perform, message end @@ -181,7 +183,7 @@ def soap_configure object_type, action, properties else message['Configurations'] = {'Configuration' => properties} end - message['Configurations'][:attributes!] = { 'Configuration' => { 'xsi:type' => ('tns:' + object_type) }} + message['Configurations'][:'@xsi:type'] = 'tns:' + object_type soap_request :configure, message end @@ -205,13 +207,12 @@ def soap_get object_type, properties=nil, filter=nil if filter and filter.kind_of? Hash message['Filter'] = filter - message[:attributes!] = { 'Filter' => { 'xsi:type' => 'tns:SimpleFilterPart' } } + message['Filter'][:'@xsi:type'] = 'tns:SimpleFilterPart' if filter.has_key?('LogicalOperator') - message[:attributes!] = { 'Filter' => { 'xsi:type' => 'tns:ComplexFilterPart' }} - message['Filter'][:attributes!] = { - 'LeftOperand' => { 'xsi:type' => 'tns:SimpleFilterPart' }, - 'RightOperand' => { 'xsi:type' => 'tns:SimpleFilterPart' }} + message['Filter'][:'@xsi:type'] = 'tns:ComplexFilterPart' + message['Filter']['LeftOperand']['@xsi:type'] = 'tns:SimpleFilterPart' + message['Filter']['RightOperand']['@xsi:type'] = 'tns:SimpleFilterPart' end end message = {'RetrieveRequest' => message} @@ -257,10 +258,13 @@ def soap_cud action, object_type, properties, upsert=nil # end # - message = { - 'Objects' => properties, - :attributes! => { 'Objects' => { 'xsi:type' => ('tns:' + object_type) } } - } + message = {'Objects' => properties} + + if properties.is_a? Array + properties.each { |p| p[:'@xsi:type'] = ('tns:' + object_type) } + else + message['Objects'][:'@xsi:type'] = 'tns:' + object_type + end if upsert message['Options'] = {"SaveOptions" => {"SaveOption" => {"PropertyName"=> "*", "SaveAction" => "UpdateAdd"}}} diff --git a/lib/new.rb b/lib/new.rb index 1588f7e..b18d76c 100644 --- a/lib/new.rb +++ b/lib/new.rb @@ -190,8 +190,10 @@ def initialize(getWSDL = true, debug = false, params = nil) self.determineStack - @authObj = {'oAuth' => {'oAuthToken' => @internalAuthToken}} - @authObj[:attributes!] = { 'oAuth' => { 'xmlns' => 'http://exacttarget.com' }} + @authObj = {'oAuth' => { + :@xmlns => 'http://exacttarget.com', + 'oAuthToken' => @internalAuthToken + }} myWSDL = File.read(@path + '/ExactTargetWSDL.xml') @auth = Savon.client( @@ -257,8 +259,10 @@ def refreshToken(force = nil) self.determineStack end - @authObj = {'oAuth' => {'oAuthToken' => @internalAuthToken}} - @authObj[:attributes!] = { 'oAuth' => { 'xmlns' => 'http://exacttarget.com' }} + @authObj = {'oAuth' => { + :@xmlns => 'http://exacttarget.com', + 'oAuthToken' => @internalAuthToken + }} myWSDL = File.read(@path + '/ExactTargetWSDL.xml') @auth = Savon.client( @@ -362,24 +366,20 @@ def initialize(authStub = nil, objType = nil) end class ET_Post < ET_Constructor - def initialize(authStub, objType, props = nil) + def initialize(authStub, objType, props = {}) @results = [] begin authStub.refreshToken if props.is_a? Array then - obj = { - 'Objects' => [], - :attributes! => { 'Objects' => { 'xsi:type' => ('tns:' + objType) } } - } + obj = { 'Objects' => [] } props.each{ |p| + p[':@xsi:type'] = 'tns:' + objType obj['Objects'] << p } else - obj = { - 'Objects' => props, - :attributes! => { 'Objects' => { 'xsi:type' => ('tns:' + objType) } } - } + obj = { 'Objects' => props } + obj['Objects']['@xsi:type'] = 'tns:' + objType end response = authStub.auth.call(:create, :message => obj) @@ -410,18 +410,14 @@ def initialize(authStub, objType, props = nil) begin authStub.refreshToken if props.is_a? Array then - obj = { - 'Objects' => [], - :attributes! => { 'Objects' => { 'xsi:type' => ('tns:' + objType) } } - } + obj = { 'Objects' => [] } props.each{ |p| + p[':@xsi:type'] = 'tns:' + objType obj['Objects'] << p } else - obj = { - 'Objects' => props, - :attributes! => { 'Objects' => { 'xsi:type' => ('tns:' + objType) } } - } + obj = { 'Objects' => props } + obj['Objects']['@xsi:type'] = 'tns:' + objType end response = authStub.auth.call(:delete, :message => obj) @@ -447,18 +443,14 @@ def initialize(authStub, objType, props = nil) begin authStub.refreshToken if props.is_a? Array then - obj = { - 'Objects' => [], - :attributes! => { 'Objects' => { 'xsi:type' => ('tns:' + objType) } } - } + obj = { 'Objects' => [] } props.each{ |p| + p[':@xsi:type'] = 'tns:' + objType obj['Objects'] << p } else - obj = { - 'Objects' => props, - :attributes! => { 'Objects' => { 'xsi:type' => ('tns:' + objType) } } - } + obj = { 'Objects' => props } + obj['Objects']['@xsi:type'] = 'tns:' + objType end response = authStub.auth.call(:update, :message => obj) @@ -537,11 +529,12 @@ def initialize(authStub, objType, props = nil, filter = nil) if filter then if filter.has_key?('LogicalOperator') then obj['Filter'] = filter - obj[:attributes!] = { 'Filter' => { 'xsi:type' => 'tns:ComplexFilterPart' }} - obj['Filter'][:attributes!] = { 'LeftOperand' => { 'xsi:type' => 'tns:SimpleFilterPart' }, 'RightOperand' => { 'xsi:type' => 'tns:SimpleFilterPart' }} + obj['Filter'][:'@xsi:type'] = 'tns:ComplexFilterPart' + obj['Filter']['LeftOperand'][:'@xsi:type'] = 'tns:SimpleFilterPart' + obj['Filter']['RightOperand'][:'@xsi:type'] = 'tns:SimpleFilterPart' else obj['Filter'] = filter - obj[:attributes!] = { 'Filter' => { 'xsi:type' => 'tns:SimpleFilterPart' } } + obj['Filter'][:'@xsi:type'] = 'tns:SimpleFilterPart' end end diff --git a/marketingcloudsdk.gemspec b/marketingcloudsdk.gemspec index 543846a..1e59563 100644 --- a/marketingcloudsdk.gemspec +++ b/marketingcloudsdk.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency "guard",'~> 1.1' spec.add_development_dependency "guard-rspec",'~> 2.0' - spec.add_dependency "savon", "2.2.0" + spec.add_dependency "savon", "2.11.0" spec.add_dependency "json", "~>1.8",">= 1.8.1" spec.add_dependency "jwt", "~>1.0",">= 1.0.0" end diff --git a/spec/soap_spec.rb b/spec/soap_spec.rb index 44ae560..865ebae 100644 --- a/spec/soap_spec.rb +++ b/spec/soap_spec.rb @@ -41,9 +41,9 @@ client.internal_token = 'innerspace' expect(client.header).to eq( { - 'oAuth' => { 'oAuthToken' => 'innerspace' }, - :attributes! => { - 'oAuth' => { 'xmlns' => 'http://exacttarget.com' } + 'oAuth' => { + :@xmlns => 'http://exacttarget.com', + 'oAuthToken' => 'innerspace' } } ) @@ -76,16 +76,17 @@ it 'formats soap :create message for single object' do expect(subject.soap_post 'Subscriber', 'EmailAddress' => 'test@fuelsdk.com' ).to eq([:create, { - 'Objects' => [{'EmailAddress' => 'test@fuelsdk.com'}], - :attributes! => {'Objects' => {'xsi:type' => ('tns:Subscriber')}} + 'Objects' => [{:'@xsi:type' => 'tns:Subscriber', 'EmailAddress' => 'test@fuelsdk.com'}] }]) end it 'formats soap :create message for multiple objects' do expect(subject.soap_post 'Subscriber', [{'EmailAddress' => 'first@fuelsdk.com'}, {'EmailAddress' => 'second@fuelsdk.com'}] ).to eq([:create, { - 'Objects' => [{'EmailAddress' => 'first@fuelsdk.com'}, {'EmailAddress' => 'second@fuelsdk.com'}], - :attributes! => {'Objects' => {'xsi:type' => ('tns:Subscriber')}} + 'Objects' => [ + {:'@xsi:type' => 'tns:Subscriber', 'EmailAddress' => 'first@fuelsdk.com'}, + {:'@xsi:type' => 'tns:Subscriber', 'EmailAddress' => 'second@fuelsdk.com'} + ], }]) end @@ -93,10 +94,10 @@ expect(subject.soap_post 'Subscriber', {'EmailAddress' => 'test@fuelsdk.com', 'Attributes'=> [{'Name'=>'First Name', 'Value'=>'first'}]}).to eq([:create, { 'Objects' => [{ + :'@xsi:type' => 'tns:Subscriber', 'EmailAddress' => 'test@fuelsdk.com', 'Attributes' => [{'Name' => 'First Name', 'Value' => 'first'}], - }], - :attributes! => {'Objects' => {'xsi:type' => ('tns:Subscriber')}} + }] }]) end @@ -110,8 +111,8 @@ {'Name' => 'First Name', 'Value' => 'first'}, {'Name' => 'Last Name', 'Value' => 'subscriber'}, ], - }], - :attributes! => {'Objects' => {'xsi:type' => ('tns:Subscriber')}} + :'@xsi:type' => 'tns:Subscriber' + }] }]) end @@ -120,19 +121,23 @@ {'EmailAddress' => 'second@fuelsdk.com', 'Attributes'=> [{'Name'=>'First Name', 'Value'=>'second'}, {'Name'=>'Last Name', 'Value'=>'subscriber'}]}]).to eq([:create, { 'Objects' => [ - {'EmailAddress' => 'first@fuelsdk.com', + { + 'EmailAddress' => 'first@fuelsdk.com', 'Attributes' => [ {'Name' => 'First Name', 'Value' => 'first'}, {'Name' => 'Last Name', 'Value' => 'subscriber'}, - ] + ], + :'@xsi:type' => 'tns:Subscriber' }, - {'EmailAddress' => 'second@fuelsdk.com', + { + 'EmailAddress' => 'second@fuelsdk.com', 'Attributes' => [ {'Name' => 'First Name', 'Value' => 'second'}, {'Name' => 'Last Name', 'Value' => 'subscriber'}, - ] - }], - :attributes! => {'Objects' => {'xsi:type' => ('tns:Subscriber')}} + ], + :'@xsi:type' => 'tns:Subscriber' + } + ] }]) end end From 15e51bbe8ab2f394bb85dd14edd20915be3c9d74 Mon Sep 17 00:00:00 2001 From: James Myers Date: Thu, 24 Sep 2020 15:25:46 -0400 Subject: [PATCH 2/2] update savon dep to ~> 2.3 hopefully reduces pain with various later versions now that we are compatible with 2.3 --- Gemfile.lock | 12 +++--------- marketingcloudsdk.gemspec | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3ff3aac..18c0853 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -4,7 +4,7 @@ PATH sfmc-fuelsdk-ruby (1.3.0) json (~> 1.8, >= 1.8.1) jwt (~> 1.0, >= 1.0.0) - savon (= 2.11.0) + savon (~> 2.3) GEM remote: https://rubygems.org/ @@ -42,8 +42,6 @@ GEM rb-inotify (>= 0.9) rb-kqueue (>= 0.2) lumberjack (1.0.13) - macaddr (1.7.2) - systemu (~> 2.6.5) method_source (0.9.0) mini_portile2 (2.4.0) nokogiri (1.10.10) @@ -72,20 +70,16 @@ GEM rspec-expectations (2.99.2) diff-lcs (>= 1.1.3, < 2.0) rspec-mocks (2.99.4) - savon (2.11.0) + savon (2.12.1) akami (~> 1.2) builder (>= 2.1.2) gyoku (~> 1.2) httpi (~> 2.3) - nokogiri (>= 1.4.0) + nokogiri (>= 1.8.1) nori (~> 2.4) - uuid (~> 2.3.7) wasabi (~> 3.4) socksify (1.7.1) - systemu (2.6.5) thor (0.20.0) - uuid (2.3.9) - macaddr (~> 1.0) wasabi (3.6.1) addressable httpi (~> 2.0) diff --git a/marketingcloudsdk.gemspec b/marketingcloudsdk.gemspec index eca9292..0660bcd 100644 --- a/marketingcloudsdk.gemspec +++ b/marketingcloudsdk.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency "guard",'~> 1.1' spec.add_development_dependency "guard-rspec",'~> 2.0' - spec.add_dependency "savon", "2.11.0" + spec.add_dependency "savon", "~> 2.3" spec.add_dependency "json", "~>1.8",">= 1.8.1" spec.add_dependency "jwt", "~>1.0",">= 1.0.0" end