email_vision-neopoly 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'savon', '>=0.8.2'
4
+
5
+ group :dev do
6
+ gem 'rake'
7
+ gem 'rspec', '~>2'
8
+ gem 'jeweler'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ builder (3.0.0)
5
+ diff-lcs (1.1.2)
6
+ git (1.2.5)
7
+ gyoku (0.4.4)
8
+ builder (>= 2.1.2)
9
+ httpi (0.9.4)
10
+ pyu-ntlm-http (>= 0.1.3.1)
11
+ rack
12
+ jeweler (1.6.2)
13
+ bundler (~> 1.0)
14
+ git (>= 1.2.5)
15
+ rake
16
+ nokogiri (1.4.4)
17
+ nori (0.2.3)
18
+ pyu-ntlm-http (0.1.3.1)
19
+ rack (1.3.0)
20
+ rake (0.9.2)
21
+ rspec (2.6.0)
22
+ rspec-core (~> 2.6.0)
23
+ rspec-expectations (~> 2.6.0)
24
+ rspec-mocks (~> 2.6.0)
25
+ rspec-core (2.6.4)
26
+ rspec-expectations (2.6.0)
27
+ diff-lcs (~> 1.1.2)
28
+ rspec-mocks (2.6.0)
29
+ savon (0.9.2)
30
+ builder (>= 2.1.2)
31
+ gyoku (>= 0.4.0)
32
+ httpi (>= 0.7.8)
33
+ nokogiri (>= 1.4.0)
34
+ nori (>= 0.2.0)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ jeweler
41
+ rake
42
+ rspec (~> 2)
43
+ savon (>= 0.8.2)
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ task :default => :spec
2
+ require "rspec/core/rake_task"
3
+ RSpec::Core::RakeTask.new(:spec) do |t|
4
+ t.rspec_opts = '--backtrace --color'
5
+ end
6
+
7
+ def account
8
+ YAML.load(File.read('spec/account.yml')) rescue {}
9
+ end
10
+
11
+ def email_vision
12
+ @email_vision ||= begin
13
+ $LOAD_PATH << 'lib'
14
+ require 'email_vision'
15
+ require 'yaml'
16
+ EmailVision.new(account)
17
+ end
18
+ end
19
+
20
+ desc 'possible actions'
21
+ task :actions do
22
+ unnecessary_actions = [:open_api_connection, :close_api_connection]
23
+ actions = email_vision.send(:connection).wsdl.soap_actions
24
+ puts (actions - unnecessary_actions).map{|x|" - #{x}"}.sort.join("\n")
25
+ end
26
+
27
+ desc 'test update here, since it takes forever to be processed'
28
+ task :test_update do
29
+ user = account[:changeable_user]
30
+ value = rand(1111111)
31
+ email_vision.update(user[:email], :firstname => value)
32
+ start = Time.now
33
+ loop do
34
+ sleep 5
35
+ puts (Time.now - start).to_i
36
+ data = email_vision.find(user[:email])
37
+ break if data[:firstname] == value.to_s
38
+ end
39
+ puts "SUCCESS!!!!!! #{(Time.now - start).to_i}"
40
+ end
41
+
42
+ begin
43
+ require 'jeweler'
44
+ Jeweler::Tasks.new do |gem|
45
+ gem.name = 'email_vision-neopoly'
46
+ gem.summary = "Ruby SOAP Api Client for EmailVision / CampaignCommander"
47
+ gem.email = "ps@neopoly.de"
48
+ gem.homepage = "http://github.com/neopoly/#{gem.name}"
49
+ gem.authors = ["Michael Grosser", "Peter Suschlik"]
50
+ gem.add_dependency 'savon'
51
+ end
52
+
53
+ Jeweler::GemcutterTasks.new
54
+ rescue LoadError
55
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
56
+ end
data/Readme.md ADDED
@@ -0,0 +1,82 @@
1
+ EmailVision SOAP Api Client
2
+
3
+ gem install email_vision
4
+
5
+ Usage
6
+ =====
7
+
8
+ Member API
9
+ ----------
10
+
11
+ emv = EmailVision::Member.new(:password => 'foo', :login => 'bar', :key => 'token')
12
+ emv.find 'me@host.com'
13
+ emv.create_or_update :email => 'me@host.com', :foo => 1
14
+
15
+ emv.create :email => 'me@host.com', :foo => 1
16
+ emv.update :email => 'me@host.com', :foo => 1
17
+ emv.update :email_was => 'me@host.com', :email => 'you@host.com'
18
+
19
+ emv.columns
20
+
21
+ emv.unjoin 'me@host.com'
22
+ emv.rejoin 'me@host.com'
23
+
24
+ # create, create_or_update, update, change_email return a job-id
25
+ # it can be used to wait for the job or fetch its status
26
+ job_id = emv.update :email => 'me@host.com', :foo => 1
27
+ puts "Status is #{emv.job_status job_id}"
28
+ emv.wait_for_job_to_finish job_id # raises when job failed
29
+
30
+
31
+ # :dateunjoin cannot be set via update, use a separate rejoin / unjoin request
32
+ class User < ActiveRecord::Base
33
+ after_save :update_email_vision
34
+
35
+ def update_email_vision
36
+ case receive_newsletter_change
37
+ when [false, true]
38
+ emv.rejoin(email)
39
+ emv.update(...data for emailv vision...)
40
+ when [true, false]
41
+ emv.unjoin(email)
42
+ end
43
+ end
44
+ end
45
+
46
+
47
+ Message API
48
+ -----------
49
+
50
+ emv = EmailVision::Message.new(:password => 'foo', :login => 'bar', :key => 'token')
51
+
52
+ # create
53
+ message_id = emv.create(:name => "test message", :body => "[EMV TEXTPART] hello world", :reply_to_email => "reply@example.com")
54
+
55
+ # find single message
56
+ message = emv.find(message_id)
57
+
58
+ # updating
59
+ message[:subject] = "cool subject"
60
+ emv.update(message) # => true || false
61
+
62
+ # sending a test message
63
+ emv.test(message_id, member_id)
64
+
65
+ # cloning and deleting
66
+ cloned_id = emv.clone(message_id, "test message clone")
67
+ cloned = emv.find(cloned_id)
68
+ emv.delete(cloned_id)
69
+
70
+ # find messages by period
71
+ message_ids = emv.find_all_by_period(2.days.ago, Time.now)
72
+
73
+
74
+ Docs
75
+ ====
76
+ - [EmailVision api](https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=1FLFs3Jautozs6-ZNcT34oSXJbH6K7szw1wD8cU5i9jpEWjA4p64StquqYa6P&hl=de&authkey=CO383_EP)
77
+
78
+ Author
79
+ ======
80
+ [Michael Grosser](http://grosser.it)<br/>
81
+ michael@grosser.it<br/>
82
+ Hereby placed under public domain, do what you want, just do not hold me accountable...
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
@@ -0,0 +1,52 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "email_vision-neopoly"
8
+ s.version = "0.3.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Grosser", "Peter Suschlik"]
12
+ s.date = "2012-05-04"
13
+ s.email = "ps@neopoly.de"
14
+ s.files = [
15
+ "Gemfile",
16
+ "Gemfile.lock",
17
+ "Rakefile",
18
+ "Readme.md",
19
+ "VERSION",
20
+ "email_vision-neopoly.gemspec",
21
+ "lib/email_vision.rb",
22
+ "lib/email_vision/base_client.rb",
23
+ "lib/email_vision/campaign.rb",
24
+ "lib/email_vision/member.rb",
25
+ "lib/email_vision/message.rb",
26
+ "spec/account.yml.example",
27
+ "spec/email_vision_campaign_spec.rb",
28
+ "spec/email_vision_member_spec.rb",
29
+ "spec/email_vision_message_spec.rb",
30
+ "spec/spec_helper.rb"
31
+ ]
32
+ s.homepage = "http://github.com/neopoly/email_vision-neopoly"
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = "1.8.17"
35
+ s.summary = "Ruby SOAP Api Client for EmailVision / CampaignCommander"
36
+
37
+ if s.respond_to? :specification_version then
38
+ s.specification_version = 3
39
+
40
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
41
+ s.add_runtime_dependency(%q<savon>, [">= 0.8.2"])
42
+ s.add_runtime_dependency(%q<savon>, [">= 0"])
43
+ else
44
+ s.add_dependency(%q<savon>, [">= 0.8.2"])
45
+ s.add_dependency(%q<savon>, [">= 0"])
46
+ end
47
+ else
48
+ s.add_dependency(%q<savon>, [">= 0.8.2"])
49
+ s.add_dependency(%q<savon>, [">= 0"])
50
+ end
51
+ end
52
+
@@ -0,0 +1,78 @@
1
+ module EmailVision
2
+ class BaseClient
3
+ SESSION_TIMEOUT = 10*60
4
+
5
+ attr_accessor :options
6
+
7
+ def initialize(options)
8
+ self.options = options
9
+ @wsdl = options.delete(:wsdl)
10
+ @namespace = options.delete(:namespace)
11
+ end
12
+
13
+ def connection
14
+ connect! unless connected?
15
+ client
16
+ end
17
+
18
+ def client
19
+ @client ||= Savon::Client.new(@wsdl)
20
+ end
21
+
22
+ def connected?
23
+ @token and @token_requested > (Time.now.to_i - SESSION_TIMEOUT)
24
+ end
25
+
26
+ def connect!
27
+ @token = request_without_protection(:open_api_connection,
28
+ :login => options[:login],
29
+ :pwd => options[:password],
30
+ :key => options[:key],
31
+ :soap_client => client
32
+ )
33
+ @token_requested = Time.now.to_i
34
+ end
35
+
36
+ def execute(method, options={})
37
+ request_without_protection(method, options.merge(:token => true))
38
+ rescue Object => e
39
+ if e.respond_to?(:http) and e.http.respond_to?(:body)
40
+ retries ||= -1
41
+ retries += 1
42
+ session_error = (e.http.body =~ /status>(SESSION_RETRIEVING_FAILED|CHECK_SESSION_FAILED)</)
43
+ if session_error
44
+ if retries < 1
45
+ connect!
46
+ retry
47
+ else
48
+ e.message << " -- retried #{retries}"
49
+ end
50
+ end
51
+ end
52
+ raise e
53
+ end
54
+
55
+ def request_without_protection(method, options)
56
+ client = options.delete(:soap_client) || connection
57
+ response = client.request(api_namespaced(method)) do |r|
58
+ r.namespaces['xmlns:api'] = @namespace
59
+ options[:token] = @token if options[:token] # token first is generated via connection method
60
+ r.body = options
61
+ end
62
+ response.to_hash["#{method}_response".to_sym][:return]
63
+ end
64
+
65
+ def api_namespaced(method)
66
+ "api:#{method.to_s.gsub(/_./){|x| x.slice(1,1).upcase }}"
67
+ end
68
+
69
+ def check_server_status!(e, status)
70
+ fault = e.to_hash[:fault]
71
+ if fault && fault[:faultcode] == "soap:Server" && status === fault[:detail].first.last[:status]
72
+ block_given? ? yield(fault[:detail][:status]) : true
73
+ else
74
+ raise e
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,35 @@
1
+ module EmailVision
2
+ class Campaign < BaseClient
3
+ def find(id)
4
+ execute(:get_campaign, :id => id)
5
+ rescue Savon::SOAP::Fault => e
6
+ check_server_status!(e, "GET_CAMPAIGN_FAILED") { nil }
7
+ end
8
+
9
+ def create(attributes)
10
+ execute(:create_campaign, format_attributes(attributes))
11
+ rescue Savon::SOAP::Fault => e
12
+ nil
13
+ end
14
+
15
+ def delete(id)
16
+ execute(:delete_campaign, :id => id)
17
+ rescue Savon::SOAP::Fault => e
18
+ check_server_status!(e, "GET_CAMPAIGN_FAILED") { false }
19
+ end
20
+
21
+ private
22
+
23
+ def format_attributes(attributes)
24
+ Hash[attributes.map do |k, v|
25
+ v = Time.parse(v.to_s) if v.is_a?(Date)
26
+ v = format_date(v) if v.is_a?(Time)
27
+ [ k, v ]
28
+ end]
29
+ end
30
+
31
+ def format_date(date)
32
+ date.strftime("%Y-%m-%d %H:%M:%S")
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,94 @@
1
+ module EmailVision
2
+ class Member < BaseClient
3
+ JOB_STATUS = {
4
+ :finished => 'Job_Done_Or_Does_Not_Exist',
5
+ :error => 'Error'
6
+ }
7
+
8
+ def find(email_or_id)
9
+ result = execute_by_email_or_id(:get_member, email_or_id)
10
+ result = result.first if result.is_a?(Array) # may return multiple users if they have the same email -> return first
11
+ return unless result.is_a?(Hash)
12
+ result = convert_to_hash(result[:attributes][:entry], :key, :value)
13
+ result.reject{|k,v| v.nil? }
14
+ end
15
+
16
+ def unjoin(email_or_id)
17
+ execute_by_email_or_id(:unjoin_member, email_or_id)
18
+ end
19
+
20
+ def rejoin(email_or_id)
21
+ execute_by_email_or_id(:rejoin_member, email_or_id)
22
+ end
23
+
24
+ def update(attributes)
25
+ execute_by_obj(:update_member_by_obj, attributes)
26
+ end
27
+
28
+ def create(attributes)
29
+ execute_by_obj(:insert_member_by_obj, attributes)
30
+ end
31
+
32
+ def create_or_update(attributes)
33
+ execute_by_obj(:insert_or_update_member_by_obj, attributes)
34
+ end
35
+
36
+ # should be one of: Insert, Processing, Processed, Error, Job_Done_Or_Does_Not_Exist
37
+ def job_status(job_id)
38
+ execute(:get_member_job_status, :synchro_id => job_id)[:status]
39
+ end
40
+
41
+ def wait_for_job_to_finish(job_id, options={})
42
+ interval = options[:interval] || 5
43
+ times = options[:times] || 20
44
+
45
+ times.times do
46
+ current_status = job_status(job_id)
47
+ raise "Job failed" if current_status == JOB_STATUS[:error]
48
+ return true if current_status == JOB_STATUS[:finished]
49
+ sleep interval
50
+ end
51
+
52
+ raise "Job not finished in time! #{current_status}"
53
+ end
54
+
55
+ def columns
56
+ result = execute(:desc_member_table)
57
+ result = convert_to_hash(result[:fields], :name, :type)
58
+ result.each{|k,v| result[k] = to_ruby_style(v)}
59
+ result
60
+ end
61
+
62
+ private
63
+
64
+ def execute_by_email_or_id(method, email_or_id)
65
+ if email_or_id.to_s.include?('@')
66
+ execute("#{method}_by_email", :email => email_or_id)
67
+ else
68
+ execute("#{method}_by_id", :id => email_or_id)
69
+ end
70
+ end
71
+
72
+ def to_ruby_style(name)
73
+ name.downcase.to_sym
74
+ end
75
+
76
+ def execute_by_obj(method, attributes)
77
+ existing_email = attributes.delete(:email_was) || attributes[:email]
78
+ entries = attributes.map do |k,v|
79
+ v = Time.parse(v.to_s) if v.is_a?(Date)
80
+ v = v.strftime('%Y-%m-%d %H:%M:%S') if v.is_a?(Time)
81
+ {:key => k, :value => v}
82
+ end
83
+
84
+ execute(method, :member => {:email => existing_email, :dynContent => {:entry => entries}})
85
+ end
86
+
87
+ def convert_to_hash(entries, key, value)
88
+ entries.inject({}) do |hash, part|
89
+ hash[to_ruby_style(part[key])] = part[value]
90
+ hash
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,49 @@
1
+ module EmailVision
2
+ class Message < BaseClient
3
+ def find(id)
4
+ execute(:get_message, :id => id)
5
+ rescue Savon::SOAP::Fault => e
6
+ check_server_status!(e, "GET_MESSAGE_FAILED") { nil }
7
+ end
8
+
9
+ def find_all_by_period(from, to)
10
+ execute(:get_messages_by_period, :date_begin => format_date(from), :date_end => format_date(to)) || []
11
+ end
12
+
13
+ def create(attributes)
14
+ defaults = { :encoding => "UTF-8" }
15
+ execute(:create_email_message_by_obj, :message => defaults.merge(attributes))
16
+ rescue Savon::SOAP::Fault => e
17
+ check_server_status!(e, "CEM_MESSAGE_FAILED") { nil }
18
+ end
19
+
20
+ def clone(id, new_name)
21
+ execute(:clone_message, :id => id, :new_name => new_name)
22
+ end
23
+
24
+ def delete(id)
25
+ execute(:delete_message, :id => id)
26
+ rescue Savon::SOAP::Fault => e
27
+ check_server_status!(e, "GET_MESSAGE_FAILED") { false }
28
+ end
29
+
30
+ def update(attributes)
31
+ execute(:update_message_by_obj, :message => attributes)
32
+ rescue Savon::SOAP::Fault => e
33
+ check_server_status!(e, "GET_MESSAGE_FAILED") { false }
34
+ end
35
+
36
+ def test(id, member_id, options={})
37
+ options = { :id => id, :member_id => member_id }.merge(options)
38
+ execute(:test_email_message_by_member, options)
39
+ rescue Savon::SOAP::Fault => e
40
+ check_server_status!(e, "TEM_MESSAGE_FAILED") { false }
41
+ end
42
+
43
+ private
44
+
45
+ def format_date(date)
46
+ date.strftime("%Y-%m-%d %H:%M:%S")
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,10 @@
1
+ require 'savon'
2
+
3
+ module EmailVision
4
+ VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
5
+ end
6
+
7
+ require 'email_vision/base_client'
8
+ require 'email_vision/member'
9
+ require 'email_vision/message'
10
+ require 'email_vision/campaign'
@@ -0,0 +1,47 @@
1
+ :member:
2
+ :login: api_your_host
3
+ :password: your_password
4
+ :key: your_api_key
5
+ :wsdl: 'http://emvapi.emv3.com/apimember/services/MemberService?wsdl'
6
+ :namespace: 'http://api.service.apimember.emailvision.com/'
7
+ :findable_user:
8
+ :country: "DE"
9
+ :gender: "0"
10
+ :email: test@test.de
11
+ :datejoin: 2009-12-07T13:36:15+01:00
12
+ :dateunjoin: 2010-09-17T11:03:01+02:00
13
+ :firstname: First
14
+ :firstname: Last
15
+ :member_id: "1014086935042"
16
+ :changeable_user: # must have firstname, lastname, country columns
17
+ :email: testaccount@testaccount.de
18
+ :member_id: "1021531859844"
19
+ :lastname: "account"
20
+ :country: "DE"
21
+ :member_id: "1021531859844"
22
+
23
+ :message:
24
+ :login: api_your_host
25
+ :password: your_password
26
+ :key: your_api_key
27
+ :wsdl: 'http://emvapi.emv3.com/apiccmd/services/CcmdService?wsdl'
28
+ :namespace: 'http://api.service.apiccmd.emailvision.com/'
29
+ :findable_user:
30
+ :member_id: "1014086935042"
31
+ :findable_email_message:
32
+ :body: "Hello world"
33
+ :description: "test message"
34
+ :message_id: "1014086935042"
35
+
36
+ :campaign:
37
+ :login: api_your_host
38
+ :password: your_password
39
+ :key: your_api_key
40
+ :wsdl: 'http://emvapi.emv3.com/apiccmd/services/CcmdService?wsdl'
41
+ :namespace: 'http://api.service.apiccmd.emailvision.com/'
42
+ :findable_campaign:
43
+ :id: "325685"
44
+ :cloneable_email_message:
45
+ :id: "1300231"
46
+ :findable_segment:
47
+ :id: "228909"
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe "EmailVision" do
4
+ describe "Campgain" do
5
+ let(:config) { YAML.load(File.read('spec/account.yml'))[:campaign] }
6
+ let(:client) { EmailVision::Campaign.new(config) }
7
+ let(:message_config) { YAML.load(File.read('spec/account.yml'))[:message] }
8
+ let(:message_client) { EmailVision::Message.new(message_config) }
9
+ let(:findable_campaign) { config[:findable_campaign] }
10
+ let(:findable_id) { findable_campaign[:id] }
11
+ let(:cloneable_message_id) { config[:cloneable_email_message][:id] }
12
+ let(:findable_segment_id) { config[:findable_segment][:id] }
13
+
14
+ context :find do
15
+ it "by id" do
16
+ campaign = client.find(findable_id)
17
+ campaign.should_not be_nil
18
+ end
19
+
20
+ it "by id again and again" do
21
+ campaign = client.find(findable_id)
22
+ campaign.should == client.find(findable_id)
23
+ end
24
+
25
+ it "returns nil for unknown campaigns" do
26
+ client.find("-123").should be_nil
27
+ end
28
+
29
+ it "raises a soap fault for invalid input" do
30
+ lambda { client.find("invalid input") }.should raise_error Savon::SOAP::Fault, /Unmarshalling Error/
31
+ end
32
+ end
33
+
34
+ context "creating and deleting" do
35
+ before { @message_id = message_client.clone(cloneable_message_id, "test message clone #{Time.now}") }
36
+ let(:attributes) do
37
+ {
38
+ :name => "test campaign #{Time.now}",
39
+ :send_date => Time.now + 86400,
40
+ :message_id => message_id,
41
+ :mailing_list_id => findable_segment_id
42
+ }
43
+ end
44
+ let(:message_id) { @message_id }
45
+ after { message_client.delete(@message_id) }
46
+
47
+ it "creates a campaign" do
48
+ campaign_id = client.create(attributes)
49
+ campaign_id.should_not be_nil
50
+ campaign = client.find(campaign_id)
51
+ campaign[:name].should == attributes[:name]
52
+ campaign[:message_id].should == attributes[:message_id]
53
+ campaign[:mailinglist_id].should == attributes[:mailing_list_id]
54
+ client.delete(campaign_id)
55
+ end
56
+
57
+ it "needs attributes for creation" do
58
+ client.create(attributes.merge(:name => nil)).should be_nil
59
+ client.create(attributes.merge(:send_date => nil)).should be_nil
60
+ client.create(attributes.merge(:message_id => nil)).should be_nil
61
+ client.create(attributes.merge(:mailing_list_id => nil)).should be_nil
62
+ end
63
+
64
+ it "deletes a campaign" do
65
+ campaign_id = client.create(attributes)
66
+ campaign_id.should_not be_nil
67
+ client.delete(campaign_id).should == true
68
+ end
69
+
70
+ it "cannot delete unknown campaign" do
71
+ client.delete("-123").should == false
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,238 @@
1
+ require 'spec_helper'
2
+
3
+ describe "EmailVision" do
4
+ describe "Member" do
5
+ let(:email){"#{rand(1111111)}.foo@justatest.com"}
6
+ let(:random_value){rand(11111111111).to_s}
7
+ let(:expired_token){'Duy-M5FktALawBJ7dZN94s6hLEgLGKXC_j7cCqlDUMXRGw2shqHYbR9Zud_19EBtFkSCbJ0ZmrZ_d0ieBqgR'}
8
+
9
+ def error_with_status(status)
10
+ # mock / stub did not work...
11
+ $the_status = status
12
+ http = ""
13
+ def http.error?; true; end
14
+ def http.body; "<status>#{$the_status}</status>"; end
15
+ def http.code; 500; end
16
+ Savon::HTTP::Error.new(http)
17
+ end
18
+
19
+ # updates need some time to finish on the server...
20
+ def wait_for_job_to_finish
21
+ client.wait_for_job_to_finish yield
22
+ end
23
+
24
+ def reset_email
25
+ email = client.find(changeable_user[:member_id])[:email]
26
+ wait_for_job_to_finish do
27
+ client.update(:email_was => email, :email => changeable_user[:email])
28
+ end
29
+ email = client.find(changeable_user[:member_id])[:email]
30
+ email.should == changeable_user[:email]
31
+ end
32
+
33
+ def steady_fields(hash)
34
+ hash.select{|k,v| [:email, :member_id, :firstname, :lastname].include?(k) }
35
+ end
36
+
37
+ let(:config){YAML.load(File.read('spec/account.yml'))[:member]}
38
+ let(:client){EmailVision::Member.new(config)}
39
+ let(:findable_user) do
40
+ data = config[:findable_user]
41
+ [:datejoin, :dateunjoin].each do |field|
42
+ data[field] = DateTime.parse(data[field].to_s) if data[field]
43
+ end
44
+ data
45
+ end
46
+ let(:changeable_user){config[:changeable_user]}
47
+
48
+ it "has a VERSION" do
49
+ EmailVision::VERSION.should =~ /^\d+\.\d+\.\d+$/
50
+ end
51
+
52
+ it "can call more than one method" do
53
+ first = client.find(findable_user[:email])
54
+ first.should == client.find(findable_user[:email])
55
+ end
56
+
57
+ it "can reconnect when token is expired" do
58
+ client.instance_variable_set('@token', expired_token)
59
+ client.instance_variable_set('@token_requested', Time.now.to_i - EmailVision::BaseClient::SESSION_TIMEOUT - 10)
60
+ client.find(findable_user[:email])[:email].should == findable_user[:email]
61
+ end
62
+
63
+ describe :find do
64
+ it "can find by email" do
65
+ response = client.find(findable_user[:email])
66
+ steady_fields(response).should == steady_fields(findable_user)
67
+ end
68
+
69
+ it "can find by id" do
70
+ response = client.find(findable_user[:member_id])
71
+ steady_fields(response).should == steady_fields(findable_user)
72
+ end
73
+
74
+ it "can find first users of multiple that have the same email" do
75
+ client.should_receive(:execute_by_email_or_id).and_return [{:attributes=>{:entry=>[{:key=>"firstname",:value=>'yyy'}]}},{:attributes=>{:entry=>[{:key=>"firstname",:value=>'zzz'}]}}]
76
+ response = client.find('foo@bar.com')
77
+ steady_fields(response).should == {:firstname => 'yyy'}
78
+ end
79
+
80
+ it "is nil when nothing was found" do
81
+ client.find('foo@bar.baz').should == nil
82
+ end
83
+ end
84
+
85
+ describe 'error handling' do
86
+ before do
87
+ @connection = client.send(:connection)
88
+ client.stub!(:connection).and_return @connection
89
+ end
90
+
91
+ it "retries if it failed due to session timeout" do
92
+ error = error_with_status("CHECK_SESSION_FAILED")
93
+ @connection.should_receive(:request).exactly(2).and_raise(error)
94
+ lambda{
95
+ client.find('aaaa')
96
+ }.should raise_error#(error)
97
+ end
98
+
99
+ it "retries if it failed due to maximum request per session" do
100
+ error = error_with_status("SESSION_RETRIEVING_FAILED")
101
+ @connection.should_receive(:request).exactly(2).and_raise(error)
102
+ lambda{
103
+ client.find('aaaa')
104
+ }.should raise_error#(error)
105
+ end
106
+
107
+ it "does not retry if it failed otherwise" do
108
+ error = error_with_status("FOO_BAR")
109
+ @connection.should_receive(:request).exactly(1).and_raise(error)
110
+ lambda{
111
+ client.find('aaaa')
112
+ }.should raise_error#(error)
113
+ end
114
+ end
115
+
116
+ describe :update do
117
+ it "can update an attribute" do
118
+ wait_for_job_to_finish do
119
+ client.update(
120
+ :email => changeable_user[:email],
121
+ :firstname => random_value,
122
+ :lastname => random_value
123
+ )
124
+ end
125
+
126
+ data = client.find(changeable_user[:email])
127
+ data[:firstname].should == random_value
128
+ data[:lastname].should == random_value
129
+
130
+ # it does not overwrite other attributes
131
+ data[:country].should == changeable_user[:country]
132
+ end
133
+
134
+ it "can update a Time" do
135
+ time = Time.now
136
+ wait_for_job_to_finish do
137
+ client.update(:email => changeable_user[:email], :dateofbirth => time)
138
+ end
139
+ data = client.find(changeable_user[:email])
140
+ data[:dateofbirth].strftime('%s').to_i.should == time.to_i
141
+ end
142
+
143
+ it "can update a Date" do
144
+ time = Date.new(2010, 5,1)
145
+ wait_for_job_to_finish do
146
+ client.update(:email => changeable_user[:email], :dateofbirth => time)
147
+ end
148
+ data = client.find(changeable_user[:email])
149
+ data[:dateofbirth].strftime('%s').to_i.should == 1272664800
150
+ end
151
+
152
+ it "can remove dateunjoin" do
153
+ pending
154
+ wait_for_job_to_finish do
155
+ client.unjoin(changeable_user[:email])
156
+ end
157
+ wait_for_job_to_finish do
158
+ client.update(:email => changeable_user[:email], :dateunjoin => 'NULL')
159
+ end
160
+ data = client.find(changeable_user[:email])
161
+ data[:dateunjoin].should == nil
162
+ end
163
+
164
+ it "returns a job id" do
165
+ job_id = client.update(:email => changeable_user[:email], :firstname => random_value)
166
+ client.job_status(job_id).should == 'Insert'
167
+ end
168
+
169
+ it "updates the email" do
170
+ begin
171
+ wait_for_job_to_finish do
172
+ client.update(:email_was => changeable_user[:email], :email => email)
173
+ end
174
+ client.find(email)[:email].should == email
175
+ ensure
176
+ reset_email
177
+ end
178
+ end
179
+ end
180
+
181
+ describe :create_or_update do
182
+ it "can create a record" do
183
+ wait_for_job_to_finish do
184
+ client.create_or_update(:email => email, :firstname => 'first-name')
185
+ end
186
+ data = client.find(email)
187
+ data[:firstname].should == 'first-name'
188
+ end
189
+
190
+ it "can update a record" do
191
+ wait_for_job_to_finish do
192
+ client.create_or_update(:email => changeable_user[:email], :firstname => random_value)
193
+ end
194
+ data = client.find(changeable_user[:email])
195
+ data[:firstname].should == random_value
196
+ end
197
+ end
198
+
199
+ describe :create do
200
+ it "can create a record" do
201
+ wait_for_job_to_finish do
202
+ client.create(:email => email, :firstname => 'first-name')
203
+ end
204
+ data = client.find(email)
205
+ data[:firstname].should == 'first-name'
206
+ end
207
+ end
208
+
209
+ describe :columns do
210
+ it "can read them" do
211
+ data = client.columns
212
+ data[:dateunjoin].should == :date
213
+ end
214
+ end
215
+
216
+ describe :unjoin do
217
+ it "can unjoin a member" do
218
+ wait_for_job_to_finish do
219
+ client.unjoin(changeable_user[:email])
220
+ end
221
+ date = client.find(changeable_user[:email])[:dateunjoin]
222
+ date.is_a?(DateTime).should == true
223
+ Time.parse(date.to_s).should be_within(40).of(Time.now)
224
+ end
225
+ end
226
+
227
+ describe :rejoin do
228
+ it "can rejoin a member" do
229
+ wait_for_job_to_finish do
230
+ client.rejoin(changeable_user[:email])
231
+ end
232
+ date = client.find(changeable_user[:email])[:datejoin]
233
+ date.is_a?(DateTime).should == true
234
+ Time.parse(date.to_s).should be_within(40).of(Time.now)
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,208 @@
1
+ require 'spec_helper'
2
+
3
+ describe "EmailVision" do
4
+ describe "Message" do
5
+ let(:config) { YAML.load(File.read('spec/account.yml'))[:message] }
6
+ let(:client) { EmailVision::Message.new(config) }
7
+ let(:findable_message) { config[:findable_email_message] }
8
+ let(:findable_id) { findable_message[:id] }
9
+
10
+ context "finding message" do
11
+ it "finds by id" do
12
+ message = client.find(findable_message[:id])
13
+ message.should_not be_nil
14
+ end
15
+
16
+ it "finds serveral times" do
17
+ message = client.find(findable_id)
18
+ message.should == client.find(findable_id)
19
+ end
20
+
21
+ it "returns nil for message not found" do
22
+ client.find("-123").should be_nil
23
+ end
24
+
25
+ it "raises soap fault for invalid input" do
26
+ lambda { client.find("invalid input") }.should raise_error Savon::SOAP::Fault, /Unmarshalling Error/
27
+ end
28
+ end
29
+
30
+ context "finding messages by period" do
31
+ let(:message) { client.find(findable_id) }
32
+
33
+ it "finds findable message" do
34
+ from = message[:create_date]
35
+ to = message[:create_date] + 1
36
+ client.find_all_by_period(from, to).should include(findable_id)
37
+ end
38
+
39
+ it "no messages found in future" do
40
+ from = Time.now + 1
41
+ to = Time.now + 2
42
+ client.find_all_by_period(from, to).should == []
43
+ end
44
+ end
45
+
46
+ context "creating message" do
47
+ let(:attributes) do
48
+ {
49
+ :name => "test message #{Time.now}",
50
+ :body => "[EMV TEXTPART]test body",
51
+ :reply_to_email => "reply@example.com"
52
+ }
53
+ end
54
+
55
+ context "successfully" do
56
+ before(:all) { @message_id = client.create(attributes) }
57
+ let(:message_id) { @message_id }
58
+ let(:message) { client.find(message_id) }
59
+ after(:all) { client.delete(message_id) }
60
+
61
+ it "has attributes set" do
62
+ message[:name].should == attributes[:name]
63
+ message[:body].should == attributes[:body]
64
+ message[:reply_to_email].should == attributes[:reply_to_email]
65
+ end
66
+
67
+ it "has UTF-8 by default" do
68
+ attributes[:encoding].should be_nil
69
+ message[:encoding].should == "UTF-8"
70
+ end
71
+
72
+ it "overrides encoding" do
73
+ message_id = client.create(attributes.merge(:encoding => "iso-8859-15"))
74
+ message = client.find(message_id)
75
+ message[:encoding].should == "iso-8859-15"
76
+ end
77
+
78
+ it "uses HTML only" do
79
+ body = "[EMV HTMLPART]<b>bold</b>"
80
+ message_id = client.create(attributes.merge(:body => body))
81
+ message = client.find(message_id)
82
+ message[:body].should == body
83
+ end
84
+
85
+ it "is an email" do
86
+ message[:type].should == "email"
87
+ end
88
+ end
89
+
90
+ it "needs a name" do
91
+ client.create(attributes.merge(:name => nil)).should be_nil
92
+ end
93
+
94
+ it "needs a body" do
95
+ client.create(attributes.merge(:body => nil)).should be_nil
96
+ end
97
+
98
+ it "needs a body with emv tag" do
99
+ client.create(attributes.merge(:body => "no emv tag")).should be_nil
100
+ end
101
+
102
+ it "needs a reply_to_email" do
103
+ client.create(attributes.merge(:reply_to_email => nil)).should be_nil
104
+ end
105
+ end
106
+
107
+ context "cloning message" do
108
+ let(:uniq_attributes) { [:id, :name, :create_date] }
109
+ let(:message) { client.find(findable_id) }
110
+ let(:clone_name) { "clone of #{message[:name]}" }
111
+
112
+ before(:all) { @clone = client.find(client.clone(message[:id], clone_name)) }
113
+ let(:clone) { @clone }
114
+ after(:all) { client.delete(@clone[:id]) }
115
+
116
+ it "has different id" do
117
+ clone[:id].should_not == message[:id]
118
+ end
119
+
120
+ it "has different name" do
121
+ clone[:name].should == clone_name
122
+ end
123
+
124
+ it "has different create date" do
125
+ clone[:create_date].should_not == message[:create_date]
126
+ end
127
+
128
+ it "has cloned non-uniq attributes" do
129
+ (clone.keys - uniq_attributes).each do |attr|
130
+ clone[attr].should == message[attr]
131
+ end
132
+ end
133
+ end
134
+
135
+ context "deleting message" do
136
+ it "returns true for successful delete" do
137
+ clone_id = client.clone(findable_message[:id], "delete me")
138
+ client.delete(clone_id).should == true
139
+ client.find(clone_id).should be_nil
140
+ end
141
+
142
+ it "returns false for undeletable message" do
143
+ client.delete("-123").should == false
144
+ end
145
+ end
146
+
147
+ context "updating message" do
148
+ before(:all) { @message = client.find(client.clone(findable_id, "test update")) }
149
+ let(:message) { @message }
150
+ after(:all) { client.delete(@message[:id]) }
151
+
152
+ let(:random_name) { "test update #{Time.now.to_f}" }
153
+
154
+ it "updates name passing message hash" do
155
+ message[:name] = random_name
156
+ client.update(message).should == true
157
+ client.find(message[:id])[:name].should == random_name
158
+ end
159
+
160
+ it "updates name passing only id and name" do
161
+ client.update(:id => message[:id], :name => random_name).should == true
162
+ client.find(message[:id])[:name].should == random_name
163
+ end
164
+
165
+ it "fails for invalid id" do
166
+ client.update(:id => "-123").should == false
167
+ end
168
+ end
169
+
170
+ context "testing message" do
171
+ let(:member_id) { config[:findable_user][:member_id] }
172
+
173
+ it "sends a test message to member" do
174
+ client.test(findable_id, member_id, :subject => subject).should == true
175
+ end
176
+
177
+ it "refuses to send a test message for invalid message" do
178
+ client.test("-123", member_id).should == false
179
+ end
180
+
181
+ it "returns true even for an invalid member_id" do
182
+ client.test(findable_id, "-123").should == true
183
+ end
184
+
185
+ it "sends a test message with an empty subject" do
186
+ client.test(findable_id, member_id, :subject => nil).should == true
187
+ end
188
+
189
+ it "sends a test html message" do
190
+ client.test(findable_id, member_id, :subject => subject("pure html"), :part => "HTML").should == true
191
+ end
192
+
193
+ it "sends a test text message" do
194
+ client.test(findable_id, member_id, :subject => subject("pure text"), :part => "TEXT").should == true
195
+ end
196
+
197
+ it "sends a test multipart message" do
198
+ client.test(findable_id, member_id, :subject => subject("multipart test"), :part => "MULTIPART").should == true
199
+ end
200
+
201
+ private
202
+
203
+ def subject(addon="")
204
+ "[TEST] spec run on #{Time.now} #{addon}"
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH << 'lib'
2
+
3
+ require 'rubygems'
4
+ require 'yaml'
5
+ require 'email_vision'
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: email_vision-neopoly
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael Grosser
9
+ - Peter Suschlik
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-05-04 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: savon
17
+ requirement: &18651300 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 0.8.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *18651300
26
+ - !ruby/object:Gem::Dependency
27
+ name: savon
28
+ requirement: &18650760 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *18650760
37
+ description:
38
+ email: ps@neopoly.de
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - Gemfile
44
+ - Gemfile.lock
45
+ - Rakefile
46
+ - Readme.md
47
+ - VERSION
48
+ - email_vision-neopoly.gemspec
49
+ - lib/email_vision.rb
50
+ - lib/email_vision/base_client.rb
51
+ - lib/email_vision/campaign.rb
52
+ - lib/email_vision/member.rb
53
+ - lib/email_vision/message.rb
54
+ - spec/account.yml.example
55
+ - spec/email_vision_campaign_spec.rb
56
+ - spec/email_vision_member_spec.rb
57
+ - spec/email_vision_message_spec.rb
58
+ - spec/spec_helper.rb
59
+ homepage: http://github.com/neopoly/email_vision-neopoly
60
+ licenses: []
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 1.8.17
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Ruby SOAP Api Client for EmailVision / CampaignCommander
83
+ test_files: []