telegem 3.2.4 → 3.3.1
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/CHANGELOG.md +103 -0
- data/Gemfile +1 -1
- data/Readme.md +2 -6
- data/bin/telegem-init +32 -0
- data/bin/telegem-ssl +7 -0
- data/lib/api/client.rb +1 -10
- data/lib/api/types.rb +321 -47
- data/lib/core/bot.rb +23 -17
- data/lib/core/context.rb +9 -7
- data/lib/core/rate_limit.rb +0 -14
- data/lib/core/scene.rb +1 -1
- data/lib/markup/inline.rb +104 -0
- data/lib/markup/keyboard.rb +77 -298
- data/lib/plugins/file_extract.rb +4 -24
- data/lib/session/memory_store.rb +91 -128
- data/lib/telegem.rb +3 -2
- data/lib/webhook/server.rb +1 -1
- metadata +17 -12
- data/CHANGELOG +0 -95
data/lib/core/bot.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
#frozen_string_literal: true
|
|
1
2
|
require 'json'
|
|
2
|
-
|
|
3
|
+
require 'async'
|
|
3
4
|
module Telegem
|
|
4
5
|
module Core
|
|
5
6
|
class Bot
|
|
@@ -135,21 +136,29 @@ module Telegem
|
|
|
135
136
|
end
|
|
136
137
|
|
|
137
138
|
def set_my_profile_photo(photo, **options)
|
|
138
|
-
@api.call('setMyProfilePhoto', {
|
|
139
|
-
|
|
139
|
+
@api.call('setMyProfilePhoto', {
|
|
140
|
+
photo: photo
|
|
141
|
+
}.merge(options))
|
|
142
|
+
end
|
|
140
143
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
+
def remove_my_profile_photo
|
|
145
|
+
@api.call('removeMyProfilePhoto', {})
|
|
146
|
+
end
|
|
144
147
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
148
|
+
def get_user_profile_audios(user_id, **options)
|
|
149
|
+
result = @api.call('getUserProfileAudios', {
|
|
150
|
+
user_id: user_id
|
|
151
|
+
}.merge(options))
|
|
152
|
+
return nil unless result && result['audios']
|
|
153
|
+
Types::UserProfileAudios.new(result)
|
|
154
|
+
end
|
|
149
155
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
def create_forum_topic(chat_id, name, **options)
|
|
157
|
+
@api.call('createForumTopic', {
|
|
158
|
+
chat_id: chat_id,
|
|
159
|
+
name: name
|
|
160
|
+
}.merge(options))
|
|
161
|
+
end
|
|
153
162
|
def location(&block)
|
|
154
163
|
on(:message, location: true) do |ctx|
|
|
155
164
|
block.call(ctx)
|
|
@@ -230,12 +239,9 @@ module Telegem
|
|
|
230
239
|
|
|
231
240
|
if updates && updates.any?
|
|
232
241
|
updates.each do |update_data|
|
|
233
|
-
Async do
|
|
234
242
|
update = Types::Update.new(update_data)
|
|
235
243
|
process_update(update)
|
|
236
244
|
end
|
|
237
|
-
end
|
|
238
|
-
|
|
239
245
|
@offset = updates.last['update_id'] + 1
|
|
240
246
|
@logger.debug("Updated offset to: #{@offset}")
|
|
241
247
|
end
|
|
@@ -385,4 +391,4 @@ module Telegem
|
|
|
385
391
|
end
|
|
386
392
|
end
|
|
387
393
|
end
|
|
388
|
-
end
|
|
394
|
+
end
|
data/lib/core/context.rb
CHANGED
|
@@ -71,7 +71,7 @@ module Telegem
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def caption_entities
|
|
74
|
-
message
|
|
74
|
+
message&.caption_entities || []
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def caption
|
|
@@ -401,9 +401,6 @@ module Telegem
|
|
|
401
401
|
def uploading_document(**options)
|
|
402
402
|
send_chat_action('upload_document', **options)
|
|
403
403
|
end
|
|
404
|
-
def scene
|
|
405
|
-
session[:telegem_scene]&.[](:id)
|
|
406
|
-
end
|
|
407
404
|
def ask(question, **options)
|
|
408
405
|
scene_data = session[:telegem_scene]
|
|
409
406
|
if scene_data
|
|
@@ -439,10 +436,15 @@ module Telegem
|
|
|
439
436
|
scene&.next_step(self, step_name)
|
|
440
437
|
end
|
|
441
438
|
def with_typing(&block)
|
|
442
|
-
|
|
443
|
-
|
|
439
|
+
thread = Thread.new do
|
|
440
|
+
while @typing_active
|
|
441
|
+
typing
|
|
442
|
+
sleep 5
|
|
443
|
+
end
|
|
444
|
+
end
|
|
444
445
|
result = block.call
|
|
445
|
-
|
|
446
|
+
@typing_active = false
|
|
447
|
+
thread.join
|
|
446
448
|
result
|
|
447
449
|
end
|
|
448
450
|
|
data/lib/core/rate_limit.rb
CHANGED
|
@@ -64,36 +64,22 @@ module Telegem
|
|
|
64
64
|
|
|
65
65
|
def increment_counters(ctx)
|
|
66
66
|
now = Time.now.to_i
|
|
67
|
-
|
|
68
|
-
|
|
69
67
|
if @options[:global]
|
|
70
68
|
key = "global"
|
|
71
|
-
cleanup_counter(:global, key, now)
|
|
72
69
|
@counters[:global].increment(key, 1, ttl: @options[:global][:per])
|
|
73
70
|
end
|
|
74
|
-
|
|
75
|
-
|
|
76
71
|
if @options[:user] && ctx.from&.id
|
|
77
72
|
key = "user:#{ctx.from.id}"
|
|
78
|
-
cleanup_counter(:user, key, now)
|
|
79
73
|
@counters[:user].increment(key, 1, ttl: @options[:user][:per])
|
|
80
74
|
end
|
|
81
75
|
|
|
82
76
|
|
|
83
77
|
if @options[:chat] && ctx.chat&.id
|
|
84
78
|
key = "chat:#{ctx.chat.id}"
|
|
85
|
-
cleanup_counter(:chat, key, now)
|
|
86
79
|
@counters[:chat].increment(key, 1, ttl: @options[:chat][:per])
|
|
87
80
|
end
|
|
88
81
|
end
|
|
89
|
-
|
|
90
|
-
def cleanup_counter(type, key, now)
|
|
91
|
-
expires = @counters[type].get_ttl(key) || now
|
|
92
|
-
@counters[type].delete(key) if now > expires
|
|
93
|
-
end
|
|
94
|
-
|
|
95
82
|
def rate_limit_response(ctx)
|
|
96
|
-
|
|
97
83
|
ctx.reply("⏳ Please wait a moment before sending another request.") rescue nil
|
|
98
84
|
nil
|
|
99
85
|
end
|
data/lib/core/scene.rb
CHANGED
|
@@ -124,7 +124,7 @@ module Telegem
|
|
|
124
124
|
def process_response(ctx, scene_data)
|
|
125
125
|
|
|
126
126
|
current_step_name = scene_data[:step]
|
|
127
|
-
scene_data[:data][current_step_name] = ctx.message
|
|
127
|
+
scene_data[:data][current_step_name] = ctx.message
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
scene_data[:waiting_for_response] = false
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module Telegem
|
|
2
|
+
module Markup
|
|
3
|
+
|
|
4
|
+
module InlineButtons
|
|
5
|
+
def callback(text, data, style: nil, icon_custom_emoji_id: nil)
|
|
6
|
+
{
|
|
7
|
+
text: text,
|
|
8
|
+
callback_data: data,
|
|
9
|
+
style: style,
|
|
10
|
+
icon_custom_emoji_id: icon_custom_emoji_id
|
|
11
|
+
}.compact
|
|
12
|
+
end
|
|
13
|
+
def url(text, url, style: nil, icon_custom_emoji_id: nil)
|
|
14
|
+
{
|
|
15
|
+
text: text,
|
|
16
|
+
url: url,
|
|
17
|
+
style: style,
|
|
18
|
+
icon_custom_emoji_id: icon_custom_emoji_id
|
|
19
|
+
}.compact
|
|
20
|
+
end
|
|
21
|
+
def switch_inline(text, query: nil, style: nil, icon_custom_emoji_id: nil)
|
|
22
|
+
{
|
|
23
|
+
text: text,
|
|
24
|
+
switch_inline_query: query,
|
|
25
|
+
style: style,
|
|
26
|
+
icon_custom_emoji_id: icon_custom_emoji_id
|
|
27
|
+
}.compact
|
|
28
|
+
end
|
|
29
|
+
def switch_inline_current_chat(text, query: nil, style: nil, icon_custom_emoji_id: nil)
|
|
30
|
+
{
|
|
31
|
+
text: text,
|
|
32
|
+
switch_inline_query_current_chat: query,
|
|
33
|
+
style: style,
|
|
34
|
+
icon_custom_emoji_id: icon_custom_emoji_id
|
|
35
|
+
}.compact
|
|
36
|
+
end
|
|
37
|
+
def callback_game(text, game_short_name, style: nil, icon_custom_emoji_id: nil)
|
|
38
|
+
{
|
|
39
|
+
text: text,
|
|
40
|
+
callback_game: { short_name: game_short_name },
|
|
41
|
+
style: style,
|
|
42
|
+
icon_custom_emoji_id: icon_custom_emoji_id
|
|
43
|
+
}.compact
|
|
44
|
+
end
|
|
45
|
+
def pay(text, style: nil, icon_custom_emoji_id: nil)
|
|
46
|
+
{
|
|
47
|
+
text: text,
|
|
48
|
+
pay: true,
|
|
49
|
+
style: style,
|
|
50
|
+
icon_custom_emoji_id: icon_custom_emoji_id
|
|
51
|
+
}.compact
|
|
52
|
+
end
|
|
53
|
+
def web_app(text, url: nil, style: nil, icon_custom_emoji_id: nil)
|
|
54
|
+
{
|
|
55
|
+
text: text,
|
|
56
|
+
web_app: { url: url },
|
|
57
|
+
style: style,
|
|
58
|
+
icon_custom_emoji_id: icon_custom_emoji_id
|
|
59
|
+
}.compact
|
|
60
|
+
end
|
|
61
|
+
def login(text, url, style: nil, icon_custom_emoji_id: nil, **options)
|
|
62
|
+
login_url = { url: url}.merge(options)
|
|
63
|
+
{
|
|
64
|
+
text: text,
|
|
65
|
+
login_url: login_url,
|
|
66
|
+
style: style,
|
|
67
|
+
icon_custom_emoji_id: icon_custom_emoji_id
|
|
68
|
+
}.compact
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
class InlineBuilder
|
|
72
|
+
include InlineButtons
|
|
73
|
+
def initialize
|
|
74
|
+
@rows = []
|
|
75
|
+
end
|
|
76
|
+
def row(*buttons)
|
|
77
|
+
@rows << buttons
|
|
78
|
+
self
|
|
79
|
+
end
|
|
80
|
+
def build
|
|
81
|
+
InlineKeyboard.new(@rows)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
class InlineKeyboard
|
|
85
|
+
attr_reader :rows
|
|
86
|
+
def initialize(rows)
|
|
87
|
+
@rows = rows
|
|
88
|
+
end
|
|
89
|
+
def to_h
|
|
90
|
+
{
|
|
91
|
+
inline_keyboard: @rows
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
def to_json(*args)
|
|
95
|
+
to_h.to_json(*args)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
def self.inline(&block)
|
|
99
|
+
builder = InlineBuilder.new
|
|
100
|
+
builder.instance_eval(&block) if block_given?
|
|
101
|
+
builder.build
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
data/lib/markup/keyboard.rb
CHANGED
|
@@ -1,321 +1,100 @@
|
|
|
1
1
|
module Telegem
|
|
2
2
|
module Markup
|
|
3
|
-
class Keyboard
|
|
4
|
-
attr_reader :buttons, :options
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
module ReplyButtons
|
|
5
|
+
def text(content, style: nil, icon_custom_emoji_id: nil)
|
|
6
|
+
{
|
|
7
|
+
text: content,
|
|
8
|
+
icon_custom_emoji_id: icon_custom_emoji_id,
|
|
9
|
+
style: style
|
|
10
|
+
}.compact
|
|
11
|
+
end
|
|
12
|
+
def request_contact(text, style: nil, icon_custom_emoji_id: nil)
|
|
13
|
+
{
|
|
14
|
+
text: text,
|
|
15
|
+
style: style,
|
|
16
|
+
icon_custom_emoji_id: icon_custom_emoji_id,
|
|
17
|
+
request_contact: true
|
|
18
|
+
}.compact
|
|
19
|
+
end
|
|
20
|
+
def request_location(text, style: nil, icon_custom_emoji_id: nil)
|
|
21
|
+
{
|
|
22
|
+
text: text,
|
|
23
|
+
style: style,
|
|
24
|
+
icon_custom_emoji_id: icon_custom_emoji_id,
|
|
25
|
+
request_location: true
|
|
26
|
+
}.compact
|
|
27
|
+
end
|
|
28
|
+
def request_poll(text, poll_type: nil, style: nil, icon_custom_emoji_id: nil)
|
|
29
|
+
{
|
|
30
|
+
text: text,
|
|
31
|
+
style: style,
|
|
32
|
+
icon_custom_emoji_id: icon_custom_emoji_id,
|
|
33
|
+
request_poll: poll_type ? { type: poll_type } : {}
|
|
34
|
+
}.compact
|
|
35
|
+
end
|
|
36
|
+
def web_app(text, url: nil, style: nil, icon_custom_emoji_id: nil)
|
|
37
|
+
{
|
|
38
|
+
text: text,
|
|
39
|
+
url: url,
|
|
40
|
+
style: style,
|
|
41
|
+
icon_custom_emoji_id: icon_custom_emoji_id
|
|
42
|
+
}.compact
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
class ReplyBuilder
|
|
46
|
+
include ReplyButtons
|
|
47
|
+
def initialize
|
|
48
|
+
@rows = []
|
|
8
49
|
@options = {
|
|
9
50
|
resize_keyboard: true,
|
|
10
51
|
one_time_keyboard: false,
|
|
11
52
|
selective: false
|
|
12
|
-
}.merge(options)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.[](*rows)
|
|
16
|
-
new(rows)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.build(&block)
|
|
20
|
-
builder = Builder.new
|
|
21
|
-
builder.instance_eval(&block) if block_given?
|
|
22
|
-
builder.keyboard
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def row(*buttons)
|
|
26
|
-
@buttons << buttons.flatten
|
|
27
|
-
self
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def button(text, style: nil, icon_custom_emoji_id: nil, **options)
|
|
31
|
-
btn = {
|
|
32
|
-
text: text
|
|
33
|
-
}.merge(options)
|
|
34
|
-
btn[:style] = style if style
|
|
35
|
-
btn[:icon_custom_emoji_id] = icon_custom_emoji_id if icon_custom_emoji_id
|
|
36
|
-
if @buttons.empty? || @buttons.last.is_a?(Array)
|
|
37
|
-
@buttons << [btn]
|
|
38
|
-
else
|
|
39
|
-
@buttons.last << btn
|
|
40
|
-
end
|
|
41
|
-
self
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def request_contact(text)
|
|
45
|
-
button(text, request_contact: true)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def request_location(text)
|
|
49
|
-
button(text, request_location: true)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def request_poll(text, type = nil)
|
|
53
|
-
opts = type ? { request_poll: { type: type } } : { request_poll: {} }
|
|
54
|
-
button(text, opts)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def resize(resize = true)
|
|
58
|
-
@options[:resize_keyboard] = resize
|
|
59
|
-
self
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def one_time(one_time = true)
|
|
63
|
-
@options[:one_time_keyboard] = one_time
|
|
64
|
-
self
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def selective(selective = true)
|
|
68
|
-
@options[:selective] = selective
|
|
69
|
-
self
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def to_h
|
|
73
|
-
{
|
|
74
|
-
keyboard: @buttons.map { |row| row.is_a?(Array) ? row : [row] },
|
|
75
|
-
**@options
|
|
76
53
|
}
|
|
77
54
|
end
|
|
78
|
-
|
|
79
|
-
def to_json(*args)
|
|
80
|
-
to_h.to_json(*args)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def self.remove(selective: false)
|
|
84
|
-
{
|
|
85
|
-
remove_keyboard: true,
|
|
86
|
-
selective: selective
|
|
87
|
-
}
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def self.force_reply(selective: false, input_field_placeholder: nil)
|
|
91
|
-
markup = {
|
|
92
|
-
force_reply: true,
|
|
93
|
-
selective: selective
|
|
94
|
-
}
|
|
95
|
-
markup[:input_field_placeholder] = input_field_placeholder if input_field_placeholder
|
|
96
|
-
markup
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
class InlineKeyboard
|
|
101
|
-
attr_reader :buttons
|
|
102
|
-
|
|
103
|
-
def initialize(buttons = [])
|
|
104
|
-
@buttons = buttons
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def self.[](*rows)
|
|
108
|
-
new(rows)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def self.build(&block)
|
|
112
|
-
builder = InlineBuilder.new
|
|
113
|
-
builder.instance_eval(&block) if block_given?
|
|
114
|
-
builder.keyboard
|
|
115
|
-
end
|
|
116
|
-
|
|
117
55
|
def row(*buttons)
|
|
118
|
-
@
|
|
56
|
+
@rows << buttons
|
|
119
57
|
self
|
|
120
58
|
end
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
btn = {
|
|
124
|
-
text: text
|
|
125
|
-
}.merge(options)
|
|
126
|
-
btn[:style] = style if style
|
|
127
|
-
btn[:icon_custom_emoji_id] = icon_custom_emoji_id if icon_custom_emoji_id
|
|
128
|
-
if @buttons.empty? || @buttons.last.is_a?(Array)
|
|
129
|
-
@buttons << [btn]
|
|
130
|
-
else
|
|
131
|
-
@buttons.last << btn
|
|
132
|
-
end
|
|
133
|
-
self
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def url(text, url)
|
|
137
|
-
button(text, url: url)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def callback(text, data)
|
|
141
|
-
button(text, callback_data: data)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def web_app(text, url)
|
|
145
|
-
button(text, web_app: { url: url })
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def login(text, url, **options)
|
|
149
|
-
button(text, login_url: { url: url, **options })
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def switch_inline(text, query = "")
|
|
153
|
-
button(text, switch_inline_query: query)
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def switch_inline_current(text, query = "")
|
|
157
|
-
button(text, switch_inline_query_current_chat: query)
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def pay(text)
|
|
161
|
-
button(text, pay: true)
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def to_h
|
|
165
|
-
clean_rows = @buttons.compact.map do |row|
|
|
166
|
-
row = Array(row).compact.select { |btn| is_a?(Hash) }
|
|
167
|
-
row.empty? ? nil : row
|
|
168
|
-
end.compact
|
|
169
|
-
{ inline_keyboard: clean_rows}
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def to_json(*args)
|
|
173
|
-
to_h.to_json(*args)
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
class Builder
|
|
178
|
-
attr_reader :keyboard
|
|
179
|
-
|
|
180
|
-
def initialize
|
|
181
|
-
@keyboard = Keyboard.new
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def row(*buttons, &block)
|
|
185
|
-
if block_given?
|
|
186
|
-
sub_builder = Builder.new
|
|
187
|
-
sub_builder.instance_eval(&block)
|
|
188
|
-
@keyboard.row(*sub_builder.keyboard.buttons.flatten(1))
|
|
189
|
-
elsif buttons.any?
|
|
190
|
-
@keyboard.row(*buttons)
|
|
191
|
-
else
|
|
192
|
-
@keyboard.row
|
|
193
|
-
end
|
|
59
|
+
def resize(value = true)
|
|
60
|
+
@options[:resize_keyboard] = value
|
|
194
61
|
self
|
|
195
62
|
end
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
@keyboard.button(text, **options)
|
|
63
|
+
def one_time(value = true)
|
|
64
|
+
@options[:one_time_keyboard] = value
|
|
199
65
|
self
|
|
200
66
|
end
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
@keyboard.request_contact(text)
|
|
67
|
+
def selective(value = true)
|
|
68
|
+
@options[:selective] = value
|
|
204
69
|
self
|
|
205
70
|
end
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
@keyboard.request_location(text)
|
|
71
|
+
def placeholder(text)
|
|
72
|
+
@options[:input_field_placeholder] = text
|
|
209
73
|
self
|
|
210
74
|
end
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
@keyboard.request_poll(text, type)
|
|
214
|
-
self
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def method_missing(name, *args, &block)
|
|
218
|
-
if @keyboard && @keyboard.respond_to?(name)
|
|
219
|
-
@keyboard.send(name, *args, &block)
|
|
220
|
-
else
|
|
221
|
-
super
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def respond_to_missing?(name, include_private = false)
|
|
226
|
-
@keyboard && @keyboard.respond_to?(name) || super
|
|
227
|
-
end
|
|
75
|
+
def build
|
|
76
|
+
ReplyKeyboard.new(@rows, @options)
|
|
228
77
|
end
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
@keyboard = InlineKeyboard.new
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def row(*buttons, &block)
|
|
238
|
-
if block_given?
|
|
239
|
-
sub_builder = InlineBuilder.new
|
|
240
|
-
sub_builder.instance_eval(&block)
|
|
241
|
-
@keyboard.row(*sub_builder.keyboard.buttons.flatten(1))
|
|
242
|
-
elsif buttons.any?
|
|
243
|
-
@keyboard.row(*buttons)
|
|
244
|
-
else
|
|
245
|
-
@keyboard.row([])
|
|
78
|
+
end
|
|
79
|
+
class ReplyKeyboard
|
|
80
|
+
def initialize(rows, options = {})
|
|
81
|
+
@rows = rows
|
|
82
|
+
@options = options
|
|
246
83
|
end
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
@keyboard.button(text, **options)
|
|
252
|
-
self
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
def url(text, url)
|
|
256
|
-
@keyboard.url(text, url)
|
|
257
|
-
self
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
def callback(text, data)
|
|
261
|
-
@keyboard.callback(text, data)
|
|
262
|
-
self
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
def web_app(text, url)
|
|
266
|
-
@keyboard.web_app(text, url)
|
|
267
|
-
self
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
def login(text, url, **options)
|
|
271
|
-
@keyboard.login(text, url, **options)
|
|
272
|
-
self
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def switch_inline(text, query = "")
|
|
276
|
-
@keyboard.switch_inline(text, query)
|
|
277
|
-
self
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
def switch_inline_current(text, query = "")
|
|
281
|
-
@keyboard.switch_inline_current(text, query)
|
|
282
|
-
self
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
def pay(text)
|
|
286
|
-
@keyboard.pay(text)
|
|
287
|
-
self
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
def method_missing(name, *args, &block)
|
|
291
|
-
if @keyboard && @keyboard.respond_to?(name)
|
|
292
|
-
@keyboard.send(name, *args, &block)
|
|
293
|
-
else
|
|
294
|
-
super
|
|
84
|
+
def to_h
|
|
85
|
+
{
|
|
86
|
+
keyboard: @rows
|
|
87
|
+
}.merge(@options)
|
|
295
88
|
end
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
def inline(&block)
|
|
309
|
-
InlineKeyboard.build(&block)
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
def remove(**options)
|
|
313
|
-
Keyboard.remove(**options)
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
def force_reply(**options)
|
|
317
|
-
Keyboard.force_reply(**options)
|
|
318
|
-
end
|
|
319
|
-
end
|
|
320
|
-
end
|
|
321
|
-
end
|
|
89
|
+
def to_json(*args)
|
|
90
|
+
to_h.to_json(*args)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
def self.keyboard(&block)
|
|
94
|
+
builder = ReplyBuilder.new
|
|
95
|
+
builder.instance_eval(&block) if block_given?
|
|
96
|
+
builder.build
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
data/lib/plugins/file_extract.rb
CHANGED
|
@@ -85,28 +85,8 @@ module Telegem
|
|
|
85
85
|
success: false,
|
|
86
86
|
error: "Failed to extract PDF: #{e.message}"
|
|
87
87
|
}
|
|
88
|
-
rescue LoadError
|
|
89
|
-
{
|
|
90
|
-
success: false,
|
|
91
|
-
error: "PDF extraction requires the 'pdf-reader' gem. Please add it to your Gemfile."
|
|
92
|
-
}
|
|
93
|
-
rescue PDF::Reader::MalformedPDFError => e
|
|
94
|
-
{
|
|
95
|
-
success: false,
|
|
96
|
-
error: "Malformed PDF: #{e.message}"
|
|
97
|
-
}
|
|
98
|
-
rescue PDF::Reader::UnsupportedFeatureError => e
|
|
99
|
-
{
|
|
100
|
-
success: false,
|
|
101
|
-
error: "Unsupported PDF feature: #{e.message}"
|
|
102
|
-
}
|
|
103
|
-
rescue PDF::Reader::EncryptedPDFError => e
|
|
104
|
-
{
|
|
105
|
-
success: false,
|
|
106
|
-
error: "Encrypted PDF: #{e.message}"
|
|
107
|
-
}
|
|
108
88
|
ensure
|
|
109
|
-
cleanup if @options[:auto_delete]
|
|
89
|
+
cleanup if @options[:auto_delete]
|
|
110
90
|
end
|
|
111
91
|
end
|
|
112
92
|
def extract_json
|
|
@@ -196,8 +176,8 @@ module Telegem
|
|
|
196
176
|
def cleanup
|
|
197
177
|
@temp_file.unlink if @temp_file
|
|
198
178
|
@temp_file = nil
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
202
182
|
end
|
|
203
183
|
end
|