telegram-bot-ruby 1.0.0.rc1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.editorconfig +10 -0
- data/.github/workflows/ci.yml +2 -5
- data/.github/workflows/stale.yml +19 -0
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +12 -7
- data/CHANGELOG.md +17 -0
- data/Gemfile +13 -0
- data/LICENSE +0 -1
- data/README.md +78 -19
- data/Rakefile +10 -8
- data/bin/console +4 -1
- data/lib/telegram/bot/api/endpoints.rb +114 -0
- data/lib/telegram/bot/api.rb +20 -44
- data/lib/telegram/bot/client.rb +8 -9
- data/lib/telegram/bot/exceptions/response_error.rb +2 -8
- data/lib/telegram/bot/types/animation.rb +1 -1
- data/lib/telegram/bot/types/audio.rb +1 -1
- data/lib/telegram/bot/types/bot_command_scope_all_chat_administrators.rb +1 -1
- data/lib/telegram/bot/types/bot_command_scope_all_group_chats.rb +1 -1
- data/lib/telegram/bot/types/bot_command_scope_all_private_chats.rb +1 -1
- data/lib/telegram/bot/types/bot_command_scope_chat.rb +2 -2
- data/lib/telegram/bot/types/bot_command_scope_chat_administrators.rb +2 -2
- data/lib/telegram/bot/types/bot_command_scope_chat_member.rb +2 -2
- data/lib/telegram/bot/types/bot_command_scope_default.rb +1 -1
- data/lib/telegram/bot/types/bot_description.rb +11 -0
- data/lib/telegram/bot/types/bot_name.rb +11 -0
- data/lib/telegram/bot/types/bot_short_description.rb +11 -0
- data/lib/telegram/bot/types/callback_query.rb +1 -1
- data/lib/telegram/bot/types/chat.rb +16 -9
- data/lib/telegram/bot/types/chat_administrator_rights.rb +3 -0
- data/lib/telegram/bot/types/chat_boost.rb +14 -0
- data/lib/telegram/bot/types/chat_boost_removed.rb +14 -0
- data/lib/telegram/bot/types/chat_boost_source.rb +13 -0
- data/lib/telegram/bot/types/chat_boost_source_gift_code.rb +12 -0
- data/lib/telegram/bot/types/chat_boost_source_giveaway.rb +14 -0
- data/lib/telegram/bot/types/chat_boost_source_premium.rb +12 -0
- data/lib/telegram/bot/types/chat_boost_updated.rb +12 -0
- data/lib/telegram/bot/types/chat_join_request.rb +1 -0
- data/lib/telegram/bot/types/chat_member.rb +11 -2
- data/lib/telegram/bot/types/chat_member_administrator.rb +8 -5
- data/lib/telegram/bot/types/chat_member_banned.rb +2 -2
- data/lib/telegram/bot/types/chat_member_left.rb +2 -2
- data/lib/telegram/bot/types/chat_member_member.rb +2 -2
- data/lib/telegram/bot/types/chat_member_owner.rb +2 -2
- data/lib/telegram/bot/types/chat_member_restricted.rb +12 -7
- data/lib/telegram/bot/types/chat_member_updated.rb +1 -0
- data/lib/telegram/bot/types/chat_permissions.rb +6 -1
- data/lib/telegram/bot/types/chat_shared.rb +12 -0
- data/lib/telegram/bot/types/compactable.rb +2 -7
- data/lib/telegram/bot/types/document.rb +1 -1
- data/lib/telegram/bot/types/external_reply_info.rb +33 -0
- data/lib/telegram/bot/types/force_reply.rb +1 -1
- data/lib/telegram/bot/types/giveaway.rb +18 -0
- data/lib/telegram/bot/types/giveaway_completed.rb +13 -0
- data/lib/telegram/bot/types/giveaway_created.rb +10 -0
- data/lib/telegram/bot/types/giveaway_winners.rb +21 -0
- data/lib/telegram/bot/types/inaccessible_message.rb +13 -0
- data/lib/telegram/bot/types/inline_keyboard_button.rb +1 -0
- data/lib/telegram/bot/types/inline_query_result_article.rb +4 -4
- data/lib/telegram/bot/types/inline_query_result_audio.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_cached_audio.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_cached_document.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_cached_gif.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_cached_mpeg4_gif.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_cached_photo.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_cached_sticker.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_cached_video.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_cached_voice.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_contact.rb +4 -4
- data/lib/telegram/bot/types/inline_query_result_document.rb +4 -4
- data/lib/telegram/bot/types/inline_query_result_game.rb +1 -1
- data/lib/telegram/bot/types/inline_query_result_gif.rb +3 -3
- data/lib/telegram/bot/types/inline_query_result_location.rb +4 -4
- data/lib/telegram/bot/types/inline_query_result_mpeg4_gif.rb +3 -3
- data/lib/telegram/bot/types/inline_query_result_photo.rb +2 -2
- data/lib/telegram/bot/types/inline_query_result_venue.rb +4 -4
- data/lib/telegram/bot/types/inline_query_result_video.rb +2 -2
- data/lib/telegram/bot/types/inline_query_result_voice.rb +1 -1
- data/lib/telegram/bot/types/input_media_animation.rb +2 -2
- data/lib/telegram/bot/types/input_media_audio.rb +2 -2
- data/lib/telegram/bot/types/input_media_document.rb +2 -2
- data/lib/telegram/bot/types/input_media_photo.rb +1 -1
- data/lib/telegram/bot/types/input_media_video.rb +2 -2
- data/lib/telegram/bot/types/input_text_message_content.rb +1 -1
- data/lib/telegram/bot/types/keyboard_button.rb +2 -0
- data/lib/telegram/bot/types/keyboard_button_request_chat.rb +18 -0
- data/lib/telegram/bot/types/keyboard_button_request_users.rb +14 -0
- data/lib/telegram/bot/types/link_preview_options.rb +15 -0
- data/lib/telegram/bot/types/maybe_inaccessible_message.rb +12 -0
- data/lib/telegram/bot/types/menu_button_commands.rb +1 -1
- data/lib/telegram/bot/types/menu_button_default.rb +1 -1
- data/lib/telegram/bot/types/menu_button_web_app.rb +1 -1
- data/lib/telegram/bot/types/message.rb +20 -15
- data/lib/telegram/bot/types/message_id.rb +11 -0
- data/lib/telegram/bot/types/message_origin.rb +14 -0
- data/lib/telegram/bot/types/message_origin_channel.rb +15 -0
- data/lib/telegram/bot/types/message_origin_chat.rb +14 -0
- data/lib/telegram/bot/types/message_origin_hidden_user.rb +13 -0
- data/lib/telegram/bot/types/message_origin_user.rb +13 -0
- data/lib/telegram/bot/types/message_reaction_count_updated.rb +14 -0
- data/lib/telegram/bot/types/message_reaction_updated.rb +17 -0
- data/lib/telegram/bot/types/passport_element_error_data_field.rb +1 -1
- data/lib/telegram/bot/types/passport_element_error_file.rb +1 -1
- data/lib/telegram/bot/types/passport_element_error_files.rb +2 -2
- data/lib/telegram/bot/types/passport_element_error_front_side.rb +1 -1
- data/lib/telegram/bot/types/passport_element_error_reverse_side.rb +1 -1
- data/lib/telegram/bot/types/passport_element_error_selfie.rb +1 -1
- data/lib/telegram/bot/types/passport_element_error_translation_file.rb +1 -1
- data/lib/telegram/bot/types/passport_element_error_translation_files.rb +2 -2
- data/lib/telegram/bot/types/passport_element_error_unspecified.rb +1 -1
- data/lib/telegram/bot/types/poll_answer.rb +2 -1
- data/lib/telegram/bot/types/reaction_count.rb +12 -0
- data/lib/telegram/bot/types/reaction_type.rb +12 -0
- data/lib/telegram/bot/types/reaction_type_custom_emoji.rb +12 -0
- data/lib/telegram/bot/types/reaction_type_emoji.rb +12 -0
- data/lib/telegram/bot/types/reply_keyboard_remove.rb +1 -1
- data/lib/telegram/bot/types/reply_parameters.rb +17 -0
- data/lib/telegram/bot/types/sticker.rb +2 -1
- data/lib/telegram/bot/types/sticker_set.rb +1 -1
- data/lib/telegram/bot/types/story.rb +9 -0
- data/lib/telegram/bot/types/switch_inline_query_chosen_chat.rb +15 -0
- data/lib/telegram/bot/types/text_quote.rb +14 -0
- data/lib/telegram/bot/types/update.rb +4 -0
- data/lib/telegram/bot/types/user.rb +2 -2
- data/lib/telegram/bot/types/user_chat_boosts.rb +11 -0
- data/lib/telegram/bot/types/users_shared.rb +12 -0
- data/lib/telegram/bot/types/video.rb +1 -1
- data/lib/telegram/bot/types/video_note.rb +1 -1
- data/lib/telegram/bot/types/webhook_info.rb +1 -1
- data/lib/telegram/bot/types/write_access_allowed.rb +3 -0
- data/lib/telegram/bot/version.rb +1 -1
- data/lib/telegram/bot.rb +1 -0
- data/telegram-bot-ruby.gemspec +1 -13
- metadata +47 -117
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5b61e5af1f53cd133496f945bc7642b2a79e12a1d2be92faca3e45246b51dba5
|
|
4
|
+
data.tar.gz: de0024292072dfa7dcc74ffa6c66ba4e30d470652bcdcd5d9b193a8cea66f420
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dab03a9d65d7582dce03bb6f5a8aea981a507f8011e2e618264177182c132c4fda82d1fc80da0590d3196e07e145e586c665af1fa8e9fd5fdfbcd8c36439bad2
|
|
7
|
+
data.tar.gz: 1b165086c50ee02e77298c575712551462c58bdb3f963a70ab823d2c9cffffdf23551af8caa3ad484e47bca3d89505f5656ae05c15648b37e6e84cc73e308011
|
data/.editorconfig
ADDED
data/.github/workflows/ci.yml
CHANGED
|
@@ -13,7 +13,7 @@ jobs:
|
|
|
13
13
|
matrix:
|
|
14
14
|
ruby:
|
|
15
15
|
- 2.7
|
|
16
|
-
- 3.
|
|
16
|
+
- 3.2
|
|
17
17
|
steps:
|
|
18
18
|
- name: Checkout
|
|
19
19
|
uses: actions/checkout@v3
|
|
@@ -31,10 +31,7 @@ jobs:
|
|
|
31
31
|
matrix:
|
|
32
32
|
ruby:
|
|
33
33
|
- 2.7
|
|
34
|
-
- 3.
|
|
35
|
-
env:
|
|
36
|
-
BOT_API_ENV: test
|
|
37
|
-
BOT_API_TOKEN: ${{ secrets.BOT_API_TOKEN }}
|
|
34
|
+
- 3.2
|
|
38
35
|
steps:
|
|
39
36
|
- name: Checkout
|
|
40
37
|
uses: actions/checkout@v3
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Close stale issues and PRs
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: 40 * * * *
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
stale:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/stale@v7
|
|
12
|
+
with:
|
|
13
|
+
days-before-close: 7
|
|
14
|
+
days-before-stale: 60
|
|
15
|
+
stale-issue-label: stale
|
|
16
|
+
stale-issue-message: This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.
|
|
17
|
+
stale-pr-label: stale
|
|
18
|
+
stale-pr-message: This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.
|
|
19
|
+
operations-per-run: 500
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
require:
|
|
3
3
|
- rubocop-rake
|
|
4
4
|
- rubocop-rspec
|
|
5
|
+
- rubocop-performance
|
|
5
6
|
|
|
6
7
|
AllCops:
|
|
7
8
|
NewCops: enable
|
|
@@ -10,18 +11,22 @@ AllCops:
|
|
|
10
11
|
Style/Documentation:
|
|
11
12
|
Enabled: false
|
|
12
13
|
|
|
13
|
-
Style/FrozenStringLiteralComment:
|
|
14
|
-
Exclude:
|
|
15
|
-
- bin/console
|
|
16
|
-
|
|
17
14
|
Metrics/BlockLength:
|
|
18
15
|
AllowedMethods:
|
|
19
16
|
- context
|
|
20
17
|
- describe
|
|
21
18
|
- task
|
|
19
|
+
Metrics/ClassLength:
|
|
20
|
+
Exclude:
|
|
21
|
+
- lib/telegram/bot/api/endpoints.rb
|
|
22
|
+
Metrics/MethodLength:
|
|
23
|
+
Exclude:
|
|
24
|
+
- spec/**/*
|
|
22
25
|
|
|
23
26
|
Layout/LineLength:
|
|
24
27
|
Max: 120
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
|
|
29
|
+
RSpec/MultipleMemoizedHelpers:
|
|
30
|
+
Enabled: false
|
|
31
|
+
RSpec/NestedGroups:
|
|
32
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- [Bot API 7.0](https://core.telegram.org/bots/api#december-29-2023)
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- API method calls now return corresponding response objects ([#285](https://github.com/atipugin/telegram-bot-ruby/pull/285), thx [@AlexWayfer](https://github.com/AlexWayfer))
|
|
12
|
+
|
|
13
|
+
## 1.0.0
|
|
14
|
+
|
|
15
|
+
- Replace [virtus](https://github.com/solnic/virtus) with [dry-struct](https://github.com/dry-rb/dry-struct)
|
|
16
|
+
- Use [zeitwerk](https://github.com/fxn/zeitwerk) for code loading
|
|
17
|
+
- Implement [Bot API 6.4](https://core.telegram.org/bots/api#december-30-2022)
|
|
18
|
+
- Implement [Bot API 6.5](https://core.telegram.org/bots/api#february-3-2023)
|
|
19
|
+
|
|
3
20
|
## 0.23.0
|
|
4
21
|
|
|
5
22
|
- Rename `Telegram::Bot.configuration` options:
|
data/Gemfile
CHANGED
|
@@ -3,3 +3,16 @@
|
|
|
3
3
|
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
5
|
gemspec
|
|
6
|
+
|
|
7
|
+
gem 'dotenv', '~> 2.8'
|
|
8
|
+
gem 'nokogiri', '~> 1.13'
|
|
9
|
+
gem 'pry'
|
|
10
|
+
gem 'rake', '~> 13.0'
|
|
11
|
+
|
|
12
|
+
gem 'rspec', '~> 3.4'
|
|
13
|
+
gem 'vcr', '~> 6.0'
|
|
14
|
+
|
|
15
|
+
gem 'rubocop', '~> 1.54.1'
|
|
16
|
+
gem 'rubocop-performance', '~> 1.18'
|
|
17
|
+
gem 'rubocop-rake', '~> 0.6.0'
|
|
18
|
+
gem 'rubocop-rspec', '~> 2.22.0'
|
data/LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -7,12 +7,29 @@ Ruby wrapper for [Telegram's Bot API](https://core.telegram.org/bots/api).
|
|
|
7
7
|
[](https://codeclimate.com/github/atipugin/telegram-bot-ruby/maintainability)
|
|
8
8
|
[](https://saythanks.io/to/atipugin)
|
|
9
9
|
|
|
10
|
+
## 🚧 Upgrading to 1.0
|
|
11
|
+
|
|
12
|
+
Since v1.0 `telegram-bot-ruby` uses [`dry-struct`](https://github.com/dry-rb/dry-struct)
|
|
13
|
+
instead of [`virtus`](https://github.com/solnic/virtus).
|
|
14
|
+
This means that type objects are now immutable and you can't change them after initialization:
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
# This won't work
|
|
18
|
+
kb = Telegram::Bot::Types::ReplyKeyboardRemove.new
|
|
19
|
+
kb.remove_keyboard = true
|
|
20
|
+
|
|
21
|
+
# You have to set attributes in constructor instead
|
|
22
|
+
kb = Telegram::Bot::Types::ReplyKeyboardRemove.new(remove_keyboard: true)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Please make sure it doesn't break your existing code before upgrading to 1.0.
|
|
26
|
+
|
|
10
27
|
## Installation
|
|
11
28
|
|
|
12
29
|
Add following line to your Gemfile:
|
|
13
30
|
|
|
14
31
|
```ruby
|
|
15
|
-
gem 'telegram-bot-ruby'
|
|
32
|
+
gem 'telegram-bot-ruby', '~> 1.0'
|
|
16
33
|
```
|
|
17
34
|
|
|
18
35
|
And then execute:
|
|
@@ -29,7 +46,8 @@ gem install telegram-bot-ruby
|
|
|
29
46
|
|
|
30
47
|
## Usage
|
|
31
48
|
|
|
32
|
-
First things first, you need to [obtain a token](https://core.telegram.org/bots#6-botfather) for your bot.
|
|
49
|
+
First things first, you need to [obtain a token](https://core.telegram.org/bots#6-botfather) for your bot.
|
|
50
|
+
Then create your Telegram bot like this:
|
|
33
51
|
|
|
34
52
|
```ruby
|
|
35
53
|
require 'telegram/bot'
|
|
@@ -48,7 +66,10 @@ Telegram::Bot::Client.run(token) do |bot|
|
|
|
48
66
|
end
|
|
49
67
|
```
|
|
50
68
|
|
|
51
|
-
Note that `bot.api` object implements
|
|
69
|
+
Note that `bot.api` object implements
|
|
70
|
+
[Telegram Bot API methods](https://core.telegram.org/bots/api#available-methods) as is.
|
|
71
|
+
So you can invoke any method inside the block without any problems.
|
|
72
|
+
All methods are available in both *snake_case* and *camelCase* notations.
|
|
52
73
|
|
|
53
74
|
If you need to start a bot in development mode you have to pass `environment: :test`:
|
|
54
75
|
|
|
@@ -58,15 +79,35 @@ Telegram::Bot::Client.run(token, environment: :test) do |bot|
|
|
|
58
79
|
end
|
|
59
80
|
```
|
|
60
81
|
|
|
61
|
-
Same thing about `message` object
|
|
82
|
+
Same thing about `message` object: it implements [Message](https://core.telegram.org/bots/api#message) spec,
|
|
83
|
+
so you always know what to expect from it.
|
|
84
|
+
|
|
85
|
+
To gracefully stop the bot, for example by `INT` signal (Ctrl-C), call the `bot.stop` method:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
bot = Telegram::Bot::Client.new(token)
|
|
89
|
+
|
|
90
|
+
Signal.trap('INT') do
|
|
91
|
+
bot.stop
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
bot.listen do |message|
|
|
95
|
+
# it will be in an infinity loop until `bot.stop` command
|
|
96
|
+
# (with a small delay for the current `fetch_updates` request)
|
|
97
|
+
end
|
|
98
|
+
```
|
|
62
99
|
|
|
63
100
|
## Webhooks
|
|
64
101
|
|
|
65
|
-
If you are going to use [webhooks](https://core.telegram.org/bots/api#setwebhook)
|
|
102
|
+
If you are going to use [webhooks](https://core.telegram.org/bots/api#setwebhook)
|
|
103
|
+
instead of [long polling](https://core.telegram.org/bots/api#getupdates),
|
|
104
|
+
you need to implement your own webhook callbacks server.
|
|
105
|
+
Take a look at [this repo](https://github.com/solyaris/BOTServer) as an example.
|
|
66
106
|
|
|
67
107
|
## Proxy
|
|
68
108
|
|
|
69
|
-
As some countries block access to Telegram, you can set up your own proxy and use it to access Telegram API.
|
|
109
|
+
As some countries block access to Telegram, you can set up your own proxy and use it to access Telegram API.
|
|
110
|
+
In this case you need to configure API URL:
|
|
70
111
|
|
|
71
112
|
```ruby
|
|
72
113
|
Telegram::Bot::Client.run(token, url: 'https://proxy.example.com') do |bot|
|
|
@@ -76,7 +117,8 @@ end
|
|
|
76
117
|
|
|
77
118
|
## Custom keyboards
|
|
78
119
|
|
|
79
|
-
You can use your own [custom keyboards](https://core.telegram.org/bots#keyboards).
|
|
120
|
+
You can use your own [custom keyboards](https://core.telegram.org/bots#keyboards).
|
|
121
|
+
Here is an example:
|
|
80
122
|
|
|
81
123
|
```ruby
|
|
82
124
|
bot.listen do |message|
|
|
@@ -116,7 +158,8 @@ end
|
|
|
116
158
|
|
|
117
159
|
## Inline keyboards
|
|
118
160
|
|
|
119
|
-
[Bot API 2.0](https://core.telegram.org/bots/2-0-intro) brought us new inline keyboards.
|
|
161
|
+
[Bot API 2.0](https://core.telegram.org/bots/2-0-intro) brought us new inline keyboards.
|
|
162
|
+
Example:
|
|
120
163
|
|
|
121
164
|
```ruby
|
|
122
165
|
bot.listen do |message|
|
|
@@ -164,13 +207,25 @@ bot.listen do |message|
|
|
|
164
207
|
end
|
|
165
208
|
```
|
|
166
209
|
|
|
167
|
-
Now, with `inline` mode enabled, your `message` object can be an instance of
|
|
210
|
+
Now, with `inline` mode enabled, your `message` object can be an instance of
|
|
211
|
+
[Message](https://core.telegram.org/bots/api#message),
|
|
212
|
+
[InlineQuery](https://core.telegram.org/bots/api#inlinequery) or
|
|
213
|
+
[ChosenInlineResult](https://core.telegram.org/bots/api#choseninlineresult).
|
|
214
|
+
That's why you need to check type of each message and decide how to handle it.
|
|
168
215
|
|
|
169
|
-
Using `answer_inline_query` you can send query results to user.
|
|
216
|
+
Using `answer_inline_query` you can send query results to user.
|
|
217
|
+
`results` field must be an array of [query result objects](https://core.telegram.org/bots/api#inlinequeryresult).
|
|
170
218
|
|
|
171
219
|
## File upload
|
|
172
220
|
|
|
173
|
-
Your bot can even upload files
|
|
221
|
+
Your bot can even upload files
|
|
222
|
+
([photos](https://core.telegram.org/bots/api#sendphoto),
|
|
223
|
+
[audio](https://core.telegram.org/bots/api#sendaudio),
|
|
224
|
+
[documents](https://core.telegram.org/bots/api#senddocument),
|
|
225
|
+
[stickers](https://core.telegram.org/bots/api#sendsticker),
|
|
226
|
+
[video](https://core.telegram.org/bots/api#sendvideo))
|
|
227
|
+
to Telegram servers.
|
|
228
|
+
Just like this:
|
|
174
229
|
|
|
175
230
|
```ruby
|
|
176
231
|
bot.listen do |message|
|
|
@@ -184,7 +239,9 @@ end
|
|
|
184
239
|
|
|
185
240
|
## Logging
|
|
186
241
|
|
|
187
|
-
By default, bot doesn't log anything (uses `NullLoger`).
|
|
242
|
+
By default, bot doesn't log anything (uses `NullLoger`).
|
|
243
|
+
You can change this behavior and provide your own logger class.
|
|
244
|
+
See example below:
|
|
188
245
|
|
|
189
246
|
```ruby
|
|
190
247
|
Telegram::Bot::Client.run(token, logger: Logger.new($stderr)) do |bot|
|
|
@@ -197,7 +254,8 @@ end
|
|
|
197
254
|
|
|
198
255
|
## Connection adapters
|
|
199
256
|
|
|
200
|
-
Since version `0.5.0` we rely on [faraday](https://github.com/lostisland/faraday) under the hood.
|
|
257
|
+
Since version `0.5.0` we rely on [faraday](https://github.com/lostisland/faraday) under the hood.
|
|
258
|
+
You can use any of supported adapters (for example, `net/http/persistent`):
|
|
201
259
|
|
|
202
260
|
```ruby
|
|
203
261
|
require 'net/http/persistent'
|
|
@@ -209,14 +267,15 @@ end
|
|
|
209
267
|
|
|
210
268
|
## Boilerplates
|
|
211
269
|
|
|
212
|
-
If you don't know how to setup database for your bot or how to use it with different languages
|
|
270
|
+
If you don't know how to setup database for your bot or how to use it with different languages
|
|
271
|
+
here are some boilerplates which can help you to start faster:
|
|
213
272
|
|
|
214
273
|
- [Ruby Telegram Bot boilerplate](https://github.com/telegram-bots/ruby-telegram-bot-boilerplate)
|
|
215
274
|
|
|
216
275
|
## Contributing
|
|
217
276
|
|
|
218
|
-
1. Fork it
|
|
219
|
-
2. Create your feature branch (git checkout -b my-new-feature)
|
|
220
|
-
3. Commit your changes (git commit -am 'Add some feature')
|
|
221
|
-
4. Push to the branch (git push origin my-new-feature)
|
|
222
|
-
5. Create new Pull Request
|
|
277
|
+
1. Fork it.
|
|
278
|
+
2. Create your feature branch (`git checkout -b my-new-feature`).
|
|
279
|
+
3. Commit your changes (`git commit -am 'Add some feature'`).
|
|
280
|
+
4. Push to the branch (`git push origin my-new-feature`).
|
|
281
|
+
5. Create a new Pull Request.
|
data/Rakefile
CHANGED
|
@@ -18,7 +18,7 @@ task default: :spec
|
|
|
18
18
|
|
|
19
19
|
desc 'Dump type definitions from docs to YAML'
|
|
20
20
|
task :dump_type_attributes do
|
|
21
|
-
|
|
21
|
+
require_relative 'lib/telegram/bot'
|
|
22
22
|
require 'nokogiri'
|
|
23
23
|
require 'open-uri'
|
|
24
24
|
require 'yaml'
|
|
@@ -30,6 +30,8 @@ task :dump_type_attributes do
|
|
|
30
30
|
# Fetch and parse docs
|
|
31
31
|
doc = Nokogiri::HTML(URI.open('https://core.telegram.org/bots/api').read)
|
|
32
32
|
|
|
33
|
+
next_type_element_names = %w[table h4]
|
|
34
|
+
|
|
33
35
|
result = types.to_h do |type|
|
|
34
36
|
# This is very hacky but working way to find table containing attributes for
|
|
35
37
|
# given type. Basic idea is to find heading with type and then iterate until
|
|
@@ -38,23 +40,23 @@ task :dump_type_attributes do
|
|
|
38
40
|
element = doc.at_xpath(%{//h4[text() = "#{type}"]})
|
|
39
41
|
loop do
|
|
40
42
|
element = element.next_element
|
|
41
|
-
break if
|
|
43
|
+
break if next_type_element_names.include?(element.name)
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
attributes = element.xpath('.//tbody//tr').map do |el|
|
|
45
47
|
cells = el.children.select { |c| c.name == 'td' }
|
|
46
48
|
{
|
|
47
49
|
'name' => cells[0].text,
|
|
48
|
-
'
|
|
49
|
-
|
|
50
|
+
'type' => cells[1].text,
|
|
51
|
+
'required' => !cells[2].text.start_with?('Optional.'),
|
|
52
|
+
'required_value' =>
|
|
53
|
+
cells[2].text.match(/^.+, (?:must be (?<found_type>\w+)|always “(?<found_type>\w+)”)$/)&.[](:found_type)
|
|
54
|
+
}.compact
|
|
50
55
|
end
|
|
51
56
|
|
|
52
57
|
[type, attributes]
|
|
53
58
|
end
|
|
54
59
|
|
|
55
60
|
# Write everything to fixture file
|
|
56
|
-
File.write
|
|
57
|
-
File.expand_path('spec/support/type_attributes.yml', __dir__),
|
|
58
|
-
result.to_yaml
|
|
59
|
-
)
|
|
61
|
+
File.write "#{__dir__}/spec/support/type_attributes.yml", result.to_yaml
|
|
60
62
|
end
|
data/bin/console
CHANGED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Telegram
|
|
4
|
+
module Bot
|
|
5
|
+
class Api
|
|
6
|
+
ENDPOINTS = {
|
|
7
|
+
'getUpdates' => Types::Array.of(Types::Update),
|
|
8
|
+
'setWebhook' => Types::Bool,
|
|
9
|
+
'deleteWebhook' => Types::Bool,
|
|
10
|
+
'getWebhookInfo' => Types::WebhookInfo,
|
|
11
|
+
'getMe' => Types::User,
|
|
12
|
+
'sendMessage' => Types::Message,
|
|
13
|
+
'forwardMessage' => Types::Message,
|
|
14
|
+
'forwardMessages' => Types::Array.of(Types::MessageId),
|
|
15
|
+
'sendPhoto' => Types::Message,
|
|
16
|
+
'sendAudio' => Types::Message,
|
|
17
|
+
'sendDocument' => Types::Message,
|
|
18
|
+
'sendVideo' => Types::Message,
|
|
19
|
+
'sendVoice' => Types::Message,
|
|
20
|
+
'sendVideoNote' => Types::Message,
|
|
21
|
+
'sendMediaGroup' => Types::Array.of(Types::Message),
|
|
22
|
+
'sendLocation' => Types::Message,
|
|
23
|
+
'editMessageLiveLocation' => Types::Message | Types::Bool,
|
|
24
|
+
'stopMessageLiveLocation' => Types::Message | Types::Bool,
|
|
25
|
+
'sendVenue' => Types::Message,
|
|
26
|
+
'sendContact' => Types::Message,
|
|
27
|
+
'sendChatAction' => Types::Bool,
|
|
28
|
+
'setMessageReaction' => Types::Bool,
|
|
29
|
+
'getUserProfilePhotos' => Types::UserProfilePhotos,
|
|
30
|
+
'getFile' => Types::File,
|
|
31
|
+
'banChatMember' => Types::Bool,
|
|
32
|
+
'unbanChatMember' => Types::Bool,
|
|
33
|
+
'restrictChatMember' => Types::Bool,
|
|
34
|
+
'promoteChatMember' => Types::Bool,
|
|
35
|
+
'leaveChat' => Types::Bool,
|
|
36
|
+
'getChat' => Types::Chat,
|
|
37
|
+
'getChatAdministrators' => Types::Array.of(Types::ChatMember),
|
|
38
|
+
'exportChatInviteLink' => Types::String,
|
|
39
|
+
'setChatPhoto' => Types::Bool,
|
|
40
|
+
'deleteChatPhoto' => Types::Bool,
|
|
41
|
+
'setChatTitle' => Types::Bool,
|
|
42
|
+
'setChatDescription' => Types::Bool,
|
|
43
|
+
'pinChatMessage' => Types::Bool,
|
|
44
|
+
'unpinChatMessage' => Types::Bool,
|
|
45
|
+
'getChatMembersCount' => Types::Integer,
|
|
46
|
+
'getChatMember' => Types::ChatMember,
|
|
47
|
+
'setChatStickerSet' => Types::Bool,
|
|
48
|
+
'deleteChatStickerSet' => Types::Bool,
|
|
49
|
+
'answerCallbackQuery' => Types::Bool,
|
|
50
|
+
'getUserChatBoosts' => Types::UserChatBoosts,
|
|
51
|
+
'editMessageText' => Types::Message | Types::Bool,
|
|
52
|
+
'editMessageCaption' => Types::Message | Types::Bool,
|
|
53
|
+
'editMessageReplyMarkup' => Types::Message | Types::Bool,
|
|
54
|
+
'deleteMessage' => Types::Bool,
|
|
55
|
+
'deleteMessages' => Types::Bool,
|
|
56
|
+
'sendSticker' => Types::Message,
|
|
57
|
+
'getStickerSet' => Types::StickerSet,
|
|
58
|
+
'uploadStickerFile' => Types::File,
|
|
59
|
+
'createNewStickerSet' => Types::Bool,
|
|
60
|
+
'addStickerToSet' => Types::Bool,
|
|
61
|
+
'setStickerPositionInSet' => Types::Bool,
|
|
62
|
+
'deleteStickerFromSet' => Types::Bool,
|
|
63
|
+
'answerInlineQuery' => Types::Bool,
|
|
64
|
+
'sendInvoice' => Types::Message,
|
|
65
|
+
'answerShippingQuery' => Types::Bool,
|
|
66
|
+
'answerPreCheckoutQuery' => Types::Bool,
|
|
67
|
+
'sendGame' => Types::Message,
|
|
68
|
+
'setGameScore' => Types::Message | Types::Bool,
|
|
69
|
+
'getGameHighScores' => Types::Array.of(Types::GameHighScore),
|
|
70
|
+
'setPassportDataErrors' => Types::Bool,
|
|
71
|
+
'editMessageMedia' => Types::Message | Types::Bool,
|
|
72
|
+
'sendAnimation' => Types::Message,
|
|
73
|
+
'sendPoll' => Types::Message,
|
|
74
|
+
'stopPoll' => Types::Poll,
|
|
75
|
+
'setChatPermissions' => Types::Bool,
|
|
76
|
+
'setChatAdministratorCustomTitle' => Types::Bool,
|
|
77
|
+
'sendDice' => Types::Message,
|
|
78
|
+
'getMyCommands' => Types::Array.of(Types::BotCommand),
|
|
79
|
+
'setMyCommands' => Types::Bool,
|
|
80
|
+
'deleteMyCommands' => Types::Bool,
|
|
81
|
+
'setStickerSetThumbnail' => Types::Bool,
|
|
82
|
+
'logOut' => Types::Bool,
|
|
83
|
+
'close' => Types::Bool,
|
|
84
|
+
'copyMessage' => Types::MessageId,
|
|
85
|
+
'copyMessages' => Types::Array.of(Types::MessageId),
|
|
86
|
+
'createChatInviteLink' => Types::ChatInviteLink,
|
|
87
|
+
'editChatInviteLink' => Types::ChatInviteLink,
|
|
88
|
+
'revokeChatInviteLink' => Types::ChatInviteLink,
|
|
89
|
+
'approveChatJoinRequest' => Types::Bool,
|
|
90
|
+
'declineChatJoinRequest' => Types::Bool,
|
|
91
|
+
'banChatSenderChat' => Types::Bool,
|
|
92
|
+
'unbanChatSenderChat' => Types::Bool,
|
|
93
|
+
'answerWebAppQuery' => Types::SentWebAppMessage,
|
|
94
|
+
'setChatMenuButton' => Types::Bool,
|
|
95
|
+
'getChatMenuButton' => Types::MenuButtonDefault | Types::MenuButtonCommands | Types::MenuButtonWebApp,
|
|
96
|
+
'setMyDefaultAdministratorRights' => Types::Bool,
|
|
97
|
+
'getMyDefaultAdministratorRights' => Types::ChatAdministratorRights,
|
|
98
|
+
'createInvoiceLink' => Types::String,
|
|
99
|
+
'editGeneralForumTopic' => Types::Bool,
|
|
100
|
+
'closeGeneralForumTopic' => Types::Bool,
|
|
101
|
+
'reopenGeneralForumTopic' => Types::Bool,
|
|
102
|
+
'hideGeneralForumTopic' => Types::Bool,
|
|
103
|
+
'unhideGeneralForumTopic' => Types::Bool,
|
|
104
|
+
'unpinAllGeneralForumTopicMessages' => Types::Bool,
|
|
105
|
+
'setMyName' => Types::Bool,
|
|
106
|
+
'getMyName' => Types::BotName,
|
|
107
|
+
'setMyDescription' => Types::Bool,
|
|
108
|
+
'getMyDescription' => Types::BotDescription,
|
|
109
|
+
'setMyShortDescription' => Types::Bool,
|
|
110
|
+
'getMyShortDescription' => Types::BotShortDescription
|
|
111
|
+
}.freeze
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
data/lib/telegram/bot/api.rb
CHANGED
|
@@ -3,34 +3,6 @@
|
|
|
3
3
|
module Telegram
|
|
4
4
|
module Bot
|
|
5
5
|
class Api
|
|
6
|
-
ENDPOINTS = %w[
|
|
7
|
-
getUpdates setWebhook deleteWebhook getWebhookInfo getMe sendMessage
|
|
8
|
-
forwardMessage sendPhoto sendAudio sendDocument sendVideo sendVoice
|
|
9
|
-
sendVideoNote sendMediaGroup sendLocation editMessageLiveLocation
|
|
10
|
-
stopMessageLiveLocation sendVenue sendContact sendChatAction
|
|
11
|
-
getUserProfilePhotos getFile kickChatMember unbanChatMember
|
|
12
|
-
restrictChatMember promoteChatMember leaveChat getChat
|
|
13
|
-
getChatAdministrators exportChatInviteLink setChatPhoto deleteChatPhoto
|
|
14
|
-
setChatTitle setChatDescription pinChatMessage unpinChatMessage
|
|
15
|
-
getChatMembersCount getChatMember setChatStickerSet deleteChatStickerSet
|
|
16
|
-
answerCallbackQuery editMessageText editMessageCaption
|
|
17
|
-
editMessageReplyMarkup deleteMessage sendSticker getStickerSet
|
|
18
|
-
uploadStickerFile createNewStickerSet addStickerToSet
|
|
19
|
-
setStickerPositionInSet deleteStickerFromSet answerInlineQuery
|
|
20
|
-
sendInvoice answerShippingQuery answerPreCheckoutQuery
|
|
21
|
-
sendGame setGameScore getGameHighScores setPassportDataErrors
|
|
22
|
-
editMessageMedia sendAnimation sendPoll stopPoll setChatPermissions
|
|
23
|
-
setChatAdministratorCustomTitle sendDice getMyCommands setMyCommands
|
|
24
|
-
deleteMyCommands setStickerSetThumb logOut close copyMessage
|
|
25
|
-
createChatInviteLink editChatInviteLink revokeChatInviteLink
|
|
26
|
-
approveChatJoinRequest declineChatJoinRequest banChatSenderChat
|
|
27
|
-
unbanChatSenderChat answerWebAppQuery setChatMenuButton
|
|
28
|
-
getChatMenuButton setMyDefaultAdministratorRights
|
|
29
|
-
getMyDefaultAdministratorRights createInvoiceLink editGeneralForumTopic
|
|
30
|
-
closeGeneralForumTopic reopenGeneralForumTopic hideGeneralForumTopic
|
|
31
|
-
unhideGeneralForumTopic
|
|
32
|
-
].freeze
|
|
33
|
-
|
|
34
6
|
attr_reader :token, :url, :environment
|
|
35
7
|
|
|
36
8
|
def initialize(token, url: 'https://api.telegram.org', environment: :production)
|
|
@@ -39,27 +11,41 @@ module Telegram
|
|
|
39
11
|
@environment = environment.downcase.to_sym
|
|
40
12
|
end
|
|
41
13
|
|
|
14
|
+
def connection
|
|
15
|
+
@connection ||= Faraday.new(url: url) do |faraday|
|
|
16
|
+
faraday.request :multipart
|
|
17
|
+
faraday.request :url_encoded
|
|
18
|
+
faraday.adapter Telegram::Bot.configuration.adapter
|
|
19
|
+
faraday.options.timeout = Telegram::Bot.configuration.connection_timeout
|
|
20
|
+
faraday.options.open_timeout = Telegram::Bot.configuration.connection_open_timeout
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
42
24
|
def method_missing(method_name, *args, &block)
|
|
43
25
|
endpoint = method_name.to_s
|
|
44
26
|
endpoint = camelize(endpoint) if endpoint.include?('_')
|
|
45
27
|
|
|
46
|
-
ENDPOINTS.
|
|
28
|
+
return super unless ENDPOINTS.key?(endpoint)
|
|
29
|
+
|
|
30
|
+
result = call(endpoint, *args)
|
|
31
|
+
|
|
32
|
+
return result['ok'] unless (result = result['result'])
|
|
33
|
+
|
|
34
|
+
ENDPOINTS[endpoint].call(result)
|
|
47
35
|
end
|
|
48
36
|
|
|
49
37
|
def respond_to_missing?(*args)
|
|
50
38
|
method_name = args[0].to_s
|
|
51
39
|
method_name = camelize(method_name) if method_name.include?('_')
|
|
52
40
|
|
|
53
|
-
ENDPOINTS.
|
|
41
|
+
ENDPOINTS.key?(method_name) || super
|
|
54
42
|
end
|
|
55
43
|
|
|
56
44
|
def call(endpoint, raw_params = {})
|
|
57
45
|
params = build_params(raw_params)
|
|
58
46
|
path = build_path(endpoint)
|
|
59
|
-
response =
|
|
60
|
-
unless response.status == 200
|
|
61
|
-
raise Exceptions::ResponseError.new(response), 'Telegram API has returned the error.'
|
|
62
|
-
end
|
|
47
|
+
response = connection.post(path, params)
|
|
48
|
+
raise Exceptions::ResponseError.new(response: response) unless response.status == 200
|
|
63
49
|
|
|
64
50
|
JSON.parse(response.body)
|
|
65
51
|
end
|
|
@@ -95,16 +81,6 @@ module Telegram
|
|
|
95
81
|
words.drop(1).map(&:capitalize!)
|
|
96
82
|
words.join
|
|
97
83
|
end
|
|
98
|
-
|
|
99
|
-
def conn
|
|
100
|
-
@conn ||= Faraday.new(url: url) do |faraday|
|
|
101
|
-
faraday.request :multipart
|
|
102
|
-
faraday.request :url_encoded
|
|
103
|
-
faraday.adapter Telegram::Bot.configuration.adapter
|
|
104
|
-
faraday.options.timeout = Telegram::Bot.configuration.connection_timeout
|
|
105
|
-
faraday.options.open_timeout = Telegram::Bot.configuration.connection_open_timeout
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
84
|
end
|
|
109
85
|
end
|
|
110
86
|
end
|
data/lib/telegram/bot/client.rb
CHANGED
|
@@ -22,18 +22,17 @@ module Telegram
|
|
|
22
22
|
|
|
23
23
|
def listen(&block)
|
|
24
24
|
logger.info('Starting bot')
|
|
25
|
-
running = true
|
|
26
|
-
|
|
27
|
-
fetch_updates(&block) while running
|
|
28
|
-
exit
|
|
25
|
+
@running = true
|
|
26
|
+
fetch_updates(&block) while @running
|
|
29
27
|
end
|
|
30
28
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
def stop
|
|
30
|
+
@running = false
|
|
31
|
+
end
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
def fetch_updates
|
|
34
|
+
api.getUpdates(options).each do |update|
|
|
35
|
+
yield handle_update(update)
|
|
37
36
|
end
|
|
38
37
|
rescue Faraday::TimeoutError, Faraday::ConnectionFailed
|
|
39
38
|
retry
|