mandrill-rails 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NWQzYTE1ZWNjNzdlMzdhNzg3ZTczOWM5Y2QzN2NlY2EyMWU2NDI3ZQ==
4
+ ZTYyZjcwNGMzNTlkMmQ1ODZlZTRkMzI5OWNmZDQwNmVmMWIzYjFmYw==
5
5
  data.tar.gz: !binary |-
6
- YzAzOWJmN2E1OGQ5YmQ2YWI2MGI2MmM1MjFmYTBlYjg0NTNlM2E5Zg==
6
+ YWQ4MDI4OGU0MTYzNDM0OTMyNzcwNDkyZjNiN2ZlNTY5MGU2YTk4YQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZmQ2Y2ZiZTgxNzZkM2QwMzVmMmFiNjM0YTcyYTUzZmVjM2YwZDFkMGY4NTgw
10
- YWJhMGRmYmZhZmI0Y2UzZjdhNDI4MzYyYjhkZmVjYjRlOWQwYTYxYjIxMTFl
11
- Nzg4M2Y0YTQyZDBjZmJjZTgwYTI1NTVkMWFhNzI5OGIwNzcwZjc=
9
+ MjA5ZDRkMGNlYzA0MTQ4MWYxNDdiODZkNTU4Nzc3OTUwNzMwMTQ4ODllYzJi
10
+ ZmMyNWFhN2E1ZDJmYjZiOTQxMTcyYmVhNjEzMmI2NWExYjg2ZWFmMzM5ZTk5
11
+ MGQxOGFiM2VmZTcyODhlZDg0ZmQwNjJkNmM2ODY3NzdiYTA2ZDU=
12
12
  data.tar.gz: !binary |-
13
- MTYyMGMxNzM0MjQ0ZWMyZWFiZWYwNjU3MDJlZTQxZTI1NjEwY2UyMGI0Nzlh
14
- ZjY3NjNjZDY2NmY0NWY1YTNmNDBjOTczMTRlZTc5NjNlMWM3MDI3YTQzYjUw
15
- MDk1MzEwMzhjOGZhNTdmNWRlZDk0ODlmMzYwMTZhNTAzNDQyM2I=
13
+ NzRhZmI4YTM2ZDA1YTlkYzU3ZTkwMjVlZGVkNTA3NjgwMGM2NjNjYTRkOTUy
14
+ YTljZmJkNGUwNDRmOWVlMDM1NzI3YTAyNTU0OGQ4ZDIzZGM3ZTU2NTBjYTdl
15
+ YjQ4MDk2MGNlMGExN2VhYzY2ZTYzMGI4YTE0YWZiODEwMjI2ZjU=
@@ -3,5 +3,5 @@ module Mandrill
3
3
  end
4
4
  end
5
5
  unless defined?(Mandrill::Rails::VERSION)
6
- Mandrill::Rails::VERSION = "1.2.0"
6
+ Mandrill::Rails::VERSION = "1.3.0"
7
7
  end
@@ -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
- event_payload = wrap_payload(raw_payload)
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
+ ]
@@ -0,0 +1,12 @@
1
+ [
2
+ {
3
+ "type": "whitelist",
4
+ "action": "add",
5
+ "reject": {
6
+ "detail": "this is a mock event, replace with a real example when available",
7
+ "email": "test@example.net",
8
+ "created_at": "2015-02-01 01:02:03"
9
+ },
10
+ "ts": 1350377135
11
+ }
12
+ ]
@@ -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 { should eql([:verify_authenticity_token]) }
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 { should eql([:authenticate_mandrill_request!, {:only=>[:create]}]) }
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 { should eql(true) }
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 { should eql(true) }
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 { should eql(true) }
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 "should call head(:forbidden) and return false" do
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 matches the original" do
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
- let(:event1) { { "event" => "inbound" } }
17
- let(:event2) { { "event" => "click" } }
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 "should pass event payload to the handler" do
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 "should pass event payload to the handler" do
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 "should pass event payload to the handler" do
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 "logs an error" do
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 { should eql(true) }
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 { should eql(true) }
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 { should eql(false) }
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 { should eql(false) }
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.2.0
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-05-25 00:00:00.000000000 Z
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