telegram-bot-ruby 1.0.0 → 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 +0 -3
- data/.github/workflows/stale.yml +19 -0
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +12 -7
- data/CHANGELOG.md +10 -0
- data/Gemfile +7 -3
- data/LICENSE +0 -1
- data/README.md +64 -20
- 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_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 +2 -2
- data/lib/telegram/bot/types/chat_member_updated.rb +1 -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 +1 -1
- data/lib/telegram/bot/types/{keyboard_button_request_user.rb → keyboard_button_request_users.rb} +2 -1
- 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 +19 -16
- 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/{user_shared.rb → users_shared.rb} +2 -2
- 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 -4
- metadata +43 -5
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
|
@@ -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,15 @@
|
|
|
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
|
+
|
|
3
13
|
## 1.0.0
|
|
4
14
|
|
|
5
15
|
- Replace [virtus](https://github.com/solnic/virtus) with [dry-struct](https://github.com/dry-rb/dry-struct)
|
data/Gemfile
CHANGED
|
@@ -8,7 +8,11 @@ gem 'dotenv', '~> 2.8'
|
|
|
8
8
|
gem 'nokogiri', '~> 1.13'
|
|
9
9
|
gem 'pry'
|
|
10
10
|
gem 'rake', '~> 13.0'
|
|
11
|
+
|
|
11
12
|
gem 'rspec', '~> 3.4'
|
|
12
|
-
gem '
|
|
13
|
-
|
|
14
|
-
gem 'rubocop
|
|
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
|
@@ -9,7 +9,9 @@ Ruby wrapper for [Telegram's Bot API](https://core.telegram.org/bots/api).
|
|
|
9
9
|
|
|
10
10
|
## 🚧 Upgrading to 1.0
|
|
11
11
|
|
|
12
|
-
Since v1.0 telegram-bot-ruby uses [dry-struct](https://github.com/dry-rb/dry-struct)
|
|
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:
|
|
13
15
|
|
|
14
16
|
```ruby
|
|
15
17
|
# This won't work
|
|
@@ -27,7 +29,7 @@ Please make sure it doesn't break your existing code before upgrading to 1.0.
|
|
|
27
29
|
Add following line to your Gemfile:
|
|
28
30
|
|
|
29
31
|
```ruby
|
|
30
|
-
gem 'telegram-bot-ruby'
|
|
32
|
+
gem 'telegram-bot-ruby', '~> 1.0'
|
|
31
33
|
```
|
|
32
34
|
|
|
33
35
|
And then execute:
|
|
@@ -44,7 +46,8 @@ gem install telegram-bot-ruby
|
|
|
44
46
|
|
|
45
47
|
## Usage
|
|
46
48
|
|
|
47
|
-
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:
|
|
48
51
|
|
|
49
52
|
```ruby
|
|
50
53
|
require 'telegram/bot'
|
|
@@ -63,7 +66,10 @@ Telegram::Bot::Client.run(token) do |bot|
|
|
|
63
66
|
end
|
|
64
67
|
```
|
|
65
68
|
|
|
66
|
-
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.
|
|
67
73
|
|
|
68
74
|
If you need to start a bot in development mode you have to pass `environment: :test`:
|
|
69
75
|
|
|
@@ -73,15 +79,35 @@ Telegram::Bot::Client.run(token, environment: :test) do |bot|
|
|
|
73
79
|
end
|
|
74
80
|
```
|
|
75
81
|
|
|
76
|
-
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
|
+
```
|
|
77
99
|
|
|
78
100
|
## Webhooks
|
|
79
101
|
|
|
80
|
-
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.
|
|
81
106
|
|
|
82
107
|
## Proxy
|
|
83
108
|
|
|
84
|
-
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:
|
|
85
111
|
|
|
86
112
|
```ruby
|
|
87
113
|
Telegram::Bot::Client.run(token, url: 'https://proxy.example.com') do |bot|
|
|
@@ -91,7 +117,8 @@ end
|
|
|
91
117
|
|
|
92
118
|
## Custom keyboards
|
|
93
119
|
|
|
94
|
-
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:
|
|
95
122
|
|
|
96
123
|
```ruby
|
|
97
124
|
bot.listen do |message|
|
|
@@ -131,7 +158,8 @@ end
|
|
|
131
158
|
|
|
132
159
|
## Inline keyboards
|
|
133
160
|
|
|
134
|
-
[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:
|
|
135
163
|
|
|
136
164
|
```ruby
|
|
137
165
|
bot.listen do |message|
|
|
@@ -179,13 +207,25 @@ bot.listen do |message|
|
|
|
179
207
|
end
|
|
180
208
|
```
|
|
181
209
|
|
|
182
|
-
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.
|
|
183
215
|
|
|
184
|
-
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).
|
|
185
218
|
|
|
186
219
|
## File upload
|
|
187
220
|
|
|
188
|
-
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:
|
|
189
229
|
|
|
190
230
|
```ruby
|
|
191
231
|
bot.listen do |message|
|
|
@@ -199,7 +239,9 @@ end
|
|
|
199
239
|
|
|
200
240
|
## Logging
|
|
201
241
|
|
|
202
|
-
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:
|
|
203
245
|
|
|
204
246
|
```ruby
|
|
205
247
|
Telegram::Bot::Client.run(token, logger: Logger.new($stderr)) do |bot|
|
|
@@ -212,7 +254,8 @@ end
|
|
|
212
254
|
|
|
213
255
|
## Connection adapters
|
|
214
256
|
|
|
215
|
-
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`):
|
|
216
259
|
|
|
217
260
|
```ruby
|
|
218
261
|
require 'net/http/persistent'
|
|
@@ -224,14 +267,15 @@ end
|
|
|
224
267
|
|
|
225
268
|
## Boilerplates
|
|
226
269
|
|
|
227
|
-
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:
|
|
228
272
|
|
|
229
273
|
- [Ruby Telegram Bot boilerplate](https://github.com/telegram-bots/ruby-telegram-bot-boilerplate)
|
|
230
274
|
|
|
231
275
|
## Contributing
|
|
232
276
|
|
|
233
|
-
1. Fork it
|
|
234
|
-
2. Create your feature branch (git checkout -b my-new-feature)
|
|
235
|
-
3. Commit your changes (git commit -am 'Add some feature')
|
|
236
|
-
4. Push to the branch (git push origin my-new-feature)
|
|
237
|
-
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
|
|
@@ -6,22 +6,16 @@ module Telegram
|
|
|
6
6
|
class ResponseError < Base
|
|
7
7
|
attr_reader :response
|
|
8
8
|
|
|
9
|
-
def initialize(response)
|
|
9
|
+
def initialize(response:)
|
|
10
10
|
@response = response
|
|
11
|
-
super
|
|
12
|
-
end
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
super +
|
|
16
|
-
format(' (%s)', data.map { |k, v| %(#{k}: "#{v}") }.join(', '))
|
|
12
|
+
super "Telegram API has returned the error. (#{data.map { |k, v| %(#{k}: #{v.inspect}) }.join(', ')})"
|
|
17
13
|
end
|
|
18
14
|
|
|
19
15
|
def error_code
|
|
20
16
|
data[:error_code] || data['error_code']
|
|
21
17
|
end
|
|
22
18
|
|
|
23
|
-
private
|
|
24
|
-
|
|
25
19
|
def data
|
|
26
20
|
@data ||= begin
|
|
27
21
|
JSON.parse(response.body)
|
|
@@ -9,7 +9,7 @@ module Telegram
|
|
|
9
9
|
attribute :width, Types::Integer
|
|
10
10
|
attribute :height, Types::Integer
|
|
11
11
|
attribute :duration, Types::Integer
|
|
12
|
-
attribute? :
|
|
12
|
+
attribute? :thumbnail, PhotoSize
|
|
13
13
|
attribute? :file_name, Types::String
|
|
14
14
|
attribute? :mime_type, Types::String
|
|
15
15
|
attribute? :file_size, Types::Integer
|