1
0
зеркало из https://github.com/glebtv/telegram-bot.git synced 2026-08-28 15:26:18 +03:00

Сравнить коммиты

..

14 Коммитов

Автор SHA1 Сообщение Дата
Max Melentiev
380f6686fc Update to Bot API 5.7 2022-03-12 19:37:53 +00:00
Max Melentiev
ea64230eab Merge pull request #168 from telegram-bot-rb/nested_files
Fix sending File objects in nested objects (ex., in sendMediaGroup)
2022-03-12 19:34:57 +00:00
Max Melentiev
5b9706ed47 Fix sending File objects in nested objects in sendMediaGroup 2022-03-12 19:33:17 +00:00
Max Melentiev
2d73d1c879 Merge pull request #174 from telegram-bot-rb/rails-7
Rails 7.0 support
2022-01-04 22:54:17 +00:00
Max Melentiev
88af1152cf Rails 7.0 support 2022-01-04 22:49:53 +00:00
Max Melentiev
586217585a Merge pull request #164 from KonstantinReido/patch-1
Fix typo in README.md
2021-08-20 12:36:46 +01:00
Konstantin Reido
f83bf92601 Fix typo in README.md 2021-08-20 11:26:00 +03:00
Max Melentiev
3049ced903 Fix tests 2021-06-26 21:25:43 +01:00
Max Melentiev
07faf87ed7 Merge pull request #163 from telegram-bot-rb/update_api
Update to Bot API 5.3
2021-06-25 19:43:17 +01:00
Max Melentiev
ac45940937 Switch from travis-ci.org to travis-ci.com 2021-06-25 19:42:59 +01:00
Max Melentiev
a49ef51da9 Update to Bot API 5.3 2021-06-25 19:31:28 +01:00
Max Melentiev
4f669fccc4 Merge pull request #157 from AlexVPopov/table-of-contents
Add a table of contents to README
2021-03-31 20:56:59 +01:00
Alexander Popov
e06252907a Add a table of contents to README 2021-03-31 21:11:08 +03:00
Max Melentiev
af229c8bcc Fix typos in readme, make some points more clear 2021-02-19 09:38:54 +00:00
20 изменённых файлов: 233 добавлений и 66 удалений

Просмотреть файл

@@ -1,3 +1,8 @@
appraise 'rails-70' do
gem 'actionpack', '~> 7.0.0'
gem 'railties', '~> 7.0.0'
end
appraise 'rails-61' do
gem 'actionpack', '~> 6.1.0'
gem 'railties', '~> 6.1.0'

Просмотреть файл

@@ -1,5 +1,15 @@
# Unreleased
# 0.15.5
- Rails 7.0 support.
- Fix sending File objects in nested objects in sendMediaGroup.
- Update to Bot API 5.7
# 0.15.4
- Update to Bot API 5.3
# 0.15.3
- Ruby 3.0 support: fix translation helpers.

Просмотреть файл

@@ -8,7 +8,7 @@ group :development do
gem 'pry-byebug', '~> 3.9.0'
gem 'sdoc', '~> 2.0.3'
gem 'telegram-bot-types', '~> 0.6.2'
gem 'telegram-bot-types', '~> 0.6.3'
gem 'rspec', '~> 3.10.0'
gem 'rspec-its', '~> 1.3.0'

Просмотреть файл

@@ -2,7 +2,7 @@
[![Gem Version](https://badge.fury.io/rb/telegram-bot.svg)](http://badge.fury.io/rb/telegram-bot)
[![Code Climate](https://codeclimate.com/github/telegram-bot-rb/telegram-bot/badges/gpa.svg)](https://codeclimate.com/github/telegram-bot-rb/telegram-bot)
[![Build Status](https://travis-ci.org/telegram-bot-rb/telegram-bot.svg)](https://travis-ci.org/telegram-bot-rb/telegram-bot)
[![Build Status](https://travis-ci.com/telegram-bot-rb/telegram-bot.svg)](https://travis-ci.com/telegram-bot-rb/telegram-bot)
Tools for developing Telegram bots. Best used with Rails, but can be used in
[standalone app](https://github.com/telegram-bot-rb/telegram-bot/wiki/Not-rails-application).
@@ -25,9 +25,33 @@ with session, keyboards and inline queries.
Run it on your local machine in 1 minute!
And here is [app template](https://github.com/telegram-bot-rb/rails_template)
to generate clean app in seconds.
to generate new rails app in seconds.
Examples and cookbook in [wiki](https://github.com/telegram-bot-rb/telegram-bot/wiki).
See examples and cookbook in [the wiki](https://github.com/telegram-bot-rb/telegram-bot/wiki).
## Table of Contents
* [Installation](#installation)
* [Usage](#usage)
* [Configuration](#configuration)
* [Configuration in Rails app](#configuration-in-rails-app)
* [Client](#client)
* [Typed responses](#typed-responses)
* [Controller](#controller)
* [Reply helpers](#reply-helpers)
* [Optional typecasting](#optional-typecasting)
* [Session](#session)
* [Message context](#message-context)
* [Callback queries](#callback-queries)
* [Routes in Rails app](#routes-in-rails-app)
* [Processing updates](#processing-updates)
* [Development & Debugging](#development--debugging)
* [Testing](#testing)
* [Deployment](#deployment)
* [Async mode](#async-mode)
* [Limitations](#limitations)
* [Development](#development)
* [Contributing](#contributing)
## Installation
@@ -39,11 +63,15 @@ gem 'telegram-bot'
And then execute:
$ bundle
```
bundle
```
Or install it yourself as:
$ gem install telegram-bot
```
gem install telegram-bot
```
Require if necessary:
@@ -170,19 +198,18 @@ Bot controllers like usual rails controllers provides features like callbacks,
```ruby
class Telegram::WebhookController < Telegram::Bot::UpdatesController
# use callbacks like in any other controllers
# use callbacks like in any other controller
around_action :with_locale
# Every update can have one of: message, inline_query, chosen_inline_result,
# Every update has one of: message, inline_query, chosen_inline_result,
# callback_query, etc.
# Define method with same name to respond to this updates.
# Define method with the same name to handle this type of update.
def message(message)
# message can be also accessed via instance method
message == self.payload # true
# store_message(message['text'])
end
# This basic methods receives commonly used params:
# For the following types of updates commonly used params are passed as arguments,
# full payload object is available with `payload` instance method.
#
# message(payload)
# inline_query(query, offset)
@@ -193,14 +220,19 @@ class Telegram::WebhookController < Telegram::Bot::UpdatesController
# Command arguments will be parsed and passed to the method.
# Be sure to use splat args and default values to not get errors when
# someone passed more or less arguments in the message.
def start!(data = nil, *)
# do_smth_with(data)
def start!(word = nil, *other_words)
# do_smth_with(word)
# full message object is also available via `payload` instance method:
# process_raw_message(payload['text'])
# There are `chat` & `from` shortcut methods.
# For callback queries `chat` if taken from `message` when it's available.
# For callback queries `chat` is taken from `message` when it's available.
response = from ? "Hello #{from['username']}!" : 'Hi there!'
# There is `respond_with` helper to set `chat_id` from received message:
respond_with :message, text: response
# `reply_with` also sets `reply_to_message_id`:
reply_with :photo, photo: File.open('party.jpg')
end
@@ -223,10 +255,10 @@ end
#### Reply helpers
There are helpers to respond for basic actions. They just set chat/message/query
identifiers from update. See
There are helpers for basic responses. They just set chat/message/query
identifiers from the update. See
[`ReplyHelpers`](https://github.com/telegram-bot-rb/telegram-bot/blob/master/lib/telegram/bot/updates_controller/reply_helpers.rb)
module for more information. Here are this methods signatures:
module for more information. Here are these methods signatures:
```ruby
def respond_with(type, params); end
@@ -389,7 +421,7 @@ telegram_webhook TelegramAuctionController, :auction
telegram_webhook TelegramController, as: :custom_telegram_webhook
```
#### Processesing updates
#### Processing updates
To process update with controller call `.dispatch(bot, update)` on it.
There are several options to run it automatically:
@@ -507,7 +539,7 @@ end
There is a context for testing bot controller in the way similar to Rails controller tests.
It's supposed to be a low-level alternative for integration tests. Among the differences is
that controller tests use a single controller instance for all dispatches in specific exaple,
that controller tests use a single controller instance for all dispatches in specific example,
session is stubbed (does not use configured store engine), and update is not serialized
so it also supports mocks. This can be useful for unit testing, but should not be used as
the default way to test the bot.

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2"
gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2"
gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2"
gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2"
gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2"
gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2"
gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2"

21
gemfiles/rails_70.gemfile Обычный файл
Просмотреть файл

@@ -0,0 +1,21 @@
# This file was generated by Appraisal
source "https://rubygems.org"
gem "actionpack", "~> 7.0.0"
gem "railties", "~> 7.0.0"
group :development do
gem "appraisal", "~> 2.2"
gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2"
gem "rubocop", "~> 0.52.1"
gem "coveralls", "~> 0.8.23", require: false
end
gemspec path: "../"

Просмотреть файл

@@ -1,5 +1,4 @@
require 'active_support/core_ext/hash/keys'
require 'json'
require 'httpclient'
module Telegram
@@ -8,7 +7,9 @@ module Telegram
SERVER = 'https://api.telegram.org'.freeze
URL_TEMPLATE = '%<server>s/bot%<token>s/'.freeze
autoload :RequestBodyFormatter, 'telegram/bot/client/request_body_formatter'
autoload :TypedResponse, 'telegram/bot/client/typed_response'
prepend Async
include DebugClient
@@ -35,16 +36,8 @@ module Telegram
prepend TypedResponse
end
# Encodes nested hashes as json.
def prepare_body(body)
body = body.dup
body.each do |k, val|
body[k] = val.to_json if val.is_a?(Hash) || val.is_a?(Array)
end
end
def prepare_async_args(action, body = {})
[action.to_s, Async.prepare_hash(prepare_body(body))]
[action.to_s, Async.prepare_hash(RequestBodyFormatter.format(body))]
end
def error_for_response(response)
@@ -70,7 +63,7 @@ module Telegram
end
def request(action, body = {})
response = http_request("#{base_uri}#{action}", self.class.prepare_body(body))
response = http_request("#{base_uri}#{action}", RequestBodyFormatter.format(body))
raise self.class.error_for_response(response) if response.status >= 300
JSON.parse(response.body)
end

Просмотреть файл

@@ -1,5 +1,5 @@
# Generated with bin/fetch-telegram-methods
# Bot API 5.0
# Bot API 5.7
getUpdates
setWebhook
@@ -30,13 +30,20 @@ sendDice
sendChatAction
getUserProfilePhotos
getFile
kickChatMember
banChatMember
unbanChatMember
restrictChatMember
promoteChatMember
setChatAdministratorCustomTitle
banChatSenderChat
unbanChatSenderChat
setChatPermissions
exportChatInviteLink
createChatInviteLink
editChatInviteLink
revokeChatInviteLink
approveChatJoinRequest
declineChatJoinRequest
setChatPhoto
deleteChatPhoto
setChatTitle
@@ -47,12 +54,13 @@ unpinAllChatMessages
leaveChat
getChat
getChatAdministrators
getChatMembersCount
getChatMemberCount
getChatMember
setChatStickerSet
deleteChatStickerSet
answerCallbackQuery
setMyCommands
deleteMyCommands
getMyCommands
editMessageText

Просмотреть файл

@@ -0,0 +1,48 @@
require 'json'
module Telegram
module Bot
class Client
# Encodes nested hashes and arrays as json and extract File objects from them
# to the top level. Top-level File objects are handled by httpclient.
# More details: https://core.telegram.org/bots/api#sending-files
module RequestBodyFormatter
extend self
def format(body, action)
body = body.dup
if action.to_s == 'sendMediaGroup'
body = extract_files_from_array!(body, :media)
end
body.each do |key, val|
body[key] = val.to_json if val.is_a?(Hash) || val.is_a?(Array)
end
end
private
def extract_files_from_array!(body, field_name)
field_name = [field_name.to_sym, field_name.to_s].find { |x| body.key?(x) }
return body unless field_name && body[field_name].is_a?(Array)
files = {}
body[field_name] = body[field_name].map { |x| extract_files_from_hash(x, files) }
body.merge!(files)
end
# Replace File objects with `attach` URIs. File objects are added into `files` hash.
def extract_files_from_hash(hash, files)
return hash unless hash.is_a?(Hash)
hash.transform_values do |value|
if value.is_a?(File)
arg_name = "_file#{files.size}"
files[arg_name] = value
"attach://#{arg_name}"
else
value
end
end
end
end
end
end
end

Просмотреть файл

@@ -99,6 +99,8 @@ module Telegram
pre_checkout_query
poll
poll_answer
my_chat_member
chat_member
].freeze
class << self

Просмотреть файл

@@ -1,6 +1,6 @@
module Telegram
module Bot
VERSION = '0.15.3'.freeze
VERSION = '0.15.5'.freeze
def self.gem_version
Gem::Version.new VERSION

Просмотреть файл

@@ -0,0 +1,62 @@
RSpec.describe Telegram::Bot::Client::RequestBodyFormatter do
describe '.format' do
subject { described_class.format(input, action) }
let(:action) { :sendMessage }
context 'when plain hash is given' do
let(:input) { {a: 1, b: '2', c: nil} }
it { should eq input }
end
context 'when nested hash is given' do
let(:input) { {a: 1, b: '2', c: [1, 2], d: {a: 1}, e: {b: []}} }
it 'encodes nested hashes to json' do
expected = input.dup
%i[c d e].each { |x| expected[x] = expected[x].to_json }
should eq expected
end
end
context 'with sendMediaGroup action' do
let(:action) { :sendMediaGroup }
let(:input) { {media: [{a: file_1}, {'b' => file_2, c: 123}, {d: 456}], x: 789} }
let(:file_1) { File.new(__FILE__) }
let(:file_2) { File.new(__FILE__) }
it 'extracts files to the top-level' do
should eq(
media: [
{a: 'attach://_file0'},
{b: 'attach://_file1', c: 123},
{d: 456},
].to_json,
x: 789,
'_file0' => file_1,
'_file1' => file_2,
)
end
context 'and input has string keys' do
let(:input) { super().stringify_keys }
it 'extracts files to the top-level' do
should eq(
'media' => [
{a: 'attach://_file0'},
{b: 'attach://_file1', c: 123},
{d: 456},
].to_json,
'x' => 789,
'_file0' => file_1,
'_file1' => file_2,
)
end
end
context 'without media' do
let(:input) { {a: 1, b: '2', c: nil} }
it { should eq input }
end
end
end
end

Просмотреть файл

@@ -71,25 +71,6 @@ RSpec.describe Telegram::Bot::Client do
end
end
describe '.prepare_body' do
subject { described_class.prepare_body(input) }
context 'when plain hash is given' do
let(:input) { {a: 1, b: '2', c: nil} }
it { should eq input }
end
context 'when nested hash is given' do
let(:input) { {a: 1, b: '2', c: [1, 2], d: {a: 1}, e: {b: []}} }
it 'encodes nested hashes to json' do
expected = input.dup
%i[c d e].each { |x| expected[x] = expected[x].to_json }
should eq expected
end
end
end
describe '.prepare_async_args' do
subject { described_class.prepare_async_args(*input) }
let(:input) { [:action, a: 1, b: :sym, c: [:other], 'd' => 'str'] }

Просмотреть файл

@@ -9,14 +9,19 @@ RSpec.describe Telegram::Bot::UpdatesController::TypedUpdate do
context 'when `update` is a virtus model' do
subject { controller }
unique_types = Telegram::Bot::UpdatesController::PAYLOAD_TYPES - %w[
unique_types = (Telegram::Bot::UpdatesController::PAYLOAD_TYPES - %w[
edited_message
channel_post
edited_channel_post
]
unique_types.each do |type|
my_chat_member
chat_member
]).
map { |x| [x, Telegram::Bot::Types.const_get(x.camelize)] }.to_h.
merge(
'chat_member' => Telegram::Bot::Types::ChatMemberUpdated
)
unique_types.each do |type, type_class|
context "with #{type}" do
type_class = Telegram::Bot::Types.const_get(type.camelize)
let(:payload_type) { type }
let(:payload) do
{}.tap do |result|

Просмотреть файл

@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = '>= 2.4'
spec.add_dependency 'actionpack', '>= 4.0', '< 6.2'
spec.add_dependency 'activesupport', '>= 4.0', '< 6.2'
spec.add_dependency 'actionpack', '>= 4.0', '< 7.1'
spec.add_dependency 'activesupport', '>= 4.0', '< 7.1'
spec.add_dependency 'httpclient', '~> 2.7'
spec.add_development_dependency 'bundler', '> 1.16'