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 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