expertsender_api 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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