| @@ -9,6 +9,7 @@ gem 'bootstrap-kaminari-views' | ||
| 9 | 9 | gem "rufus-scheduler", :require => false | 
| 10 | 10 | gem 'json', '>= 1.7.7' | 
| 11 | 11 | gem 'jsonpath' | 
| 12 | +gem 'twilio-ruby' | |
| 12 | 13 |  | 
| 13 | 14 | gem 'delayed_job', :git => 'https://github.com/wok/delayed_job' # Until the YAML issues are fixed in master. | 
| 14 | 15 | gem 'delayed_job_active_record', "~> 0.3.3" # newer was giving a strange MySQL error | 
| @@ -0,0 +1,58 @@ | ||
| 1 | +require 'rubygems' | |
| 2 | +require 'twilio-ruby' | |
| 3 | + | |
| 4 | +module Agents | |
| 5 | + class TwilioAgent < Agent | |
| 6 | + | |
| 7 | + default_schedule "every_10m" | |
| 8 | + | |
| 9 | + description <<-MD | |
| 10 | + The TwilioAgent receives and collects events and send them via text message to cellphone when scheduled.It is assumed that events have `:message`,`:text` or `:sms` key, the value of which is sent as the content of the text message. | |
| 11 | + Set `receiver_cell` to the number on which you would like to receive text messages. | |
| 12 | + `expected_receive_period_in_days` is maximum days that you would expect to pass between events being received by this agent. | |
| 13 | + MD | |
| 14 | + | |
| 15 | + def default_options | |
| 16 | +            { | |
| 17 | + :account_sid => "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", | |
| 18 | + :auth_token => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", | |
| 19 | + :sender_cell => "xxxxxxxxxx", | |
| 20 | + :receiver_cell => "xxxxxxxxxx", | |
| 21 | + :expected_receive_period_in_days => "x" | |
| 22 | + } | |
| 23 | + end | |
| 24 | + | |
| 25 | + def validate_options | |
| 26 | + errors.add(:base, "account_sid,auth_token,sender_cell,receiver_cell,expected_receive_period_in_days are all required") unless options[:account_sid].present? && options[:auth_token].present? && options[:sender_cell].present? && options[:receiver_cell].present? && options[:expected_receive_period_in_days].present? | |
| 27 | + end | |
| 28 | + | |
| 29 | + def receive(incoming_events) | |
| 30 | + incoming_events.each do |event| | |
| 31 | + self.memory[:queue] ||= [] # If memory[:queue] is not true, assign [] to it, a || a = b | |
| 32 | + self.memory[:queue] << event.payload # Append | |
| 33 | + end | |
| 34 | + end | |
| 35 | + | |
| 36 | + def working? | |
| 37 | + last_receive_at && last_receive_at > options[:expected_receive_period_in_days].to_i.days.ago | |
| 38 | + end | |
| 39 | + | |
| 40 | + def send_message(client,message) | |
| 41 | + client.account.sms.messages.create(:from=>options[:sender_cell],:to=>options[:receiver_cell],:body=>message) | |
| 42 | + end | |
| 43 | + | |
| 44 | + def check | |
| 45 | + if self.memory[:queue] && self.memory[:queue].length > 0 | |
| 46 | + @client = Twilio::REST::Client.new options[:account_sid],options[:auth_token] | |
| 47 | + self.memory[:queue].each do |text| | |
| 48 | + message = text[:message] || text[:text] || text[:sms] | |
| 49 | + if message | |
| 50 | + message.slice! 160, message.length | |
| 51 | + send_message @client, message | |
| 52 | + end | |
| 53 | + end | |
| 54 | + self.memory[:queue] = [] | |
| 55 | + end | |
| 56 | + end | |
| 57 | + end | |
| 58 | +end | 
| @@ -51,7 +51,7 @@ describe Agents::TriggerAgent do | ||
| 51 | 51 |  | 
| 52 | 52 | @checker.should_not be_working # no events have ever been received | 
| 53 | 53 | Agents::TriggerAgent.async_receive(@checker.id, [@event.id]) | 
| 54 | - @checker.reload.should be_working # no events have ever been received | |
| 54 | + @checker.reload.should be_working # Events received | |
| 55 | 55 | three_days_from_now = 3.days.from_now | 
| 56 | 56 |        stub(Time).now { three_days_from_now } | 
| 57 | 57 | @checker.reload.should_not be_working # too much time has passed | 
| @@ -0,0 +1,56 @@ | ||
| 1 | +require 'spec_helper' | |
| 2 | + | |
| 3 | +describe Agents::TwilioAgent do | |
| 4 | + before do | |
| 5 | +        @checker = Agents::TwilioAgent.new(:name => "somename", :options => {:account_sid => "x",:auth_token => "x",:sender_cell => "x", :receiver_cell => "x", :expected_receive_period_in_days => "1"}) | |
| 6 | + @checker.user = users(:bob) | |
| 7 | + @checker.save! | |
| 8 | + | |
| 9 | + @event = Event.new | |
| 10 | + @event.agent = agents(:bob_weather_agent) | |
| 11 | +        @event.payload = {:message => "Gonna rain.."} | |
| 12 | + @event.save! | |
| 13 | + | |
| 14 | +        stub.any_instance_of(Agents::TwilioAgent).send_message {} | |
| 15 | + end | |
| 16 | + | |
| 17 | + describe "#receive" do | |
| 18 | + it "should queue any payload it receives" do | |
| 19 | + event1 = Event.new | |
| 20 | + event1.agent = agents(:bob_rain_notifier_agent) | |
| 21 | + event1.payload = "Some payload" | |
| 22 | + event1.save! | |
| 23 | + | |
| 24 | + event2 = Event.new | |
| 25 | + event2.agent = agents(:bob_weather_agent) | |
| 26 | + event2.payload = "More payload" | |
| 27 | + event2.save! | |
| 28 | + | |
| 29 | + Agents::TwilioAgent.async_receive(@checker.id, [event1.id,event2.id]) | |
| 30 | + @checker.reload.memory[:queue].should == ["Some payload", "More payload"] | |
| 31 | + end | |
| 32 | + end | |
| 33 | + | |
| 34 | + describe "#working?" do | |
| 35 | + it "checks if events have been received within expected receive period" do | |
| 36 | + @checker.should_not be_working # No events received | |
| 37 | + Agents::TwilioAgent.async_receive @checker.id, [@event.id] | |
| 38 | + @checker.reload.should be_working # Just received events | |
| 39 | + two_days_from_now = 2.days.from_now | |
| 40 | +            stub(Time).now { two_days_from_now } | |
| 41 | + @checker.reload.should_not be_working # More time have passed than expected receive period without sign of any new event | |
| 42 | + end | |
| 43 | + end | |
| 44 | + | |
| 45 | + describe "#check" do | |
| 46 | + before do | |
| 47 | + Agents::TwilioAgent.async_receive @checker.id, [@event.id] | |
| 48 | + end | |
| 49 | + it "should send text message and Memory should be empty after that" do | |
| 50 | +            @checker.reload.memory[:queue].should == [{:message => "Gonna rain.."}] | |
| 51 | + Agents::TwilioAgent.async_check(@checker.id) | |
| 52 | + @checker.reload.memory[:queue].should == [] | |
| 53 | + | |
| 54 | + end | |
| 55 | + end | |
| 56 | +end |