Merge pull request #408 from cantino/multiple_email_recipients

allow email agents to accept an optional "recipients" list to override the account default

Andrew Cantino 10 ans auparavant
Parent
Commettre
67fcfef70c

+ 21 - 0
app/concerns/email_concern.rb

@@ -9,6 +9,27 @@ module EmailConcern
9 9
 
10 10
   def validate_email_options
11 11
     errors.add(:base, "subject and expected_receive_period_in_days are required") unless options['subject'].present? && options['expected_receive_period_in_days'].present?
12
+
13
+    if options['recipients'].present?
14
+      emails = options['recipients']
15
+      emails = [emails] if emails.is_a?(String)
16
+      unless emails.all? { |email| email =~ Devise.email_regexp }
17
+        errors.add(:base, "'when provided, 'recipients' should be an email address or an array of email addresses")
18
+      end
19
+    end
20
+  end
21
+
22
+  def recipients(payload = {})
23
+    emails = interpolated(payload)['recipients']
24
+    if emails.present?
25
+      if emails.is_a?(String)
26
+        [emails]
27
+      else
28
+        emails
29
+      end
30
+    else
31
+      [user.email]
32
+    end
12 33
   end
13 34
 
14 35
   def working?

+ 9 - 4
app/models/agents/email_agent.rb

@@ -7,9 +7,12 @@ module Agents
7 7
 
8 8
     description <<-MD
9 9
       The EmailAgent sends any events it receives via email immediately.
10
-      The email will be sent to your account's address and will have a `subject` and an optional `headline` before
11
-      listing the Events.  If the Events' payloads contain a `:message`, that will be highlighted, otherwise everything in
12
-      their payloads will be shown.
10
+
11
+      The email will have a `subject` and an optional `headline` before listing the Events.  If the Events' payloads
12
+      contain a `:message`, that will be highlighted, otherwise everything in their payloads will be shown.
13
+
14
+      You can specify one or more `recipients` for the email, or skip the option in order to send the email to your
15
+      account's default email address.
13 16
 
14 17
       Set `expected_receive_period_in_days` to the maximum amount of time that you'd expect to pass between Events being received by this Agent.
15 18
     MD
@@ -25,7 +28,9 @@ module Agents
25 28
     def receive(incoming_events)
26 29
       incoming_events.each do |event|
27 30
         log "Sending digest mail to #{user.email} with event #{event.id}"
28
-        SystemMailer.delay.send_message(:to => user.email, :subject => interpolated(event.payload)['subject'], :headline => interpolated(event.payload)['headline'], :groups => [present(event.payload)])
31
+        recipients(event.payload).each do |recipient|
32
+          SystemMailer.delay.send_message(:to => recipient, :subject => interpolated(event.payload)['subject'], :headline => interpolated(event.payload)['headline'], :groups => [present(event.payload)])
33
+        end
29 34
       end
30 35
     end
31 36
   end

+ 10 - 4
app/models/agents/email_digest_agent.rb

@@ -7,11 +7,15 @@ module Agents
7 7
     cannot_create_events!
8 8
 
9 9
     description <<-MD
10
-      The EmailDigestAgent collects any Events sent to it and sends them all via email when run.
11
-      The email will be sent to your account's address and will have a `subject` and an optional `headline` before
12
-      listing the Events.  If the Events' payloads contain a `message`, that will be highlighted, otherwise everything in
10
+      The EmailDigestAgent collects any Events sent to it and sends them all via email when scheduled.
11
+
12
+      By default, the will have a `subject` and an optional `headline` before listing the Events.  If the Events'
13
+      payloads contain a `message`, that will be highlighted, otherwise everything in
13 14
       their payloads will be shown.
14 15
 
16
+      You can specify one or more `recipients` for the email, or skip the option in order to send the email to your
17
+      account's default email address.
18
+
15 19
       Set `expected_receive_period_in_days` to the maximum amount of time that you'd expect to pass between Events being received by this Agent.
16 20
     MD
17 21
 
@@ -37,7 +41,9 @@ module Agents
37 41
         ids = self.memory['events'].join(",")
38 42
         groups = self.memory['queue'].map { |payload| present(payload) }
39 43
         log "Sending digest mail to #{user.email} with events [#{ids}]"
40
-        SystemMailer.delay.send_message(:to => user.email, :subject => interpolated['subject'], :headline => interpolated['headline'], :groups => groups)
44
+        recipients.each do |recipient|
45
+          SystemMailer.delay.send_message(:to => recipient, :subject => interpolated['subject'], :headline => interpolated['headline'], :groups => groups)
46
+        end
41 47
         self.memory['queue'] = []
42 48
         self.memory['events'] = []
43 49
       end

+ 3 - 2
spec/models/agents/email_agent_spec.rb

@@ -1,12 +1,14 @@
1 1
 require 'spec_helper'
2 2
 
3 3
 describe Agents::EmailAgent do
4
+  it_behaves_like EmailConcern
5
+
4 6
   def get_message_part(mail, content_type)
5 7
     mail.body.parts.find { |p| p.content_type.match content_type }.body.raw_source
6 8
   end
7 9
 
8 10
   before do
9
-    @checker = Agents::EmailAgent.new(:name => "something", :options => { :expected_receive_period_in_days => 2, :subject => "something interesting" })
11
+    @checker = Agents::EmailAgent.new(:name => "something", :options => { :expected_receive_period_in_days => "2", :subject => "something interesting" })
10 12
     @checker.user = users(:bob)
11 13
     @checker.save!
12 14
   end
@@ -54,6 +56,5 @@ describe Agents::EmailAgent do
54 56
       plain_email_text.should =~ /avehumidity/
55 57
       html_email_text.should =~ /avehumidity/
56 58
     end
57
-
58 59
   end
59 60
 end

+ 3 - 1
spec/models/agents/email_digest_agent_spec.rb

@@ -1,12 +1,14 @@
1 1
 require 'spec_helper'
2 2
 
3 3
 describe Agents::EmailDigestAgent do
4
+  it_behaves_like EmailConcern
5
+
4 6
   def get_message_part(mail, content_type)
5 7
     mail.body.parts.find { |p| p.content_type.match content_type }.body.raw_source
6 8
   end
7 9
 
8 10
   before do
9
-    @checker = Agents::EmailDigestAgent.new(:name => "something", :options => { :expected_receive_period_in_days => 2, :subject => "something interesting" })
11
+    @checker = Agents::EmailDigestAgent.new(:name => "something", :options => { :expected_receive_period_in_days => "2", :subject => "something interesting" })
10 12
     @checker.user = users(:bob)
11 13
     @checker.save!
12 14
   end

+ 88 - 0
spec/support/shared_examples/email_concern.rb

@@ -0,0 +1,88 @@
1
+require 'spec_helper'
2
+
3
+shared_examples_for EmailConcern do
4
+  let(:valid_options) {
5
+    {
6
+      :subject => "hello!",
7
+      :expected_receive_period_in_days => "2"
8
+    }
9
+  }
10
+
11
+  let(:agent) do
12
+    _agent = described_class.new(:name => "some email agent", :options => valid_options)
13
+    _agent.user = users(:jane)
14
+    _agent
15
+  end
16
+
17
+  describe "validations" do
18
+    it "should be valid" do
19
+      agent.should be_valid
20
+    end
21
+
22
+    it "should validate the presence of 'subject'" do
23
+      agent.options['subject'] = ''
24
+      agent.should_not be_valid
25
+
26
+      agent.options['subject'] = nil
27
+      agent.should_not be_valid
28
+    end
29
+
30
+    it "should validate the presence of 'expected_receive_period_in_days'" do
31
+      agent.options['expected_receive_period_in_days'] = ''
32
+      agent.should_not be_valid
33
+
34
+      agent.options['expected_receive_period_in_days'] = nil
35
+      agent.should_not be_valid
36
+    end
37
+
38
+    it "should validate that recipients, when provided, is one or more valid email addresses" do
39
+      agent.options['recipients'] = ''
40
+      agent.should be_valid
41
+
42
+      agent.options['recipients'] = nil
43
+      agent.should be_valid
44
+
45
+      agent.options['recipients'] = 'bob@example.com'
46
+      agent.should be_valid
47
+
48
+      agent.options['recipients'] = ['bob@example.com']
49
+      agent.should be_valid
50
+
51
+      agent.options['recipients'] = ['bob@example.com', 'jane@example.com']
52
+      agent.should be_valid
53
+
54
+      agent.options['recipients'] = ['bob@example.com', 'example.com']
55
+      agent.should_not be_valid
56
+
57
+      agent.options['recipients'] = ['hi!']
58
+      agent.should_not be_valid
59
+
60
+      agent.options['recipients'] = { :foo => "bar" }
61
+      agent.should_not be_valid
62
+
63
+      agent.options['recipients'] = "wut"
64
+      agent.should_not be_valid
65
+    end
66
+  end
67
+
68
+  describe "#recipients" do
69
+    it "defaults to the user's email address" do
70
+      agent.recipients.should == [users(:jane).email]
71
+    end
72
+
73
+    it "wraps a string with an array" do
74
+      agent.options['recipients'] = 'bob@bob.com'
75
+      agent.recipients.should == ['bob@bob.com']
76
+    end
77
+
78
+    it "handles an array" do
79
+      agent.options['recipients'] = ['bob@bob.com', 'jane@jane.com']
80
+      agent.recipients.should == ['bob@bob.com', 'jane@jane.com']
81
+    end
82
+
83
+    it "interpolates" do
84
+      agent.options['recipients'] = "{{ username }}@{{ domain }}"
85
+      agent.recipients('username' => 'bob', 'domain' => 'example.com').should == ["bob@example.com"]
86
+    end
87
+  end
88
+end