Browse Source

Merge pull request #114 from albertsun/event-email-agent

Event email agent
Andrew Cantino 11 years ago
parent
commit
744ec91b37

+ 37 - 0
app/concerns/email_concern.rb

@@ -0,0 +1,37 @@
+module EmailConcern
+  extend ActiveSupport::Concern
+
+  MAIN_KEYS = %w[title message text main value].map(&:to_sym)
+
+  included do
+    self.validate :validate_email_options
+  end
+
+  def validate_email_options
+    errors.add(:base, "subject and expected_receive_period_in_days are required") unless options[:subject].present? && options[:expected_receive_period_in_days].present?
+  end
+
+  def working?
+    last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
+  end
+
+  def present(payload)
+    if payload.is_a?(Hash)
+      payload = ActiveSupport::HashWithIndifferentAccess.new(payload)
+      MAIN_KEYS.each do |key|
+        return { :title => payload[key].to_s, :entries => present_hash(payload, key) } if payload.has_key?(key)
+      end
+
+      { :title => "Event", :entries => present_hash(payload) }
+    else
+      { :title => payload.to_s, :entries => [] }
+    end
+  end
+
+  def present_hash(hash, skip_key = nil)
+    hash.to_a.sort_by {|a| a.first.to_s }.map { |k, v| "#{k}: #{v}" unless k.to_s == skip_key.to_s }.compact
+  end
+
+  module ClassMethods
+  end
+end

+ 7 - 27
app/models/agents/digest_email_agent.rb

@@ -1,6 +1,7 @@
 module Agents
   class DigestEmailAgent < Agent
-    MAIN_KEYS = %w[title message text main value].map(&:to_sym)
+    include EmailConcern
+
     default_schedule "5am"
 
     cannot_create_events!
@@ -22,45 +23,24 @@ module Agents
       }
     end
 
-    def working?
-      last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago && !recent_error_logs?
-    end
-
-    def validate_options
-      errors.add(:base, "subject and expected_receive_period_in_days are required") unless options[:subject].present? && options[:expected_receive_period_in_days].present?
-    end
-
     def receive(incoming_events)
       incoming_events.each do |event|
         self.memory[:queue] ||= []
         self.memory[:queue] << event.payload
+        self.memory[:events] ||= []
+        self.memory[:events] << event.id
       end
     end
 
     def check
       if self.memory[:queue] && self.memory[:queue].length > 0
+        ids = self.memory[:events].join(",")
         groups = self.memory[:queue].map { |payload| present(payload) }
-        log "Sending digest mail to #{user.email}"
+        log "Sending digest mail to #{user.email} with events [#{ids}]"
         SystemMailer.delay.send_message(:to => user.email, :subject => options[:subject], :headline => options[:headline], :groups => groups)
         self.memory[:queue] = []
+        self.memory[:events] = []
       end
     end
-
-    def present(payload)
-      if payload.is_a?(Hash)
-        payload = ActiveSupport::HashWithIndifferentAccess.new(payload)
-        MAIN_KEYS.each do |key|
-          return { :title => payload[key].to_s, :entries => present_hash(payload, key) } if payload.has_key?(key)
-        end
-
-        { :title => "Event", :entries => present_hash(payload) }
-      else
-        { :title => payload.to_s, :entries => [] }
-      end
-    end
-
-    def present_hash(hash, skip_key = nil)
-      hash.to_a.sort_by {|a| a.first.to_s }.map { |k, v| "#{k}: #{v}" unless k.to_s == skip_key.to_s }.compact
-    end
   end
 end

+ 32 - 0
app/models/agents/email_agent.rb

@@ -0,0 +1,32 @@
+module Agents
+  class EmailAgent < Agent
+    include EmailConcern
+
+    cannot_be_scheduled!
+    cannot_create_events!
+
+    description <<-MD
+      The EmailAgent sends any events it receives via email immediately.
+      The email will be sent to your account's address and will have a `subject` and an optional `headline` before
+      listing the Events.  If the Events' payloads contain a `:message`, that will be highlighted, otherwise everything in
+      their payloads will be shown.
+
+      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.
+    MD
+
+    def default_options
+      {
+          :subject => "You have a notification!",
+          :headline => "Your notification:",
+          :expected_receive_period_in_days => "2"
+      }
+    end
+
+    def receive(incoming_events)
+      incoming_events.each do |event|
+        log "Sending digest mail to #{user.email} with event #{event.id}"
+        SystemMailer.delay.send_message(:to => user.email, :subject => options[:subject], :headline => options[:headline], :groups => [present(event.payload)])
+      end
+    end
+  end
+end

+ 1 - 0
spec/models/agents/digest_email_agent_spec.rb

@@ -41,6 +41,7 @@ describe Agents::DigestEmailAgent do
                                  { :title => "Foo", :url => "http://google.com", :bar => 2 },
                                  { "message" => "hi", :woah => "there" },
                                  { "test" => 2 }]
+      @checker.memory[:events] = [1,2,3,4]
       @checker.save!
 
       Agents::DigestEmailAgent.async_check(@checker.id)

+ 59 - 0
spec/models/agents/email_agent_spec.rb

@@ -0,0 +1,59 @@
+require 'spec_helper'
+
+describe Agents::EmailAgent do
+  def get_message_part(mail, content_type)
+    mail.body.parts.find { |p| p.content_type.match content_type }.body.raw_source
+  end
+
+  before do
+    @checker = Agents::EmailAgent.new(:name => "something", :options => { :expected_receive_period_in_days => 2, :subject => "something interesting" })
+    @checker.user = users(:bob)
+    @checker.save!
+  end
+
+  after do
+    ActionMailer::Base.deliveries = []
+  end
+
+  describe "#receive" do
+    it "immediately sends any payloads it receives" do
+      ActionMailer::Base.deliveries.should == []
+
+      event1 = Event.new
+      event1.agent = agents(:bob_rain_notifier_agent)
+      event1.payload = "Something you should know about"
+      event1.save!
+
+      event2 = Event.new
+      event2.agent = agents(:bob_weather_agent)
+      event2.payload = "Something else you should know about"
+      event2.save!
+
+      Agents::EmailAgent.async_receive(@checker.id, [event1.id])
+      Agents::EmailAgent.async_receive(@checker.id, [event2.id])
+
+      ActionMailer::Base.deliveries.count.should == 2
+      ActionMailer::Base.deliveries.last.to.should == ["bob@example.com"]
+      ActionMailer::Base.deliveries.last.subject.should == "something interesting"
+      get_message_part(ActionMailer::Base.deliveries.last, /plain/).strip.should == "Something else you should know about"
+      get_message_part(ActionMailer::Base.deliveries.first, /plain/).strip.should == "Something you should know about"
+    end
+
+    it "can receive complex events and send them on" do
+      stub_request(:any, /wunderground/).to_return(:body => File.read(Rails.root.join("spec/data_fixtures/weather.json")), :status => 200)
+      stub.any_instance_of(Agents::WeatherAgent).is_tomorrow?(anything) { true }
+      @checker.sources << agents(:bob_weather_agent)
+
+      Agent.async_check(agents(:bob_weather_agent).id)
+
+      Agent.receive!
+
+      plain_email_text = get_message_part(ActionMailer::Base.deliveries.last, /plain/).strip
+      html_email_text = get_message_part(ActionMailer::Base.deliveries.last, /html/).strip
+
+      plain_email_text.should =~ /avehumidity/
+      html_email_text.should =~ /avehumidity/
+    end
+
+  end
+end