dotmailer 0.0.1 → 0.0.2
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/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
|