diff --git a/CHANGELOG.md b/CHANGELOG.md index 032c28d..194188f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.7.0 Unreleased + +- New Bot API methods. +- Helpers for inline keyboards. + # 0.6.0 - StaleChat error. diff --git a/lib/telegram/bot/client.rb b/lib/telegram/bot/client.rb index 62cb1b2..d9d5db9 100644 --- a/lib/telegram/bot/client.rb +++ b/lib/telegram/bot/client.rb @@ -68,22 +68,27 @@ module Telegram end %w( + answerCallbackQuery answerInlineQuery forwardMessage getFile getMe getUpdates getUserProfilePhotos + kickChatMember sendAudio sendChatAction + sendContact sendDocument sendLocation sendMessage sendPhoto sendSticker + sendVenue sendVideo sendVoice setWebhook + unbanChatMember ).each do |method| define_method(method.underscore) { |*args| request(method, *args) } end diff --git a/lib/telegram/bot/updates_controller.rb b/lib/telegram/bot/updates_controller.rb index b41c94b..99ea2fd 100644 --- a/lib/telegram/bot/updates_controller.rb +++ b/lib/telegram/bot/updates_controller.rb @@ -56,6 +56,7 @@ module Telegram require 'telegram/bot/updates_controller/session' require 'telegram/bot/updates_controller/log_subscriber' require 'telegram/bot/updates_controller/instrumentation' + require 'telegram/bot/updates_controller/reply_helpers' autoload :MessageContext, 'telegram/bot/updates_controller/message_context' autoload :Botan, 'telegram/bot/updates_controller/botan' @@ -71,6 +72,7 @@ module Telegram end include AbstractController::Translation + include ReplyHelpers prepend Instrumentation extend Session::ConfigMethods @@ -80,6 +82,7 @@ module Telegram message inline_query chosen_inline_result + callback_query ).freeze CMD_REGEX = %r{\A/([a-z\d_]{,31})(@(\S+))?(\s|$)}i CONFLICT_CMD_REGEX = Regexp.new("^(#{PAYLOAD_TYPES.join('|')}|\\d)") @@ -161,46 +164,27 @@ module Telegram def action_for_payload case payload_type when 'message' then action_for_message + when 'callback_query' then action_for_callback_query end || [false, payload_type, [payload]] end + # Separate method, so it can be easily overriden (ex. MessageContext). def action_for_message cmd, args = self.class.command_from_text(payload['text'], bot_username) cmd &&= self.class.action_for_command(cmd) [true, cmd, args] if cmd end + # Same purpose as #action_for_message. + def action_for_callback_query + [false, payload_type, [payload]] + end + # Silently ignore unsupported messages. # Params are `action, *args`. def action_missing(*) end - # Helper to call bot's `send_#{type}` method with already set `chat_id` and - # `reply_to_message_id`: - # - # reply_with :message, text: 'Hello!' - # reply_with :message, text: '__Hello!__', parse_mode: :Markdown - # reply_with :photo, photo: File.open(photo_to_send), caption: "It's incredible!" - def reply_with(type, params) - method = "send_#{type}" - chat = self.chat - payload = self.payload - params = params.merge( - chat_id: (chat && chat['id'] or raise 'Can not reply_with when chat is not present'), - reply_to_message: payload && payload['message_id'], - ) - bot.public_send(method, params) - end - - # Same as reply_with, but for inline queries. - def answer_inline_query(results, params = {}) - params = params.merge( - inline_query_id: payload['id'], - results: results, - ) - bot.answer_inline_query(params) - end - ActiveSupport.run_load_hooks('telegram.bot.updates_controller', self) end end diff --git a/lib/telegram/bot/updates_controller/instrumentation.rb b/lib/telegram/bot/updates_controller/instrumentation.rb index f59c96c..3b6eb1f 100644 --- a/lib/telegram/bot/updates_controller/instrumentation.rb +++ b/lib/telegram/bot/updates_controller/instrumentation.rb @@ -39,6 +39,12 @@ module Telegram Instrumentation.instrument(:reply_with, type: type) { super } end + %i(answer_callback_query answer_inline_query).each do |type| + define_method(type) do |*args| + Instrumentation.instrument(:reply_with, type: type) { super(*args) } + end + end + private # A hook invoked every time a before callback is halted. diff --git a/lib/telegram/bot/updates_controller/reply_helpers.rb b/lib/telegram/bot/updates_controller/reply_helpers.rb new file mode 100644 index 0000000..f94f80e --- /dev/null +++ b/lib/telegram/bot/updates_controller/reply_helpers.rb @@ -0,0 +1,42 @@ +module Telegram + module Bot + class UpdatesController + module ReplyHelpers + # Helper to call bot's `send_#{type}` method with already set `chat_id` and + # `reply_to_message_id`: + # + # reply_with :message, text: 'Hello!' + # reply_with :message, text: '__Hello!__', parse_mode: :Markdown + # reply_with :photo, photo: File.open(photo_to_send), caption: "It's incredible!" + def reply_with(type, params) + method = "send_#{type}" + chat = self.chat + payload = self.payload + params = params.merge( + chat_id: (chat && chat['id'] or raise 'Can not reply_with when chat is not present'), + reply_to_message: payload && payload['message_id'], + ) + bot.public_send(method, params) + end + + # Same as reply_with, but for inline queries. + def answer_inline_query(results, params = {}) + params = params.merge( + inline_query_id: payload['id'], + results: results, + ) + bot.answer_inline_query(params) + end + + # Same as reply_with, but for callback queries. + def answer_callback_query(text, params = {}) + params = params.merge( + callback_query_id: payload['id'], + text: text, + ) + bot.answer_callback_query(params) + end + end + end + end +end diff --git a/spec/telegram/bot/updates_controller/reply_helpers_spec.rb b/spec/telegram/bot/updates_controller/reply_helpers_spec.rb new file mode 100644 index 0000000..91a2a97 --- /dev/null +++ b/spec/telegram/bot/updates_controller/reply_helpers_spec.rb @@ -0,0 +1,38 @@ +RSpec.describe Telegram::Bot::UpdatesController do + include_context 'telegram/bot/updates_controller' + + describe '#reply_with' do + subject { controller.reply_with type, params } + let(:params) { {arg: 1, 'other_arg' => 2} } + let(:type) { :photo } + let(:result) { double(:result) } + let(:payload_type) { :message } + let(:payload) { {message_id: double(:message_id)} } + let(:chat) { {'id' => double(:chat_id)} } + + it 'sets chat_id & reply_to_message' do + expect(controller).to receive(:chat) { chat } + expect(bot).to receive("send_#{type}").with(params.merge( + chat_id: chat['id'], + reply_to_message: payload[:message_id], + )) { result } + should eq result + end + + context 'when chat is missing' do + let(:payload_type) { :some_type } + it { expect { subject }.to raise_error(/chat/) } + end + + context 'when update is not set' do + let(:update) { {chat: chat} } + it 'sets chat_id & reply_to_message' do + expect(bot).to receive("send_#{type}").with(params.merge( + chat_id: chat['id'], + reply_to_message: nil, + )) { result } + should eq result + end + end + end +end diff --git a/spec/telegram/bot/updates_controller_spec.rb b/spec/telegram/bot/updates_controller_spec.rb index 88f5c51..e8202e8 100644 --- a/spec/telegram/bot/updates_controller_spec.rb +++ b/spec/telegram/bot/updates_controller_spec.rb @@ -268,39 +268,4 @@ RSpec.describe Telegram::Bot::UpdatesController do end end end - - describe '#reply_with' do - subject { controller.reply_with type, params } - let(:params) { {arg: 1, 'other_arg' => 2} } - let(:type) { :photo } - let(:result) { double(:result) } - let(:payload_type) { :message } - let(:payload) { {message_id: double(:message_id)} } - let(:chat) { {'id' => double(:chat_id)} } - - it 'sets chat_id & reply_to_message' do - expect(controller).to receive(:chat) { chat } - expect(bot).to receive("send_#{type}").with(params.merge( - chat_id: chat['id'], - reply_to_message: payload[:message_id], - )) { result } - should eq result - end - - context 'when chat is missing' do - let(:payload_type) { :some_type } - it { expect { subject }.to raise_error(/chat/) } - end - - context 'when update is not set' do - let(:update) { {chat: chat} } - it 'sets chat_id & reply_to_message' do - expect(bot).to receive("send_#{type}").with(params.merge( - chat_id: chat['id'], - reply_to_message: nil, - )) { result } - should eq result - end - end - end end