rbender 0.5.35 → 0.7.3
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 +5 -5
- data/bin/rbender +47 -3
- data/lib/rbender/base.rb +184 -182
- data/lib/rbender/config_handler.rb +39 -39
- data/lib/rbender/fly_settings.rb +30 -0
- data/lib/rbender/keyboard.rb +79 -80
- data/lib/rbender/keyboard_inline.rb +29 -15
- data/lib/rbender/methods.rb +453 -376
- data/lib/rbender/mongo_client.rb +2 -1
- data/lib/rbender/{sessionmanager.rb → session_manager.rb} +11 -14
- data/lib/rbender/state.rb +305 -241
- data/templates/sample.rb +2 -1
- metadata +7 -5
data/lib/rbender/mongo_client.rb
CHANGED
|
@@ -6,6 +6,7 @@ class RBender::MongoClient
|
|
|
6
6
|
attr_reader :mongo_client
|
|
7
7
|
|
|
8
8
|
public
|
|
9
|
+
|
|
9
10
|
def self.client
|
|
10
11
|
instance.mongo_client
|
|
11
12
|
end
|
|
@@ -15,7 +16,7 @@ class RBender::MongoClient
|
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def setup(bot_name, mongo_string)
|
|
18
|
-
@bot_name
|
|
19
|
+
@bot_name = bot_name
|
|
19
20
|
@mongo_client = Mongo::Client.new(mongo_string, :database => bot_name)
|
|
20
21
|
|
|
21
22
|
Mongo::Logger.logger.level = ::Logger::FATAL
|
|
@@ -2,8 +2,9 @@ module RBender
|
|
|
2
2
|
module SessionManager
|
|
3
3
|
|
|
4
4
|
private
|
|
5
|
+
|
|
5
6
|
def session_setup(mongo_client)
|
|
6
|
-
@mongo_client
|
|
7
|
+
@mongo_client = mongo_client
|
|
7
8
|
@sessions_mongo = @mongo_client[:sessions]
|
|
8
9
|
end
|
|
9
10
|
|
|
@@ -16,9 +17,9 @@ module RBender
|
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def save_session(session)
|
|
19
|
-
@sessions_mongo.update_one({chat_id: session[:
|
|
20
|
-
{'$set' => {session: session}},
|
|
21
|
-
{upsert: true})
|
|
20
|
+
@sessions_mongo.update_one({ chat_id: session[:chat_id] },
|
|
21
|
+
{ '$set' => { session: session } },
|
|
22
|
+
{ upsert: true })
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
def has_session?(chat_id)
|
|
@@ -27,26 +28,22 @@ module RBender
|
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
public
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
|
|
32
|
+
def self.chat_id_list
|
|
33
|
+
sessions = RBender::MongoClient.client[:sessions]
|
|
34
|
+
result = sessions.distinct('chat_id')
|
|
35
|
+
chat_id_list = []
|
|
34
36
|
result.each do |doc|
|
|
35
37
|
chatid_list << doc
|
|
36
38
|
end
|
|
37
|
-
|
|
39
|
+
chat_id_list
|
|
38
40
|
end
|
|
39
41
|
end
|
|
40
42
|
end
|
|
41
43
|
|
|
42
|
-
#
|
|
43
44
|
# Mongo scheme:
|
|
44
45
|
# Session
|
|
45
46
|
# {chat_id: {session_key: session_value}}
|
|
46
47
|
#
|
|
47
48
|
# States
|
|
48
49
|
# {chat_id: state}
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
data/lib/rbender/state.rb
CHANGED
|
@@ -1,244 +1,308 @@
|
|
|
1
1
|
class RBender::State
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
2
|
+
def initialize(message, api, session, &state_block)
|
|
3
|
+
@message = message
|
|
4
|
+
@api = api
|
|
5
|
+
@session = session
|
|
6
|
+
@chat_id = @session[:chat_id]
|
|
7
|
+
@methods = RBender::Methods.new(message, api, session)
|
|
8
|
+
@state_block = state_block
|
|
9
|
+
|
|
10
|
+
@keyboard = nil
|
|
11
|
+
|
|
12
|
+
@inline_keyboards_blocks = {}
|
|
13
|
+
@after_block = nil
|
|
14
|
+
@before_block = nil
|
|
15
|
+
@text_block = nil
|
|
16
|
+
@helpers_block = nil
|
|
17
|
+
@pre_checkout_block = nil
|
|
18
|
+
@checkout_block = nil
|
|
19
|
+
@shipping_block = nil
|
|
20
|
+
@photo_block = nil
|
|
21
|
+
@contact_block = nil
|
|
22
|
+
|
|
23
|
+
@commands_blocks = {}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def get_keyboard
|
|
27
|
+
@keyboard
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def message
|
|
31
|
+
@message
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Invokes states and processes user's input
|
|
35
|
+
def invoke
|
|
36
|
+
case message
|
|
37
|
+
when Telegram::Bot::Types::CallbackQuery
|
|
38
|
+
process_callback
|
|
39
|
+
when Telegram::Bot::Types::Message
|
|
40
|
+
if @message.text
|
|
41
|
+
if @message.text[0] == '/' and @message.text != '/start'
|
|
42
|
+
process_command(@message.text)
|
|
43
|
+
else
|
|
44
|
+
process_text_message
|
|
45
|
+
end
|
|
46
|
+
elsif @message.successful_payment
|
|
47
|
+
process_checkout
|
|
48
|
+
elsif @message.contact
|
|
49
|
+
process_contact
|
|
50
|
+
elsif @message.photo
|
|
51
|
+
process_photo
|
|
52
|
+
end
|
|
53
|
+
when Telegram::Bot::Types::Document
|
|
54
|
+
if @message.photo
|
|
55
|
+
process_photo
|
|
56
|
+
end
|
|
57
|
+
when Telegram::Bot::Types::PreCheckoutQuery
|
|
58
|
+
process_pre_checkout
|
|
59
|
+
when Telegram::Bot::Types::ShippingQuery
|
|
60
|
+
process_shipping
|
|
61
|
+
else
|
|
62
|
+
raise "This type isn't available: #{message.class}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def process_pre_checkout
|
|
67
|
+
instance_exec(@message, &@pre_checkout_block)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def process_checkout
|
|
71
|
+
instance_exec(@message.successful_payment, &@checkout_block)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def process_shipping
|
|
75
|
+
instance_exec(@message.shipping_query, &@shipping_block)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @param command String
|
|
79
|
+
def process_command(command_line)
|
|
80
|
+
splitted = command_line.split(" ")
|
|
81
|
+
command = splitted[0]
|
|
82
|
+
splitted.delete_at 0
|
|
83
|
+
params = splitted
|
|
84
|
+
|
|
85
|
+
if @commands_blocks.include? command
|
|
86
|
+
instance_exec(params, &@commands_blocks[command])
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def process_photo
|
|
91
|
+
instance_exec(message.photo, &@photo_block) unless @photo_block.nil?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def process_contact
|
|
95
|
+
instance_exec(message.contact, &@contact_block) unless @contact_block.nil?
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Process if message is just text
|
|
99
|
+
def process_text_message
|
|
100
|
+
unless @keyboard.nil? # if state has keyboard
|
|
101
|
+
@keyboard.instance_eval(&@helpers_block) unless @helpers_block.nil?
|
|
102
|
+
build_keyboard
|
|
103
|
+
|
|
104
|
+
@keyboard.markup_final.each do |btn, final_btn|
|
|
105
|
+
if message.text == final_btn
|
|
106
|
+
instance_exec(&@keyboard.actions[btn]) # Process keyboard action
|
|
107
|
+
return
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
unless @text_block.nil? # Else process text action
|
|
113
|
+
instance_exec(@message.text, &@text_block)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Process if message is inline keyboard callback
|
|
118
|
+
def process_callback
|
|
119
|
+
keyboard_name, action = @message.data.split(RBender::CALLBACK_SPLITTER)
|
|
120
|
+
keyboard = @inline_keyboards_blocks[keyboard_name.to_sym]
|
|
121
|
+
keyboard.instance_eval(&@helpers_block) unless @helpers_block.nil?
|
|
122
|
+
keyboard.invoke unless keyboard.nil?
|
|
123
|
+
|
|
124
|
+
unless keyboard.nil?
|
|
125
|
+
unless keyboard.buttons_actions[action].nil?
|
|
126
|
+
instance_eval(&keyboard.buttons_actions[action])
|
|
127
|
+
else
|
|
128
|
+
raise "There is no action called '#{action}'"
|
|
129
|
+
end
|
|
130
|
+
else
|
|
131
|
+
edit_message_text text: "deleted"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def build
|
|
136
|
+
instance_exec(&@state_block)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def build_keyboard
|
|
140
|
+
@keyboard.build(@session)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def invoke_keyboard
|
|
144
|
+
@api.send_message(chat_id: @chat_id,
|
|
145
|
+
text: @keyboard.response,
|
|
146
|
+
reply_markup: @keyboard.markup_tg)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def invoke_before
|
|
150
|
+
instance_eval(&@before_block)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def has_after?
|
|
154
|
+
@after_block.nil? ? false : true
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def has_before?
|
|
158
|
+
@before_block.nil? ? false : true
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def invoke_after
|
|
162
|
+
instance_eval(&@after_block)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def has_keyboard?
|
|
166
|
+
@keyboard.nil? ? false : true
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
public
|
|
170
|
+
|
|
171
|
+
# adds inline keyboard
|
|
172
|
+
def keyboard_inline(inline_keyboard_name, &inline_keyboard_block)
|
|
173
|
+
@inline_keyboards_blocks[inline_keyboard_name] = RBender::KeyboardInline.new(inline_keyboard_name,
|
|
174
|
+
@session,
|
|
175
|
+
inline_keyboard_block)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
#before hook
|
|
179
|
+
def before(&action)
|
|
180
|
+
if @before_block.nil?
|
|
181
|
+
@before_block = action
|
|
182
|
+
else
|
|
183
|
+
raise 'Too many before hooks!'
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
#after hook
|
|
188
|
+
def after(&action)
|
|
189
|
+
if @after_block.nil?
|
|
190
|
+
@after_block = action
|
|
191
|
+
else
|
|
192
|
+
raise 'Too many after hooks!'
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Text callbacks
|
|
197
|
+
def text(&action)
|
|
198
|
+
if @text_block.nil?
|
|
199
|
+
@text_block = action
|
|
200
|
+
else
|
|
201
|
+
raise 'Too many text processors!'
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def keyboard(&keyboard_block)
|
|
206
|
+
if @is_global
|
|
207
|
+
raise 'Global state doesn\'t support :keyboard method'
|
|
208
|
+
end
|
|
209
|
+
@keyboard = RBender::Keyboard.new
|
|
210
|
+
@keyboard.session = @session
|
|
211
|
+
@keyboard.instance_eval(&keyboard_block)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
#initialize helper methods
|
|
215
|
+
def helpers(&helpers_block)
|
|
216
|
+
@helpers_block = helpers_block
|
|
217
|
+
instance_eval(&helpers_block)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def photo(&block)
|
|
221
|
+
if @photo_action.nil?
|
|
222
|
+
@photo_block = block
|
|
223
|
+
else
|
|
224
|
+
raise 'Image block already defined'
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
alias image photo
|
|
229
|
+
alias picture photo
|
|
230
|
+
|
|
231
|
+
def contact(&block)
|
|
232
|
+
if @contact_block.nil?
|
|
233
|
+
@contact_block = block
|
|
234
|
+
else
|
|
235
|
+
raise 'Contact block already defined'
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def command(command, &action)
|
|
240
|
+
if @commands_blocks.include? command
|
|
241
|
+
raise "Command #{command} already exists"
|
|
242
|
+
else
|
|
243
|
+
if command[0] == '/'
|
|
244
|
+
@commands_blocks[command] = action
|
|
245
|
+
else
|
|
246
|
+
raise "Command should be started from slash symbol (/)"
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def method_missing(m, *args, &block)
|
|
253
|
+
if RBender::Methods.method_defined? m
|
|
254
|
+
if block_given?
|
|
255
|
+
if args.empty?
|
|
256
|
+
return @methods.send(m, &block)
|
|
257
|
+
else
|
|
258
|
+
args = args[0] if args.count == 1
|
|
259
|
+
return @methods.send(m, args, &block)
|
|
260
|
+
end
|
|
261
|
+
else
|
|
262
|
+
if args.empty?
|
|
263
|
+
return @methods.send(m)
|
|
264
|
+
else
|
|
265
|
+
args = args[0] if args.count == 1
|
|
266
|
+
return @methods.send(m, args)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
else
|
|
270
|
+
raise NoMethodError, "Method #{m} is missing"
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Returns Inline keyboard object by name
|
|
275
|
+
def inline_markup(name)
|
|
276
|
+
raise "Keyboard #{name} doesn't exists!" unless @inline_keyboards_blocks.member? name
|
|
277
|
+
keyboard = @inline_keyboards_blocks[name]
|
|
278
|
+
keyboard.instance_eval(&@helpers_block) unless @helpers_block.nil?
|
|
279
|
+
keyboard.build
|
|
280
|
+
keyboard.markup_tg
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def pre_checkout(&block)
|
|
284
|
+
if @pre_checkout_block.nil?
|
|
285
|
+
@pre_checkout_block = block
|
|
286
|
+
else
|
|
287
|
+
raise 'Too many pre_checkout actions'
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
alias pre_checkout_query pre_checkout
|
|
292
|
+
|
|
293
|
+
def checkout(&block)
|
|
294
|
+
if @checkout_block.nil?
|
|
295
|
+
@checkout_block = block
|
|
296
|
+
else
|
|
297
|
+
raise 'Too many pre_checkout actions'
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
alias successful_payment checkout
|
|
302
|
+
alias payment checkout
|
|
303
|
+
|
|
304
|
+
def shipping(&block)
|
|
305
|
+
@shipping_block = block
|
|
306
|
+
end
|
|
243
307
|
end
|
|
244
308
|
|