email_vision-neopoly 0.3.0

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.
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: []