mandrill-rails 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/lib/mandrill-rails/version.rb +1 -1
- data/lib/mandrill/web_hook/event_decorator.rb +19 -3
- data/lib/mandrill/web_hook/processor.rb +25 -27
- data/spec/fixtures/webhook_examples/sync_blacklist.json +18 -0
- data/spec/fixtures/webhook_examples/sync_whitelist.json +12 -0
- data/spec/mandrill-rails/web_hook_processor_spec.rb +16 -6
- data/spec/mandrill/web_hook/event_decorator_spec.rb +63 -1
- data/spec/mandrill/web_hook/processor_spec.rb +31 -24
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZTYyZjcwNGMzNTlkMmQ1ODZlZTRkMzI5OWNmZDQwNmVmMWIzYjFmYw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YWQ4MDI4OGU0MTYzNDM0OTMyNzcwNDkyZjNiN2ZlNTY5MGU2YTk4YQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MjA5ZDRkMGNlYzA0MTQ4MWYxNDdiODZkNTU4Nzc3OTUwNzMwMTQ4ODllYzJi
|
10
|
+
ZmMyNWFhN2E1ZDJmYjZiOTQxMTcyYmVhNjEzMmI2NWExYjg2ZWFmMzM5ZTk5
|
11
|
+
MGQxOGFiM2VmZTcyODhlZDg0ZmQwNjJkNmM2ODY3NzdiYTA2ZDU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NzRhZmI4YTM2ZDA1YTlkYzU3ZTkwMjVlZGVkNTA3NjgwMGM2NjNjYTRkOTUy
|
14
|
+
YTljZmJkNGUwNDRmOWVlMDM1NzI3YTAyNTU0OGQ4ZDIzZGM3ZTU2NTBjYTdl
|
15
|
+
YjQ4MDk2MGNlMGExN2VhYzY2ZTYzMGI4YTE0YWZiODEwMjI2ZjU=
|
@@ -13,7 +13,23 @@ class Mandrill::WebHook::EventDecorator < Hash
|
|
13
13
|
# Returns the event type.
|
14
14
|
# Applicable events: all
|
15
15
|
def event_type
|
16
|
-
self['event']
|
16
|
+
self['event'] || if sync_type.present?
|
17
|
+
'sync'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the sync type.
|
22
|
+
# Applicable events: sync
|
23
|
+
def sync_type
|
24
|
+
if %w(blacklist whitelist).include?(type = self['type'])
|
25
|
+
type
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the reject Hash.
|
30
|
+
# Applicable events: sync
|
31
|
+
def reject
|
32
|
+
self['reject']||{}
|
17
33
|
end
|
18
34
|
|
19
35
|
# Returns the message subject.
|
@@ -69,14 +85,14 @@ class Mandrill::WebHook::EventDecorator < Hash
|
|
69
85
|
# Inbound messages: references 'from_email' message attribute.
|
70
86
|
# Send/Open/Click messages: references 'sender' message attribute.
|
71
87
|
def sender_email
|
72
|
-
msg['from_email']||msg['sender']
|
88
|
+
msg['from_email'] || msg['sender'] || reject['sender']
|
73
89
|
end
|
74
90
|
|
75
91
|
# Returns the subject user email address.
|
76
92
|
# Inbound messages: references 'email' message attribute (represents the sender).
|
77
93
|
# Send/Open/Click messages: references 'email' message attribute (represents the recipient).
|
78
94
|
def user_email
|
79
|
-
msg['email']
|
95
|
+
msg['email'] || reject['email']
|
80
96
|
end
|
81
97
|
|
82
98
|
# Returns an array of all unique recipients (to/cc)
|
@@ -12,41 +12,17 @@ class Mandrill::WebHook::Processor
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def mandrill_events
|
15
|
-
@mandrill_events ||= JSON.parse(params['mandrill_events']
|
16
|
-
rescue
|
17
|
-
@mandrill_events = []
|
15
|
+
@mandrill_events ||= JSON.parse(params['mandrill_events']) rescue []
|
18
16
|
end
|
19
17
|
|
20
18
|
# Command: processes all +mandrill_events+
|
21
19
|
def run!
|
22
20
|
mandrill_events.each do |raw_payload|
|
23
|
-
|
24
|
-
handler = "handle_#{event_payload.event_type}".to_sym
|
25
|
-
if callback_host && callback_host.respond_to?(handler, true)
|
26
|
-
callback_host.send(handler,event_payload)
|
27
|
-
elsif self.respond_to?(handler)
|
28
|
-
self.send(handler,event_payload)
|
29
|
-
else
|
30
|
-
error_message = "Expected handler method `#{handler}` for event type `#{event_payload.event_type}`"
|
31
|
-
case on_unhandled_mandrill_events
|
32
|
-
when :ignore
|
33
|
-
# NOP
|
34
|
-
when :raise_exception
|
35
|
-
raise Mandrill::Rails::Errors::MissingEventHandler, error_message
|
36
|
-
else
|
37
|
-
Rails.logger.error error_message rescue nil
|
38
|
-
end
|
39
|
-
end
|
21
|
+
process_event(Mandrill::WebHook::EventDecorator[raw_payload])
|
40
22
|
end
|
41
23
|
end
|
42
24
|
|
43
|
-
# Returns a suitably ecapsulated +raw_event_payload+
|
44
|
-
def wrap_payload(raw_event_payload)
|
45
|
-
Mandrill::WebHook::EventDecorator[raw_event_payload]
|
46
|
-
end
|
47
|
-
|
48
25
|
class << self
|
49
|
-
|
50
26
|
# Returns true if +params+ sent to +original_url+ are authentic given +expected_signature+ and +mandrill_webhook_keys+.
|
51
27
|
def authentic?(expected_signature, mandrill_webhook_keys, original_url, params)
|
52
28
|
result = true
|
@@ -67,7 +43,29 @@ class Mandrill::WebHook::Processor
|
|
67
43
|
end
|
68
44
|
Base64.encode64("#{OpenSSL::HMAC.digest('sha1', webhook_key, signed_data)}").strip
|
69
45
|
end
|
70
|
-
|
71
46
|
end
|
72
47
|
|
48
|
+
private
|
49
|
+
|
50
|
+
|
51
|
+
# Command: attempts to process +event_payload+
|
52
|
+
def process_event(event_payload)
|
53
|
+
handler = "handle_#{event_payload.event_type}".to_sym
|
54
|
+
|
55
|
+
if callback_host && callback_host.respond_to?(handler, true)
|
56
|
+
callback_host.send(handler,event_payload)
|
57
|
+
elsif self.respond_to?(handler)
|
58
|
+
self.send(handler,event_payload)
|
59
|
+
else
|
60
|
+
error_message = "Expected handler method `#{handler}` for event type `#{event_payload.event_type}`"
|
61
|
+
case on_unhandled_mandrill_events
|
62
|
+
when :ignore
|
63
|
+
# NOP
|
64
|
+
when :raise_exception
|
65
|
+
raise Mandrill::Rails::Errors::MissingEventHandler, error_message
|
66
|
+
else
|
67
|
+
Rails.logger.error error_message rescue nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
73
71
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"type": "blacklist",
|
4
|
+
"action": "add",
|
5
|
+
"reject": {
|
6
|
+
"reason": "test",
|
7
|
+
"detail": "this is a mock event, replace with a real example when available",
|
8
|
+
"last_event_at": "2015-01-01 01:02:03",
|
9
|
+
"email": "test@example.net",
|
10
|
+
"created_at": "2015-02-01 01:02:03",
|
11
|
+
"expires_at": "2016-01-01 01:02:03",
|
12
|
+
"expired": "false",
|
13
|
+
"subaccount": "",
|
14
|
+
"sender": "sender@example.net"
|
15
|
+
},
|
16
|
+
"ts": 1350377135
|
17
|
+
}
|
18
|
+
]
|
@@ -24,12 +24,16 @@ describe Mandrill::Rails::WebHookProcessor do
|
|
24
24
|
|
25
25
|
describe "##skip_before_filter settings" do
|
26
26
|
subject { processor_class.skip_before_filter_settings }
|
27
|
-
it
|
27
|
+
it "includes verify_authenticity_token" do
|
28
|
+
expect(subject).to eql([:verify_authenticity_token])
|
29
|
+
end
|
28
30
|
end
|
29
31
|
|
30
32
|
describe "##before_filter settings" do
|
31
33
|
subject { processor_class.before_filter_settings }
|
32
|
-
it
|
34
|
+
it "includes authenticate_mandrill_request" do
|
35
|
+
expect(subject).to eql([:authenticate_mandrill_request!, {:only=>[:create]}])
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
describe "#mandrill_webhook_keys" do
|
@@ -135,7 +139,9 @@ describe Mandrill::Rails::WebHookProcessor do
|
|
135
139
|
subject { processor_instance.send(:authenticate_mandrill_request!) }
|
136
140
|
|
137
141
|
context "when authentication not enabled" do
|
138
|
-
it
|
142
|
+
it "passes" do
|
143
|
+
expect(subject).to eql(true)
|
144
|
+
end
|
139
145
|
end
|
140
146
|
context "when authentication enabled" do
|
141
147
|
before do
|
@@ -143,15 +149,19 @@ describe Mandrill::Rails::WebHookProcessor do
|
|
143
149
|
end
|
144
150
|
context "with valid key" do
|
145
151
|
let(:mandrill_webhook_keys) { valid_webhook_key }
|
146
|
-
it
|
152
|
+
it "passes" do
|
153
|
+
expect(subject).to eql(true)
|
154
|
+
end
|
147
155
|
end
|
148
156
|
context "with mix of valid and invalid keys" do
|
149
157
|
let(:mandrill_webhook_keys) { ['bogative',valid_webhook_key] }
|
150
|
-
it
|
158
|
+
it "passes" do
|
159
|
+
expect(subject).to eql(true)
|
160
|
+
end
|
151
161
|
end
|
152
162
|
context "with invalid key" do
|
153
163
|
let(:mandrill_webhook_keys) { 'bogative' }
|
154
|
-
it "
|
164
|
+
it "calls head(:forbidden) and return false" do
|
155
165
|
expect(processor_instance).to receive(:head).with(:forbidden, :text => "Mandrill signature did not match.")
|
156
166
|
expect(subject).to eql(false)
|
157
167
|
end
|
@@ -20,6 +20,8 @@ describe Mandrill::WebHook::EventDecorator do
|
|
20
20
|
{
|
21
21
|
'inbound' => {
|
22
22
|
:event_type => 'inbound',
|
23
|
+
:sync_type => nil,
|
24
|
+
:reject => {},
|
23
25
|
:subject => '[inbound] Sample Subject',
|
24
26
|
:message_id => '<CAGBx7GhULS7d6ZsdLREHnKQ68V6w2fbGmD85dPn63s6RtpsZeQ@mail.gmail.com>',
|
25
27
|
:message_version => nil,
|
@@ -47,6 +49,8 @@ describe Mandrill::WebHook::EventDecorator do
|
|
47
49
|
},
|
48
50
|
'inbound_reply' => {
|
49
51
|
:event_type => 'inbound',
|
52
|
+
:sync_type => nil,
|
53
|
+
:reject => {},
|
50
54
|
:subject => '[inbound] Sample Subject 2',
|
51
55
|
:message_id => '<CAGBx7GhsVk7Q-aO-FQ-m+Oix7GQyEVHyL60qv0__G8EpH8pA4w@mail.gmail.com>',
|
52
56
|
:message_version => nil,
|
@@ -80,6 +84,8 @@ describe Mandrill::WebHook::EventDecorator do
|
|
80
84
|
},
|
81
85
|
'click' => {
|
82
86
|
:event_type => 'click',
|
87
|
+
:sync_type => nil,
|
88
|
+
:reject => {},
|
83
89
|
:subject => '[click] Sample Subject',
|
84
90
|
:message_id => '8606637.6692f6cac28e45a9b371e182d5ca0a35',
|
85
91
|
:message_version => 5,
|
@@ -107,6 +113,8 @@ describe Mandrill::WebHook::EventDecorator do
|
|
107
113
|
},
|
108
114
|
'send' => {
|
109
115
|
:event_type => 'send',
|
116
|
+
:sync_type => nil,
|
117
|
+
:reject => {},
|
110
118
|
:subject => '[send] Sample Subject',
|
111
119
|
:message_id => '9a32184309ad4d5e9bfd20368d9d7981',
|
112
120
|
:message_version => nil,
|
@@ -124,6 +132,8 @@ describe Mandrill::WebHook::EventDecorator do
|
|
124
132
|
},
|
125
133
|
'open' => {
|
126
134
|
:event_type => 'open',
|
135
|
+
:sync_type => nil,
|
136
|
+
:reject => {},
|
127
137
|
:subject => '[open] Sample Subject',
|
128
138
|
:message_id => '12847763.9a32184309ad4d5e9bfd20368d9d7981',
|
129
139
|
:message_version => 3,
|
@@ -139,6 +149,58 @@ describe Mandrill::WebHook::EventDecorator do
|
|
139
149
|
:all_clicks => [{"ts"=>1350693098, "url"=>"http://feedproxy.google.com/~r/AccidentalTechnologist/~3/Jc7hYTVjcmM/"}],
|
140
150
|
:all_clicked_links => ["http://feedproxy.google.com/~r/AccidentalTechnologist/~3/Jc7hYTVjcmM/"]
|
141
151
|
},
|
152
|
+
'sync_blacklist' => {
|
153
|
+
:event_type => 'sync',
|
154
|
+
:sync_type => 'blacklist',
|
155
|
+
:reject => {
|
156
|
+
"reason"=>"test",
|
157
|
+
"detail"=>"this is a mock event, replace with a real example when available",
|
158
|
+
"last_event_at"=>"2015-01-01 01:02:03",
|
159
|
+
"email"=>"test@example.net",
|
160
|
+
"created_at"=>"2015-02-01 01:02:03",
|
161
|
+
"expires_at"=>"2016-01-01 01:02:03",
|
162
|
+
"expired"=>"false",
|
163
|
+
"subaccount"=>"",
|
164
|
+
"sender"=>"sender@example.net"
|
165
|
+
},
|
166
|
+
:subject => nil,
|
167
|
+
:message_id => nil,
|
168
|
+
:message_version => nil,
|
169
|
+
:in_reply_to => nil,
|
170
|
+
:references => [],
|
171
|
+
:headers => {},
|
172
|
+
:sender_email => "sender@example.net",
|
173
|
+
:user_email => "test@example.net",
|
174
|
+
:recipients => [],
|
175
|
+
:recipient_emails => [],
|
176
|
+
:message_body => nil,
|
177
|
+
:click => nil,
|
178
|
+
:all_clicks => [],
|
179
|
+
:all_clicked_links => []
|
180
|
+
},
|
181
|
+
'sync_whitelist' => {
|
182
|
+
:event_type => 'sync',
|
183
|
+
:sync_type => 'whitelist',
|
184
|
+
:reject => {
|
185
|
+
"detail"=>"this is a mock event, replace with a real example when available",
|
186
|
+
"email"=>"test@example.net",
|
187
|
+
"created_at"=>"2015-02-01 01:02:03"
|
188
|
+
},
|
189
|
+
:subject => nil,
|
190
|
+
:message_id => nil,
|
191
|
+
:message_version => nil,
|
192
|
+
:in_reply_to => nil,
|
193
|
+
:references => [],
|
194
|
+
:headers => {},
|
195
|
+
:sender_email => nil,
|
196
|
+
:user_email => "test@example.net",
|
197
|
+
:recipients => [],
|
198
|
+
:recipient_emails => [],
|
199
|
+
:message_body => nil,
|
200
|
+
:click => nil,
|
201
|
+
:all_clicks => [],
|
202
|
+
:all_clicked_links => []
|
203
|
+
}
|
142
204
|
}.each do |event_type,expectations|
|
143
205
|
context "with #{event_type} event_type" do
|
144
206
|
let(:raw_event) { webhook_example_event(event_type) }
|
@@ -281,7 +343,7 @@ describe Mandrill::WebHook::EventDecorator do
|
|
281
343
|
expect(image.content).to match(/^iVBORw0K/)
|
282
344
|
expect(image.decoded_content).to match(/^\x89PNG\r\n/n)
|
283
345
|
end
|
284
|
-
it "decoded_content exactly
|
346
|
+
it "has decoded_content exactly matching the original" do
|
285
347
|
original_digest = Digest::SHA1.hexdigest(payload_example('sample.png'))
|
286
348
|
decoded_digest = Digest::SHA1.hexdigest(image.decoded_content)
|
287
349
|
expect(original_digest).to eql(decoded_digest)
|
@@ -9,16 +9,27 @@ describe Mandrill::WebHook::Processor do
|
|
9
9
|
describe "#run!" do
|
10
10
|
|
11
11
|
context "when handler methods are present" do
|
12
|
+
let(:event1) { { "event" => "inbound" } }
|
13
|
+
let(:event2) { { "event" => "click" } }
|
14
|
+
let(:event3) { { "type" => "blacklist" } }
|
15
|
+
let(:params) { { "mandrill_events" => [event1, event2, event3].to_json } }
|
16
|
+
|
12
17
|
before do
|
13
18
|
allow(processor_class).to receive(:handle_inbound)
|
14
19
|
allow(processor_class).to receive(:handle_click)
|
20
|
+
allow(processor_class).to receive(:handle_sync)
|
15
21
|
end
|
16
|
-
|
17
|
-
|
18
|
-
let(:params) { { "mandrill_events" => [event1,event2].to_json } }
|
19
|
-
it "should pass all event payloads to the handler" do
|
22
|
+
|
23
|
+
it "passes all event payloads to the handler" do
|
20
24
|
expect(processor).to receive(:handle_inbound)
|
21
25
|
expect(processor).to receive(:handle_click)
|
26
|
+
expect(processor).to receive(:handle_sync)
|
27
|
+
processor.run!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
context "but no valid handler methods are present" do
|
31
|
+
let(:params) { nil }
|
32
|
+
it "keeps calm and carries on" do
|
22
33
|
processor.run!
|
23
34
|
end
|
24
35
|
end
|
@@ -39,7 +50,7 @@ describe Mandrill::WebHook::Processor do
|
|
39
50
|
end
|
40
51
|
end
|
41
52
|
|
42
|
-
it "
|
53
|
+
it "passes event payload to the handler" do
|
43
54
|
expect(callback_host).to receive(:handle_inbound).twice
|
44
55
|
processor.run!
|
45
56
|
end
|
@@ -53,7 +64,7 @@ describe Mandrill::WebHook::Processor do
|
|
53
64
|
end
|
54
65
|
end
|
55
66
|
|
56
|
-
it "
|
67
|
+
it "passes event payload to the handler" do
|
57
68
|
expect(callback_host).to receive(:handle_inbound).twice
|
58
69
|
processor.run!
|
59
70
|
end
|
@@ -67,7 +78,7 @@ describe Mandrill::WebHook::Processor do
|
|
67
78
|
end
|
68
79
|
end
|
69
80
|
|
70
|
-
it "
|
81
|
+
it "passes event payload to the handler" do
|
71
82
|
expect(callback_host).to receive(:handle_inbound).twice
|
72
83
|
processor.run!
|
73
84
|
end
|
@@ -96,7 +107,7 @@ describe Mandrill::WebHook::Processor do
|
|
96
107
|
end
|
97
108
|
|
98
109
|
context "and ignore missing handler behaviour" do
|
99
|
-
it "
|
110
|
+
it "keeps calm and carries on" do
|
100
111
|
processor.on_unhandled_mandrill_events = :ignore
|
101
112
|
expect { processor.run! }.to_not raise_error
|
102
113
|
end
|
@@ -109,19 +120,7 @@ describe Mandrill::WebHook::Processor do
|
|
109
120
|
.to raise_error(Mandrill::Rails::Errors::MissingEventHandler)
|
110
121
|
end
|
111
122
|
end
|
112
|
-
|
113
123
|
end
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
end
|
119
|
-
|
120
|
-
describe "#wrap_payload" do
|
121
|
-
let(:raw_payload) { {} }
|
122
|
-
subject { processor.wrap_payload(raw_payload) }
|
123
|
-
it "returns a decorated hash" do
|
124
|
-
expect(subject.class).to eql(Mandrill::WebHook::EventDecorator)
|
125
124
|
end
|
126
125
|
end
|
127
126
|
|
@@ -134,19 +133,27 @@ describe Mandrill::WebHook::Processor do
|
|
134
133
|
let(:params) { example_payload['raw_params'] }
|
135
134
|
subject { processor_class.authentic?(expected_signature, mandrill_webhook_keys, original_url, params) }
|
136
135
|
context "when valid" do
|
137
|
-
it
|
136
|
+
it "passes" do
|
137
|
+
expect(subject).to eql(true)
|
138
|
+
end
|
138
139
|
end
|
139
140
|
context "when no keys" do
|
140
141
|
let(:mandrill_webhook_keys) { [] }
|
141
|
-
it
|
142
|
+
it "passes" do
|
143
|
+
expect(subject).to eql(true)
|
144
|
+
end
|
142
145
|
end
|
143
146
|
context "when keys don't match" do
|
144
147
|
let(:mandrill_webhook_keys) { ['bogative'] }
|
145
|
-
it
|
148
|
+
it "fails" do
|
149
|
+
expect(subject).to eql(false)
|
150
|
+
end
|
146
151
|
end
|
147
152
|
context "when signature don't match" do
|
148
153
|
let(:expected_signature) { 'bogative' }
|
149
|
-
it
|
154
|
+
it "fails" do
|
155
|
+
expect(subject).to eql(false)
|
156
|
+
end
|
150
157
|
end
|
151
158
|
|
152
159
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mandrill-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Gallagher
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -139,6 +139,8 @@ files:
|
|
139
139
|
- spec/fixtures/webhook_examples/inbound_without_msg.json
|
140
140
|
- spec/fixtures/webhook_examples/open.json
|
141
141
|
- spec/fixtures/webhook_examples/send.json
|
142
|
+
- spec/fixtures/webhook_examples/sync_blacklist.json
|
143
|
+
- spec/fixtures/webhook_examples/sync_whitelist.json
|
142
144
|
- spec/mandrill-rails/web_hook_processor_spec.rb
|
143
145
|
- spec/mandrill/web_hook/attachment_spec.rb
|
144
146
|
- spec/mandrill/web_hook/event_decorator_spec.rb
|
@@ -191,6 +193,8 @@ test_files:
|
|
191
193
|
- spec/fixtures/webhook_examples/inbound_without_msg.json
|
192
194
|
- spec/fixtures/webhook_examples/open.json
|
193
195
|
- spec/fixtures/webhook_examples/send.json
|
196
|
+
- spec/fixtures/webhook_examples/sync_blacklist.json
|
197
|
+
- spec/fixtures/webhook_examples/sync_whitelist.json
|
194
198
|
- spec/mandrill-rails/web_hook_processor_spec.rb
|
195
199
|
- spec/mandrill/web_hook/attachment_spec.rb
|
196
200
|
- spec/mandrill/web_hook/event_decorator_spec.rb
|