responsys-api 0.1.0 → 0.2.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.
Files changed (39) hide show
  1. checksums.yaml +5 -13
  2. data/.travis.yml +7 -2
  3. data/lib/responsys/api/all.rb +2 -2
  4. data/lib/responsys/api/authentication.rb +45 -0
  5. data/lib/responsys/api/client.rb +21 -50
  6. data/lib/responsys/api/session.rb +22 -35
  7. data/lib/responsys/api/session_pool.rb +32 -0
  8. data/lib/responsys/configuration.rb +7 -2
  9. data/lib/responsys/i18n/en.yml +35 -0
  10. data/lib/responsys_api.rb +7 -1
  11. data/responsys-api.gemspec +3 -2
  12. data/spec/api/campaign_spec.rb +5 -5
  13. data/spec/api/client_spec.rb +7 -69
  14. data/spec/api/list_spec.rb +6 -6
  15. data/spec/api/session_spec.rb +50 -0
  16. data/spec/api/table_spec.rb +12 -12
  17. data/spec/api_credentials.sample.yml +1 -1
  18. data/spec/fixtures/vcr_cassettes/api/campaign/trigger_custom_event_1.yml +45 -29
  19. data/spec/fixtures/vcr_cassettes/api/campaign/trigger_custom_event_2.yml +45 -29
  20. data/spec/fixtures/vcr_cassettes/api/campaign/trigger_message_1.yml +926 -29
  21. data/spec/fixtures/vcr_cassettes/api/campaign/trigger_message_2.yml +45 -29
  22. data/spec/fixtures/vcr_cassettes/api/client/expired_session.yml +1 -48
  23. data/spec/fixtures/vcr_cassettes/api/list/merge.yml +46 -28
  24. data/spec/fixtures/vcr_cassettes/api/list/retrieve.yml +927 -28
  25. data/spec/fixtures/vcr_cassettes/api/list/retrieve_single.yml +46 -28
  26. data/spec/fixtures/vcr_cassettes/api/list/retrieve_single_single.yml +46 -28
  27. data/spec/fixtures/vcr_cassettes/api/profile_extension/delete_profile_extension_records.yml +65 -0
  28. data/spec/fixtures/vcr_cassettes/api/profile_extension/merge_profile_extension_records.yml +46 -28
  29. data/spec/fixtures/vcr_cassettes/api/profile_extension/retrieve_profile_extension_records.yml +46 -28
  30. data/spec/fixtures/vcr_cassettes/api/table/create_with_pk.yml +927 -28
  31. data/spec/fixtures/vcr_cassettes/api/table/delete_with_pk.yml +46 -28
  32. data/spec/fixtures/vcr_cassettes/member/present1.yml +927 -28
  33. data/spec/fixtures/vcr_cassettes/member/present2.yml +46 -28
  34. data/spec/fixtures/vcr_cassettes/member/present3.yml +46 -30
  35. data/spec/fixtures/vcr_cassettes/member/present4.yml +46 -30
  36. data/spec/fixtures/vcr_cassettes/member/present5.yml +46 -30
  37. data/spec/fixtures/vcr_cassettes/member/retrieve_profile_extension.yml +92 -56
  38. data/spec/spec_helper.rb +9 -19
  39. metadata +43 -23
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MTlmMTI3NDdjZmE5MjYwYTllNzRiMTU3OTE1ZDc4OGQ2N2EwZTNhNQ==
5
- data.tar.gz: !binary |-
6
- ZjU1YjUxYWUxMWE0Yzg0NTk0YWRmYTAyNDYxMjI3YmQ1YzNiMzYyNA==
2
+ SHA1:
3
+ metadata.gz: 6f00d1395d9bcceca1e501060dda3682ba6c9efe
4
+ data.tar.gz: e7f470e8a49e3bdacc06696ae5eeab07f20686f6
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MjAwMmE5OWU3YzRhMjliZjNhZmQ2ODNkNGE3ZWEzOWY4NjAxYmJmMWU5YjE0
10
- ZDk1M2MwOTlmZjQyYWRmYTM5ODVkZDQwMzA1MjNmMTkyYWQ2NzJmZTc2NWFl
11
- NjdiNTlmMDNlMDMzY2M1YmVlNzYwNTJlZDNjNTEyZjg3NWE0OGE=
12
- data.tar.gz: !binary |-
13
- NTJlNjI3MDZkOWNhMWI2MDNjNTk3ZDAxMGQ3MWM1ZTdiODM5NGU3ODRjNGI3
14
- NmY5MGIxNjE2ZWZkMTc0MDZiOTQ5MzdhZTgzNDMyZWRjMGJhNGM0ZTNkN2Mx
15
- YmM2NjY1NTlhOWRhM2Y0NWY5MjkwYTgzZjBjODU1ZWRjNzdlZjU=
6
+ metadata.gz: 217b1ad9d39b0a44392e7b5ffbbbca9ed27e6d39ff776fae6a55fdd29d3d04b6bfdbe800ede0c767eecaeddd232418b5857bf37eb89caae4f902ce0a7fc25b02
7
+ data.tar.gz: 2a7fd19395a831029fb5e11b39194d560ba62514a0b26bb07b01a308bc5a87765e2fecd027cb14100130fa57af0b72eaf389a3801c4ae6fdb7e88a33464a5444
@@ -2,6 +2,11 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 2.1.2
5
-
6
5
  gemfile:
7
- - Gemfile
6
+ - Gemfile
7
+ notifications:
8
+ email:
9
+ on_success: never
10
+ on_failure: never
11
+ slack:
12
+ secure: 8b8dwwpHEw7vYd5Vma/BK2dZBrKYpFtu8TN8+NtpW8Xp+boYY3hEaFCeeEySzDvacCBZFKjjvDxverOFd4jqml2MtOukNZ/zlFc7ZVybGsNirfisNucS7auvwoWPwVrzrHoNpB5nTLU4tm0tWdaKkfLa4Yssr/tEO8yBIGwT8ds=
@@ -1,15 +1,15 @@
1
+ require "responsys/api/authentication"
1
2
  require "responsys/api/folder"
2
3
  require "responsys/api/list"
3
- require "responsys/api/session"
4
4
  require "responsys/api/table"
5
5
  require "responsys/api/campaign"
6
6
 
7
7
  module Responsys
8
8
  module Api
9
9
  module All
10
+ include Responsys::Api::Authentication
10
11
  include Responsys::Api::Folder
11
12
  include Responsys::Api::List
12
- include Responsys::Api::Session
13
13
  include Responsys::Api::Table
14
14
  include Responsys::Api::Campaign
15
15
  end
@@ -0,0 +1,45 @@
1
+ module Responsys
2
+ module Api
3
+ module Authentication
4
+ def login
5
+ logout if logged_in?
6
+
7
+ response = run(:login, credentials)
8
+ establish_session_id(response)
9
+ establish_jsession_id(response)
10
+ set_session_credentials
11
+ end
12
+
13
+ def logout
14
+ return unless logged_in?
15
+
16
+ run_with_credentials(:logout, nil)
17
+ destroy_session_objects
18
+ end
19
+
20
+ def logged_in?
21
+ !(session_id.nil? || jsession_id.nil? || header.nil?)
22
+ end
23
+
24
+ private
25
+
26
+ def establish_session_id(login_response)
27
+ @session_id = login_response.body[:login_response][:result][:session_id]
28
+ end
29
+
30
+ def establish_jsession_id(login_response)
31
+ @jsession_id = login_response.http.cookies[0]
32
+ end
33
+
34
+ def set_session_credentials
35
+ @header = { SessionHeader: { sessionId: session_id } }
36
+ end
37
+
38
+ def destroy_session_objects
39
+ @session_id = nil
40
+ @jsession_id = nil
41
+ @header = nil
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,68 +1,39 @@
1
- require "responsys/configuration"
2
- require "savon"
3
- require "responsys/helper"
4
- require "responsys/api/all"
5
- require "responsys/api/object/all"
6
- require "singleton"
7
-
8
1
  module Responsys
9
2
  module Api
10
3
  class Client
11
- include Singleton
12
4
  include Responsys::Api::All
5
+ attr_accessor :client
13
6
 
14
- attr_accessor :credentials, :client, :session_id, :jsession_id, :header
15
-
16
- def initialize
17
- settings = Responsys.configuration.settings
18
- @credentials = {
19
- username: settings[:username],
20
- password: settings[:password]
21
- }
22
-
23
- ssl_version = settings[:ssl_version] || :TLSv1
24
-
25
- if settings[:debug]
26
- @client = Savon.client(wsdl: settings[:wsdl], element_form_default: :qualified, ssl_version: ssl_version, log_level: :debug, log: true, pretty_print_xml: true)
27
- else
28
- @client = Savon.client(wsdl: settings[:wsdl], element_form_default: :qualified, ssl_version: ssl_version)
29
- end
7
+ #TODO allows to keep the use of .instance. The client is no longer a singleton so it needs to be removed in a newer release.
8
+ class << self
9
+ alias :instance :new
30
10
  end
31
11
 
32
12
  def api_method(action, message = nil, response_type = :hash)
33
13
  raise Responsys::Helper.get_message("api.client.api_method.wrong_action_#{action.to_s}") if action.to_sym == :login || action.to_sym == :logout
34
14
 
35
- begin
36
- login
37
-
38
- response = run_with_credentials(action, message, jsession_id, header)
39
-
40
- case response_type
41
- when :result
42
- Responsys::Helper.format_response_result(response, action)
43
- when :hash
44
- Responsys::Helper.format_response_hash(response, action)
15
+ SessionPool.instance.with do |session|
16
+ begin
17
+ session.login
18
+ response = session.run_with_credentials(action, message)
19
+ case response_type
20
+ when :result
21
+ Responsys::Helper.format_response_result(response, action)
22
+ when :hash
23
+ Responsys::Helper.format_response_hash(response, action)
24
+ end
25
+ rescue Exception => e
26
+ Responsys::Helper.format_response_with_errors(e)
27
+ ensure
28
+ session.logout
45
29
  end
46
-
47
- rescue Exception => e
48
- Responsys::Helper.format_response_with_errors(e)
49
- ensure
50
- logout
51
30
  end
52
31
  end
53
32
 
54
33
  def available_operations
55
- @client.operations
56
- end
57
-
58
- private
59
-
60
- def run(method, message)
61
- @client.call(method.to_sym, message: message)
62
- end
63
-
64
- def run_with_credentials(method, message, cookie, header)
65
- @client.call(method.to_sym, message: message, cookies: cookie, soap_header: header)
34
+ SessionPool.instance.with do |session|
35
+ session.operations
36
+ end
66
37
  end
67
38
  end
68
39
  end
@@ -1,44 +1,31 @@
1
1
  module Responsys
2
2
  module Api
3
- module Session
4
- def login
5
- logout if logged_in?
6
-
7
- response = run("login", credentials)
8
- establish_session_id(response)
9
- establish_jsession_id(response)
10
- set_session_credentials
11
- end
12
-
13
- def logout
14
- return unless logged_in?
15
-
16
- run_with_credentials(:logout, nil, jsession_id, header)
17
- destroy_session_objects
18
- end
19
-
20
- def logged_in?
21
- !(session_id.nil? || jsession_id.nil? || header.nil?)
22
- end
23
-
24
- private
25
-
26
- def establish_session_id(login_response)
27
- @session_id = login_response.body[:login_response][:result][:session_id]
28
- end
29
-
30
- def establish_jsession_id(login_response)
31
- @jsession_id = login_response.http.cookies[0]
3
+ class Session
4
+ attr_accessor :credentials, :session_id, :jsession_id, :header
5
+ include Responsys::Api::Authentication
6
+
7
+ def initialize
8
+ settings = Responsys.configuration.settings
9
+ @credentials = {
10
+ username: settings[:username],
11
+ password: settings[:password]
12
+ }
13
+
14
+ ssl_version = settings[:ssl_version] || :TLSv1
15
+
16
+ if settings[:debug]
17
+ @savon_client = Savon.client(wsdl: settings[:wsdl], element_form_default: :qualified, ssl_version: ssl_version, log_level: :debug, log: true, pretty_print_xml: true)
18
+ else
19
+ @savon_client = Savon.client(wsdl: settings[:wsdl], element_form_default: :qualified, ssl_version: ssl_version)
20
+ end
32
21
  end
33
22
 
34
- def set_session_credentials
35
- @header = { SessionHeader: { sessionId: session_id } }
23
+ def run(method, message)
24
+ @savon_client.call(method.to_sym, message: message)
36
25
  end
37
26
 
38
- def destroy_session_objects
39
- @session_id = nil
40
- @jsession_id = nil
41
- @header = nil
27
+ def run_with_credentials(method, message)
28
+ @savon_client.call(method.to_sym, message: message, cookies: jsession_id, soap_header: header)
42
29
  end
43
30
  end
44
31
  end
@@ -0,0 +1,32 @@
1
+ require "singleton"
2
+
3
+ module Responsys
4
+ module Api
5
+ class SessionPool
6
+ include Singleton
7
+ attr_accessor :pool
8
+ ACCEPTED_SETTINGS = [:timeout, :size]
9
+
10
+ class << self
11
+ alias :init :instance
12
+ end
13
+
14
+ def initialize
15
+ settings = Responsys.configuration.settings[:sessions]
16
+ params = if settings
17
+ settings.select { |option, value| ACCEPTED_SETTINGS.include?(option) }
18
+ else
19
+ {}
20
+ end
21
+
22
+ @pool = ConnectionPool.new(params) { Responsys::Api::Session.new }
23
+ end
24
+
25
+ def with
26
+ @pool.with do |session|
27
+ yield session
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -7,7 +7,11 @@ module Responsys
7
7
  username: nil,
8
8
  password: nil,
9
9
  wsdl: "",
10
- debug: false
10
+ debug: false,
11
+ sessions: {
12
+ size: 80,
13
+ timeout: 30
14
+ }
11
15
  }
12
16
  end
13
17
  end
@@ -22,5 +26,6 @@ module Responsys
22
26
 
23
27
  def self.configure
24
28
  yield(configuration)
29
+ Responsys::Api::SessionPool.init
25
30
  end
26
- end
31
+ end
@@ -18,6 +18,41 @@ en:
18
18
  empty_event: The event_name or event_id must be specified
19
19
  incorrect_event_object: "custom_event must be a CustomEvent instance"
20
20
  client:
21
+ available_methods:
22
+ - wsdl
23
+ - endpoint
24
+ - namespace
25
+ - raise_errors
26
+ - proxy
27
+ - headers
28
+ - open_timeout
29
+ - read_timeout
30
+ - ssl_verify_mode
31
+ - ssl_version
32
+ - ssl_cert_file
33
+ - ssl_cert_key_file
34
+ - ssl_ca_cert_file
35
+ - ssl_cert_key_password
36
+ - convert_request_keys_to
37
+ - soap_header
38
+ - element_form_default
39
+ - env_namespace
40
+ - namespace_identifier
41
+ - namespaces
42
+ - encoding
43
+ - soap_version
44
+ - basic_auth
45
+ - digest_auth
46
+ - wsse_auth
47
+ - wsse_timestamp
48
+ - ntlm
49
+ - strip_namespaces
50
+ - convert_response_tags_to
51
+ - logger
52
+ - log_level
53
+ - log
54
+ - filters
55
+ - pretty_print_xml
21
56
  api_method:
22
57
  wrong_action_login: Please use the dedicated login method
23
58
  wrong_action_logout: Please use the dedicated logout method
@@ -1,9 +1,15 @@
1
1
  require "i18n"
2
+ require "connection_pool"
3
+ require "savon"
2
4
 
3
5
  I18n.load_path.concat Dir.glob( File.dirname(__FILE__) + "/responsys/i18n/*.yml" )
4
6
 
5
7
  require "responsys/exceptions/all"
6
8
  require "responsys/helper"
7
9
  require "responsys/configuration"
10
+ require "responsys/api/all"
11
+ require "responsys/api/object/all"
12
+ require "responsys/api/session_pool"
13
+ require "responsys/api/session"
8
14
  require "responsys/api/client"
9
- require "responsys/member"
15
+ require "responsys/member"
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "responsys-api"
7
- spec.version = "0.1.0"
7
+ spec.version = "0.2.1"
8
8
  spec.authors = ["Dan DeMeyere", "Florian Lorrain", "Morgan Griggs", "Mike Rocco"]
9
9
  spec.email = ["dan@thredup.com", "florian.lorrain@thredup.com", "morgan@thredup.com", "michael.rocco@thredup.com"]
10
10
  spec.description = "A gem to integrate with the Responsys SOAP API"
@@ -21,9 +21,10 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency "savon", "2.6.0"
22
22
  spec.add_dependency "wasabi", "3.3.0"
23
23
  spec.add_dependency "i18n", "~> 0.6"
24
+ spec.add_dependency "connection_pool", "2.0.0"
24
25
  spec.add_development_dependency "bundler", "~> 1.3"
25
26
  spec.add_development_dependency "rake", "~> 10.3"
26
- spec.add_development_dependency "rspec", "~> 3.0"
27
+ spec.add_development_dependency "rspec", "~> 3.1.0"
27
28
  spec.add_development_dependency "vcr", "~> 2.5"
28
29
  spec.add_development_dependency "webmock", "~> 1.9"
29
30
  end
@@ -11,20 +11,20 @@ describe Responsys::Api::Campaign do
11
11
  let(:custom_event) { Responsys::Api::Object::CustomEvent.new(DATA[:custom_events][:custom_event1][:name]) }
12
12
 
13
13
  before(:all) do
14
- @client = Responsys::Api::Client.instance
14
+ @client = Responsys::Api::Client.new
15
15
  end
16
16
 
17
17
  context "Trigger Message" do
18
18
  it "should return a status of ok when triggering a message for one recipient" do
19
19
  VCR.use_cassette("api/campaign/trigger_message_1") do
20
- response = Responsys::Api::Client.instance.trigger_message(campaign, [recipientData1])
20
+ response = Responsys::Api::Client.new.trigger_message(campaign, [recipientData1])
21
21
  expect(response[:status]).to eq("ok")
22
22
  end
23
23
  end
24
24
 
25
25
  it "should return a status of ok when triggering a message for more than one recipient" do
26
26
  VCR.use_cassette("api/campaign/trigger_message_2") do
27
- response = Responsys::Api::Client.instance.trigger_message(campaign, [recipientData1,recipientData2])
27
+ response = Responsys::Api::Client.new.trigger_message(campaign, [recipientData1,recipientData2])
28
28
  expect(response[:status]).to eq("ok")
29
29
  end
30
30
  end
@@ -43,14 +43,14 @@ describe Responsys::Api::Campaign do
43
43
  context "#trigger_custom_event" do
44
44
  it "should return a status of ok when triggering a custom event for one recipient" do
45
45
  VCR.use_cassette("api/campaign/trigger_custom_event_1") do
46
- response = Responsys::Api::Client.instance.trigger_custom_event(custom_event, [recipientData1])
46
+ response = Responsys::Api::Client.new.trigger_custom_event(custom_event, [recipientData1])
47
47
  expect(response[:status]).to eq("ok")
48
48
  end
49
49
  end
50
50
 
51
51
  it "should return a status of ok when triggering a custom event for more than one recipient" do
52
52
  VCR.use_cassette("api/campaign/trigger_custom_event_2") do
53
- response = Responsys::Api::Client.instance.trigger_custom_event(custom_event, [recipientData1,recipientData2])
53
+ response = Responsys::Api::Client.new.trigger_custom_event(custom_event, [recipientData1,recipientData2])
54
54
  expect(response[:status]).to eq("ok")
55
55
  end
56
56
  end
@@ -1,77 +1,15 @@
1
1
  require "spec_helper.rb"
2
- require "responsys/api/client"
3
- require "singleton"
4
2
 
5
3
  describe Responsys::Api::Client do
6
4
 
7
- context "Authentication" do
8
- subject { Responsys::Api::Client.instance }
9
- let(:savon_client) { double("savon client") }
10
-
11
- before(:context) do
12
- @credentials = { username: CREDENTIALS["username"], password: CREDENTIALS["password"] }
13
- end
14
-
15
- after(:context) do
16
- Singleton.__init__(Responsys::Api::Client)
17
- end
18
-
19
- it "should set the credentials" do
20
- allow_any_instance_of(Responsys::Api::Client).to receive(:login).and_return(nil)
21
-
22
- responsys = Responsys::Api::Client.instance
23
-
24
- expect(responsys.credentials).to eq({ username: CREDENTIALS["username"], password: CREDENTIALS["password"] })
25
- end
26
-
27
- context "login" do
28
- before(:example) do
29
- response = double("response")
30
-
31
- cookies = %w(fake_jsession_id)
32
- body = {
33
- login_response: {
34
- result: {
35
- session_id: "fake_session_id"
36
- }
37
- }
38
- }
39
-
40
- allow(response).to receive(:body).and_return(body)
41
- allow(response).to receive(:http).and_return(double("cookies", cookies: cookies))
42
-
43
- allow(Savon).to receive(:client).with({ wsdl: CREDENTIALS["wsdl"], element_form_default: :qualified, ssl_version: :TLSv1}).and_return(savon_client) #Avoid the verification of the wsdl
44
- allow_any_instance_of(Responsys::Api::Client).to receive(:run).with("login", @credentials).and_return(response) #Verification of credentials
45
- allow(savon_client).to receive(:call).with(:login, @credentials ).and_return(response) #Actual login call
46
-
47
- Singleton.__init__(Responsys::Api::Client)
48
- end
49
-
50
- it "should set the session ids" do
51
- subject.login
52
-
53
- expect(subject.header).to eq({ SessionHeader: { sessionId: "fake_session_id" } }) #Test the ids are right
54
- expect(subject.jsession_id).to eq("fake_jsession_id")
55
- end
56
-
57
- it "should refuse the access to api_method for login" do
58
- expect{ subject.api_method(:login) }.to raise_error("Please use the dedicated login method")
59
- end
5
+ describe "Authentication methods" do
6
+ it "should refuse the access to api_method for logout" do
7
+ expect{ subject.api_method(:logout) }.to raise_error("Please use the dedicated logout method")
60
8
  end
61
9
 
62
- context "logout" do
63
- subject { Responsys::Api::Client.instance }
64
-
65
- it "should logout" do
66
- allow(subject).to receive(:logged_in?).and_return(true)
67
- expect(subject).to receive(:run_with_credentials).with(:logout, anything, anything, anything) #Check the call is actually being done
68
-
69
- subject.logout
70
- end
71
-
72
- it "should refuse the access to api_method for logout" do
73
- expect{ subject.api_method(:logout) }.to raise_error("Please use the dedicated logout method")
74
- end
10
+ it "should refuse the access to api_method for login" do
11
+ expect{ subject.api_method(:login) }.to raise_error("Please use the dedicated login method")
75
12
  end
76
13
  end
77
- end
14
+
15
+ end