Skip to content

Commit

Permalink
Merge pull request #2138 from dsander/improve-telegram-agent
Browse files Browse the repository at this point in the history
Make TelegramAgent FormConfigurable, DryRunable and add logging
  • Loading branch information
dsander committed Oct 3, 2017
2 parents ec16163 + da72ecd commit 1448f15
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 15 deletions.
52 changes: 40 additions & 12 deletions app/models/agents/telegram_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@

module Agents
class TelegramAgent < Agent
include FormConfigurable

cannot_be_scheduled!
cannot_create_events!
no_bulk_receive!
can_dry_run!

description <<-MD
The Telegram Agent receives and collects events and sends them via [Telegram](https://telegram.org/).
Expand All @@ -18,16 +21,15 @@ class TelegramAgent < Agent
**Setup**
1. Obtain an `auth_token` by [creating a new bot](https://telegram.me/botfather).
2a. If you would like to send messages to a public channel:
1. Add your bot to the channel as an administrator
2. Set `chat_id` to the name of your channel - e.g. `@YourHugginChannel`
2b. If you would like to send messages to a group:
1. Add the bot to the group
2. Obtain your group `chat_id` from the recently started conversation by visiting https://api.telegram.org/bot`<auth_token>`/getUpdates
2c. If you would like to send messages privately to yourself:
1. Send a private message to your bot by visiting https://telegram.me/YourHuginnBot
2. Obtain your private `chat_id` from the recently started conversation by visiting https://api.telegram.org/bot`<auth_token>`/getUpdates
* Obtain an `auth_token` by [creating a new bot](https://telegram.me/botfather).
* If you would like to send messages to a public channel:
* Add your bot to the channel as an administrator
* If you would like to send messages to a group:
* Add the bot to the group
* If you would like to send messages privately to yourself:
* Open a conservation with the bot by visiting https://telegram.me/YourHuginnBot
* Send a message to the bot, group or channel.
* Select the `chat_id` from the dropdown.
MD

def default_options
Expand All @@ -37,6 +39,20 @@ def default_options
}
end

form_configurable :auth_token, roles: :validatable
form_configurable :chat_id, roles: :completable
form_configurable :parse_mode, type: :array, values: ['', 'html', 'markdown']

def validate_auth_token
HTTMultiParty.post(telegram_bot_uri('getMe'))['ok'] == true
end

def complete_chat_id
response = HTTMultiParty.post(telegram_bot_uri('getUpdates'))
return [] unless response['ok']
response['result'].map { |update| update_to_complete(update) }.uniq
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?
Expand Down Expand Up @@ -68,18 +84,23 @@ def telegram_bot_uri(method)
end

def receive_event(event)
TELEGRAM_ACTIONS.each do |field, method|
messages_send = TELEGRAM_ACTIONS.count 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
true
end
error("No valid key found in event #{event.payload.inspect}") if messages_send.zero?
end

def send_telegram_message(method, params)
params[:chat_id] = interpolated['chat_id']
params[:parse_mode] = interpolated['parse_mode'] if interpolated['parse_mode'].present?
HTTMultiParty.post telegram_bot_uri(method), query: params
response = HTTMultiParty.post telegram_bot_uri(method), query: params
if response['ok'] == false
error(response)
end
end

def load_field(event, field)
Expand All @@ -101,5 +122,12 @@ def unlink_file(file)
file.close
file.unlink
end

private

def update_to_complete(update)
chat = (update['message'] || update.fetch('channel_post', {})).fetch('chat', {})
{id: chat['id'], text: chat['title'] || "#{chat['first_name']} #{chat['last_name']}"}
end
end
end
56 changes: 53 additions & 3 deletions spec/models/agents/telegram_agent_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
@checker = Agents::TelegramAgent.new name: 'Telegram Tester', options: default_options
@checker.user = users(:bob)
@checker.save!

@sent_messages = []
stub_methods
end

def stub_methods
Expand Down Expand Up @@ -49,6 +46,11 @@ def event_with_payload(payload)
end

describe '#receive' do
before do
@sent_messages = []
stub_methods
end

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'
Expand Down Expand Up @@ -87,6 +89,24 @@ def event_with_payload(payload)

expect(@sent_messages).to eq([{ sendVideo: { video: :stubbed_file } }])
end

it 'creates a log entry when no key of the received event was useable' do
event = event_with_payload test: '1234'
expect {
@checker.receive [event]
}.to change(AgentLog, :count).by(1)
end
end

it 'creates and error log if the request fails' do
event = event_with_payload text: 'hello'
stub_request(:post, "https://api.telegram.org/botxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/sendMessage").
with(headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
to_return(status: 200, body: '{"ok": false}', headers: {'Content-Type' => 'application/json'})

expect {
@checker.receive [event]
}.to change(AgentLog, :count).by(1)
end

describe '#working?' do
Expand All @@ -99,4 +119,34 @@ def event_with_payload(payload)
expect(@checker).to be_working
end
end

describe '#complete_chat_id' do
it 'returns a list of all recents chats, groups and channels' do
stub_request(:post, "https://api.telegram.org/botxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/getUpdates").
with(headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
to_return(status: 200, body: '{"ok":true,"result":[{"update_id":252965475,"message":{"message_id":15,"from":{"id":97201077,"is_bot":false,"first_name":"Dominik","last_name":"Sander","language_code":"en-US"},"chat":{"id":97201077,"first_name":"Dominik","last_name":"Sander","type":"private"},"date":1506774710,"text":"test"}},{"update_id":252965476,"channel_post":{"message_id":4,"chat":{"id":-1001144599139,"title":"Much channel","type":"channel"},"date":1506782283,"text":"channel"}},{"update_id":252965477,"message":{"message_id":18,"from":{"id":97201077,"is_bot":false,"first_name":"Dominik","last_name":"Sander","language_code":"en-US"},"chat":{"id":-217850512,"title":"Just a test","type":"group","all_members_are_administrators":true},"date":1506782504,"left_chat_participant":{"id":136508315,"is_bot":true,"first_name":"Huginn","username":"HuginnNotificationBot"},"left_chat_member":{"id":136508315,"is_bot":true,"first_name":"Huginn","username":"HuginnNotificationBot"}}}]}', headers: {'Content-Type' => 'application/json'})

expect(@checker.complete_chat_id).to eq([{:id=>97201077, :text=>"Dominik Sander"},
{:id=>-1001144599139, :text=>"Much channel"},
{:id=>-217850512, :text=>"Just a test"}])
end
end

describe '#validate_auth_token' do
it 'returns true if the token is valid' do
stub_request(:post, "https://api.telegram.org/botxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/getMe").
with(headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
to_return(status: 200, body: '{"ok": true}', headers: {'Content-Type' => 'application/json'})

expect(@checker.validate_auth_token).to be_truthy
end

it 'returns false if the token is invalid' do
stub_request(:post, "https://api.telegram.org/botxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/getMe").
with(headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
to_return(status: 200, body: "{}")

expect(@checker.validate_auth_token).to be_falsy
end
end
end

0 comments on commit 1448f15

Please sign in to comment.