dotmailer 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +162 -11
- data/TODO.md +6 -0
- data/dotmailer.gemspec +4 -3
- data/lib/dot_mailer.rb +11 -0
- data/lib/dot_mailer/account.rb +66 -0
- data/lib/dot_mailer/client.rb +108 -0
- data/lib/dot_mailer/contact.rb +179 -0
- data/lib/dot_mailer/contact_import.rb +94 -0
- data/lib/{dotmailer → dot_mailer}/data_field.rb +24 -1
- data/lib/dot_mailer/exceptions.rb +16 -0
- data/lib/dot_mailer/opt_in_type.rb +16 -0
- data/lib/dot_mailer/suppression.rb +29 -0
- data/lib/dot_mailer/version.rb +3 -0
- data/lib/dotmailer.rb +1 -3
- data/spec/dot_mailer/account_spec.rb +113 -0
- data/spec/dot_mailer/client_spec.rb +160 -0
- data/spec/dot_mailer/contact_import_spec.rb +173 -0
- data/spec/dot_mailer/contact_spec.rb +303 -0
- data/spec/dot_mailer/data_field_spec.rb +109 -0
- data/spec/dot_mailer/opt_in_type_spec.rb +21 -0
- data/spec/dot_mailer/suppression_spec.rb +67 -0
- data/spec/spec_helper.rb +5 -1
- data/spec/support/assignable_attributes_helper.rb +20 -0
- metadata +37 -8
- data/lib/dotmailer/client.rb +0 -78
- data/lib/dotmailer/exceptions.rb +0 -4
- data/lib/dotmailer/version.rb +0 -3
- data/spec/dotmailer/client_spec.rb +0 -159
- data/spec/dotmailer/data_field_spec.rb +0 -32
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DotMailer::ContactImport do
|
4
|
+
let(:client) { double 'client' }
|
5
|
+
let(:account) { double 'account', :client => client }
|
6
|
+
|
7
|
+
let(:contacts) do
|
8
|
+
[
|
9
|
+
{ 'Email' => 'john.doe@example.com' }
|
10
|
+
]
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'Class' do
|
14
|
+
subject { DotMailer::ContactImport }
|
15
|
+
|
16
|
+
describe '.import' do
|
17
|
+
let(:contact_import) { double 'contact import', :start => double }
|
18
|
+
|
19
|
+
before(:each) do
|
20
|
+
subject.stub :new => contact_import
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should create a new instance with the account and contacts' do
|
24
|
+
subject.should_receive(:new).with(account, contacts)
|
25
|
+
|
26
|
+
subject.import account, contacts
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should start the new contact import' do
|
30
|
+
contact_import.should_receive :start
|
31
|
+
|
32
|
+
subject.import account, contacts
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should return the contact import' do
|
36
|
+
subject.import(account, contacts).should == contact_import
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
subject { DotMailer::ContactImport.new(account, contacts) }
|
42
|
+
|
43
|
+
its(:id) { should be_nil }
|
44
|
+
|
45
|
+
describe '#start' do
|
46
|
+
before(:each) do
|
47
|
+
account.stub :data_fields => [double('data field', :name => 'CODE')]
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when the contacts include a non existent data field' do
|
51
|
+
let(:data_field_name) { 'UNKNOWN' }
|
52
|
+
|
53
|
+
let(:contacts) do
|
54
|
+
[
|
55
|
+
{ 'Email' => 'john.doe@example.com', data_field_name => 'some value' }
|
56
|
+
]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should raise an UnknownDataField error with the data field name' do
|
60
|
+
expect { subject.start }.to raise_error(DotMailer::UnknownDataField, data_field_name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
let(:contacts_csv) { "Email\njohn.doe@example.com\n" }
|
65
|
+
let(:id) { double 'id' }
|
66
|
+
let(:response) { { 'id' => id, 'status' => 'NotFinished' } }
|
67
|
+
|
68
|
+
before(:each) do
|
69
|
+
client.stub :post_csv => response
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should call post_csv on the client with the contacts in CSV format' do
|
73
|
+
client.should_receive(:post_csv).with('/contacts/import', contacts_csv)
|
74
|
+
|
75
|
+
subject.start
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should set the id from the response' do
|
79
|
+
subject.start
|
80
|
+
subject.id.should == id
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#status' do
|
85
|
+
before(:each) do
|
86
|
+
subject.stub :id => id
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when the import has not started' do
|
90
|
+
let(:id) { nil }
|
91
|
+
|
92
|
+
its(:status) { should == 'NotStarted' }
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when the import has started' do
|
96
|
+
let(:id) { '12345' }
|
97
|
+
let(:status) { double 'status' }
|
98
|
+
let(:response) { { 'id' => id, 'status' => status } }
|
99
|
+
|
100
|
+
before(:each) do
|
101
|
+
client.stub :get => response
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should get the status from the client' do
|
105
|
+
client.should_receive(:get).with("/contacts/import/#{id}")
|
106
|
+
|
107
|
+
subject.status
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should return the status from the client' do
|
111
|
+
subject.status.should == status
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '#finished?' do
|
117
|
+
context 'when the import status is not "Finished"' do
|
118
|
+
before(:each) do
|
119
|
+
subject.stub :status => 'NotFinished'
|
120
|
+
end
|
121
|
+
|
122
|
+
specify { subject.should_not be_finished }
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'when the import status is "Finished"' do
|
126
|
+
before(:each) do
|
127
|
+
subject.stub :status => 'Finished'
|
128
|
+
end
|
129
|
+
|
130
|
+
specify { subject.should be_finished }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '#errors' do
|
135
|
+
let(:id) { '12345' }
|
136
|
+
|
137
|
+
before(:each) do
|
138
|
+
subject.stub :id => id
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'when the import has no yet finished' do
|
142
|
+
before(:each) do
|
143
|
+
subject.stub :finished? => false
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should raise an ImportNotFinished error' do
|
147
|
+
expect { subject.errors }.to raise_error(DotMailer::ImportNotFinished)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'when the import has finished' do
|
152
|
+
before(:each) do
|
153
|
+
subject.stub :finished? => true
|
154
|
+
end
|
155
|
+
|
156
|
+
let(:errors) { double 'errors' }
|
157
|
+
|
158
|
+
before(:each) do
|
159
|
+
client.stub :get_csv => errors
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should call get_csv on the client with the import id in the path' do
|
163
|
+
client.should_receive(:get_csv).with("/contacts/import/#{id}/report-faults")
|
164
|
+
|
165
|
+
subject.errors
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'should return the status from the client' do
|
169
|
+
subject.errors.should == errors
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,303 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DotMailer::Contact do
|
4
|
+
let(:client) { double 'client' }
|
5
|
+
let(:account) { double 'account', :client => client }
|
6
|
+
|
7
|
+
describe 'Class' do
|
8
|
+
subject { DotMailer::Contact }
|
9
|
+
|
10
|
+
describe '.find_by_email' do
|
11
|
+
let(:email) { 'john.doe@example.com' }
|
12
|
+
let(:response) { double 'response' }
|
13
|
+
let(:contact) { double 'contact' }
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
client.stub :get => response
|
17
|
+
subject.stub :new => contact
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should get the contact from the client' do
|
21
|
+
client.should_receive(:get).with("/contacts/#{email}")
|
22
|
+
|
23
|
+
subject.find_by_email account, email
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should initialize a new Contact with the response from the client' do
|
27
|
+
subject.should_receive(:new).with(account, response)
|
28
|
+
|
29
|
+
subject.find_by_email account, email
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should return the new Contact object' do
|
33
|
+
subject.find_by_email(account, email).should == contact
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when the contact doesnt exist' do
|
37
|
+
before(:each) do
|
38
|
+
client.stub(:get).and_raise(DotMailer::NotFound)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should return nil' do
|
42
|
+
subject.find_by_email(account, email).should be_nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '.find_by_id' do
|
48
|
+
let(:id) { 123 }
|
49
|
+
let(:contact) { double 'contact' }
|
50
|
+
|
51
|
+
before(:each) do
|
52
|
+
subject.stub :find_by_email => contact
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should call find_by_email with the id' do
|
56
|
+
subject.should_receive(:find_by_email).with(account, id)
|
57
|
+
|
58
|
+
subject.find_by_id account, id
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should return the contact from find_by_email' do
|
62
|
+
subject.find_by_id(account, id).should == contact
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '.modified_since' do
|
67
|
+
let(:time) { Time.parse('1st March 2013 15:30:45 +00:00') }
|
68
|
+
let(:attributes) { double 'attributes' }
|
69
|
+
let(:response) { 3.times.map { attributes } }
|
70
|
+
let(:contact) { double 'contact' }
|
71
|
+
|
72
|
+
before(:each) do
|
73
|
+
client.stub :get => response
|
74
|
+
subject.stub :new => contact
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should call get on the client with a path containing the time in UTC XML schema format' do
|
78
|
+
client.should_receive(:get).with('/contacts/modified-since/2013-03-01T15:30:45Z')
|
79
|
+
|
80
|
+
subject.modified_since(account, time)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should initialize some contacts' do
|
84
|
+
subject.should_receive(:new).exactly(3).times.with(account, attributes)
|
85
|
+
|
86
|
+
subject.modified_since(account, time)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should return the contacts' do
|
90
|
+
subject.modified_since(account, time).should == 3.times.map { contact }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
let(:id) { double 'id' }
|
96
|
+
let(:email) { double 'email' }
|
97
|
+
let(:opt_in_type) { double 'opt in type' }
|
98
|
+
let(:email_type) { double 'email type' }
|
99
|
+
let(:status) { double 'status' }
|
100
|
+
|
101
|
+
let(:attributes) do
|
102
|
+
{
|
103
|
+
'id' => id,
|
104
|
+
'email' => email,
|
105
|
+
'optInType' => opt_in_type,
|
106
|
+
'emailType' => email_type,
|
107
|
+
'status' => status
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
subject { DotMailer::Contact.new(account, attributes) }
|
112
|
+
|
113
|
+
its(:id) { should == id }
|
114
|
+
its(:email) { should == email }
|
115
|
+
its(:opt_in_type) { should == opt_in_type }
|
116
|
+
its(:email_type) { should == email_type }
|
117
|
+
its(:status) { should == status }
|
118
|
+
|
119
|
+
it_should_have_assignable_attributes :email, :email_type
|
120
|
+
|
121
|
+
describe '#opt_in_type=' do
|
122
|
+
let(:value) { 'some opt in type' }
|
123
|
+
|
124
|
+
context 'when the opt in type exists' do
|
125
|
+
before(:each) do
|
126
|
+
DotMailer::OptInType.stub :exists? => true
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should change the opt in type' do
|
130
|
+
expect { subject.opt_in_type = value }.to \
|
131
|
+
change { subject.opt_in_type }.to(value)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'when the opt in type doesnt exist' do
|
136
|
+
before(:each) do
|
137
|
+
DotMailer::OptInType.stub :exists? => false
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should raise an UnknownOptInType error with the value' do
|
141
|
+
expect { subject.opt_in_type = value }.to \
|
142
|
+
raise_error(DotMailer::UnknownOptInType, value)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '#[]' do
|
148
|
+
let(:data_fields) { {} }
|
149
|
+
|
150
|
+
before(:each) do
|
151
|
+
subject.stub :data_fields => data_fields
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when the data field doesnt exist' do
|
155
|
+
let(:key) { 'UNKNOWN' }
|
156
|
+
|
157
|
+
it 'should raise an UnknownDataField error' do
|
158
|
+
expect { subject[key] }.to raise_error(DotMailer::UnknownDataField)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'when the data field does exist' do
|
163
|
+
let(:key) { double 'key' }
|
164
|
+
let(:value) { double 'value' }
|
165
|
+
let(:data_fields) { { key => value } }
|
166
|
+
|
167
|
+
specify { subject[key].should == value }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#[]=' do
|
172
|
+
let(:new_value) { double 'new value' }
|
173
|
+
|
174
|
+
let(:data_fields) { {} }
|
175
|
+
|
176
|
+
before(:each) do
|
177
|
+
subject.stub :data_fields => data_fields
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when the data field doesnt exist' do
|
181
|
+
let(:key) { 'UNKNOWN' }
|
182
|
+
|
183
|
+
it 'should raise an UnknownDataField error' do
|
184
|
+
expect { subject[key] = new_value }.to raise_error(DotMailer::UnknownDataField)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'when the data field does exist' do
|
189
|
+
let(:key) { double 'key' }
|
190
|
+
let(:old_value) { double 'old value' }
|
191
|
+
let(:data_fields) { { key => old_value } }
|
192
|
+
|
193
|
+
specify do
|
194
|
+
expect { subject[key] = new_value }.to \
|
195
|
+
change { subject[key] }.from(old_value).to(new_value)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe '#save' do
|
201
|
+
let(:id) { '12345' }
|
202
|
+
let(:key) { double 'key' }
|
203
|
+
let(:value) { 'some value' }
|
204
|
+
let(:data_fields) { { key => value } }
|
205
|
+
|
206
|
+
before(:each) do
|
207
|
+
client.stub :put_json
|
208
|
+
subject.stub :data_fields => data_fields
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should call put_json on the client with the id path' do
|
212
|
+
client.should_receive(:put_json).with("/contacts/#{id}", anything)
|
213
|
+
|
214
|
+
subject.save
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should call put_json on the client with the attributes in the correct format' do
|
218
|
+
client.should_receive(:put_json).with(anything, {
|
219
|
+
'id' => id,
|
220
|
+
'email' => email,
|
221
|
+
'optInType' => opt_in_type,
|
222
|
+
'emailType' => email_type,
|
223
|
+
'status' => status,
|
224
|
+
'dataFields' => [
|
225
|
+
{ 'key' => key, 'value' => value }
|
226
|
+
]
|
227
|
+
})
|
228
|
+
|
229
|
+
subject.save
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe '#subscribed?' do
|
234
|
+
context 'when the status is the SUBSCRIBED_STATUS' do
|
235
|
+
let(:status) { DotMailer::SUBSCRIBED_STATUS }
|
236
|
+
|
237
|
+
it { should be_subscribed }
|
238
|
+
end
|
239
|
+
|
240
|
+
context 'when the status is not the SUBSCRIBED_STATUS' do
|
241
|
+
let(:status) { 'Unsubscribed' }
|
242
|
+
|
243
|
+
it { should_not be_subscribed }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe '#resubscribe' do
|
248
|
+
let(:return_url) { 'some return url' }
|
249
|
+
let(:client) { double 'client' }
|
250
|
+
|
251
|
+
before(:each) do
|
252
|
+
subject.stub :client => client
|
253
|
+
end
|
254
|
+
|
255
|
+
context 'when the contact is already subscribed' do
|
256
|
+
before(:each) do
|
257
|
+
subject.stub :subscribed? => true
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'should not call put_json on the client' do
|
261
|
+
client.should_not_receive(:put_json)
|
262
|
+
|
263
|
+
subject.resubscribe return_url
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'should return false' do
|
267
|
+
subject.resubscribe(return_url).should be_false
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
context 'when the contact is not subscribed' do
|
272
|
+
before(:each) do
|
273
|
+
client.stub :post_json
|
274
|
+
subject.stub :subscribed? => false
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'should call post_json on the client with the correct path' do
|
278
|
+
client.should_receive(:post_json).with("/contacts/resubscribe", anything)
|
279
|
+
|
280
|
+
subject.resubscribe return_url
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'should call post_json on the client with the contacts id and email address' do
|
284
|
+
client.should_receive(:post_json).with anything, hash_including(
|
285
|
+
'UnsubscribedContact' => {
|
286
|
+
'id' => id,
|
287
|
+
'Email' => email
|
288
|
+
}
|
289
|
+
)
|
290
|
+
|
291
|
+
subject.resubscribe return_url
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'should call post_json on the client with the return url' do
|
295
|
+
client.should_receive(:post_json).with anything, hash_including(
|
296
|
+
'ReturnUrlToUseIfChallenged' => return_url
|
297
|
+
)
|
298
|
+
|
299
|
+
subject.resubscribe return_url
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|