Merge pull request #1381 from tomknig/telegram_agent

add telegram agent
This commit is contained in:
Andrew Cantino 2016-03-30 19:35:55 -07:00
commit 85d901b403
4 changed files with 209 additions and 6 deletions

View file

@ -35,7 +35,7 @@ gem 'hipchat', '~> 1.2.0' # HipchatAgent
gem 'xmpp4r', '~> 0.5.6' # JabberAgent
gem 'mqtt' # MQTTAgent
gem 'slack-notifier', '~> 1.0.0' # SlackAgent
gem 'hypdf', '~> 1.0.7' # PDFInfoAgent
gem 'hypdf', '~> 1.0.10' # PDFInfoAgent
# Weibo Agents
gem 'weibo_2', github: 'cantino/weibo_2', branch: 'master'
@ -100,6 +100,7 @@ gem 'foreman', '~> 0.63.0'
gem 'geokit', '~> 1.8.4'
gem 'geokit-rails', '~> 2.0.1'
gem 'httparty', '~> 0.13'
gem 'httmultiparty', '~> 0.3.16'
gem 'jquery-rails', '~> 3.1.3'
gem 'json', '~> 1.8.1'
gem 'jsonpath', '~> 0.5.6'

View file

@ -267,19 +267,21 @@ GEM
hipchat (1.2.0)
httparty
hpricot (0.8.6)
httmultiparty (0.3.10)
httmultiparty (0.3.16)
httparty (>= 0.7.3)
mimemagic
multipart-post
http (0.6.4)
http_parser.rb (~> 0.6.0)
http-cookie (1.0.2)
domain_name (~> 0.5)
http_parser.rb (0.6.0)
httparty (0.13.1)
httparty (0.13.7)
json (~> 1.8)
multi_xml (>= 0.5.2)
hypdf (1.0.7)
httmultiparty (= 0.3.10)
hypdf (1.0.10)
httmultiparty (~> 0.3)
httparty (~> 0.13)
i18n (0.7.0)
jmespath (1.1.3)
jquery-rails (3.1.3)
@ -318,6 +320,7 @@ GEM
thread_safe (~> 0.3, >= 0.3.1)
method_source (0.8.2)
mime-types (2.99.1)
mimemagic (0.3.1)
mini_magick (4.2.3)
mini_portile2 (2.0.0)
minitest (5.8.4)
@ -616,8 +619,9 @@ DEPENDENCIES
guard-rspec (~> 4.6.4)
haversine
hipchat (~> 1.2.0)
httmultiparty (~> 0.3.16)
httparty (~> 0.13)
hypdf (~> 1.0.7)
hypdf (~> 1.0.10)
jquery-rails (~> 3.1.3)
json (~> 1.8.1)
jsonpath (~> 0.5.6)

View file

@ -0,0 +1,96 @@
require 'httmultiparty'
require 'open-uri'
require 'tempfile'
module Agents
class TelegramAgent < Agent
cannot_be_scheduled!
cannot_create_events!
no_bulk_receive!
description <<-MD
The Telegram Agent receives and collects events and sends them via [Telegram](https://telegram.org/).
It is assumed that events have either a `text`, `photo`, `audio`, `document` or `video` key. You can use the EventFormattingAgent if your event does not provide these keys.
The value of `text` key is sent as a plain text message.
The value of `photo`, `audio`, `document` and `video` keys should be a url whose contents will be sent to you.
**Setup**
1. Obtain an `auth_token` by [creating a new bot](https://telegram.me/botfather).
2. Send a private message to your bot by visiting https://telegram.me/YourHuginnBot
3. Obtain your private `chat_id` from the recently started conversation by visiting https://api.telegram.org/bot<auth_token>/getUpdates
MD
def default_options
{
auth_token: 'xxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
chat_id: 'xxxxxxxx'
}
end
def validate_options
errors.add(:base, 'auth_token is required') unless options['auth_token'].present?
errors.add(:base, 'chat_id is required') unless options['chat_id'].present?
end
def working?
received_event_without_error? && !recent_error_logs?
end
def receive(incoming_events)
incoming_events.each do |event|
receive_event event
end
end
private
TELEGRAM_ACTIONS = {
text: :sendMessage,
photo: :sendPhoto,
audio: :sendAudio,
document: :sendDocument,
video: :sendVideo
}.freeze
def telegram_bot_uri(method)
"https://api.telegram.org/bot#{interpolated['auth_token']}/#{method}"
end
def receive_event(event)
TELEGRAM_ACTIONS.each do |field, method|
payload = load_field event, field
next unless payload
send_telegram_message method, field => payload
unlink_file payload if payload.is_a? Tempfile
end
end
def send_telegram_message(method, params)
params[:chat_id] = interpolated['chat_id']
HTTMultiParty.post telegram_bot_uri(method), query: params
end
def load_field(event, field)
payload = event.payload[field]
return false unless payload.present?
return payload if field == :text
load_file payload
end
def load_file(url)
file = Tempfile.new [File.basename(url), File.extname(url)]
file.binmode
file.write open(url).read
file.rewind
file
end
def unlink_file(file)
file.close
file.unlink
end
end
end

View file

@ -0,0 +1,102 @@
require 'rails_helper'
describe Agents::TelegramAgent do
before do
default_options = {
auth_token: 'xxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
chat_id: 'xxxxxxxx'
}
@checker = Agents::TelegramAgent.new name: 'Telegram Tester', options: default_options
@checker.user = users(:bob)
@checker.save!
@sent_messages = []
stub_methods
end
def stub_methods
stub.any_instance_of(Agents::TelegramAgent).send_telegram_message do |method, params|
@sent_messages << { method => params }
end
stub.any_instance_of(Agents::TelegramAgent).load_file do |_url|
:stubbed_file
end
end
def event_with_payload(payload)
event = Event.new
event.agent = agents(:bob_weather_agent)
event.payload = payload
event.save!
event
end
describe 'validation' do
before do
expect(@checker).to be_valid
end
it 'should validate presence of of auth_token' do
@checker.options[:auth_token] = ''
expect(@checker).not_to be_valid
end
it 'should validate presence of of chat_id' do
@checker.options[:chat_id] = ''
expect(@checker).not_to be_valid
end
end
describe '#receive' do
it 'processes multiple events properly' do
event_0 = event_with_payload text: 'Looks like its going to rain'
event_1 = event_with_payload text: 'Another text message'
@checker.receive [event_0, event_1]
expect(@sent_messages).to eq([
{ sendMessage: { text: 'Looks like its going to rain' } },
{ sendMessage: { text: 'Another text message' } }
])
end
it 'accepts photo key and uses :send_photo to send the file' do
event = event_with_payload photo: 'https://example.com/image.png'
@checker.receive [event]
expect(@sent_messages).to eq([{ sendPhoto: { photo: :stubbed_file } }])
end
it 'accepts audio key and uses :send_audio to send the file' do
event = event_with_payload audio: 'https://example.com/sound.mp3'
@checker.receive [event]
expect(@sent_messages).to eq([{ sendAudio: { audio: :stubbed_file } }])
end
it 'accepts document key and uses :send_document to send the file' do
event = event_with_payload document: 'https://example.com/document.pdf'
@checker.receive [event]
expect(@sent_messages).to eq([{ sendDocument: { document: :stubbed_file } }])
end
it 'accepts video key and uses :send_video to send the file' do
event = event_with_payload video: 'https://example.com/video.avi'
@checker.receive [event]
expect(@sent_messages).to eq([{ sendVideo: { video: :stubbed_file } }])
end
end
describe '#working?' do
it 'is not working without having received an event' do
expect(@checker).not_to be_working
end
it 'is working after receiving an event without error' do
@checker.last_receive_at = Time.now
expect(@checker).to be_working
end
end
end