kogno 1.0.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 +7 -0
- data/bin/kogno +92 -0
- data/lib/boot.rb +9 -0
- data/lib/core/bin_helpers/messenger_ctl.rb +48 -0
- data/lib/core/bin_helpers/scaffolding.rb +203 -0
- data/lib/core/bin_helpers/scheduled_messages_ctl.rb +95 -0
- data/lib/core/bin_helpers/sequences_ctl.rb +95 -0
- data/lib/core/bin_helpers/server_ctl.rb +127 -0
- data/lib/core/bin_helpers/telegram_ctl.rb +48 -0
- data/lib/core/bin_helpers/webhook_ctl.rb +96 -0
- data/lib/core/db.rb +8 -0
- data/lib/core/extensions/array.rb +28 -0
- data/lib/core/extensions/hash.rb +12 -0
- data/lib/core/extensions/logger.rb +70 -0
- data/lib/core/extensions/string.rb +6 -0
- data/lib/core/extensions/wit.rb +60 -0
- data/lib/core/global_methods.rb +67 -0
- data/lib/core/helpers/string.rb +105 -0
- data/lib/core/lib/base_config.rb +17 -0
- data/lib/core/lib/block_params.rb +4 -0
- data/lib/core/lib/context.rb +1573 -0
- data/lib/core/lib/error_handler.rb +36 -0
- data/lib/core/lib/message.rb +182 -0
- data/lib/core/lib/messenger/api.rb +281 -0
- data/lib/core/lib/messenger/facebook_graph.rb +32 -0
- data/lib/core/lib/messenger/message.rb +202 -0
- data/lib/core/lib/messenger/notification.rb +351 -0
- data/lib/core/lib/messenger/post_comment.rb +104 -0
- data/lib/core/lib/messenger/recurring_notification.rb +81 -0
- data/lib/core/lib/nlp.rb +191 -0
- data/lib/core/lib/notification.rb +371 -0
- data/lib/core/lib/spelling.rb +13 -0
- data/lib/core/lib/telegram/api.rb +197 -0
- data/lib/core/lib/telegram/chat_activity.rb +111 -0
- data/lib/core/lib/telegram/inline_query.rb +112 -0
- data/lib/core/lib/telegram/message.rb +327 -0
- data/lib/core/lib/telegram/notification.rb +507 -0
- data/lib/core/lib/whatsapp/api.rb +153 -0
- data/lib/core/lib/whatsapp/message.rb +132 -0
- data/lib/core/lib/whatsapp/notification.rb +206 -0
- data/lib/core/lib/whatsapp/status_message.rb +58 -0
- data/lib/core/loaders/config_files.rb +15 -0
- data/lib/core/models/chat_log.rb +4 -0
- data/lib/core/models/long_payload.rb +25 -0
- data/lib/core/models/matched_message.rb +5 -0
- data/lib/core/models/messenger_recurring_notification.rb +16 -0
- data/lib/core/models/scheduled_message.rb +40 -0
- data/lib/core/models/sequence.rb +29 -0
- data/lib/core/models/telegram_chat_group.rb +26 -0
- data/lib/core/models/user.rb +285 -0
- data/lib/core/web/webhook.rb +198 -0
- data/lib/kogno.rb +130 -0
- data/scaffolding/new_project/Gemfile +3 -0
- data/scaffolding/new_project/application.rb +5 -0
- data/scaffolding/new_project/bot/contexts/main_context.rb +10 -0
- data/scaffolding/new_project/bot/conversation.rb +14 -0
- data/scaffolding/new_project/bot/models/user.rb +3 -0
- data/scaffolding/new_project/config/application.rb +28 -0
- data/scaffolding/new_project/config/database.yml +8 -0
- data/scaffolding/new_project/config/locales/en.yml +4 -0
- data/scaffolding/new_project/config/locales/es.yml +3 -0
- data/scaffolding/new_project/config/nlp.rb +23 -0
- data/scaffolding/new_project/config/platforms/messenger.rb +74 -0
- data/scaffolding/new_project/config/platforms/telegram.rb +45 -0
- data/scaffolding/new_project/config/platforms/whatsapp.rb +13 -0
- data/scaffolding/new_project/web/routes.rb +10 -0
- metadata +220 -0
@@ -0,0 +1,1573 @@
|
|
1
|
+
class Kogno::Context
|
2
|
+
|
3
|
+
@@callbacks = {} # class callbacks: after_initialize,before_blocks, before_exit, after_blocks
|
4
|
+
@@expiration_time = {}
|
5
|
+
|
6
|
+
def initialize(user,msg,notification,temp_context=nil,notification_group=nil,chat=nil)
|
7
|
+
|
8
|
+
@user = user
|
9
|
+
@chat = chat || @user
|
10
|
+
@message = msg
|
11
|
+
@reply = notification
|
12
|
+
@reply_group = notification_group
|
13
|
+
|
14
|
+
# return true if call_expiration_time()
|
15
|
+
|
16
|
+
@sub_contexts = []
|
17
|
+
@sub_context_route = ""
|
18
|
+
# @sub_contexts = {}
|
19
|
+
@sub_contexts_tree = []
|
20
|
+
|
21
|
+
@blocks = {
|
22
|
+
deep_link: {},
|
23
|
+
anything: {},
|
24
|
+
before: {},
|
25
|
+
intents: {},
|
26
|
+
commands: {},
|
27
|
+
expressions: {},
|
28
|
+
postbacks: {},
|
29
|
+
stickers: {},
|
30
|
+
attachments: {},
|
31
|
+
keywords: {},
|
32
|
+
regular_expressions: {},
|
33
|
+
any_number: {},
|
34
|
+
any_text: {},
|
35
|
+
location: {},
|
36
|
+
nlp_entities: {},
|
37
|
+
nlp_datetime_range: {},
|
38
|
+
nlp_location: {},
|
39
|
+
nlp_search_query: {},
|
40
|
+
nlp_datetime: {},
|
41
|
+
nlp_duration: {},
|
42
|
+
any_postback: {},
|
43
|
+
any_intent: {},
|
44
|
+
everything_else: {},
|
45
|
+
after: {},
|
46
|
+
membership_new: {},
|
47
|
+
membership_drop: {},
|
48
|
+
recurring_notification: {}
|
49
|
+
}
|
50
|
+
|
51
|
+
@sequences={}
|
52
|
+
@current_sequence_stage = nil
|
53
|
+
|
54
|
+
@impact = :self
|
55
|
+
@deep_blocks = Marshal.load(Marshal.dump(@blocks))
|
56
|
+
|
57
|
+
@callbacks = {
|
58
|
+
before_delegate:{},
|
59
|
+
on_delegate:{},
|
60
|
+
on_exit:{},
|
61
|
+
on_enter:{}
|
62
|
+
}
|
63
|
+
|
64
|
+
|
65
|
+
@halt = false
|
66
|
+
@continue = false
|
67
|
+
|
68
|
+
# self.class.after_initialize()
|
69
|
+
|
70
|
+
@reply.set_context(self)
|
71
|
+
@reply_group.set_context(self) unless @reply_group.nil?
|
72
|
+
@context = self
|
73
|
+
|
74
|
+
@current = temp_context.nil? ? @user.context : temp_context
|
75
|
+
# @current = Kogno::Application.config.routes.default if @current.nil? || @current.empty?
|
76
|
+
|
77
|
+
@memorized_message = nil
|
78
|
+
|
79
|
+
@current_action = {
|
80
|
+
action: nil,
|
81
|
+
value: nil
|
82
|
+
}
|
83
|
+
|
84
|
+
@called_block = {
|
85
|
+
action: nil,
|
86
|
+
value: nil,
|
87
|
+
params: nil,
|
88
|
+
context: nil,
|
89
|
+
deep: false
|
90
|
+
}
|
91
|
+
|
92
|
+
call_class_callback(:after_initialize)
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.expiration_in(expiration_time)
|
97
|
+
@@expiration_time[self] = expiration_time
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.after_initialize(method)
|
101
|
+
self.set_class_callback(:after_initialize, method)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.before_blocks(method)
|
105
|
+
self.set_class_callback(:before_blocks, method)
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.before_exit(method)
|
109
|
+
self.set_class_callback(:before_exit, method)
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.after_blocks(method)
|
113
|
+
self.set_class_callback(:after_blocks, method)
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.set_class_callback(action,method)
|
117
|
+
@@callbacks[self] = {} if @@callbacks[self].nil?
|
118
|
+
@@callbacks[self][action] = [] if @@callbacks[self][action].nil?
|
119
|
+
@@callbacks[self][action].push(method)
|
120
|
+
end
|
121
|
+
|
122
|
+
def set_block(action, input, impact, block)
|
123
|
+
|
124
|
+
if input.nil?
|
125
|
+
@blocks[action][@sub_context_route] = block
|
126
|
+
if impact == :deep
|
127
|
+
# logger.write "---- ADD DEEP IMPACT TO #{action}", :red
|
128
|
+
@deep_blocks[action] = block
|
129
|
+
end
|
130
|
+
else
|
131
|
+
@blocks[action][@sub_context_route] = {} if @blocks[action][@sub_context_route].nil?
|
132
|
+
@blocks[action][@sub_context_route][input] = block
|
133
|
+
if impact == :deep
|
134
|
+
@deep_blocks[action][input] = block
|
135
|
+
# logger.write "---- ADD DEEP IMPACT TO #{action}(#{imput})", :red
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# if impact == :deep
|
140
|
+
# @deep_blocks[action][input] = block
|
141
|
+
# end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
def deep
|
146
|
+
@impact = :deep
|
147
|
+
self
|
148
|
+
end
|
149
|
+
|
150
|
+
def before(section, &block)
|
151
|
+
|
152
|
+
set_block(:before, section, @impact, block)
|
153
|
+
@impact = :self
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
def after(section, &block)
|
158
|
+
|
159
|
+
set_block(:after, section, @impact, block)
|
160
|
+
@impact = :self
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
def before_anything(&block)
|
165
|
+
|
166
|
+
before :blocks do
|
167
|
+
block.call
|
168
|
+
end
|
169
|
+
@impact = :self
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
def after_all(&block)
|
174
|
+
|
175
|
+
after :blocks do
|
176
|
+
block.call
|
177
|
+
end
|
178
|
+
@impact = :self
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
def membership(type, &block)
|
183
|
+
if type == :new
|
184
|
+
set_block(:membership_new, nil, :self, block)
|
185
|
+
elsif type == :drop
|
186
|
+
set_block(:membership_drop, nil, :self, block)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def recurring_notification(type, &block)
|
191
|
+
set_block(:recurring_notification, type, :self, block)
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
def deep_link(&block)
|
196
|
+
set_block(:deep_link, nil, @impact, block)
|
197
|
+
@impact = :self
|
198
|
+
end
|
199
|
+
|
200
|
+
def intent(input, &block)
|
201
|
+
if input.class == Array
|
202
|
+
input.each do |i|
|
203
|
+
set_block(:intents, i.to_s.downcase, @impact, block)
|
204
|
+
end
|
205
|
+
else
|
206
|
+
set_block(:intents, input.to_s.downcase, @impact, block)
|
207
|
+
end
|
208
|
+
@impact = :self
|
209
|
+
end
|
210
|
+
|
211
|
+
def command(input, &block) # Telegram only
|
212
|
+
set_block(:commands, input.to_s.downcase, @impact, block)
|
213
|
+
@impact = :self
|
214
|
+
end
|
215
|
+
|
216
|
+
def expression(input, &block)
|
217
|
+
set_block(:expressions, input, @impact, block)
|
218
|
+
@impact = :self
|
219
|
+
end
|
220
|
+
|
221
|
+
def inline_query(&block)
|
222
|
+
sub_context :inline_query do
|
223
|
+
block.call
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def postback(input, &block)
|
228
|
+
if input.class == Array
|
229
|
+
input.each do |i|
|
230
|
+
set_block(:postbacks, i.to_s.downcase, @impact, block)
|
231
|
+
end
|
232
|
+
else
|
233
|
+
set_block(:postbacks, input.to_s.downcase, @impact, block)
|
234
|
+
end
|
235
|
+
@impact = :self
|
236
|
+
end
|
237
|
+
|
238
|
+
def sticker(input, &block)
|
239
|
+
set_block(:stickers, sticker_id, @impact, block)
|
240
|
+
@impact = :self
|
241
|
+
end
|
242
|
+
|
243
|
+
def any_attachment(&block)
|
244
|
+
set_block(:attachments, nil, @impact, block)
|
245
|
+
@impact = :self
|
246
|
+
end
|
247
|
+
|
248
|
+
def keyword(input, &block)
|
249
|
+
if input.class == Array
|
250
|
+
input.each do |i|
|
251
|
+
set_block(:keywords, i.to_s.downcase, @impact, block)
|
252
|
+
end
|
253
|
+
else
|
254
|
+
set_block(:keywords, input.to_s.downcase, @impact, block)
|
255
|
+
end
|
256
|
+
@impact = :self
|
257
|
+
end
|
258
|
+
|
259
|
+
def regular_expression(input, &block)
|
260
|
+
set_block(:regular_expressions, input, @impact, block)
|
261
|
+
@impact = :self
|
262
|
+
end
|
263
|
+
|
264
|
+
def location(&block)
|
265
|
+
set_block(:location, nil, @impact, block)
|
266
|
+
@impact = :self
|
267
|
+
end
|
268
|
+
|
269
|
+
def nlp_entity(input, &block)
|
270
|
+
set_block(:nlp_entities, input.to_s.downcase.to_sym, @impact, block)
|
271
|
+
@impact = :self
|
272
|
+
end
|
273
|
+
|
274
|
+
def entity(input, &block)
|
275
|
+
nlp_entity(input, &block)
|
276
|
+
@impact = :self
|
277
|
+
end
|
278
|
+
|
279
|
+
def datetime(&block)
|
280
|
+
entity "wit$datetime:datetime" do |values|
|
281
|
+
block.call values.map{|v| v[:value] || v[:from][:value] rescue nil}
|
282
|
+
end
|
283
|
+
@impact = :self
|
284
|
+
end
|
285
|
+
|
286
|
+
|
287
|
+
def duration(&block)
|
288
|
+
entity "wit$duration:duration" do |values|
|
289
|
+
block.call values
|
290
|
+
end
|
291
|
+
@impact = :self
|
292
|
+
end
|
293
|
+
|
294
|
+
def nlp_location(&block)
|
295
|
+
nlp_entity("wit$location:location", &block)
|
296
|
+
@impact = :self
|
297
|
+
end
|
298
|
+
|
299
|
+
def datetime_range(&block)
|
300
|
+
set_block(:nlp_datetime_range, nil, @impact, block)
|
301
|
+
end
|
302
|
+
|
303
|
+
def anything(&block)
|
304
|
+
set_block(:anything, nil, @impact, block)
|
305
|
+
@impact = :self
|
306
|
+
end
|
307
|
+
|
308
|
+
def any_number(&block)
|
309
|
+
set_block(:any_number, nil, @impact, block)
|
310
|
+
@impact = :self
|
311
|
+
end
|
312
|
+
|
313
|
+
def any_text(&block)
|
314
|
+
set_block(:any_text, nil, @impact, block)
|
315
|
+
@impact = :self
|
316
|
+
end
|
317
|
+
|
318
|
+
def any_postback(&block)
|
319
|
+
set_block(:any_postback, nil, @impact, block)
|
320
|
+
@impact = :self
|
321
|
+
end
|
322
|
+
|
323
|
+
def any_intent(&block)
|
324
|
+
set_block(:any_intent, nil, @impact, block)
|
325
|
+
@impact = :self
|
326
|
+
end
|
327
|
+
|
328
|
+
def everything_else(&block)
|
329
|
+
set_block(:everything_else, nil, @impact, block)
|
330
|
+
@impact = :self
|
331
|
+
end
|
332
|
+
|
333
|
+
def callback(callback_name,&block)
|
334
|
+
@callbacks[callback_name.to_sym][@sub_context_route] = block
|
335
|
+
end
|
336
|
+
|
337
|
+
# CallBacks shortcuts
|
338
|
+
|
339
|
+
def before_delegate(&block)
|
340
|
+
callback :before_delegate do
|
341
|
+
block.call
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def on_delegate(&block)
|
346
|
+
callback :on_delegate do
|
347
|
+
block.call
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def on_exit(&block)
|
352
|
+
callback :on_exit do
|
353
|
+
block.call
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
def on_enter(&block)
|
358
|
+
callback :on_enter do
|
359
|
+
block.call
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
#---
|
364
|
+
|
365
|
+
# def opt_out(route=nil,type=:change,impact=:self,&block)
|
366
|
+
|
367
|
+
# if route.nil?
|
368
|
+
# opt_out_block = block # you define what to do in opt_out
|
369
|
+
# elsif type==:delegate
|
370
|
+
|
371
|
+
# if route == :main # Goes to main context
|
372
|
+
# opt_out_block = proc {delegate_to("main")}
|
373
|
+
# elsif route == :parent #Goes to parent context, if isn't. Goes go main
|
374
|
+
# opt_out_block = proc {delegate_to(self.parent_context_route)}
|
375
|
+
# elsif route == :root #Goes to root contexts, not main.
|
376
|
+
# opt_out_block = proc {delegate_to(self.root_context_route)}
|
377
|
+
# else
|
378
|
+
# opt_out_block = proc {delegate_to(route)}
|
379
|
+
# end
|
380
|
+
|
381
|
+
# else # :change
|
382
|
+
|
383
|
+
# if route == :main or route == :exit # Goes to main context
|
384
|
+
# opt_out_block = proc {change_to("main", true)}
|
385
|
+
# elsif route == :parent #Goes to parent context, if isn't. Goes go main
|
386
|
+
# opt_out_block = proc {change_to(self.parent_context_route, true)}
|
387
|
+
# elsif route == :root #Goes to root contexts, not main.
|
388
|
+
# opt_out_block = proc {change_to(self.root_context_route, true)}
|
389
|
+
# else
|
390
|
+
# opt_out_block = proc {change_to(route, true)}
|
391
|
+
# end
|
392
|
+
|
393
|
+
# end
|
394
|
+
|
395
|
+
# expression "CANCEL", impact do
|
396
|
+
# opt_out_block.call
|
397
|
+
# end
|
398
|
+
|
399
|
+
# postback "LEAVE_CONTEXT", impact do
|
400
|
+
# opt_out_block.call
|
401
|
+
# end
|
402
|
+
|
403
|
+
# end
|
404
|
+
|
405
|
+
def sub_context(route, &block)
|
406
|
+
@sub_contexts_tree.push(route)
|
407
|
+
@sub_context_route = @sub_contexts_tree.join(".")
|
408
|
+
@sub_contexts.push(@sub_context_route)
|
409
|
+
if in_route? # The sub_context to execute will be only the ones that are in the route of the current context.
|
410
|
+
# @halt = {@sub_context_route => false}
|
411
|
+
block.call @user.get_context_params
|
412
|
+
end
|
413
|
+
@sub_contexts_tree.pop
|
414
|
+
@sub_context_route = @sub_contexts_tree.join(".")
|
415
|
+
end
|
416
|
+
|
417
|
+
def answer(route, &block)
|
418
|
+
sub_context route do |params|
|
419
|
+
block.call params
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
def halt(silent=false)
|
424
|
+
logger.write("********** HALT **********", :red) unless silent
|
425
|
+
@halt = true
|
426
|
+
end
|
427
|
+
|
428
|
+
def halted?
|
429
|
+
@halt
|
430
|
+
end
|
431
|
+
|
432
|
+
def continue
|
433
|
+
@continue = true
|
434
|
+
end
|
435
|
+
|
436
|
+
def continue?
|
437
|
+
if @continue
|
438
|
+
logger.write "********** CONTINUE **********", :red
|
439
|
+
@continue = false
|
440
|
+
return true
|
441
|
+
else
|
442
|
+
return false
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def in_route?
|
447
|
+
current_sub_context = current_sub_context()
|
448
|
+
if current_sub_context.include?("#{@sub_context_route}.") or @sub_context_route == current_sub_context
|
449
|
+
true
|
450
|
+
else
|
451
|
+
false
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
# CALLS
|
456
|
+
|
457
|
+
def call_block(action, params=nil, input=:empty)
|
458
|
+
@current_action = {
|
459
|
+
name: action,
|
460
|
+
value: input == :empty ? nil : input
|
461
|
+
}
|
462
|
+
if input.nil?
|
463
|
+
return false
|
464
|
+
elsif input == :empty
|
465
|
+
block = @blocks[action][current_sub_context()] rescue nil
|
466
|
+
else
|
467
|
+
block = @blocks[action][current_sub_context()][input] rescue nil
|
468
|
+
end
|
469
|
+
if block.class == Proc
|
470
|
+
logger_call(action, input, params, true)
|
471
|
+
if params.class == Kogno::BlockParams
|
472
|
+
block.call params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7]
|
473
|
+
else
|
474
|
+
block.call params
|
475
|
+
end
|
476
|
+
unless continue?
|
477
|
+
@called_block = {
|
478
|
+
name: action,
|
479
|
+
value: input == :empty ? nil : input,
|
480
|
+
params: params,
|
481
|
+
context: @current,
|
482
|
+
deep: false
|
483
|
+
}
|
484
|
+
return true
|
485
|
+
else
|
486
|
+
logger_call(action, input, [], false)
|
487
|
+
return false
|
488
|
+
end
|
489
|
+
else
|
490
|
+
if input == :empty
|
491
|
+
deep_action_block = @deep_blocks[action] rescue nil
|
492
|
+
else
|
493
|
+
deep_action_block = @deep_blocks[action][input] rescue nil
|
494
|
+
end
|
495
|
+
|
496
|
+
if deep_action_block.class == Proc
|
497
|
+
logger_call(action, input, params, true, true)
|
498
|
+
if params.class == Kogno::BlockParams
|
499
|
+
deep_action_block.call params[0], params[1], params[3], params[4], params[5], params[6], params[7]
|
500
|
+
else
|
501
|
+
deep_action_block.call params
|
502
|
+
end
|
503
|
+
unless continue?
|
504
|
+
@called_block = {
|
505
|
+
name: action,
|
506
|
+
value: input == :empty ? nil : input,
|
507
|
+
params: params,
|
508
|
+
context: @current,
|
509
|
+
deep: true
|
510
|
+
}
|
511
|
+
return true
|
512
|
+
else
|
513
|
+
logger_call(action, input, [], false)
|
514
|
+
return false
|
515
|
+
end
|
516
|
+
else
|
517
|
+
logger_call(action, input, [], false)
|
518
|
+
return false
|
519
|
+
end
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
def call_before(section=:blocks, values=nil)
|
524
|
+
return true if halted?
|
525
|
+
call_block(:before, values, section)
|
526
|
+
end
|
527
|
+
|
528
|
+
def call_after(section=:blocks, values=nil)
|
529
|
+
return true if halted?
|
530
|
+
call_block(:after, values, section)
|
531
|
+
end
|
532
|
+
|
533
|
+
|
534
|
+
def call_membership_new
|
535
|
+
if @message.type == :chat_activity and @message.chat_membership_status
|
536
|
+
return call_block(:membership_new, @message.chat)
|
537
|
+
end
|
538
|
+
return false
|
539
|
+
end
|
540
|
+
|
541
|
+
def call_membership_drop
|
542
|
+
if @message.type == :chat_activity and !@message.chat_membership_status
|
543
|
+
return call_block(:membership_drop, @message.chat)
|
544
|
+
end
|
545
|
+
return false
|
546
|
+
end
|
547
|
+
|
548
|
+
def call_deep_link
|
549
|
+
if !@message.referral(:ref).nil?
|
550
|
+
return true if halted?
|
551
|
+
param = @message.deep_link_param || @message.referral(:ref)
|
552
|
+
call_block(:deep_link, param)
|
553
|
+
elsif !@message.deep_link_data.nil?
|
554
|
+
param = @message.deep_link_param || @message.deep_link_data
|
555
|
+
call_block(:deep_link, param)
|
556
|
+
else
|
557
|
+
return false
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
def call_recurring_notifications
|
562
|
+
return false if @message.type != :recurring_notification
|
563
|
+
if @message.notification_messages_status == :active
|
564
|
+
return call_block(:recurring_notification, @user.messenger_recurring_notification.data, :granted)
|
565
|
+
elsif @message.notification_messages_status == :stopped
|
566
|
+
return call_block(:recurring_notification, @user.messenger_recurring_notification.data, :removed)
|
567
|
+
else
|
568
|
+
return false
|
569
|
+
end
|
570
|
+
|
571
|
+
end
|
572
|
+
|
573
|
+
def call_anything
|
574
|
+
call_block(:anything)
|
575
|
+
end
|
576
|
+
|
577
|
+
def call_intents
|
578
|
+
intent_data = @message.nlp.intent(false)
|
579
|
+
intent = intent_data[:name] rescue nil
|
580
|
+
confidence = intent_data[:confidence] rescue nil
|
581
|
+
unless intent.nil?
|
582
|
+
context_in_intent = self.class.get(intent)
|
583
|
+
new_context = nil
|
584
|
+
unless context_in_intent.nil?
|
585
|
+
new_context = context_in_intent[:context]
|
586
|
+
intent = context_in_intent[:param]
|
587
|
+
end
|
588
|
+
if !new_context.nil? && self.name != new_context
|
589
|
+
# new_context = "#{new_context}.inline_query" if @message.type == :inline_query
|
590
|
+
logger_call(:intents, intent, [], true)
|
591
|
+
if self.delegate_to("/#{new_context}")
|
592
|
+
halt
|
593
|
+
return true
|
594
|
+
else
|
595
|
+
return false
|
596
|
+
end
|
597
|
+
else
|
598
|
+
return true if halted?
|
599
|
+
block_response = call_block(:intents, Kogno::BlockParams.new([@message.text, @message.nlp.entities, @message.nlp.traits, confidence]), intent)
|
600
|
+
block_response = call_any_intent(Kogno::BlockParams.new([intent, @message.text, @message.nlp.entities, @message.nlp.traits, confidence])) unless block_response
|
601
|
+
return block_response
|
602
|
+
end
|
603
|
+
else
|
604
|
+
return false
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
def call_commands
|
609
|
+
return false unless @message.platform == :telegram
|
610
|
+
command = @message.command
|
611
|
+
unless command.nil?
|
612
|
+
@message.nlp.process_phrase(@message.command_text)
|
613
|
+
block_response = call_block(:commands, Kogno::BlockParams.new([@message.command_text, @message.nlp.entities, @message.nlp.traits]), command)
|
614
|
+
if block_response
|
615
|
+
return block_response
|
616
|
+
else
|
617
|
+
default_context = get_default_context_for_command(command)
|
618
|
+
unless self.name == default_context.to_s
|
619
|
+
logger_call(:commands, command, [], true)
|
620
|
+
if self.delegate_to(default_context)
|
621
|
+
halt
|
622
|
+
return true
|
623
|
+
else
|
624
|
+
return false
|
625
|
+
end
|
626
|
+
else
|
627
|
+
false
|
628
|
+
end
|
629
|
+
end
|
630
|
+
else
|
631
|
+
return false
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
# def call_expressions
|
636
|
+
# expression = @message.nlp.expression
|
637
|
+
|
638
|
+
# unless expression.nil?
|
639
|
+
# call_before(:expressions)
|
640
|
+
# return true if halted?
|
641
|
+
|
642
|
+
# block_response = call_block(:expressions, nil, expression)
|
643
|
+
# call_after(:expressions)
|
644
|
+
# return block_response
|
645
|
+
# else
|
646
|
+
# return false
|
647
|
+
# end
|
648
|
+
# end
|
649
|
+
|
650
|
+
|
651
|
+
def self.get_from_typed_postback(msg,user)
|
652
|
+
typed_postbacks = user.vars[:typed_postbacks]
|
653
|
+
keyword = msg.text.to_payload
|
654
|
+
postback = (typed_postbacks[keyword] rescue nil)
|
655
|
+
return(self.get_from_payload(postback))
|
656
|
+
end
|
657
|
+
|
658
|
+
def call_typed_postbacks
|
659
|
+
# expression = @message.nlp.expression
|
660
|
+
typed_postbacks = @user.vars[:typed_postbacks]
|
661
|
+
@user.vars.delete(:typed_postbacks)
|
662
|
+
|
663
|
+
if !@message.text.nil?
|
664
|
+
keyword = @message.text.to_payload
|
665
|
+
logger_call("typed_postbacks", keyword, [], false)
|
666
|
+
postback = (typed_postbacks[keyword] rescue nil)
|
667
|
+
unless postback.nil?
|
668
|
+
logger.write "KEYWORD FOUND:#{postback.to_yaml}", :green
|
669
|
+
@message.overwrite_postback(postback)
|
670
|
+
return call_postbacks()
|
671
|
+
end
|
672
|
+
|
673
|
+
end
|
674
|
+
return false
|
675
|
+
end
|
676
|
+
|
677
|
+
def call_postbacks(triggers=true)
|
678
|
+
postback = @message.payload(true)
|
679
|
+
unless postback.nil?
|
680
|
+
postback = postback.downcase
|
681
|
+
block_params = Kogno::BlockParams.new([postback, @message.params])
|
682
|
+
# call_before(:postbacks, block_params) if triggers
|
683
|
+
return true if halted?
|
684
|
+
block_response = call_block(:postbacks, @message.params, postback)
|
685
|
+
block_response = call_any_postback(block_params) unless block_response
|
686
|
+
# call_after(:postbacks, block_params) if triggers
|
687
|
+
return block_response
|
688
|
+
else
|
689
|
+
return false
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
# def call_stickers
|
694
|
+
# block_response = false
|
695
|
+
# unless @message.stickers.empty?
|
696
|
+
# call_before(:stickers)
|
697
|
+
# return true if halted?
|
698
|
+
# @message.stickers.each do |sticker|
|
699
|
+
# block_response = call_block(:stickers, nil, sticker)
|
700
|
+
# end
|
701
|
+
# block_response = call_block(:stickers, nil, "*") unless block_response
|
702
|
+
# call_after(:stickers)
|
703
|
+
# return block_response
|
704
|
+
# else
|
705
|
+
# return false
|
706
|
+
# end
|
707
|
+
# end
|
708
|
+
|
709
|
+
def call_keywords
|
710
|
+
keyword = @message.text.downcase.strip
|
711
|
+
unless keyword.empty?
|
712
|
+
|
713
|
+
# call_before(:keywords)
|
714
|
+
return true if halted?
|
715
|
+
|
716
|
+
block_response = call_block(:keywords, nil ,keyword)
|
717
|
+
# call_after(:keywords)
|
718
|
+
return block_response
|
719
|
+
else
|
720
|
+
return false
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
def call_regular_expressions
|
725
|
+
text = @message.text.upcase
|
726
|
+
regular_expressions = @blocks[:regular_expressions][current_sub_context()]
|
727
|
+
unless regular_expressions.nil?
|
728
|
+
regular_expressions.each do |regular_expression,block|
|
729
|
+
@current_action = {
|
730
|
+
name: :regular_expressions,
|
731
|
+
value: regular_expression,
|
732
|
+
deep: false
|
733
|
+
}
|
734
|
+
matches = text.scan(regular_expression)
|
735
|
+
if matches.count > 0
|
736
|
+
logger_call("regular_expression", regular_expression, matches, true)
|
737
|
+
block.call matches
|
738
|
+
@called_block = {
|
739
|
+
name: :regular_expressions,
|
740
|
+
value: regular_expression,
|
741
|
+
params: nil,
|
742
|
+
context: @current,
|
743
|
+
deep: false
|
744
|
+
}
|
745
|
+
return true unless continue?
|
746
|
+
end
|
747
|
+
end
|
748
|
+
end
|
749
|
+
deep_regular_expressions = @deep_blocks[:regular_expressions][current_sub_context()]
|
750
|
+
unless deep_regular_expressions.nil?
|
751
|
+
deep_regular_expressions.each do |regular_expression,block|
|
752
|
+
@current_action = {
|
753
|
+
name: :regular_expressions,
|
754
|
+
value: regular_expression,
|
755
|
+
deep: true
|
756
|
+
}
|
757
|
+
matches = text.scan(regular_expression)
|
758
|
+
if matches.count > 0
|
759
|
+
logger_call("regular_expression", regular_expression, matches, true, true)
|
760
|
+
block.call matches
|
761
|
+
@called_block = {
|
762
|
+
name: :regular_expressions,
|
763
|
+
value: regular_expression,
|
764
|
+
param: nil,
|
765
|
+
context: @current,
|
766
|
+
deep: true
|
767
|
+
}
|
768
|
+
return true unless continue?
|
769
|
+
end
|
770
|
+
end
|
771
|
+
end
|
772
|
+
logger_call("regular_expression", nil, [], false)
|
773
|
+
return false
|
774
|
+
end
|
775
|
+
|
776
|
+
def call_location
|
777
|
+
unless @message.location.nil?
|
778
|
+
# call_before(:location)
|
779
|
+
# return true if halted?
|
780
|
+
|
781
|
+
block_response = call_block(:location, @message.location)
|
782
|
+
# call_after(:location)
|
783
|
+
return block_response
|
784
|
+
else
|
785
|
+
return false
|
786
|
+
end
|
787
|
+
end
|
788
|
+
|
789
|
+
def call_nlp_entity
|
790
|
+
block_response = false
|
791
|
+
# call_before(:nlp_entity)
|
792
|
+
# return true if halted?
|
793
|
+
|
794
|
+
if @message.nlp.datetime_range?
|
795
|
+
range = @message.nlp.datetime_range
|
796
|
+
block_response = call_block(:nlp_datetime_range, Kogno::BlockParams.new([range[:from], range[:to]]))
|
797
|
+
end
|
798
|
+
|
799
|
+
unless block_response
|
800
|
+
@message.nlp.entities.each do |entity,values|
|
801
|
+
return true if block_response
|
802
|
+
block_response = call_block(:nlp_entities, values, entity)
|
803
|
+
end
|
804
|
+
end
|
805
|
+
# call_after(:nlp_entity) if block_response
|
806
|
+
return block_response
|
807
|
+
end
|
808
|
+
|
809
|
+
def call_any_number
|
810
|
+
if @message.numbers_in_text.count > 0
|
811
|
+
block_response = call_block(:any_number, @message.numbers_in_text)
|
812
|
+
return block_response
|
813
|
+
|
814
|
+
else
|
815
|
+
return false
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
def call_any_text
|
820
|
+
unless @message.text.empty?
|
821
|
+
return call_block(:any_text, @message.text)
|
822
|
+
else
|
823
|
+
return false
|
824
|
+
end
|
825
|
+
end
|
826
|
+
|
827
|
+
def call_any_attachment
|
828
|
+
unless @message.attachments.nil?
|
829
|
+
return call_block(:attachments, @message.attachments)
|
830
|
+
else
|
831
|
+
return false
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
def call_any_postback(block_params)
|
836
|
+
unless @message.payload.nil?
|
837
|
+
return call_block(:any_postback, block_params)
|
838
|
+
else
|
839
|
+
return false
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
def call_any_intent(block_params)
|
844
|
+
unless @message.nlp.intent.nil?
|
845
|
+
return call_block(:any_intent, block_params)
|
846
|
+
else
|
847
|
+
return false
|
848
|
+
end
|
849
|
+
end
|
850
|
+
|
851
|
+
def call_everything_else
|
852
|
+
params = @message.type == :post_comment ? { text: @message.text } : { text: @message.text, payload: @message.payload, entities: @message.nlp.entities, traits: @message.nlp.traits }
|
853
|
+
return call_block(:everything_else, params)
|
854
|
+
end
|
855
|
+
|
856
|
+
def call_callback(callback_name)
|
857
|
+
callback_block = (@callbacks[callback_name.to_sym][current_sub_context()] rescue nil)
|
858
|
+
unless callback_block.nil?
|
859
|
+
logger_call("callback", callback_name, [], true)
|
860
|
+
callback_block.call
|
861
|
+
return true
|
862
|
+
else
|
863
|
+
logger_call("callback", callback_name, [], false)
|
864
|
+
return false
|
865
|
+
end
|
866
|
+
end
|
867
|
+
|
868
|
+
def call_class_callback(callback_name)
|
869
|
+
conversation_methods = (@@callbacks[Conversation][callback_name].uniq rescue [])
|
870
|
+
class_methods = (@@callbacks[self.class][callback_name] rescue [])
|
871
|
+
methods = []
|
872
|
+
methods += conversation_methods unless conversation_methods.nil?
|
873
|
+
methods += class_methods unless class_methods.nil?
|
874
|
+
if methods.length > 0
|
875
|
+
methods.each do |method|
|
876
|
+
if !method.nil? and !halted?
|
877
|
+
logger.write "\t#{method}() method found", :red
|
878
|
+
self.send(method)
|
879
|
+
end
|
880
|
+
end
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
884
|
+
def self.class_callbacks
|
885
|
+
@@callbacks
|
886
|
+
end
|
887
|
+
|
888
|
+
def call_expiration_time
|
889
|
+
unless @@expiration_time[self.class].nil?
|
890
|
+
if @user.last_usage > @@expiration_time[self.class]
|
891
|
+
delegate_to(:main, true)
|
892
|
+
return true
|
893
|
+
end
|
894
|
+
end
|
895
|
+
return false
|
896
|
+
end
|
897
|
+
|
898
|
+
def current_sub_context
|
899
|
+
context_tree = @current.to_s.split(Regexp.union(["/","."]))
|
900
|
+
context_tree.shift
|
901
|
+
return context_tree.join(".")
|
902
|
+
end
|
903
|
+
|
904
|
+
def parent_context_route(context_path=nil)
|
905
|
+
context_tree = context_path.nil? ? @current.to_s.split(Regexp.union(["/","."])) : context_path.split(Regexp.union(["/","."]))
|
906
|
+
context_tree.pop
|
907
|
+
return context_tree.join(".")
|
908
|
+
end
|
909
|
+
|
910
|
+
def root_context_route(context_path=nil)
|
911
|
+
context_tree = context_path.nil? ? @current.to_s.split(Regexp.union(["/","."])) : context_path.split(Regexp.union(["/","."]))
|
912
|
+
return context_tree.first
|
913
|
+
end
|
914
|
+
|
915
|
+
def current_context_route
|
916
|
+
if @current.nil? || @current.empty?
|
917
|
+
self.name
|
918
|
+
else
|
919
|
+
@current
|
920
|
+
end
|
921
|
+
end
|
922
|
+
|
923
|
+
def valid_context_route?
|
924
|
+
if @current.nil? || @current.empty?
|
925
|
+
return true
|
926
|
+
elsif @current == self.name
|
927
|
+
return true
|
928
|
+
elsif @sub_contexts.include?(current_sub_context())
|
929
|
+
return true
|
930
|
+
else
|
931
|
+
return false
|
932
|
+
end
|
933
|
+
end
|
934
|
+
|
935
|
+
def nlp_entities_present?(entities)
|
936
|
+
(entities & @message.nlp.entities.keys).present?
|
937
|
+
end
|
938
|
+
|
939
|
+
|
940
|
+
def run(args={run_blocks_method: true, ignore_everything_else: false})
|
941
|
+
|
942
|
+
@run_type = :full
|
943
|
+
|
944
|
+
logger.write "\n\n#{self.nice_current_route} => Starting matching process\n", :bright
|
945
|
+
|
946
|
+
# before_blocks()
|
947
|
+
|
948
|
+
call_class_callback(:before_blocks)
|
949
|
+
|
950
|
+
unless halted?
|
951
|
+
blocks() if args[:run_blocks_method] #Loading blocks
|
952
|
+
|
953
|
+
unless self.valid_context_route?
|
954
|
+
logger.write "Error: the context in route #{@current} doesn't exist", :red
|
955
|
+
self.exit_context()
|
956
|
+
return false
|
957
|
+
end
|
958
|
+
|
959
|
+
call_before(:blocks)
|
960
|
+
|
961
|
+
if !call_location() and !halted? # Deprecated
|
962
|
+
if !call_postbacks() and !halted?
|
963
|
+
if !call_typed_postbacks() and !halted?
|
964
|
+
if !call_deep_link() and !halted?
|
965
|
+
if !@message.empty?
|
966
|
+
if !call_commands() and !halted? # Telegram only
|
967
|
+
# if !call_stickers() and !halted?
|
968
|
+
if !call_any_attachment() and !halted?
|
969
|
+
if !call_regular_expressions() and !halted?
|
970
|
+
if !call_keywords() and !halted?
|
971
|
+
call_before(:nlp)
|
972
|
+
@message.nlp.process_phrase_once
|
973
|
+
call_after(:nlp, @message.nlp.entities)
|
974
|
+
# if !call_expressions() and !halted?
|
975
|
+
if !call_intents() and !halted?
|
976
|
+
if !call_nlp_entity() and !halted?
|
977
|
+
if !call_any_number() and !halted?
|
978
|
+
if !call_any_text() and !halted?
|
979
|
+
unless args[:ignore_everything_else]
|
980
|
+
if !call_everything_else() and !halted?
|
981
|
+
logger.write "\tNo match found in #{@current}", :yellow
|
982
|
+
call_after(:blocks)
|
983
|
+
call_class_callback(:after_blocks)
|
984
|
+
return false
|
985
|
+
end
|
986
|
+
else
|
987
|
+
return false
|
988
|
+
end
|
989
|
+
end
|
990
|
+
end
|
991
|
+
end
|
992
|
+
end
|
993
|
+
# end
|
994
|
+
end
|
995
|
+
end
|
996
|
+
end
|
997
|
+
# end
|
998
|
+
end
|
999
|
+
else
|
1000
|
+
logger.write "---- THIS MESSAGE IS EMPTY ----", :red
|
1001
|
+
end
|
1002
|
+
end
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
unless halted?
|
1007
|
+
call_after(:blocks)
|
1008
|
+
call_class_callback(:after_blocks)
|
1009
|
+
end
|
1010
|
+
end
|
1011
|
+
return @called_block
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
def run_class_callbacks_only
|
1015
|
+
call_class_callback(:before_blocks)
|
1016
|
+
unless halted?
|
1017
|
+
call_class_callback(:after_blocks)
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def run_for_text_only(args={run_blocks_method: true, ignore_everything_else: false})
|
1022
|
+
|
1023
|
+
@run_type = :text_only
|
1024
|
+
|
1025
|
+
logger.write "\n\n#{self.nice_current_route} => Starting matching process (text only)\n", :bright
|
1026
|
+
|
1027
|
+
# before_blocks()
|
1028
|
+
|
1029
|
+
call_class_callback(:before_blocks)
|
1030
|
+
|
1031
|
+
unless halted?
|
1032
|
+
blocks() if args[:run_blocks_method] #Loading blocks
|
1033
|
+
|
1034
|
+
unless self.valid_context_route?
|
1035
|
+
logger.write "Error: the context in route #{@current} doesn't exist", :red
|
1036
|
+
self.exit_context()
|
1037
|
+
return false
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
call_before(:blocks)
|
1041
|
+
if !@message.empty?
|
1042
|
+
if !call_regular_expressions() and !halted?
|
1043
|
+
if !call_keywords() and !halted?
|
1044
|
+
call_before(:nlp)
|
1045
|
+
@message.nlp.process_phrase_once
|
1046
|
+
call_after(:nlp, @message.nlp.entities)
|
1047
|
+
# if !call_expressions() and !halted?
|
1048
|
+
if !call_intents() and !halted?
|
1049
|
+
if !call_nlp_entity() and !halted?
|
1050
|
+
if !call_any_number() and !halted?
|
1051
|
+
if !call_any_text() and !halted?
|
1052
|
+
unless args[:ignore_everything_else]
|
1053
|
+
if !call_everything_else() and !halted?
|
1054
|
+
logger.write "#{self.class.name.to_s}.run_for_text_only => nothing found | #{@current}", :yellow
|
1055
|
+
call_after(:blocks)
|
1056
|
+
call_class_callback(:after_blocks)
|
1057
|
+
return false
|
1058
|
+
end
|
1059
|
+
else
|
1060
|
+
return false
|
1061
|
+
end
|
1062
|
+
end
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
end
|
1066
|
+
# end
|
1067
|
+
end
|
1068
|
+
end
|
1069
|
+
else
|
1070
|
+
logger.write "---- THIS MESSAGE IS EMPTY AND WE DON'T DOING NOTHING WITH IT ----", :red
|
1071
|
+
end
|
1072
|
+
unless halted?
|
1073
|
+
call_after(:blocks)
|
1074
|
+
call_class_callback(:after_blocks)
|
1075
|
+
end
|
1076
|
+
end
|
1077
|
+
return @called_block
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
def run_for_chat_activity_only(args={run_blocks_method: true, ignore_everything_else: false})
|
1081
|
+
|
1082
|
+
@run_type = :text_only
|
1083
|
+
|
1084
|
+
logger.write "\n\n#{self.nice_current_route} => Starting matching process (chat activity only)\n", :bright
|
1085
|
+
|
1086
|
+
|
1087
|
+
call_class_callback(:before_blocks)
|
1088
|
+
|
1089
|
+
unless halted?
|
1090
|
+
blocks() if args[:run_blocks_method] #Loading blocks
|
1091
|
+
|
1092
|
+
unless self.valid_context_route?
|
1093
|
+
logger.write "Error: the context in route #{@current} doesn't exist", :red
|
1094
|
+
self.exit_context()
|
1095
|
+
return false
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
call_before(:blocks)
|
1099
|
+
if !call_membership_new()
|
1100
|
+
if !call_membership_drop()
|
1101
|
+
logger.write "#{self.nice_current_route}.run_for_chat_activity_only => nothing found", :yellow
|
1102
|
+
call_after(:blocks)
|
1103
|
+
call_class_callback(:after_blocks)
|
1104
|
+
end
|
1105
|
+
return false
|
1106
|
+
end
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
return @called_block
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
def run_for_recurring_notification_only()
|
1113
|
+
|
1114
|
+
@run_type = :text_only
|
1115
|
+
|
1116
|
+
logger.write "\n\n#{self.nice_current_route} => Starting matching process (recurring notification only)\n", :bright
|
1117
|
+
|
1118
|
+
|
1119
|
+
|
1120
|
+
call_class_callback(:before_blocks)
|
1121
|
+
|
1122
|
+
unless halted?
|
1123
|
+
blocks()
|
1124
|
+
|
1125
|
+
unless self.valid_context_route?
|
1126
|
+
logger.write "Error: the context in route #{@current} doesn't exist", :red
|
1127
|
+
self.exit_context()
|
1128
|
+
return false
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
call_before(:blocks)
|
1132
|
+
call_recurring_notifications()
|
1133
|
+
if !call_postbacks(false) and !halted?
|
1134
|
+
call_class_callback(:after_blocks)
|
1135
|
+
return false
|
1136
|
+
end
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
call_class_callback(:after_blocks)
|
1140
|
+
return @called_block
|
1141
|
+
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
def name
|
1145
|
+
self.class.to_s.underscore.sub("_context","")
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
def type
|
1149
|
+
:context
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
def self.router(route,type=:default)
|
1153
|
+
type = :default if type.to_sym == :message
|
1154
|
+
context_class = nil
|
1155
|
+
sub_context_route = nil
|
1156
|
+
if route.to_s.empty?
|
1157
|
+
context_class = "#{Kogno::Application.routes.to_h[type.to_s]}_context".classify
|
1158
|
+
else
|
1159
|
+
route_array = route.to_s.split(Regexp.union(["/","."]))
|
1160
|
+
context_name = route_array[0]
|
1161
|
+
sub_context_route = route_array[1..].join(".")
|
1162
|
+
context_class = "#{context_name}_context".classify
|
1163
|
+
end
|
1164
|
+
|
1165
|
+
valid_class = (eval(context_class) rescue nil)
|
1166
|
+
if valid_class.nil?
|
1167
|
+
valid = false
|
1168
|
+
else
|
1169
|
+
valid = true
|
1170
|
+
context_class = valid_class
|
1171
|
+
end
|
1172
|
+
return (
|
1173
|
+
{
|
1174
|
+
class: context_class,
|
1175
|
+
sub_context_route: sub_context_route,
|
1176
|
+
valid: valid
|
1177
|
+
}
|
1178
|
+
)
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
def self.get_from_payload(postback_payload)
|
1182
|
+
if !postback_payload.nil? && postback_payload.class == String
|
1183
|
+
routes = postback_payload.split(Regexp.union(["/","-",'__']))
|
1184
|
+
if routes.count > 1
|
1185
|
+
routes.pop
|
1186
|
+
return routes.join(".")
|
1187
|
+
end
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
return nil
|
1191
|
+
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
def self.get(value)
|
1195
|
+
|
1196
|
+
if !value.nil? && value.class == String
|
1197
|
+
$contexts.each do |context|
|
1198
|
+
if value.start_with?("#{context}_")
|
1199
|
+
return(
|
1200
|
+
{
|
1201
|
+
context: context,
|
1202
|
+
param: value.sub("#{context}_","")
|
1203
|
+
}
|
1204
|
+
)
|
1205
|
+
end
|
1206
|
+
end
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
return nil
|
1210
|
+
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
def delegate_to(route, args={})
|
1214
|
+
args = {ignore_everything_else:true}.merge(args)
|
1215
|
+
action_found = false
|
1216
|
+
route = translate_route(route)
|
1217
|
+
call_callback(:before_delegate)
|
1218
|
+
context_route = self.class.router(route, @message.type)
|
1219
|
+
context_class = context_route[:class]
|
1220
|
+
sub_context_route = context_route[:sub_context_route]
|
1221
|
+
unless context_route[:valid]
|
1222
|
+
logger.write "ERROR: #{context_class.to_s} doesn't exist.", :red
|
1223
|
+
return false
|
1224
|
+
end
|
1225
|
+
logger.write "Delegating to #{route}", :pink
|
1226
|
+
delegated_context = context_class.new(@user,@message,@reply,route)
|
1227
|
+
delegated_context.blocks()
|
1228
|
+
delegated_context.call_callback(:on_delegate)
|
1229
|
+
unless delegated_context.halted?
|
1230
|
+
if @run_type == :text_only
|
1231
|
+
action_found = delegated_context.run_for_text_only({run_blocks_method: false, ignore_everything_else: args[:ignore_everything_else]})
|
1232
|
+
else
|
1233
|
+
action_found = delegated_context.run({run_blocks_method: false, ignore_everything_else: args[:ignore_everything_else]})
|
1234
|
+
end
|
1235
|
+
end
|
1236
|
+
# if action_found
|
1237
|
+
halt(true)
|
1238
|
+
return true
|
1239
|
+
# else
|
1240
|
+
# return false
|
1241
|
+
# end
|
1242
|
+
end
|
1243
|
+
|
1244
|
+
def change_to(route, params={})
|
1245
|
+
route = translate_route(route)
|
1246
|
+
call_callback(:on_exit) unless sub_context?(route) # will_exit? prevents to not execute :on_exit callback when the the contexts changes to a sub_context
|
1247
|
+
context_route = self.class.router(route, @message.type)
|
1248
|
+
context_class = context_route[:class]
|
1249
|
+
|
1250
|
+
unless context_route[:valid]
|
1251
|
+
logger.write "ERROR: #{context_class.to_s} doesn't exist.", :red
|
1252
|
+
return false
|
1253
|
+
else
|
1254
|
+
call_class_callback(:before_exit) if self.class != context_class # only will be executed if the contexts is changed to another
|
1255
|
+
unless self.halted?
|
1256
|
+
@user.set_context(route, params)
|
1257
|
+
context = context_class.new(@user,@message,@reply)
|
1258
|
+
context.blocks()
|
1259
|
+
context.call_callback(:on_enter)
|
1260
|
+
end
|
1261
|
+
end
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
def ask(answer_route=nil, params={}, &block)
|
1265
|
+
unless answer_route.nil?
|
1266
|
+
route = (self.parent_context_route != "" and answer_route[0] != "/") ? "../#{answer_route}" : answer_route
|
1267
|
+
change_to(route, params)
|
1268
|
+
end
|
1269
|
+
|
1270
|
+
unless block.nil?
|
1271
|
+
if answer_route.nil?
|
1272
|
+
callback :on_enter do
|
1273
|
+
block.call
|
1274
|
+
end
|
1275
|
+
else
|
1276
|
+
block.call
|
1277
|
+
end
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
def save_current_context
|
1283
|
+
@user.save_current_context
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
def change_to_saved_context
|
1287
|
+
saved_context = @user.vars[:saved_context]
|
1288
|
+
unless saved_context.nil?
|
1289
|
+
@user.delete_previous_context
|
1290
|
+
change_to(saved_context[:context], saved_context[:params])
|
1291
|
+
else
|
1292
|
+
self.exit()
|
1293
|
+
end
|
1294
|
+
end
|
1295
|
+
|
1296
|
+
def exit_answer
|
1297
|
+
self.exit()
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
def keep
|
1301
|
+
@user.set_context(@current)
|
1302
|
+
end
|
1303
|
+
|
1304
|
+
def translate_route(route)
|
1305
|
+
route = route.to_s
|
1306
|
+
case route
|
1307
|
+
when "/", "", nil
|
1308
|
+
return ""
|
1309
|
+
when :parent, "../"
|
1310
|
+
return self.parent_context_route
|
1311
|
+
else
|
1312
|
+
if route[0] == "/"
|
1313
|
+
tmp_route = route.split("/")
|
1314
|
+
tmp_route.slice!(0)
|
1315
|
+
return tmp_route.join(".")
|
1316
|
+
elsif route[0..2] == "../"
|
1317
|
+
return "#{self.parent_context_route}.#{route[3..]}"
|
1318
|
+
elsif route [0..1] == "./"
|
1319
|
+
return "#{self.current_context_route}.#{route[2..]}"
|
1320
|
+
elsif !route.index("/").nil?
|
1321
|
+
return route.gsub("/",".")
|
1322
|
+
else
|
1323
|
+
# return "#{@current}.#{route}"
|
1324
|
+
return "#{self.current_context_route}.#{route}"
|
1325
|
+
end
|
1326
|
+
end
|
1327
|
+
end
|
1328
|
+
|
1329
|
+
def exit
|
1330
|
+
call_callback(:on_exit)
|
1331
|
+
call_class_callback(:before_exit) unless self.class == MainContext
|
1332
|
+
unless self.halted?
|
1333
|
+
@user.exit_context
|
1334
|
+
end
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
def exit_context
|
1338
|
+
self.exit
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
def sub_context?(sub_context)
|
1342
|
+
(sub_context =~ /#{@current.to_s}/) == 0
|
1343
|
+
end
|
1344
|
+
|
1345
|
+
def set_nlp_reference(**values) # This is used to send context references to Wit https://wit.ai/docs/http/20170307#context_link
|
1346
|
+
@user.vars[:nlp_context_ref] = values
|
1347
|
+
end
|
1348
|
+
|
1349
|
+
def destroy_nlp_reference
|
1350
|
+
@user.vars.delete(:nlp_context_ref)
|
1351
|
+
end
|
1352
|
+
|
1353
|
+
# Methods to overwrite
|
1354
|
+
|
1355
|
+
def blocks
|
1356
|
+
#overwrite this with your routes
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
def params
|
1360
|
+
@user.get_context_params
|
1361
|
+
end
|
1362
|
+
|
1363
|
+
def self.base_template(action_group,action, params,returnable, instance)
|
1364
|
+
template = $context_blocks[action_group.to_sym][action.to_sym] rescue nil
|
1365
|
+
|
1366
|
+
log_string = " Rendering template: #{File.join("bot","templates",action_group.to_s,"#{action.to_s}.erb")}"
|
1367
|
+
log_string = "#{log_string} with params #{params.to_h}" unless params.to_h.empty?
|
1368
|
+
logger.write log_string, :pink
|
1369
|
+
|
1370
|
+
unless template.nil?
|
1371
|
+
if !returnable
|
1372
|
+
template.render(instance, params)
|
1373
|
+
else
|
1374
|
+
template
|
1375
|
+
end
|
1376
|
+
else
|
1377
|
+
logger.write " ERROR: Template #{action_group}/#{action}.erb not found.", :red
|
1378
|
+
end
|
1379
|
+
end
|
1380
|
+
|
1381
|
+
def template(action_group,action, params={})
|
1382
|
+
self.class.base_template(action_group, action, params, false, self)
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
# def self.html_template(action_group,action, params={}, instance=nil)
|
1386
|
+
# instance = self if instance.nil?
|
1387
|
+
# template = $context_html_templates[action_group.to_sym][action.to_sym]
|
1388
|
+
# if template.nil?
|
1389
|
+
# logger.write "Template bot/templates/#{action_group}/#{action}.rhtml not found.", :red
|
1390
|
+
# return ""
|
1391
|
+
# else
|
1392
|
+
# return template.render(instance, params)
|
1393
|
+
# end
|
1394
|
+
# end
|
1395
|
+
|
1396
|
+
# def html_template(route,params,instance)
|
1397
|
+
# self.class.html_template(action_group, action, params, false, self)
|
1398
|
+
# end
|
1399
|
+
|
1400
|
+
def root
|
1401
|
+
class_name = self.class.to_s
|
1402
|
+
last_occurence = class_name.rindex("Context") - 1
|
1403
|
+
class_name[0..last_occurence].underscore
|
1404
|
+
end
|
1405
|
+
|
1406
|
+
# Sequences
|
1407
|
+
|
1408
|
+
def sequences
|
1409
|
+
|
1410
|
+
#You should overwrite this in the Context
|
1411
|
+
|
1412
|
+
end
|
1413
|
+
|
1414
|
+
def start_sequence(stage_route, context_name=nil)
|
1415
|
+
stage_array = stage_route.to_s.split("/")
|
1416
|
+
if stage_array.count == 2
|
1417
|
+
context_name = stage_array[0]
|
1418
|
+
stage = stage_array[1]
|
1419
|
+
else
|
1420
|
+
context_name = self.name
|
1421
|
+
stage = stage_route
|
1422
|
+
end
|
1423
|
+
@user.set_sequence(stage, context_name)
|
1424
|
+
end
|
1425
|
+
|
1426
|
+
def stop_sequence(stage_route)
|
1427
|
+
stage_array = stage_route.to_s.split("/")
|
1428
|
+
if stage_array.count == 2
|
1429
|
+
context_name = stage_array[0]
|
1430
|
+
stage = stage_array[1]
|
1431
|
+
else
|
1432
|
+
context_name = self.name
|
1433
|
+
stage = stage_route
|
1434
|
+
end
|
1435
|
+
@user.exit_sequence(stage, context_name)
|
1436
|
+
end
|
1437
|
+
|
1438
|
+
|
1439
|
+
def sequence(stage_name, &block)
|
1440
|
+
@current_sequence_stage = stage_name.to_sym
|
1441
|
+
sequence = sequence_name()
|
1442
|
+
@sequences[sequence] = {} if @sequences[sequence].nil?
|
1443
|
+
block.call
|
1444
|
+
@current_sequence_stage = nil
|
1445
|
+
end
|
1446
|
+
|
1447
|
+
def past(time_elapsed,&block)
|
1448
|
+
return false if @current_sequence_stage.nil?
|
1449
|
+
sequence = sequence_name()
|
1450
|
+
@sequences[sequence][time_elapsed.to_i] = block
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
def sequence_name
|
1454
|
+
return nil if @current_sequence_stage.nil?
|
1455
|
+
"#{self.name}.#{@current_sequence_stage}"
|
1456
|
+
end
|
1457
|
+
|
1458
|
+
|
1459
|
+
def self.run_sequence(action)
|
1460
|
+
logger.write "Running delayed action ##{action.id}|#{action.route} for user ##{action.user.psid}"
|
1461
|
+
action.user.get_session_vars
|
1462
|
+
if action.user.platform == "messenger"
|
1463
|
+
notification = Kogno::Messenger::Notification.new(action.user)
|
1464
|
+
elsif action.user.platform == "telegram"
|
1465
|
+
notification = Kogno::Telegram::Notification.new(action.user)
|
1466
|
+
else
|
1467
|
+
notification = Kogno::Notification.new(action.user)
|
1468
|
+
end
|
1469
|
+
context = self.router(action.route)[:class].new(action.user,{},notification)
|
1470
|
+
context.sequences()
|
1471
|
+
user = action.user
|
1472
|
+
# context.get_sequences[action.route].sort{|x,y| y<=>x}.each do |past,block|
|
1473
|
+
if !context.get_sequences[action.route].nil?
|
1474
|
+
context.get_sequences[action.route].sort.each do |past,block|
|
1475
|
+
if past > action.last_executed
|
1476
|
+
execution_time = action.last_hit_at+past
|
1477
|
+
if Time.now.utc > execution_time
|
1478
|
+
block.call
|
1479
|
+
notification.send
|
1480
|
+
user.log_response(notification) if Kogno::Application.config.store_log_in_database
|
1481
|
+
action.last_executed = past
|
1482
|
+
action.save
|
1483
|
+
else
|
1484
|
+
action.execution_time = execution_time
|
1485
|
+
action.save
|
1486
|
+
logger.write "It's not time yet. Execution time at #{execution_time} it will be executed at #{execution_time-Time.now.utc} seconds.", :red
|
1487
|
+
return false
|
1488
|
+
end
|
1489
|
+
end
|
1490
|
+
end
|
1491
|
+
logger.write "End of cycle, there is no more in this sequence so this user will be exited from the stage:#{action.route}"
|
1492
|
+
context.stop_sequence
|
1493
|
+
return false
|
1494
|
+
else
|
1495
|
+
logger.write "Not action found for #{action.route}"
|
1496
|
+
context.stop_sequence
|
1497
|
+
return false
|
1498
|
+
end
|
1499
|
+
end
|
1500
|
+
|
1501
|
+
def get_sequences
|
1502
|
+
@sequences
|
1503
|
+
end
|
1504
|
+
|
1505
|
+
def memorize_message
|
1506
|
+
@user.vars[:memory] = @message.data
|
1507
|
+
end
|
1508
|
+
|
1509
|
+
def remember_message
|
1510
|
+
unless @user.vars[:memory].nil?
|
1511
|
+
@memorized_message = @user.vars[:memory]
|
1512
|
+
@user.vars.delete(:memory)
|
1513
|
+
end
|
1514
|
+
end
|
1515
|
+
|
1516
|
+
def handle_message_from_memory(platform=nil)
|
1517
|
+
unless @memorized_message.nil?
|
1518
|
+
if platform == :telegram
|
1519
|
+
message = Kogno::Telegram::Message.new(@memorized_message)
|
1520
|
+
else
|
1521
|
+
message = Kogno::Messenger::Message.new(@memorized_message)
|
1522
|
+
end
|
1523
|
+
message.handle_event()
|
1524
|
+
@memorized_message = nil
|
1525
|
+
end
|
1526
|
+
end
|
1527
|
+
|
1528
|
+
def change_locale(locale)
|
1529
|
+
@user.set_locale(locale)
|
1530
|
+
@message.set_nlp(locale)
|
1531
|
+
I18n.locale = locale
|
1532
|
+
end
|
1533
|
+
|
1534
|
+
def get_default_context_for_command(command)
|
1535
|
+
default_context = Kogno::Application.config.routes.commands[command.to_sym]
|
1536
|
+
default_context = Kogno::Application.config.routes.default if default_context.nil?
|
1537
|
+
return default_context
|
1538
|
+
end
|
1539
|
+
|
1540
|
+
def debugger
|
1541
|
+
{
|
1542
|
+
blocks: @blocks,
|
1543
|
+
deep_blocks: @deep_blocks,
|
1544
|
+
callbacks: @callbacks
|
1545
|
+
}
|
1546
|
+
end
|
1547
|
+
|
1548
|
+
protected
|
1549
|
+
|
1550
|
+
def logger_call(action_name, argument, params=[], found=false, deep_action=false)
|
1551
|
+
sub_context = current_sub_context
|
1552
|
+
sub_context_string = ".#{sub_context}" unless sub_context.empty?
|
1553
|
+
argument_string = "(\"#{argument}\")" unless argument.nil?
|
1554
|
+
deep_action_string = "deep." if deep_action
|
1555
|
+
params = params.map{|param| param.class == String ? "\"#{param}\"" : param.to_s }.join(", ") if params.class == Kogno::BlockParams
|
1556
|
+
unless params.nil? || params.empty?
|
1557
|
+
logger.write "- #{deep_action_string}#{action_name}#{argument_string} => |#{params}|", found ? :green : :white
|
1558
|
+
else
|
1559
|
+
logger.write "- #{deep_action_string}#{action_name}#{argument_string}#{deep_action_string}", found ? :green : :white
|
1560
|
+
end
|
1561
|
+
|
1562
|
+
end
|
1563
|
+
|
1564
|
+
def nice_current_route
|
1565
|
+
current_sub_context = self.current_sub_context()
|
1566
|
+
unless current_sub_context.empty?
|
1567
|
+
"#{self.class.name.to_s}.#{current_sub_context}"
|
1568
|
+
else
|
1569
|
+
self.class.name.to_s
|
1570
|
+
end
|
1571
|
+
end
|
1572
|
+
|
1573
|
+
end
|