Bläddra i källkod

Add more options to the GrowlAgent

It now additionally allows to use `sticky`, `priority` and
`callback_url`. The Agent is now `FormConfigurable` and supports Liquid
in all options.
`register_growl` had to be moved inside of the `events` loop to allow
Liquid interpolation for the previously static `growl_*` options.

 #2018
Dominik Sander 7 år sedan
förälder
incheckning
5f92b38f6e

+ 47 - 18
app/models/agents/growl_agent.rb

@@ -1,9 +1,11 @@
 module Agents
   class GrowlAgent < Agent
+    include FormConfigurable
     attr_reader :growler
 
     cannot_be_scheduled!
     cannot_create_events!
+    can_dry_run!
 
     gem_dependency_check { defined?(Growl) }
 
@@ -11,10 +13,16 @@ module Agents
       The Growl Agent sends any events it receives to a Growl GNTP server immediately.
 
       #{'## Include `ruby-growl` in your Gemfile to use this Agent!' if dependencies_missing?}
-      
-      It is assumed that events have a `message` or `text` key, which will hold the body of the growl notification, and a `subject` key, which will have the headline of the Growl notification. You can use Event Formatting Agent if your event does not provide these keys.
 
-      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.
+      The option `message`, which will hold the body of the growl notification, and the `subject` option,
+      which will have the headline of the Growl notification are required. All other options are optional.
+      When `callback_url` is set to a URL clicking on the notification will open the link in your default browser.
+
+      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.
+
+      Have a look at the [Wiki](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) to learn
+      more about liquid templating.
     MD
 
     def default_options
@@ -23,12 +31,27 @@ module Agents
           'growl_password' => '',
           'growl_app_name' => 'HuginnGrowl',
           'growl_notification_name' => 'Notification',
-          'expected_receive_period_in_days' => "2"
+          'expected_receive_period_in_days' => "2",
+          'subject' => '{{subject}}',
+          'message' => '{{message}}',
+          'sticky' => 'false',
+          'priority' => '0'
       }
     end
-    
+
+    form_configurable :growl_server
+    form_configurable :growl_password
+    form_configurable :growl_app_name
+    form_configurable :growl_notification_name
+    form_configurable :expected_receive_period_in_days
+    form_configurable :subject
+    form_configurable :message, type: :text
+    form_configurable :sticky, type: :boolean
+    form_configurable :priority
+    form_configurable :callback_url
+
     def working?
-      last_receive_at && last_receive_at > interpolated['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
+      last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
     end
 
     def validate_options
@@ -38,25 +61,31 @@ module Agents
     end
 
     def register_growl
-      @growler = Growl.new interpolated['growl_server'], interpolated['growl_app_name'], "GNTP"
+      @growler = Growl::GNTP.new(interpolated['growl_server'], interpolated['growl_app_name'])
       @growler.password = interpolated['growl_password']
-      @growler.add_notification interpolated['growl_notification_name']
+      @growler.add_notification(interpolated['growl_notification_name'])
     end
 
-    def notify_growl(subject, message)
-      @growler.notify(interpolated['growl_notification_name'], subject, message)
+    def notify_growl(subject:, message:, priority:, sticky:, callback_url:)
+      @growler.notify(interpolated['growl_notification_name'], subject, message, priority, sticky, nil, callback_url)
     end
 
     def receive(incoming_events)
-      register_growl
       incoming_events.each do |event|
-        message = (event.payload['message'] || event.payload['text']).to_s
-        subject = event.payload['subject'].to_s
-        if message.present? && subject.present?
-          log "Sending Growl notification '#{subject}': '#{message}' to #{interpolated(event)['growl_server']} with event #{event.id}"
-          notify_growl(subject,message)
-        else
-          log "Event #{event.id} not sent, message and subject expected"
+        interpolate_with(event) do
+          register_growl
+          message = interpolated[:message]
+          subject = interpolated[:subject]
+          if message.present? && subject.present?
+            log "Sending Growl notification '#{subject}': '#{message}' to #{interpolated(event)['growl_server']} with event #{event.id}"
+            notify_growl(subject: subject,
+                         message: message,
+                         priority: interpolated[:priority].to_i,
+                         sticky: boolify(interpolated[:sticky]) || false,
+                         callback_url: interpolated[:callback_url].presence)
+          else
+            log "Event #{event.id} not sent, message and subject expected"
+          end
         end
       end
     end

+ 18 - 0
db/migrate/20170731191002_migrate_growl_agent_to_liquid.rb

@@ -0,0 +1,18 @@
+class MigrateGrowlAgentToLiquid < ActiveRecord::Migration[5.1]
+  def up
+    Agents::GrowlAgent.find_each do |agent|
+      agent.options['subject'] = '{{subject}}' if agent.options['subject'].blank?
+      agent.options['message'] = '{{ message | default: text }}' if agent.options['message'].blank?
+      agent.save(validate: false)
+    end
+  end
+
+  def down
+    Agents::GrowlAgent.find_each do |agent|
+      %w(subject message sticky priority).each do |key|
+        agent.options.delete(key)
+      end
+      agent.save(validate: false)
+    end
+  end
+end

+ 24 - 21
spec/models/agents/growl_agent_spec.rb

@@ -7,11 +7,13 @@ describe Agents::GrowlAgent do
                                                     :growl_app_name => 'HuginnGrowlApp',
                                                     :growl_password => 'mypassword',
                                                     :growl_notification_name => 'Notification',
-                                                    :expected_receive_period_in_days => '1' })
+                                                    expected_receive_period_in_days: '1' ,
+                                                    message: '{{message}}',
+                                                    subject: '{{subject}}'})
     @checker.user = users(:bob)
     @checker.save!
-    
-    stub.any_instance_of(Growl).notify
+
+    stub.any_instance_of(Growl::GNTP).notify
 
     @event = Event.new
     @event.agent = agents(:bob_weather_agent)
@@ -45,7 +47,7 @@ describe Agents::GrowlAgent do
       expect(@checker).not_to be_valid
     end
   end
-  
+
   describe "register_growl" do
     it "should set the password for the Growl connection from the agent options" do
       @checker.register_growl
@@ -54,34 +56,34 @@ describe Agents::GrowlAgent do
 
     it "should add a notification to the Growl connection" do
       called = false
-      any_instance_of(Growl) do |obj|
+      any_instance_of(Growl::GNTP) do |obj|
         called = true
         mock(obj).add_notification(@checker.options[:growl_notification_name])
       end
-      
+
       @checker.register_growl
       expect(called).to be_truthy
     end
   end
-  
+
   describe "notify_growl" do
     before do
       @checker.register_growl
     end
-    
+
     it "should call Growl.notify with the correct notification name, subject, and message" do
       message = "message"
       subject = "subject"
       called = false
-      any_instance_of(Growl) do |obj|
+      any_instance_of(Growl::GNTP) do |obj|
         called = true
-        mock(obj).notify(@checker.options[:growl_notification_name],subject,message)
+        mock(obj).notify(@checker.options[:growl_notification_name], subject, message, 0, false, nil, '')
       end
-      @checker.notify_growl(subject,message)
+      @checker.notify_growl(subject: subject, message: message, sticky: false, priority: 0, callback_url: '')
       expect(called).to be_truthy
     end
   end
-  
+
   describe "receive" do
     def generate_events_array
       events = []
@@ -90,31 +92,32 @@ describe Agents::GrowlAgent do
       end
       return events
     end
-    
-    it "should call register_growl once regardless of number of events received" do
-      mock.proxy(@checker).register_growl.once
-      @checker.receive(generate_events_array)
+
+    it "should call register_growl once per received event" do
+      events = generate_events_array
+      mock.proxy(@checker).register_growl.times(events.length)
+      @checker.receive(events)
     end
-    
+
     it "should call notify_growl one time for each event received" do
       events = generate_events_array
       events.each do |event|
-        mock.proxy(@checker).notify_growl(event.payload['subject'], event.payload['message'])
+        mock.proxy(@checker).notify_growl(subject: event.payload['subject'], message: event.payload['message'], priority: 0, sticky: false, callback_url: nil)
       end
       @checker.receive(events)
     end
-    
+
     it "should not call notify_growl if message or subject are missing" do
       event_without_a_subject = Event.new
       event_without_a_subject.agent = agents(:bob_weather_agent)
       event_without_a_subject.payload = { :message => 'Looks like its going to rain' }
       event_without_a_subject.save!
-      
+
       event_without_a_message = Event.new
       event_without_a_message.agent = agents(:bob_weather_agent)
       event_without_a_message.payload = { :subject => 'Weather Alert YO!' }
       event_without_a_message.save!
-      
+
       mock.proxy(@checker).notify_growl.never
       @checker.receive([event_without_a_subject,event_without_a_message])
     end