mirror of
https://github.com/Fishwaldo/huginn.git
synced 2025-03-15 19:31:26 +00:00
Twitter retweet agent (#1181)
* Agent to retweet all received tweet events * Cache twitter rest client * Update description, remove unused local * Makes context strings more readable, style consistency * to_h is not implemented in ruby 2.0 * In error case, include all agent_ids and event_ids * Adds capability to favorite tweets This restructures the Agent slightly to allow for retweeting and favoriting. It is possible to do both at the same time. - Renames the Agent from TwitterRetweetAgent to TwitterActionAgent. - Specs refactored
This commit is contained in:
parent
9d2626dd4f
commit
414743556f
3 changed files with 233 additions and 1 deletions
|
@ -36,7 +36,7 @@ module TwitterConcern
|
|||
end
|
||||
|
||||
def twitter
|
||||
Twitter::REST::Client.new do |config|
|
||||
@twitter ||= Twitter::REST::Client.new do |config|
|
||||
config.consumer_key = twitter_consumer_key
|
||||
config.consumer_secret = twitter_consumer_secret
|
||||
config.access_token = twitter_oauth_token
|
||||
|
|
74
app/models/agents/twitter_action_agent.rb
Normal file
74
app/models/agents/twitter_action_agent.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
module Agents
|
||||
class TwitterActionAgent < Agent
|
||||
include TwitterConcern
|
||||
|
||||
cannot_be_scheduled!
|
||||
|
||||
description <<-MD
|
||||
The Twitter Action Agent is able to retweet or favorite tweets from the events it receives.
|
||||
|
||||
#{ twitter_dependencies_missing if dependencies_missing? }
|
||||
|
||||
It expects to consume events generated by twitter agents where the payload is a hash of tweet information. The existing TwitterStreamAgent is one example of a valid event producer for this Agent.
|
||||
|
||||
To be able to use this Agent you need to authenticate with Twitter in the [Services](/services) section first.
|
||||
|
||||
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.
|
||||
Set `retweet` to either true or false.
|
||||
Set `favorite` to either true or false.
|
||||
MD
|
||||
|
||||
def validate_options
|
||||
unless options['expected_receive_period_in_days'].present?
|
||||
errors.add(:base, "expected_receive_period_in_days is required")
|
||||
end
|
||||
unless retweet? || favorite?
|
||||
errors.add(:base, "at least one action must be true")
|
||||
end
|
||||
end
|
||||
|
||||
def working?
|
||||
last_receive_at && last_receive_at > interpolated['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
|
||||
end
|
||||
|
||||
def default_options
|
||||
{
|
||||
'expected_receive_period_in_days' => '2',
|
||||
'favorite' => 'false',
|
||||
'retweet' => 'true',
|
||||
}
|
||||
end
|
||||
|
||||
def retweet?
|
||||
boolify(options['retweet'])
|
||||
end
|
||||
|
||||
def favorite?
|
||||
boolify(options['favorite'])
|
||||
end
|
||||
|
||||
def receive(incoming_events)
|
||||
tweets = tweets_from_events(incoming_events)
|
||||
|
||||
begin
|
||||
twitter.favorite(tweets) if favorite?
|
||||
twitter.retweet(tweets) if retweet?
|
||||
rescue Twitter::Error => e
|
||||
create_event :payload => {
|
||||
'success' => false,
|
||||
'error' => e.message,
|
||||
'tweets' => Hash[tweets.map { |t| [t.id, t.text] }],
|
||||
'agent_ids' => incoming_events.map(&:agent_id),
|
||||
'event_ids' => incoming_events.map(&:id)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def tweets_from_events(events)
|
||||
events.map do |e|
|
||||
Twitter::Tweet.new(id: e.payload["id"], text: e.payload["text"])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
158
spec/models/agents/twitter_action_agent_spec.rb
Normal file
158
spec/models/agents/twitter_action_agent_spec.rb
Normal file
|
@ -0,0 +1,158 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe Agents::TwitterActionAgent do
|
||||
describe '#receive' do
|
||||
before do
|
||||
@event1 = Event.new
|
||||
@event1.agent = agents(:bob_twitter_user_agent)
|
||||
@event1.payload = { id: 123, text: 'So awesome.. gotta retweet' }
|
||||
@event1.save!
|
||||
@tweet1 = Twitter::Tweet.new(
|
||||
id: @event1.payload[:id],
|
||||
text: @event1.payload[:text]
|
||||
)
|
||||
|
||||
@event2 = Event.new
|
||||
@event2.agent = agents(:bob_twitter_user_agent)
|
||||
@event2.payload = { id: 456, text: 'Something Justin Bieber said' }
|
||||
@event2.save!
|
||||
@tweet2 = Twitter::Tweet.new(
|
||||
id: @event2.payload[:id],
|
||||
text: @event2.payload[:text]
|
||||
)
|
||||
end
|
||||
|
||||
context 'when set up to retweet' do
|
||||
before do
|
||||
@agent = build_agent({
|
||||
'expected_receive_period_in_days' => '2',
|
||||
'favorite' => 'false',
|
||||
'retweet' => 'true',
|
||||
})
|
||||
@agent.save!
|
||||
end
|
||||
|
||||
context 'when the twitter client succeeds retweeting' do
|
||||
it 'should retweet the tweets from the payload' do
|
||||
mock(@agent.twitter).retweet([@tweet1, @tweet2])
|
||||
@agent.receive([@event1, @event2])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the twitter client fails retweeting' do
|
||||
it 'creates an event with tweet info and the error message' do
|
||||
stub(@agent.twitter).retweet(anything) {
|
||||
raise Twitter::Error.new('uh oh')
|
||||
}
|
||||
|
||||
@agent.receive([@event1, @event2])
|
||||
|
||||
failure_event = @agent.events.last
|
||||
expect(failure_event.payload[:error]).to eq('uh oh')
|
||||
expect(failure_event.payload[:tweets]).to eq(
|
||||
{
|
||||
@event1.payload[:id].to_s => @event1.payload[:text],
|
||||
@event2.payload[:id].to_s => @event2.payload[:text]
|
||||
}
|
||||
)
|
||||
expect(failure_event.payload[:agent_ids]).to match_array(
|
||||
[@event1.agent_id, @event2.agent_id]
|
||||
)
|
||||
expect(failure_event.payload[:event_ids]).to match_array(
|
||||
[@event2.id, @event1.id]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when set up to favorite' do
|
||||
before do
|
||||
@agent = build_agent(
|
||||
'expected_receive_period_in_days' => '2',
|
||||
'favorite' => 'true',
|
||||
'retweet' => 'false',
|
||||
)
|
||||
@agent.save!
|
||||
end
|
||||
|
||||
context 'when the twitter client succeeds favoriting' do
|
||||
it 'should favorite the tweets from the payload' do
|
||||
mock(@agent.twitter).favorite([@tweet1, @tweet2])
|
||||
@agent.receive([@event1, @event2])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the twitter client fails retweeting' do
|
||||
it 'creates an event with tweet info and the error message' do
|
||||
stub(@agent.twitter).favorite(anything) {
|
||||
raise Twitter::Error.new('uh oh')
|
||||
}
|
||||
|
||||
@agent.receive([@event1, @event2])
|
||||
|
||||
failure_event = @agent.events.last
|
||||
expect(failure_event.payload[:error]).to eq('uh oh')
|
||||
expect(failure_event.payload[:tweets]).to eq(
|
||||
{
|
||||
@event1.payload[:id].to_s => @event1.payload[:text],
|
||||
@event2.payload[:id].to_s => @event2.payload[:text]
|
||||
}
|
||||
)
|
||||
expect(failure_event.payload[:agent_ids]).to match_array(
|
||||
[@event1.agent_id, @event2.agent_id]
|
||||
)
|
||||
expect(failure_event.payload[:event_ids]).to match_array(
|
||||
[@event2.id, @event1.id]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#validate_options" do
|
||||
context 'when set up to neither favorite or retweet' do
|
||||
it 'is invalid' do
|
||||
agent = build_agent(
|
||||
'expected_receive_period_in_days' => '2',
|
||||
'favorite' => 'false',
|
||||
'retweet' => 'false',
|
||||
)
|
||||
|
||||
expect(agent).not_to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#working?' do
|
||||
before do
|
||||
stub.any_instance_of(Twitter::REST::Client).retweet(anything)
|
||||
end
|
||||
|
||||
it 'checks if events have been received within the expected time period' do
|
||||
agent = build_agent(
|
||||
'expected_receive_period_in_days' => '2',
|
||||
'favorite' => 'false',
|
||||
'retweet' => 'true',
|
||||
)
|
||||
agent.save!
|
||||
|
||||
expect(agent).not_to be_working # No events received
|
||||
|
||||
described_class.async_receive(agent.id, [events(:bob_website_agent_event)])
|
||||
expect(agent.reload).to be_working # Just received events
|
||||
|
||||
two_days_from_now = 2.days.from_now
|
||||
stub(Time).now { two_days_from_now }
|
||||
expect(agent.reload).not_to be_working # Too much time has passed
|
||||
end
|
||||
end
|
||||
|
||||
def build_agent(options)
|
||||
described_class.new do |agent|
|
||||
agent.name = 'twitter stuff'
|
||||
agent.options = options
|
||||
agent.service = services(:generic)
|
||||
agent.user = users(:bob)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue