expertsender_api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 38a52cdaf7f8d15625b76d4fa4032729a903b341
4
+ data.tar.gz: a3a9ff5795c99eb610e10977d5e3996ce0ff3bb7
5
+ SHA512:
6
+ metadata.gz: 5d995b6cafc6e7208646554f105861909c3401e160cb1e80ecfe28079415881374e64ac1a61a6b05bd6e8fbd010bcbed0e8d6bfb9adadc8babb861e8905e7878
7
+ data.tar.gz: 68e2f8414cf3d93a119c8f93ac8d5941df52d9c7b6acd147812dd7086c1b240849e94005d01a4f9ecd562c79aa0b963f5ad8b4b6b8366c03e57613b26fa27d47
@@ -0,0 +1,14 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile ~/.gitignore_global
6
+
7
+ # Ignore bundler config
8
+ /.bundle
9
+ /Gemfile.lock
10
+ /gems
11
+ /tags
12
+
13
+ *.swp
14
+ .ruby-version
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,3 @@
1
+ # ExpertSenderApi
2
+
3
+ ExpertSenderApi is an API wrapper for ExpertSender's [API](https://sites.google.com/a/expertsender.com/api-documentation-russian).
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubygems/specification'
4
+ require 'bundler/gem_tasks'
5
+
6
+ task :default => :spec
7
+ desc "Run specs"
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.pattern = FileList['spec/**/*_spec.rb']
10
+ t.rspec_opts = %w(-fs --color)
11
+ end
@@ -0,0 +1,26 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "expertsender_api"
5
+ s.version = "0.0.1"
6
+ s.authors = ["kinderly"]
7
+ s.email = ["beorc@httplab.ru"]
8
+ s.homepage = "http://github.com/kinderly/expertsender_api"
9
+
10
+ s.summary = %q{A wrapper for ExpertSender API}
11
+ s.description = %q{A wrapper for ExpertSender API}
12
+ s.license = "MIT"
13
+
14
+ s.rubyforge_project = "expertsender_api"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency('httparty')
22
+ s.add_dependency('nokogiri')
23
+
24
+ s.add_development_dependency 'rake'
25
+ s.add_development_dependency "rspec"
26
+ end
@@ -0,0 +1,22 @@
1
+ require 'httparty'
2
+ require 'nokogiri'
3
+ require 'cgi'
4
+
5
+ require 'expertsender_api/email'
6
+ require 'expertsender_api/concerns/serializeable'
7
+
8
+ require 'expertsender_api/subscriber'
9
+ require 'expertsender_api/subscriber/tag'
10
+ require 'expertsender_api/subscriber/property'
11
+ require 'expertsender_api/email/recipients'
12
+ require 'expertsender_api/email/receiver'
13
+ require 'expertsender_api/email/content'
14
+ require 'expertsender_api/email/snippet'
15
+ require 'expertsender_api/result'
16
+ require 'expertsender_api/expertsender_error'
17
+
18
+ require 'expertsender_api/api'
19
+
20
+
21
+ module ExpertSenderApi
22
+ end
@@ -0,0 +1,190 @@
1
+ module ExpertSenderApi
2
+ class API
3
+ include HTTParty
4
+
5
+ class << self
6
+ attr_accessor :api_key, :api_endpoint, :throws_exceptions
7
+ end
8
+
9
+ attr_accessor :api_key, :api_endpoint, :throws_exceptions
10
+
11
+ SUBSCRIBER_INFO_OPTION_SHORT = 1
12
+ SUBSCRIBER_INFO_OPTION_MEDIUM = 2
13
+ SUBSCRIBER_INFO_OPTION_FULL = 3
14
+
15
+ XML_NAMESPACES = { 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
16
+ 'xmlns:xs' => 'http://www.w3.org/2001/XMLSchema' }
17
+
18
+ def initialize(key: nil, **parameters)
19
+ @api_key = key || self.class.api_key || ENV['EXPERTSENDER_API_KEY']
20
+ @api_key = @api_key.strip if @api_key
21
+
22
+ @throws_exceptions = parameters.has_key?(:throws_exceptions) ? parameters.delete(:throws_exceptions) : self.class.throws_exceptions
23
+ @api_endpoint = parameters.delete(:api_endpoint) || self.class.api_endpoint
24
+
25
+ unless api_endpoint.nil?
26
+ @subscribers_url = api_endpoint + '/Api/Subscribers'
27
+ @removed_subscribers_url = api_endpoint + '/Api/RemovedSubscribers'
28
+ @newsletters_url = api_endpoint + '/Api/Newsletters'
29
+ @transactionals_url = api_endpoint + '/Api/Transactionals'
30
+ end
31
+ end
32
+
33
+ def add_subscriber_to_list(subscriber)
34
+ add_subscribers_to_list([subscriber])
35
+ end
36
+
37
+ def add_subscribers_to_list(subscribers)
38
+ builder = Nokogiri::XML::Builder.new do |xml|
39
+ xml.ApiRequest(XML_NAMESPACES) {
40
+ xml.ApiKey api_key
41
+ xml.MultiData {
42
+ subscribers.each { |subscriber| subscriber.insert_to(xml) }
43
+ }
44
+ }
45
+ end
46
+
47
+ xml = builder.to_xml save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
48
+ response = self.class.post(@subscribers_url, body: xml)
49
+
50
+ handle_response(response)
51
+ end
52
+
53
+ def remove_subscriber_from_list(options)
54
+ email = options.delete :email
55
+ id = options.delete :id
56
+
57
+ response = id.nil? ? remove_subscriber_by_email(email, options) : remove_subscriber_by_id(id, options)
58
+
59
+ handle_response(response)
60
+ end
61
+
62
+ def get_subscriber_info(option: SUBSCRIBER_INFO_OPTION_FULL, email: nil)
63
+ params = { apiKey: api_key, email: email, option: option }
64
+
65
+ response = self.class.get(@subscribers_url, query: params)
66
+
67
+ handle_response(response)
68
+ end
69
+
70
+ def update_subscriber(email, subscriber)
71
+ result = get_subscriber_info(email: email)
72
+
73
+ return result if result.failed?
74
+
75
+ expertsender_id = result.parsed_response.xpath('//Data/Id').text
76
+ list_ids = result.parsed_response.xpath('//StateOnList/ListId').map(&:text)
77
+
78
+ subscriber.id = expertsender_id
79
+
80
+ list_ids.each do |list_id|
81
+ subscriber.list_id = list_id
82
+ res = add_subscriber_to_list(subscriber)
83
+ end
84
+
85
+ result
86
+ end
87
+
88
+ def add_or_update_subscriber(email, subscriber)
89
+ result = update_subscriber(email, subscriber)
90
+
91
+ return add_subscriber_to_list(subscriber) if result.failed?
92
+
93
+ result
94
+ end
95
+
96
+ def create_and_send_email(options)
97
+ recipients = options.delete :recipients
98
+ content = options.delete :content
99
+
100
+ builder = Nokogiri::XML::Builder.new do |xml|
101
+ xml.ApiRequest(XML_NAMESPACES) {
102
+ xml.ApiKey api_key
103
+ xml.Data {
104
+ recipients.insert_to xml
105
+ content.insert_to xml
106
+ }
107
+ }
108
+ end
109
+
110
+ xml = builder.to_xml save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
111
+ response = self.class.post(@newsletters_url, body: xml)
112
+
113
+ handle_response(response)
114
+ end
115
+
116
+ def send_transaction_email(options)
117
+ letter_id = options.delete :letter_id
118
+ receiver = options.delete :receiver
119
+ snippets = options.delete :snippets
120
+
121
+ builder = Nokogiri::XML::Builder.new do |xml|
122
+ xml.ApiRequest(XML_NAMESPACES) {
123
+ xml.ApiKey api_key
124
+ xml.Data {
125
+ receiver.insert_to xml
126
+ if snippets.any?
127
+ xml.Snippets {
128
+ snippets.each { |snippet| snippet.insert_to(xml) }
129
+ }
130
+ end
131
+ }
132
+ }
133
+ end
134
+
135
+ xml = builder.to_xml save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
136
+ response = self.class.post("#{@transactionals_url}/#{letter_id}", body: xml)
137
+
138
+ handle_response(response)
139
+ end
140
+
141
+ def get_deleted_subscribers(options = {})
142
+ params = { apiKey: api_key }
143
+
144
+ list_ids = options[:list_ids]
145
+ remove_types = options[:remove_types]
146
+ start_date = options[:start_date]
147
+ end_date = options[:end_date]
148
+
149
+ params[:listIds] = list_ids.join(',') if list_ids.respond_to?(:any?)
150
+ params[:removeTypes] = remove_types.join(',') if remove_types.respond_to?(:any?)
151
+ params[:startDate] = start_date.to_s unless start_date.nil?
152
+ params[:endDate] = end_date.to_s unless end_date.nil?
153
+
154
+ response = self.class.get(@removed_subscribers_url, query: params)
155
+
156
+ handle_response(response)
157
+ end
158
+
159
+ private
160
+
161
+ def handle_response(response)
162
+ result = Result.new(response)
163
+
164
+ if should_raise_for_response?(result)
165
+ error = ExpertSenderError.new("ExpertSender API Error: #{result.error_message} (code #{result.error_code})")
166
+ error.code = result.error_code
167
+ raise error
168
+ end
169
+
170
+ result
171
+ end
172
+
173
+ def should_raise_for_response?(result)
174
+ @throws_exceptions and result.failed?
175
+ end
176
+
177
+ def remove_subscriber_by_email(email, options = {})
178
+ params = options.merge({ apiKey: api_key, email: email })
179
+
180
+ self.class.delete(@subscribers_url, query: params)
181
+ end
182
+
183
+ def remove_subscriber_by_id(id, options = {})
184
+ params = options.merge({ apiKey: api_key })
185
+
186
+ self.class.delete("#{@subscribers_url}/#{id}", query: params)
187
+ end
188
+ end
189
+ end
190
+
@@ -0,0 +1,21 @@
1
+ module ExpertSenderApi
2
+ module Serializeable
3
+
4
+ private
5
+
6
+ def attributes
7
+ variables_to_serialize.map do |ivar|
8
+ { name: camel_case(ivar.to_s[1..-1]), value: instance_variable_get(ivar) }
9
+ end
10
+ end
11
+
12
+ def camel_case(str)
13
+ str.split(/[\W_]/).map {|c| c.capitalize}.join
14
+ end
15
+
16
+ def variables_to_serialize
17
+ instance_variables
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,5 @@
1
+ module ExpertSenderApi
2
+ module Email
3
+ end
4
+ end
5
+
@@ -0,0 +1,23 @@
1
+ module ExpertSenderApi::Email
2
+ class Content
3
+ include ::ExpertSenderApi::Serializeable
4
+
5
+ attr_accessor :from_name, :from_email, :reply_to_name, :reply_to_email,
6
+ :subject, :html, :plain
7
+
8
+ def initialize(parameters = {})
9
+ parameters.each { |key, value| send("#{key}=", value) }
10
+ end
11
+
12
+ def insert_to(xml)
13
+ xml.Content {
14
+ attributes.each do |attr|
15
+ xml.send(attr[:name], attr[:value]) unless attr[:value].nil?
16
+ end
17
+ }
18
+ end
19
+ end
20
+ end
21
+
22
+
23
+
@@ -0,0 +1,22 @@
1
+ module ExpertSenderApi::Email
2
+ class Receiver
3
+ include ::ExpertSenderApi::Serializeable
4
+ attr_accessor :id, :email, :list_id
5
+
6
+ def initialize(parameters = {})
7
+ parameters.each { |key, value| send("#{key}=", value) }
8
+ end
9
+
10
+ def insert_to(xml)
11
+ xml.Receiver {
12
+ attributes.each do |attr|
13
+ xml.send(attr[:name], attr[:value]) unless attr[:value].nil?
14
+ end
15
+ }
16
+ end
17
+ end
18
+ end
19
+
20
+
21
+
22
+
@@ -0,0 +1,23 @@
1
+ module ExpertSenderApi::Email
2
+ class Recipients
3
+ attr_accessor :subscriber_lists
4
+
5
+ def initialize(subscriber_lists: [])
6
+ @subscriber_lists = subscriber_lists
7
+ end
8
+
9
+ def insert_to(xml)
10
+ xml.Recipients {
11
+ if subscriber_lists.any?
12
+ xml.SubscriberLists {
13
+ subscriber_lists.each do |list_id|
14
+ xml.SubscriberList list_id
15
+ end
16
+ }
17
+ end
18
+ }
19
+ end
20
+ end
21
+ end
22
+
23
+
@@ -0,0 +1,27 @@
1
+ module ExpertSenderApi::Email
2
+ class Snippet
3
+ attr_accessor :name, :value, :cdata
4
+
5
+ def initialize(name: nil, value: nil, cdata: true)
6
+ @name = name
7
+ @value = value
8
+ @cdata = cdata
9
+ end
10
+
11
+ def insert_to(xml)
12
+ if !name.empty? and !value.empty?
13
+ xml.Snippet {
14
+ xml.Name name
15
+ if cdata
16
+ xml.Value { xml.cdata value }
17
+ else
18
+ xml.Value value
19
+ end
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+
27
+
@@ -0,0 +1,5 @@
1
+ module ExpertSenderApi
2
+ class ExpertSenderError < StandardError
3
+ attr_accessor :code
4
+ end
5
+ end
@@ -0,0 +1,64 @@
1
+ module ExpertSenderApi
2
+ class Result
3
+ attr_reader :response, :parsed_response, :error_code, :error_message
4
+
5
+ def initialize(response)
6
+ @response = response
7
+
8
+ if (@response.body)
9
+ @parsed_response = Nokogiri::XML(@response.body)
10
+
11
+ if @parsed_response.xpath('//ErrorMessage').any?
12
+ @error_message = @parsed_response.xpath('//ErrorMessage/Message').text
13
+ @error_code = @parsed_response.xpath('//ErrorMessage/Code').text
14
+ end
15
+ end
16
+
17
+ freeze
18
+ end
19
+
20
+ def success?
21
+ status_success? and
22
+ error_code.nil? and
23
+ error_message.nil?
24
+ end
25
+
26
+ def failed?
27
+ not success?
28
+ end
29
+
30
+ def status_success?
31
+ response.code == 200 or
32
+ response.code == 201 or
33
+ response.code == 202
34
+ end
35
+ end
36
+ end
37
+
38
+
39
+ clients=Client.joins(:childs).
40
+ where("clients.created_at > '2014-01-13 00:00:00.000000' and clients.created_at < '2014-01-13 23:59:59.999999'").
41
+ where(synchronized: false).
42
+ where('children.client_id is not null')
43
+ not_subscribed_clients = []
44
+ clients.each do |c|
45
+ si = account.expertsender.get_subscriber_info email: c.email
46
+ subscribed = si.parsed_response.css('StateOnList').
47
+ select { |e| e.css('ListId').text.to_i == 2 && e.css('Status').text == 'Active' }.size == 1
48
+ p "Client: #{c.email}, sync: #{c.synchronized}, uns: #{c.unsubscribed}, registered: #{c.registered}, MainList: #{subscribed}"
49
+ not_subscribed_clients.push c unless subscribed
50
+ end;nil
51
+ p "Subscribed: #{clients.count - not_subscribed_clients.size}/#{clients.count}"
52
+
53
+ orders = OrderChange.where("created_at > '2014-01-13 00:00:00.000000' and created_at < '2014-01-13 23:59:59.999999'").map(&:order)
54
+ ios = []
55
+ no_ios = []
56
+ orders.each do |o|
57
+ begin
58
+ io = InsalesApi::Order.find o.insales_order_id
59
+ ios << io
60
+ rescue => e
61
+ p e
62
+ no_ios << o
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ module ExpertSenderApi
2
+ module Subscriber
3
+ end
4
+ end
5
+
@@ -0,0 +1,27 @@
1
+ module ExpertSenderApi::Subscriber
2
+ class Property
3
+ attr_accessor :id, :value, :type
4
+
5
+ TYPE_INTEGER = 'int'
6
+ TYPE_STRING = 'string'
7
+ TYPE_DATE = 'date'
8
+ TYPE_DATE_TIME = 'dateTime'
9
+
10
+ def initialize(id: nil, value: nil, type: TYPE_STRING)
11
+ @id = id
12
+ @value = value
13
+ @type = type
14
+ end
15
+
16
+ def insert_to(xml)
17
+ xml.Property {
18
+ xml.Id id
19
+ xml.Value value, 'xsi:type' => "xs:#{type}"
20
+ }
21
+ end
22
+ end
23
+ end
24
+
25
+
26
+
27
+
@@ -0,0 +1,47 @@
1
+ module ExpertSenderApi::Subscriber
2
+ class Tag
3
+ include ::ExpertSenderApi::Serializeable
4
+
5
+ MODE_ADD_AND_UPDATE = 'AddAndUpdate'
6
+ MODE_ADD_AND_REPLACE = 'AddAndReplace'
7
+ MODE_ADD_AND_IGNORE = 'AddAndIgnore'
8
+ MODE_IGNORE_AND_UPDATE = 'IgnoreAndUpdate'
9
+ MODE_IGNORE_AND_REPLACE = 'IgnoreAndReplace'
10
+
11
+ class << self
12
+ attr_accessor :mode, :force, :list_id
13
+ end
14
+
15
+ attr_accessor :mode, :force, :list_id, :id, :email, :firstname, :lastname,
16
+ :tracking_code, :name, :vendor, :ip, :properties
17
+
18
+ def initialize(mode: MODE_ADD_AND_UPDATE, **parameters)
19
+ @mode = mode || self.class.mode
20
+ @force = parameters[:force] || self.class.force
21
+ @list_id = parameters[:list_id] || self.class.list_id
22
+ @properties = parameters.delete(:properties) || []
23
+
24
+ parameters.each { |key, value| send("#{key}=", value) }
25
+ end
26
+
27
+ def insert_to(xml)
28
+ xml.Subscriber {
29
+ attributes.each do |attr|
30
+ xml.send(attr[:name], attr[:value]) unless attr[:value].nil?
31
+ end
32
+ if properties.any?
33
+ xml.Properties {
34
+ properties.each { |property| property.insert_to(xml) }
35
+ }
36
+ end
37
+ }
38
+ end
39
+
40
+ private
41
+
42
+ def variables_to_serialize
43
+ instance_variables.select { |var| var != :@properties }
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,232 @@
1
+ require 'spec_helper'
2
+
3
+ describe ExpertSenderApi::API do
4
+ let(:api_key) { "123-us1" }
5
+ let(:api_endpoint) { 'https://api2.esv2.com' }
6
+
7
+ let(:subscribers) { [ExpertSenderApi::Subscriber::Tag.new(subscriber_attributes)] }
8
+ let(:subscriber_attributes) { { id: 1, list_id: 52, email: "test@httplab.ru" } }
9
+ let(:subscribers_url) { "#{api_endpoint}/Api/Subscribers" }
10
+
11
+ let(:recipients) { ExpertSenderApi::Email::Recipients.new(recipients_attributes) }
12
+ let(:recipients_attributes) { { subscriber_lists: [52, 53] } }
13
+
14
+ let(:content) { ExpertSenderApi::Email::Content.new(content_attributes) }
15
+ let(:content_attributes) { { from_name: 'From Name Test',
16
+ from_email: 'test@httplab.ru',
17
+ reply_to_name: 'Reply To Name Test',
18
+ reply_to_email: 'Reply To Email Test',
19
+ subject: 'Subject test',
20
+ plain: 'Plain Test Content' } }
21
+
22
+ let(:receiver) { ExpertSenderApi::Email::Receiver.new(receiver_attributes) }
23
+ let(:receiver_attributes) { { id: 123,
24
+ email: 'test@test.ru',
25
+ list_id: 53 } }
26
+
27
+ let(:snippets) { [ExpertSenderApi::Email::Snippet.new(snippet_attributes)] }
28
+ let(:snippet_attributes) { { name: 'Test snippet name',
29
+ value: 'Test snippet value' } }
30
+ describe "attributes" do
31
+ it "have no API key by default" do
32
+ having_env('EXPERTSENDER_API_KEY', nil) { @expertsender = ExpertSenderApi::API.new }
33
+ expect(@expertsender.api_key).to be_nil
34
+ end
35
+
36
+ it "set an API key in constructor" do
37
+ @expertsender = ExpertSenderApi::API.new(key: api_key)
38
+ expect(@expertsender.api_key).to eq(api_key)
39
+ end
40
+
41
+ it "set an API key from the 'EXPERTSENDER_API_KEY' ENV variable" do
42
+ having_env('EXPERTSENDER_API_KEY', api_key) { @expertsender = ExpertSenderApi::API.new }
43
+ expect(@expertsender.api_key).to eq(api_key)
44
+ end
45
+
46
+ it "set an API key via setter" do
47
+ @expertsender = ExpertSenderApi::API.new
48
+ @expertsender.api_key = api_key
49
+ expect(@expertsender.api_key).to eq(api_key)
50
+ end
51
+
52
+ it "detect api endpoint from initializer parameters" do
53
+ @expertsender = ExpertSenderApi::API.new(key: api_key, api_endpoint: api_endpoint)
54
+ expect(api_endpoint).to eq(@expertsender.api_endpoint)
55
+ end
56
+
57
+ it "sets the 'throws_exceptions' option from initializer parameters" do
58
+ @expertsender = ExpertSenderApi::API.new(key: api_key, throws_exceptions: false)
59
+ expect(false).to eq(@expertsender.throws_exceptions)
60
+ end
61
+ end
62
+
63
+ describe "ExpertSenderApi class variables" do
64
+ before do
65
+ ExpertSenderApi::API.api_key = "123-us1"
66
+ ExpertSenderApi::API.throws_exceptions = false
67
+ ExpertSenderApi::API.api_endpoint = api_endpoint
68
+ end
69
+
70
+ after do
71
+ ExpertSenderApi::API.api_key = nil
72
+ ExpertSenderApi::API.throws_exceptions = nil
73
+ ExpertSenderApi::API.api_endpoint = nil
74
+ end
75
+
76
+ it "set api key on new instances" do
77
+ expect(ExpertSenderApi::API.new.api_key).to eq(ExpertSenderApi::API.api_key)
78
+ end
79
+
80
+ it "set throws_exceptions on new instances" do
81
+ expect(ExpertSenderApi::API.new.throws_exceptions).to eq(ExpertSenderApi::API.throws_exceptions)
82
+ end
83
+
84
+ it "set api_endpoint on new instances" do
85
+ expect(ExpertSenderApi::API.api_endpoint).not_to be_nil
86
+ expect(ExpertSenderApi::API.new.api_endpoint).to eq(ExpertSenderApi::API.api_endpoint)
87
+ end
88
+ end
89
+
90
+ context 'when configured properly' do
91
+ subject { ExpertSenderApi::API.new key: api_key, api_endpoint: api_endpoint }
92
+
93
+ its '#add_subscribers_to_list calls post with correct body' do
94
+ builder = Nokogiri::XML::Builder.new do |xml|
95
+ xml.ApiRequest {
96
+ xml.ApiKey api_key
97
+ xml.MultiData {
98
+ subscribers.each { |subscriber| subscriber.insert_to(xml) }
99
+ }
100
+ }
101
+ end
102
+
103
+ xml = builder.to_xml save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
104
+
105
+ expect_post(subscribers_url, xml)
106
+ subject.add_subscribers_to_list(subscribers)
107
+ end
108
+
109
+ its '#remove_subscriber_from_list by id calls delete with correct parameters' do
110
+ expected_params = { apiKey: api_key,
111
+ listId: subscriber_attributes[:list_id] }
112
+ expect_delete("#{subscribers_url}/#{subscriber_attributes[:id]}", expected_params)
113
+
114
+ subject.remove_subscriber_from_list(id: subscriber_attributes[:id], listId: subscriber_attributes[:list_id])
115
+ end
116
+
117
+ its '#remove_subscriber_from_list by email returns success response' do
118
+ expected_params = { apiKey: api_key,
119
+ email: subscriber_attributes[:email],
120
+ listId: subscriber_attributes[:list_id] }
121
+ expect_delete(subscribers_url, expected_params)
122
+
123
+ subject.remove_subscriber_from_list(email: subscriber_attributes[:email], listId: subscriber_attributes[:list_id])
124
+ end
125
+
126
+ its '#get_subscriber_info calls get with correct parameters' do
127
+ expected_params = { apiKey: api_key,
128
+ email: subscriber_attributes[:email],
129
+ option: ExpertSenderApi::API::SUBSCRIBER_INFO_OPTION_FULL }
130
+ expect_get(subscribers_url, expected_params)
131
+
132
+ subject.get_subscriber_info(email: subscriber_attributes[:email])
133
+ end
134
+
135
+ its '#create_and_send_email calls post with correct body' do
136
+
137
+ builder = Nokogiri::XML::Builder.new do |xml|
138
+ xml.ApiRequest {
139
+ xml.ApiKey api_key
140
+ xml.Data {
141
+ recipients.insert_to xml
142
+ content.insert_to xml
143
+ }
144
+ }
145
+ end
146
+
147
+ xml = builder.to_xml save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
148
+
149
+ expect_post("#{api_endpoint}/Api/Newsletters", xml)
150
+ subject.create_and_send_email(recipients: recipients, content: content)
151
+ end
152
+
153
+ its '#send_transaction_email' do
154
+ letter_id = 93
155
+
156
+ builder = Nokogiri::XML::Builder.new do |xml|
157
+ xml.ApiRequest {
158
+ xml.ApiKey api_key
159
+ xml.Data {
160
+ receiver.insert_to xml
161
+ if snippets.any?
162
+ xml.Snippets {
163
+ snippets.each { |snippet| snippet.insert_to(xml) }
164
+ }
165
+ end
166
+ }
167
+ }
168
+ end
169
+
170
+ xml = builder.to_xml save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
171
+
172
+ expect_post("#{api_endpoint}/Api/Transactionals/#{letter_id}", xml)
173
+ subject.send_transaction_email(letter_id: letter_id,
174
+ receiver: receiver,
175
+ snippets: snippets)
176
+ end
177
+
178
+ its '#get_deleted_subscribers calls get with correct parameters' do
179
+ expected_params = { apiKey: api_key,
180
+ listIds: '52,53',
181
+ removeTypes: 'OptOutLink,Compliant,Ui',
182
+ startDate: Date.today.to_s,
183
+ endDate: Date.new(2090, 1, 1).to_s }
184
+
185
+ expect_get("#{api_endpoint}/Api/RemovedSubscribers", expected_params)
186
+
187
+ subject.get_deleted_subscribers(list_ids: [52, 53],
188
+ remove_types: ['OptOutLink', 'Compliant', 'Ui'],
189
+ start_date: Date.today,
190
+ end_date: Date.new(2090, 1, 1))
191
+ end
192
+ end
193
+
194
+ context 'when has wrong api key' do
195
+ subject { ExpertSenderApi::API.new key: 'wrong', api_endpoint: api_endpoint, throws_exceptions: true }
196
+
197
+ its '#add_subscribers_to_list raises exception' do
198
+ expect { subject.add_subscribers_to_list(subscribers) }.to raise_error(ExpertSenderApi::ExpertSenderError)
199
+ end
200
+ end
201
+
202
+ private
203
+
204
+ def having_env(key, value)
205
+ prev_value = ENV[key]
206
+ ENV[key] = value
207
+ yield
208
+ ENV[key] = prev_value
209
+ end
210
+
211
+ def expect_get(expected_url, expected_params)
212
+ ExpertSenderApi::API.should_receive(:get).with do |url, opts|
213
+ expect(url).to eq expected_url
214
+ expect(expected_params).to eq opts[:query]
215
+ end.and_return(Struct.new(:body).new(nil))
216
+ end
217
+
218
+ def expect_post(expected_url, expected_body)
219
+ ExpertSenderApi::API.should_receive(:post).with do |url, opts|
220
+ expect(url).to eq expected_url
221
+ expect(expected_body).to eq opts[:body]
222
+ end.and_return(Struct.new(:body).new(nil))
223
+ end
224
+
225
+ def expect_delete(expected_url, expected_params)
226
+ ExpertSenderApi::API.should_receive(:delete).with do |url, opts|
227
+ expect(url).to eq expected_url
228
+ expect(expected_params).to eq opts[:query]
229
+ end.and_return(Struct.new(:body).new(nil))
230
+ end
231
+ end
232
+
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe ExpertSenderApi::Email::Content do
4
+ context :with_valid_attributes do
5
+ let(:valid_attributes) { { from_name: 'From Name Test',
6
+ from_email: 'test@httplab.ru',
7
+ reply_to_name: 'Reply To Name Test',
8
+ reply_to_email: 'Reply To Email Test',
9
+ subject: 'Subject test',
10
+ html: 'Html Test Content',
11
+ plain: 'Plain Test Content' } }
12
+
13
+ subject do
14
+ ExpertSenderApi::Email::Content.new valid_attributes
15
+ end
16
+
17
+ it 'has proper attributes' do
18
+ valid_attributes.each do |key, value|
19
+ subject.send(key).should eq value
20
+ end
21
+ end
22
+
23
+ it 'generates proper markup' do
24
+ builder = Nokogiri::XML::Builder.new do |xml|
25
+ subject.insert_to(xml)
26
+ end
27
+
28
+ xml = Nokogiri::XML(builder.to_xml)
29
+
30
+ xml.xpath('//FromName').text.should eq valid_attributes[:from_name]
31
+ xml.xpath('//FromEmail').text.should eq valid_attributes[:from_email]
32
+ xml.xpath('//ReplyToName').text.should eq valid_attributes[:reply_to_name]
33
+ xml.xpath('//ReplyToEmail').text.should eq valid_attributes[:reply_to_email]
34
+ xml.xpath('//Subject').text.should eq valid_attributes[:subject]
35
+ xml.xpath('//Html').text.should eq valid_attributes[:html]
36
+ xml.xpath('//Plain').text.should eq valid_attributes[:plain]
37
+ end
38
+ end
39
+ end
40
+
41
+
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe ExpertSenderApi::Email::Receiver do
4
+ context :with_valid_attributes do
5
+ let(:valid_attributes) { { id: '777',
6
+ email: 'test@test.com',
7
+ list_id: '53' } }
8
+
9
+ subject do
10
+ ExpertSenderApi::Email::Receiver.new valid_attributes
11
+ end
12
+
13
+ it 'has proper attributes' do
14
+ subject.id.should eq valid_attributes[:id]
15
+ subject.email.should eq valid_attributes[:email]
16
+ subject.list_id.should eq valid_attributes[:list_id]
17
+ end
18
+
19
+ it 'generates proper markup' do
20
+ builder = Nokogiri::XML::Builder.new do |xml|
21
+ subject.insert_to(xml)
22
+ end
23
+
24
+ xml = Nokogiri::XML(builder.to_xml)
25
+
26
+ xml.xpath('//Receiver/Id').text.should eq valid_attributes[:id]
27
+ xml.xpath('//Receiver/Email').text.should eq valid_attributes[:email]
28
+ xml.xpath('//Receiver/ListId').text.should eq valid_attributes[:list_id]
29
+ end
30
+ end
31
+ end
32
+
33
+
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe ExpertSenderApi::Email::Recipients do
4
+ context :with_valid_attributes do
5
+ let(:valid_attributes) { { subscriber_lists: [53, 53] } }
6
+
7
+ subject do
8
+ ExpertSenderApi::Email::Recipients.new valid_attributes
9
+ end
10
+
11
+ it 'has proper attributes' do
12
+ valid_attributes.each do |key, value|
13
+ subject.send(key).should eq value
14
+ end
15
+ end
16
+
17
+ it 'generates proper markup' do
18
+ builder = Nokogiri::XML::Builder.new do |xml|
19
+ subject.insert_to(xml)
20
+ end
21
+
22
+ xml = Nokogiri::XML(builder.to_xml)
23
+
24
+ xml.xpath('//SubscriberLists/SubscriberList').map(&:text).should eq valid_attributes[:subscriber_lists].map(&:to_s)
25
+ end
26
+ end
27
+ end
28
+
29
+
30
+
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe ExpertSenderApi::Email::Snippet do
4
+ context :with_valid_attributes do
5
+ let(:valid_attributes) { { name: 'TestSnippetName',
6
+ value: 'TestSnippetValue' } }
7
+
8
+ subject do
9
+ ExpertSenderApi::Email::Snippet.new valid_attributes
10
+ end
11
+
12
+ it 'has proper attributes' do
13
+ subject.name.should eq valid_attributes[:name]
14
+ subject.value.should eq valid_attributes[:value]
15
+ end
16
+
17
+ it 'generates proper markup' do
18
+ builder = Nokogiri::XML::Builder.new do |xml|
19
+ subject.insert_to(xml)
20
+ end
21
+
22
+ xml = Nokogiri::XML(builder.to_xml)
23
+
24
+ xml.xpath('//Name').text.should eq valid_attributes[:name]
25
+ xml.xpath('//Value').text.should eq valid_attributes[:value]
26
+ end
27
+ end
28
+ end
29
+
30
+
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe ExpertSenderApi::Subscriber::Property do
4
+ context :with_valid_attributes do
5
+ let(:valid_attributes) { { id: 123,
6
+ type: 'string',
7
+ value: 'Test Property Value' } }
8
+
9
+ subject do
10
+ ExpertSenderApi::Subscriber::Property.new valid_attributes
11
+ end
12
+
13
+ it 'has proper attributes' do
14
+ subject.id.should eq valid_attributes[:id]
15
+ subject.type.should eq valid_attributes[:type]
16
+ subject.value.should eq valid_attributes[:value]
17
+ end
18
+
19
+ it 'generates proper markup' do
20
+ builder = Nokogiri::XML::Builder.new do |xml|
21
+ subject.insert_to(xml)
22
+ end
23
+
24
+ xml = Nokogiri::XML(builder.to_xml)
25
+
26
+ xml.xpath('//Property/Id').text.to_i.should eq valid_attributes[:id]
27
+ xml.xpath('//Property/Value').attribute('xsi:type').value.should eq "xs:#{valid_attributes[:type]}"
28
+ xml.xpath('//Property/Value').text.should eq valid_attributes[:value]
29
+ end
30
+ end
31
+ end
32
+
33
+
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe ExpertSenderApi::Subscriber::Tag do
4
+ context :with_valid_attributes do
5
+ let(:properties) { [ExpertSenderApi::Subscriber::Property.new(id: 123,
6
+ value: 'test',
7
+ type: 'string'),
8
+ ExpertSenderApi::Subscriber::Property.new(id: 456,
9
+ value: 'test1',
10
+ type: 'string')] }
11
+ let(:valid_attributes) { { list_id: 52,
12
+ email: 'test@httplab.ru',
13
+ mode: ExpertSenderApi::Subscriber::Tag::MODE_ADD_AND_IGNORE,
14
+ id: 777,
15
+ firstname: 'Test1',
16
+ lastname: 'Test2',
17
+ name: 'Test3',
18
+ tracking_code: '123',
19
+ vendor: 'Vendor',
20
+ ip: '127.0.0.1',
21
+ properties: properties } }
22
+
23
+ subject do
24
+ ExpertSenderApi::Subscriber::Tag.new valid_attributes
25
+ end
26
+
27
+ it 'has proper attributes' do
28
+ valid_attributes.each do |key, value|
29
+ subject.send(key).should eq value
30
+ end
31
+ end
32
+
33
+ it 'generates proper markup' do
34
+ builder = Nokogiri::XML::Builder.new do |xml|
35
+ subject.insert_to(xml)
36
+ end
37
+
38
+ xml = Nokogiri::XML(builder.to_xml)
39
+
40
+ xml.xpath('//Subscriber/ListId').text.to_i.should eq valid_attributes[:list_id]
41
+ xml.xpath('//Subscriber/Email').text.should eq valid_attributes[:email]
42
+ xml.xpath('//Subscriber/Mode').text.should eq valid_attributes[:mode]
43
+ xml.xpath('//Subscriber/Id').text.to_i.should eq valid_attributes[:id]
44
+ xml.xpath('//Subscriber/Firstname').text.should eq valid_attributes[:firstname]
45
+ xml.xpath('//Subscriber/Lastname').text.should eq valid_attributes[:lastname]
46
+ xml.xpath('//Subscriber/Name').text.should eq valid_attributes[:name]
47
+ xml.xpath('//Subscriber/TrackingCode').text.should eq valid_attributes[:tracking_code]
48
+ xml.xpath('//Subscriber/Vendor').text.should eq valid_attributes[:vendor]
49
+ xml.xpath('//Subscriber/Ip').text.should eq valid_attributes[:ip]
50
+
51
+ properties.each_with_index do |property, i|
52
+ xml_prop = xml.xpath('//Subscriber/Properties/Property')[i]
53
+ xml_prop.xpath('Id').text.to_i.should eq property.id
54
+ xml_prop.xpath('Value').attribute('xsi:type').value.should eq "xs:#{property.type}"
55
+ xml_prop.xpath('Value').text.should eq property.value
56
+ end
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.setup(:default, :development)
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'expertsender_api'
9
+
10
+ RSpec.configure do |config|
11
+ config.color_enabled = true
12
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: expertsender_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - kinderly
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A wrapper for ExpertSender API
70
+ email:
71
+ - beorc@httplab.ru
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - README.md
79
+ - Rakefile
80
+ - expertsender_api.gemspec
81
+ - lib/expertsender_api.rb
82
+ - lib/expertsender_api/api.rb
83
+ - lib/expertsender_api/concerns/serializeable.rb
84
+ - lib/expertsender_api/email.rb
85
+ - lib/expertsender_api/email/content.rb
86
+ - lib/expertsender_api/email/receiver.rb
87
+ - lib/expertsender_api/email/recipients.rb
88
+ - lib/expertsender_api/email/snippet.rb
89
+ - lib/expertsender_api/expertsender_error.rb
90
+ - lib/expertsender_api/result.rb
91
+ - lib/expertsender_api/subscriber.rb
92
+ - lib/expertsender_api/subscriber/property.rb
93
+ - lib/expertsender_api/subscriber/tag.rb
94
+ - spec/expertsender_api/api_spec.rb
95
+ - spec/expertsender_api/email/content_spec.rb
96
+ - spec/expertsender_api/email/receiver_spec.rb
97
+ - spec/expertsender_api/email/recipients_spec.rb
98
+ - spec/expertsender_api/email/snippet_spec.rb
99
+ - spec/expertsender_api/subscriber/property_spec.rb
100
+ - spec/expertsender_api/subscriber/tag_spec.rb
101
+ - spec/spec_helper.rb
102
+ homepage: http://github.com/kinderly/expertsender_api
103
+ licenses:
104
+ - MIT
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project: expertsender_api
122
+ rubygems_version: 2.2.2
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: A wrapper for ExpertSender API
126
+ test_files:
127
+ - spec/expertsender_api/api_spec.rb
128
+ - spec/expertsender_api/email/content_spec.rb
129
+ - spec/expertsender_api/email/receiver_spec.rb
130
+ - spec/expertsender_api/email/recipients_spec.rb
131
+ - spec/expertsender_api/email/snippet_spec.rb
132
+ - spec/expertsender_api/subscriber/property_spec.rb
133
+ - spec/expertsender_api/subscriber/tag_spec.rb
134
+ - spec/spec_helper.rb