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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/bin/kogno +92 -0
  3. data/lib/boot.rb +9 -0
  4. data/lib/core/bin_helpers/messenger_ctl.rb +48 -0
  5. data/lib/core/bin_helpers/scaffolding.rb +203 -0
  6. data/lib/core/bin_helpers/scheduled_messages_ctl.rb +95 -0
  7. data/lib/core/bin_helpers/sequences_ctl.rb +95 -0
  8. data/lib/core/bin_helpers/server_ctl.rb +127 -0
  9. data/lib/core/bin_helpers/telegram_ctl.rb +48 -0
  10. data/lib/core/bin_helpers/webhook_ctl.rb +96 -0
  11. data/lib/core/db.rb +8 -0
  12. data/lib/core/extensions/array.rb +28 -0
  13. data/lib/core/extensions/hash.rb +12 -0
  14. data/lib/core/extensions/logger.rb +70 -0
  15. data/lib/core/extensions/string.rb +6 -0
  16. data/lib/core/extensions/wit.rb +60 -0
  17. data/lib/core/global_methods.rb +67 -0
  18. data/lib/core/helpers/string.rb +105 -0
  19. data/lib/core/lib/base_config.rb +17 -0
  20. data/lib/core/lib/block_params.rb +4 -0
  21. data/lib/core/lib/context.rb +1573 -0
  22. data/lib/core/lib/error_handler.rb +36 -0
  23. data/lib/core/lib/message.rb +182 -0
  24. data/lib/core/lib/messenger/api.rb +281 -0
  25. data/lib/core/lib/messenger/facebook_graph.rb +32 -0
  26. data/lib/core/lib/messenger/message.rb +202 -0
  27. data/lib/core/lib/messenger/notification.rb +351 -0
  28. data/lib/core/lib/messenger/post_comment.rb +104 -0
  29. data/lib/core/lib/messenger/recurring_notification.rb +81 -0
  30. data/lib/core/lib/nlp.rb +191 -0
  31. data/lib/core/lib/notification.rb +371 -0
  32. data/lib/core/lib/spelling.rb +13 -0
  33. data/lib/core/lib/telegram/api.rb +197 -0
  34. data/lib/core/lib/telegram/chat_activity.rb +111 -0
  35. data/lib/core/lib/telegram/inline_query.rb +112 -0
  36. data/lib/core/lib/telegram/message.rb +327 -0
  37. data/lib/core/lib/telegram/notification.rb +507 -0
  38. data/lib/core/lib/whatsapp/api.rb +153 -0
  39. data/lib/core/lib/whatsapp/message.rb +132 -0
  40. data/lib/core/lib/whatsapp/notification.rb +206 -0
  41. data/lib/core/lib/whatsapp/status_message.rb +58 -0
  42. data/lib/core/loaders/config_files.rb +15 -0
  43. data/lib/core/models/chat_log.rb +4 -0
  44. data/lib/core/models/long_payload.rb +25 -0
  45. data/lib/core/models/matched_message.rb +5 -0
  46. data/lib/core/models/messenger_recurring_notification.rb +16 -0
  47. data/lib/core/models/scheduled_message.rb +40 -0
  48. data/lib/core/models/sequence.rb +29 -0
  49. data/lib/core/models/telegram_chat_group.rb +26 -0
  50. data/lib/core/models/user.rb +285 -0
  51. data/lib/core/web/webhook.rb +198 -0
  52. data/lib/kogno.rb +130 -0
  53. data/scaffolding/new_project/Gemfile +3 -0
  54. data/scaffolding/new_project/application.rb +5 -0
  55. data/scaffolding/new_project/bot/contexts/main_context.rb +10 -0
  56. data/scaffolding/new_project/bot/conversation.rb +14 -0
  57. data/scaffolding/new_project/bot/models/user.rb +3 -0
  58. data/scaffolding/new_project/config/application.rb +28 -0
  59. data/scaffolding/new_project/config/database.yml +8 -0
  60. data/scaffolding/new_project/config/locales/en.yml +4 -0
  61. data/scaffolding/new_project/config/locales/es.yml +3 -0
  62. data/scaffolding/new_project/config/nlp.rb +23 -0
  63. data/scaffolding/new_project/config/platforms/messenger.rb +74 -0
  64. data/scaffolding/new_project/config/platforms/telegram.rb +45 -0
  65. data/scaffolding/new_project/config/platforms/whatsapp.rb +13 -0
  66. data/scaffolding/new_project/web/routes.rb +10 -0
  67. metadata +220 -0
@@ -0,0 +1,327 @@
1
+ module Kogno
2
+ module Telegram
3
+ class Message < Kogno::Message
4
+
5
+ @overwritten_payload = nil
6
+
7
+ def initialize(data, type=nil)
8
+ @data = data
9
+ @type = type
10
+ end
11
+
12
+ def type
13
+ @type
14
+ end
15
+
16
+ def platform
17
+ :telegram
18
+ end
19
+
20
+ def chat
21
+ if @type == :callback_query
22
+ @data[:message][:chat]
23
+ else
24
+ @data[:chat]
25
+ end
26
+ end
27
+
28
+ def chat_id
29
+ self.chat[:id]
30
+ end
31
+
32
+ def chat_title
33
+ self.chat[:title]
34
+ end
35
+
36
+ def chat_type
37
+ self.chat[:type].to_sym
38
+ end
39
+
40
+ def via_bot
41
+ @data[:via_bot] rescue nil
42
+ end
43
+
44
+ def inviter_user_id
45
+ @data[:from][:id]
46
+ end
47
+
48
+ def page_id
49
+ nil
50
+ end
51
+
52
+ def attachments
53
+ a = nil
54
+ a = @data[:audio]
55
+ a = @data[:document] if a.nil?
56
+ a = @data[:photo] if a.nil?
57
+ a = @data[:sticker] if a.nil?
58
+ a = @data[:video] if a.nil?
59
+ a = @data[:voice] if a.nil?
60
+ return a
61
+ end
62
+
63
+ def sender_id
64
+ return @data[:from][:id]
65
+ end
66
+
67
+ def sender_first_name
68
+ return @data[:from][:first_name] rescue ""
69
+ end
70
+
71
+ def sender_last_name
72
+ return @data[:from][:last_name] rescue ""
73
+ end
74
+
75
+ def sender_language
76
+ return @data[:from][:language_code] rescue ""
77
+ end
78
+
79
+ def callback_query_id
80
+ if @type == :callback_query
81
+ return @data[:id]
82
+ else
83
+ return nil
84
+ end
85
+ end
86
+
87
+ def raw_payload
88
+ payload = @data[:data] rescue nil
89
+ payload = get_long_payload(payload) unless payload.nil?
90
+ payload = @overwritten_payload if payload.nil?
91
+ return(payload)
92
+ end
93
+
94
+ def get_long_payload(data)
95
+ return @long_payload unless @long_payload.nil?
96
+
97
+ long_data = data.split("kogno__",2)
98
+ if long_data.length == 2
99
+ token = long_data[1]
100
+ @long_payload = LongPayload.get(token)
101
+ else
102
+ @long_payload = data
103
+ end
104
+
105
+ return @long_payload
106
+ end
107
+
108
+ def payload(action_only=false)
109
+ if action_only
110
+ pl = self.raw_payload.split(":",2)[0] rescue nil
111
+ if pl.nil?
112
+ return pl
113
+ else
114
+ return pl.split(Regexp.union(["/","-"])).last
115
+ end
116
+ else
117
+ self.raw_payload.split(":",2)[0] rescue nil
118
+ end
119
+ end
120
+
121
+ def referral(field=nil)
122
+ nil
123
+ end
124
+
125
+ def payload_action
126
+ payload(true)
127
+ end
128
+
129
+ def command(command_only=true)
130
+ bot_command_entity = @data[:entities].find{|e| e[:type] == "bot_command"} rescue nil
131
+ if !bot_command_entity.nil?
132
+ if command_only
133
+ return @data[:text].split(" ").first.sub("/","").split("@")[0]
134
+ else
135
+ return @data[:text]
136
+ end
137
+ else
138
+ return nil
139
+ end
140
+ end
141
+
142
+ def deep_link_data
143
+ if self.command == "start"
144
+ command_param = self.command_text.to_s
145
+ if !command_param.empty?
146
+ return command_param
147
+ end
148
+ end
149
+ return nil
150
+ end
151
+
152
+ def deep_link_params
153
+ end
154
+
155
+ def command_text
156
+ command = self.command(false)
157
+ unless command.nil?
158
+ a = command.split(" ")
159
+ a.shift
160
+ return a.join(" ")
161
+ else
162
+ return ""
163
+ end
164
+ end
165
+
166
+ def empty_thread_from_ad?
167
+ if self.empty?
168
+ unless self.referral.nil?
169
+ if self.referral(:source) == "ADS" and self.referral(:type) == "OPEN_THREAD"
170
+ return true
171
+ end
172
+ end
173
+ end
174
+
175
+ return false
176
+ end
177
+
178
+ def params
179
+ raw_params = self.raw_payload.to_s.split(":",2)[1].to_s
180
+ if raw_params.empty?
181
+ return({})
182
+ else
183
+ p = (JSON.parse(raw_params, {:symbolize_names => true}) rescue nil)
184
+ p = raw_params if p.nil?
185
+ return(p)
186
+ end
187
+ end
188
+
189
+ def get_kgn_id
190
+ self.params[:kgn_id] rescue nil
191
+ end
192
+
193
+ def raw_message
194
+ t = @data[:text] rescue nil
195
+ unless t.nil?
196
+ return({
197
+ :type => :text,
198
+ :value => t
199
+ })
200
+ end
201
+ end
202
+
203
+ def text
204
+ return self.raw_message[:value].to_s rescue ""
205
+ end
206
+
207
+ def overwrite_postback(payload)
208
+ @overwritten_payload = payload
209
+ end
210
+
211
+ def location
212
+ if (self.raw_message[:type] == :location rescue false)
213
+ return self.raw_message[:value]
214
+ else
215
+ return nil
216
+ end
217
+ end
218
+
219
+ def get_context(user,notification,chat)
220
+
221
+ if !(context_from_postback = Context.get_from_payload(self.payload)).nil?
222
+ context_route = context_from_postback
223
+ elsif !(context_in_link = Context.get(self.deep_link_data)).nil?
224
+ context_route = context_in_link[:context]
225
+ @data[:deep_link_param] = context_in_link[:param]
226
+ logger.write "-----context_from_deep_link:#{context_route}-----", :pink
227
+ elsif !(context_from_typed_postback = Context.get_from_typed_postback(self,user)).nil?
228
+ context_route = context_from_typed_postback
229
+ else
230
+ context_route = user.context
231
+ end
232
+
233
+ context_class = Context.router(context_route)[:class]
234
+ if context_class.nil?
235
+ user.exit_context
236
+ context_class = Context.router(Kogno::Application.config.routes.default)[:class]
237
+ end
238
+ context = context_class.new(user,self,notification,context_route, nil, chat)
239
+ context
240
+ end
241
+
242
+
243
+ def handle_event(debug=false)
244
+
245
+ begin
246
+
247
+ unless self.via_bot.nil?
248
+ logger.debug "Shared message via inline_query detected. We don't do nothing here yet.", :pink
249
+ return false
250
+ end
251
+
252
+ user = User.find_or_create_by_psid(self.sender_id, :telegram)
253
+ user.get_session_vars
254
+ user.first_name = self.sender_first_name
255
+ user.last_name = self.sender_last_name
256
+ user.locale = self.sender_language if user.locale.nil?
257
+ user.save
258
+
259
+ self.set_nlp(user.locale)
260
+ I18n.locale = user.locale unless user.locale.nil?
261
+
262
+ if [:group,:channel, :supergroup].include?(self.chat_type)
263
+ chat = TelegramChatGroup.find_by_chat_id(self.chat_id)
264
+ else
265
+ chat = user
266
+ end
267
+
268
+
269
+ unless user.vars[:nlp_context_ref].nil?
270
+ self.nlp.set_context_reference(user.vars[:nlp_context_ref])
271
+ user.vars.delete(:nlp_context_ref) # context references will only be used once
272
+ end
273
+
274
+ if [:group,:channel, :supergroup].include?(self.chat_type)
275
+ notification = Notification.new(chat,self)
276
+ else
277
+ notification = Notification.new(user,self)
278
+ end
279
+
280
+ self.log_message_info(user)
281
+
282
+ context = get_context(user,notification,chat)
283
+
284
+ return({msg: self, user: user, notification: notification, context: context, chat: chat}) if debug
285
+
286
+ unless empty_thread_from_ad?
287
+
288
+ called_action = context.run
289
+ if Kogno::Application.config.store_log_in_database
290
+ message_log_id = user.log_message(self).id
291
+ else
292
+ message_chat_log_id = 0
293
+ end
294
+
295
+ notification.answer_callback_query if self.type == :callback_query
296
+ notification.send
297
+
298
+ response_log_id = 0
299
+ if Kogno::Application.config.store_log_in_database
300
+ response_log = user.log_response(notification)
301
+ response_log_id = response_log.id unless response_log.nil?
302
+ end
303
+
304
+ # user.set_last_usage
305
+ user.save_session_vars
306
+ context.handle_message_from_memory
307
+
308
+ else
309
+ context.run_class_callbacks_only
310
+ user.save_session_vars
311
+ user.log_message(self) if Kogno::Application.config.store_log_in_database
312
+ end
313
+ logger.write "- Current user context: #{user.context}", :blue unless user.context.nil?
314
+
315
+ rescue StandardError => e
316
+ error_token = Digest::MD5.hexdigest("#{Time.now}#{rand(1000)}") # This helps to identify the error that arrives to Slack in order to search it in logs/http.log
317
+ logger.write e.message, :red
318
+ logger.write "Error Token: #{error_token}", :red
319
+ logger.write "Backtrace:\n\t#{e.backtrace.join("\n\t")}", :red
320
+ ErrorHandler.notify_by_slack(Kogno::Application.config.app_name,e, error_token) if Kogno::Application.config.error_notifier.slack[:enable] rescue false
321
+ end
322
+
323
+ end
324
+
325
+ end
326
+ end
327
+ end