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,36 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'openssl'
4
+
5
+ module Kogno
6
+ class ErrorHandler
7
+ class << self
8
+
9
+ def notify_by_slack(username, error, token)
10
+
11
+ error_message = %{```
12
+ Error Message: #{error.message[0..256]}
13
+ Error Token: #{token}
14
+ Backtrace:#{error.backtrace.join("\n\t")[0..1024]}
15
+ ```}
16
+
17
+ url = URI(Kogno::Application.config.error_notifier.slack[:webhook])
18
+
19
+ http = Net::HTTP.new(url.host, url.port)
20
+ http.use_ssl = true
21
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
22
+
23
+ request = Net::HTTP::Post.new(url)
24
+ request["content-type"] = 'application/json'
25
+ request.body = {
26
+ username: username,
27
+ text: error_message
28
+ }.to_json
29
+
30
+ response = http.request(request)
31
+ logger.write "-- This error was notified in Slack ---", :red
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,182 @@
1
+ module Kogno
2
+ class Message
3
+
4
+ attr_accessor :event
5
+
6
+ @overwritten_payload = nil
7
+
8
+ def type
9
+ :message
10
+ end
11
+
12
+ def sender_id
13
+ 0
14
+ end
15
+
16
+ def page_id
17
+ nil
18
+ end
19
+
20
+ def stickers
21
+ []
22
+ end
23
+
24
+ def attachments
25
+ []
26
+ end
27
+
28
+ def referral(field=nil)
29
+ nil
30
+ end
31
+
32
+ def deep_link_data
33
+ nil
34
+ end
35
+
36
+ def set_nlp(lang)
37
+ @nlp = Nlp.new(self.text,lang)
38
+ end
39
+
40
+ def nlp
41
+ @nlp
42
+ end
43
+
44
+ def deep_link_param
45
+ @data[:deep_link_param] rescue nil
46
+ end
47
+
48
+ def webhook_data
49
+ @data
50
+ end
51
+
52
+ def overwrite_postback(payload)
53
+ @overwritten_payload = payload
54
+ end
55
+
56
+ def payload(action_only=false)
57
+ if action_only
58
+ pl = self.raw_payload.split(":",2)[0] rescue nil
59
+ if pl.nil?
60
+ return pl
61
+ else
62
+ return pl.split(Regexp.union(["/","-"])).last
63
+ end
64
+ else
65
+ self.raw_payload.split(":",2)[0] rescue nil
66
+ end
67
+ end
68
+
69
+ def payload_action
70
+ self.payload(true)
71
+ end
72
+
73
+ def postback_payload
74
+ self.payload(true)
75
+ end
76
+
77
+ def postback_params
78
+ self.params
79
+ end
80
+
81
+ # def event
82
+ # JSON.parse(self.body,{:symbolize_names => true})
83
+ # end
84
+
85
+ def empty?
86
+ self.raw_payload.nil? && self.raw_message.nil? && self.attachments.nil?
87
+ end
88
+
89
+ def empty_thread_from_ad?
90
+ if self.empty?
91
+ unless self.referral.nil?
92
+ if self.referral(:source) == "ADS" and self.referral(:type) == "OPEN_THREAD"
93
+ return true
94
+ end
95
+ end
96
+ end
97
+
98
+ return false
99
+ end
100
+
101
+ def params
102
+ raw_params = self.raw_payload.to_s.split(":",2)[1].to_s
103
+ if raw_params.empty?
104
+ return({})
105
+ else
106
+ p = (JSON.parse(raw_params, {:symbolize_names => true}) rescue nil)
107
+ p = raw_params if p.nil?
108
+ return(p)
109
+ end
110
+ end
111
+
112
+ def raw_payload
113
+ # In order to implement in another platform, this function must exist
114
+ nil
115
+ end
116
+
117
+ def raw_message
118
+ # In order to implement in another platform, this function must exist
119
+ {}
120
+ end
121
+
122
+ def text
123
+ # In order to implement in another platform, this function must exist
124
+ ""
125
+ end
126
+
127
+ def numbers_in_text
128
+ # self.text.scan(/\d+/).map{|n| n.to_i}
129
+ self.text.scan(/(\d+(?:\.\d+)?)/).map{|n| n.first}
130
+ end
131
+
132
+ def location
133
+ if (self.raw_message[:type] == :location rescue false)
134
+ return self.raw_message[:value]
135
+ else
136
+ return nil
137
+ end
138
+ end
139
+
140
+ def get_context(user,msg,notification)
141
+
142
+ # Context::call_typed_postbacks(msg,user) if msg.payload.nil? && !user.vars[:typed_postbacks].nil?
143
+ # user.vars.delete(:typed_postbacks)
144
+
145
+ if !(context_from_postback = Context.get_from_payload(msg.payload)).nil?
146
+ context_route = context_from_postback
147
+ elsif !(context_from_typed_postback = Context.get_from_typed_postback(msg,user)).nil?
148
+ context_route = context_from_typed_postback
149
+ else
150
+ context_route = user.context
151
+ end
152
+
153
+ context_class = Context.router(context_route, msg.type)[:class]
154
+ if context_class.nil?
155
+ user.exit_context
156
+ context_class = Context.router(Kogno::Application.config.routes.default)[:class]
157
+ end
158
+ context = context_class.new(user,msg,notification,context_route)
159
+ context
160
+ end
161
+
162
+
163
+ def handle_event(debug=false)
164
+ # In order to implement in another platform, this function must exist
165
+ end
166
+
167
+ def log_message_info(user)
168
+ context = user.context
169
+ logger.write "\n-------- INCOMING MESSAGE -------", :yellow
170
+ logger.write "Text : \"#{self.text}\"", :yellow
171
+ unless self.params.empty?
172
+ logger.write "Payload : #{self.payload} => params: #{self.params}", :yellow
173
+ else
174
+ logger.write "Payload : #{self.payload}", :yellow
175
+ end
176
+ logger.write "User ID : #{user.psid}", :yellow
177
+ logger.write "Context : #{(context.nil? || context.empty?) ? Kogno::Application.config.routes.default : context}", :yellow
178
+ logger.write "---------------------------------\n", :yellow
179
+ end
180
+
181
+ end
182
+ end
@@ -0,0 +1,281 @@
1
+ module Kogno
2
+ module Messenger
3
+ class Api
4
+
5
+ require 'uri'
6
+ require 'net/http'
7
+ require 'json'
8
+ require 'openssl'
9
+
10
+ class << self
11
+
12
+ def request(body,access_token,type=:messages,method=:post) # :messages, :messenger_profile
13
+ url = URI("#{Kogno::Application.messenger.graph_url}/#{type}?access_token=#{access_token}")
14
+
15
+ logger.write "REQUEST TO: #{url}", :pink
16
+ logger.write "SENT: #{JSON.parse(body)}", :blue
17
+
18
+ http = Net::HTTP.new(url.host, url.port)
19
+ http.use_ssl = true
20
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
21
+
22
+ case method
23
+ when :delete
24
+ request = Net::HTTP::Delete.new(url)
25
+ else
26
+ request = Net::HTTP::Post.new(url)
27
+ end
28
+
29
+ request["content-type"] = 'application/json'
30
+
31
+ request.body = body
32
+
33
+ response = http.request(request)
34
+ # logger.debug_json JSON.parse(body), :green
35
+ response_hash = JSON.parse(response.read_body, {:symbolize_names => true})
36
+ logger.write "RESPONSE: #{response_hash}\n", :light_blue
37
+ return(response_hash)
38
+ end
39
+
40
+ def setting(body,page_id=nil)
41
+ access_token = self.get_access_token(page_id)
42
+ self.request(body,access_token,:messenger_profile)
43
+ end
44
+
45
+ def setting_delete(fields,page_id=nil)
46
+ access_token = self.get_access_token(page_id)
47
+ self.request({
48
+ fields: fields
49
+ }.to_json,access_token,:messenger_profile, :delete)
50
+ end
51
+
52
+ def send_message(recipient_psid,message,messaging_type="RESPONSE",page_id=nil)
53
+
54
+ body = {
55
+ messaging_type: messaging_type,
56
+ recipient: {
57
+ id: recipient_psid
58
+ },
59
+ message: message
60
+ }.to_json
61
+
62
+ access_token = self.get_access_token(page_id)
63
+ return(self.request(body,access_token))
64
+
65
+ end
66
+
67
+ def send_message_with_rn_token(notification_token,message,page_id=nil)
68
+
69
+ body = {
70
+ recipient: {
71
+ notification_messages_token: notification_token
72
+ },
73
+ message: message
74
+ }.to_json
75
+
76
+ access_token = self.get_access_token(page_id)
77
+ return(self.request(body,access_token))
78
+
79
+ end
80
+
81
+
82
+ def send_private_reply(recipient_id,message,page_id=nil)
83
+
84
+ body = {
85
+ :recipient => {
86
+ :comment_id => recipient_id
87
+ },
88
+ :message => message
89
+ }.to_json
90
+
91
+ access_token = self.get_access_token(page_id)
92
+ return(self.request(body,access_token))
93
+ end
94
+
95
+
96
+
97
+ def send_action(recipient_psid,action,messaging_type="RESPONSE",page_id=nil) # action => mark_seen, typing_on, typing_off
98
+ # body = %{{"recipient":{"id":"#{recipient_psid}"},"sender_action":"#{action}"}}
99
+ body = {
100
+ messaging_type: messaging_type,
101
+ recipient: {
102
+ id: recipient_psid
103
+ },
104
+ sender_action: action
105
+ }.to_json
106
+
107
+ access_token = self.get_access_token(page_id)
108
+ return(self.request(body,access_token))
109
+ end
110
+
111
+ def text_message(text)
112
+
113
+ {
114
+ :text => text
115
+ }
116
+ # return %{{"text":"#{text}"}}
117
+
118
+ end
119
+
120
+
121
+ def attachment_message(attachment)
122
+
123
+ {
124
+ attachment: attachment
125
+ }
126
+
127
+ end
128
+
129
+ def button_template(text,buttons)
130
+
131
+ attachment = {
132
+ type: :template,
133
+ payload: {
134
+ template_type: :button,
135
+ text: text,
136
+ buttons: buttons
137
+ }
138
+ }
139
+ return self.attachment_message(attachment)
140
+
141
+ end
142
+
143
+ def quick_replies(title,replies)
144
+
145
+ response = {
146
+ text: title,
147
+ quick_replies: replies
148
+ }
149
+
150
+ return response
151
+
152
+ end
153
+
154
+ def list_template(elements, buttons = [])
155
+ attachment = {
156
+ type: :template,
157
+ payload: {
158
+ template_type: :list,
159
+ top_element_style: :compact,
160
+ elements: elements,
161
+ buttons: buttons
162
+ }
163
+ }
164
+
165
+ return self.attachment_message(attachment)
166
+
167
+ end
168
+
169
+ def generic_template(elements,image_aspect_ratio=:horizontal)
170
+
171
+ elements = [elements] unless elements.class == Array
172
+
173
+ attachment = {
174
+ type: :template,
175
+ payload: {
176
+ template_type: :generic,
177
+ image_aspect_ratio: image_aspect_ratio,
178
+ elements: elements
179
+ }
180
+ }
181
+
182
+ return self.attachment_message(attachment)
183
+
184
+ end
185
+
186
+ def generic_template_with_replies(elements,image_aspect_ratio=:horizontal, quick_replies)
187
+ message = generic_template(elements,image_aspect_ratio=:horizontal)
188
+ message[:quick_replies] = quick_replies
189
+ return message
190
+ end
191
+
192
+ def show_ad_message(message)
193
+
194
+ JSON.pretty_generate(
195
+ {
196
+ message: message,
197
+ user_edit: true
198
+ }
199
+ )
200
+
201
+ end
202
+
203
+ def get_access_token(page_id=nil)
204
+
205
+ if page_id.nil?
206
+ Kogno::Application.messenger.pages.first[1][:token]
207
+ else
208
+ Kogno::Application.messenger.pages[page_id][:token] rescue nil
209
+ end
210
+
211
+ end
212
+
213
+ def persistent_menu(page_id=nil)
214
+ persistent_menu = Kogno::Application.messenger.persistent_menu
215
+ if persistent_menu.nil?
216
+ body = {
217
+ persistent_menu:[
218
+ {
219
+ locale: "default",
220
+ composer_input_disabled: false,
221
+ }
222
+ ]
223
+ }
224
+ else
225
+ body = {
226
+ persistent_menu: persistent_menu
227
+ }
228
+ end
229
+ logger.write_json body, :bright
230
+ self.setting(body.to_json, page_id)
231
+ end
232
+
233
+ def get_started_button(page_id=nil)
234
+ body = {
235
+ get_started: {
236
+ payload: Kogno::Application.messenger.welcome_screen_payload
237
+ }
238
+ }
239
+ logger.write_json body, :bright
240
+ self.setting(body.to_json, page_id)
241
+ end
242
+
243
+ def ice_breakers(page_id=nil)
244
+ body = {
245
+ ice_breakers: Kogno::Application.messenger.ice_breakers
246
+ }
247
+ logger.write_json body, :bright
248
+ self.setting(body.to_json, page_id)
249
+ end
250
+
251
+ def add_domain(domain)
252
+ body = {
253
+ whitelisted_domains: [
254
+ domain
255
+ ]
256
+ }
257
+ logger.write_json body, :bright
258
+ self.setting(body.to_json)
259
+ end
260
+
261
+ def update_whitelisted_domains
262
+ body = {
263
+ whitelisted_domains: Kogno::Application.messenger.whitelisted_domains
264
+ }
265
+ logger.write_json body, :bright
266
+ self.setting(body.to_json)
267
+ end
268
+
269
+ def greeting(page_id=nil)
270
+ body = {
271
+ greeting: Kogno::Application.messenger.greeting
272
+ }
273
+ logger.write_json body, :bright
274
+ self.setting(body.to_json, page_id)
275
+ end
276
+
277
+ end
278
+
279
+ end
280
+ end
281
+ end
@@ -0,0 +1,32 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'openssl'
4
+
5
+ module Kogno
6
+ class FacebookGraph
7
+ class << self
8
+
9
+ def fetch_user_data(psid,page_id=nil)
10
+ url = URI("https://graph.facebook.com/v3.3/#{psid}/?access_token=#{self.get_access_token(page_id)}&fields=name,first_name,last_name,timezone,locale,profile_pic")
11
+ puts url
12
+ http = Net::HTTP.new(url.host, url.port)
13
+ http.use_ssl = true
14
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
15
+ request = Net::HTTP::Get.new(url)
16
+ response = http.request(request)
17
+ return(JSON.parse(response.read_body, {:symbolize_names => true}))
18
+ end
19
+
20
+ def get_access_token(page_id=nil)
21
+ if page_id.nil?
22
+ Kogno::Application.messenger.pages.first[1][:token]
23
+ else
24
+ Kogno::Application.messenger.pages[page_id][:token] rescue nil
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+
31
+ end
32
+ end