diff --git a/CHANGELOG.md b/CHANGELOG.md index 324f3f3..608a601 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# Unreleased + +- Remove Bot::StaleChat in favor of Bot::Forbidden, as Telegram adds more + and more new descriptions. + Please open an issue if you face a problem. + # 0.10.2 - Support `(edited_)channel_post` updates. diff --git a/README.md b/README.md index 2c43b8c..16ac2ea 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ bot.get_me.class # => Telegram::Bot::Types::User ``` Any API request error will raise `Telegram::Bot::Error` with description in its message. -Special `Telegram::Bot::StaleChat` is raised when bot can't post messages to the chat anymore. +Special `Telegram::Bot::Forbidden` is raised when bot can't post messages to the chat anymore. ### Controller diff --git a/lib/telegram/bot.rb b/lib/telegram/bot.rb index 237f92d..ada5111 100644 --- a/lib/telegram/bot.rb +++ b/lib/telegram/bot.rb @@ -6,26 +6,7 @@ module Telegram module Bot class Error < StandardError; end class NotFound < Error; end - - # Error class for events when chat is not available anymore for bot. - # While Telegram has same error codes for different messages and there is no - # official docs for this error codes it uses `description` to - # check response. - class StaleChat < Error - DESCRIPTIONS = [ - 'Bot was blocked', - 'bot was kicked', - "can't write to", - 'group chat is deactivated', - ].freeze - - class << self - def match_response?(response) - description = response['description'].to_s - DESCRIPTIONS.any? { |x| description[x] } - end - end - end + class Forbidden < Error; end autoload :Async, 'telegram/bot/async' autoload :Botan, 'telegram/bot/botan' diff --git a/lib/telegram/bot/client.rb b/lib/telegram/bot/client.rb index c299e9f..699c24c 100644 --- a/lib/telegram/bot/client.rb +++ b/lib/telegram/bot/client.rb @@ -46,18 +46,20 @@ module Telegram @base_uri = format URL_TEMPLATE, self.token end - def request(action, body = {}) # rubocop:disable PerceivedComplexity + def request(action, body = {}) res = http_request("#{base_uri}#{action}", self.class.prepare_body(body)) status = res.status return JSON.parse(res.body) if 300 > status result = JSON.parse(res.body) rescue nil # rubocop:disable RescueModifier - err_msg = "#{res.reason}: #{result && result['description'] || '-'}" + err_msg = result && result['description'] || '-' if result - # NotFound is raised only for valid responses from Telegram - raise NotFound, err_msg if 404 == status - raise StaleChat, err_msg if StaleChat.match_response?(result) + # This errors are raised only for valid responses from Telegram + case status + when 403 then raise Forbidden, err_msg + when 404 then raise NotFound, err_msg + end end - raise Error, err_msg + raise Error, "#{res.reason}: #{err_msg}" end # Splited to the sections similar to API docs. diff --git a/spec/telegram/bot/botan_spec.rb b/spec/telegram/bot/botan_spec.rb index 03a072b..4343240 100644 --- a/spec/telegram/bot/botan_spec.rb +++ b/spec/telegram/bot/botan_spec.rb @@ -3,7 +3,7 @@ RSpec.describe Telegram::Bot::Botan do let(:token) { 'token' } include_examples 'initializers', :botans - include_examples 'async', request_args: -> { [double(:method), double(:url)] } + it_behaves_like 'async', request_args: -> { [double(:method), double(:url)] } describe '.new' do subject { described_class.new(*args) } diff --git a/spec/telegram/bot/client_spec.rb b/spec/telegram/bot/client_spec.rb index df4d1a8..caf9c63 100644 --- a/spec/telegram/bot/client_spec.rb +++ b/spec/telegram/bot/client_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Telegram::Bot::Client do let(:botan_token) { double(:botan_token) } include_examples 'initializers' - include_examples 'async', request_args: -> { [double(:action), {body: :content}] } + it_behaves_like 'async', request_args: -> { [double(:action), {body: :content}] } describe '.prepare_body' do subject { described_class.prepare_body(input) } @@ -48,4 +48,49 @@ RSpec.describe Telegram::Bot::Client do its(:base_uri) { should include args[0][:token] } end end + + describe '#request' do + subject { -> { instance.request(action, request_body) } } + let(:action) { :some_action } + let(:url) { "#{format described_class::URL_TEMPLATE, token}#{action}" } + let(:request_body) { double(:body) } + let(:prepared_body) { double(:prepared_body) } + let(:response) { HTTP::Message.new_response(body).tap { |x| x.status = status } } + + let(:status) { 200 } + let(:body) { body_json.to_json } + let(:body_json) { {'param' => 'val', 'description' => 'some description'} } + before do + expect(described_class).to receive(:prepare_body).with(request_body) { prepared_body } + expect(instance).to receive(:http_request).with(url, prepared_body) { response } + end + around { |ex| Telegram::Bot::ClientStub.stub_all!(false) { ex.run } } + + shared_examples 'invalid body' do |error = Telegram::Bot::Error| + context 'when body is not json' do + let(:body) { '{' } + it { should raise_error error } + end + end + + its(:call) { should eq body_json } + include_examples 'invalid body', JSON::ParserError + + context 'when status is 403' do + let(:status) { 403 } + it { should raise_error Telegram::Bot::Forbidden, body_json['description'] } + include_examples 'invalid body' + end + + context 'when status is 404' do + let(:status) { 404 } + it { should raise_error Telegram::Bot::NotFound, body_json['description'] } + include_examples 'invalid body' + end + + context 'when status is other' do + let(:status) { 500 } + it { should raise_error Telegram::Bot::Error, /#{body_json['description']}/ } + end + end end diff --git a/spec/telegram/bot_spec.rb b/spec/telegram/bot_spec.rb index 1fa1681..19a51f4 100644 --- a/spec/telegram/bot_spec.rb +++ b/spec/telegram/bot_spec.rb @@ -2,25 +2,4 @@ RSpec.describe Telegram::Bot do it 'has a version number' do expect(described_class::VERSION).not_to be nil end - - describe described_class::StaleChat do - describe '.match_response?' do - subject { ->(val) { described_class.match_response?(val) } } - - it 'returns true for specific errors' do - expect(subject.call({})).to eq false - expect(subject.call('description' => 'test')).to eq false - expect(subject.call('description' => 'Error: bot was kicked from')).to eq true - expect(subject.call( - 'description' => "Forbidden: can't write to private chat with deleted user" - )).to eq true - expect(subject.call( - 'description' => 'Bad request: group chat is deactivated' - )).to eq true - expect(subject.call( - 'description' => 'Forbidden: Bot was blocked by the user' - )).to eq true - end - end - end end