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,197 @@
|
|
1
|
+
module Kogno
|
2
|
+
module Telegram
|
3
|
+
|
4
|
+
class Api
|
5
|
+
|
6
|
+
require 'uri'
|
7
|
+
require 'net/http'
|
8
|
+
require 'openssl'
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def request(body,type,method=:post) # :messages, :messenger_profile
|
13
|
+
|
14
|
+
url = URI("#{Kogno::Application.config.telegram.api_url}/#{Kogno::Application.config.telegram.token}/#{type}")
|
15
|
+
|
16
|
+
logger.write "REQUEST TO: #{url}", :pink
|
17
|
+
logger.write "SENT: #{JSON.parse(body)}", :blue
|
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
|
+
case method
|
24
|
+
when :delete
|
25
|
+
request = Net::HTTP::Delete.new(url)
|
26
|
+
else
|
27
|
+
request = Net::HTTP::Post.new(url)
|
28
|
+
end
|
29
|
+
|
30
|
+
request["content-type"] = 'application/json'
|
31
|
+
|
32
|
+
request.body = body
|
33
|
+
|
34
|
+
response = http.request(request)
|
35
|
+
# logger.debug_json JSON.parse(body), :green
|
36
|
+
response_hash = JSON.parse(response.read_body, {:symbolize_names => true})
|
37
|
+
logger.write "RESPONSE: #{response_hash}\n", :light_blue
|
38
|
+
return(response_hash)
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_webhook(webhook, drop_pending_updates=true)
|
43
|
+
body = {
|
44
|
+
url: webhook,
|
45
|
+
drop_pending_updates: drop_pending_updates
|
46
|
+
}
|
47
|
+
logger.write_json body, :blue
|
48
|
+
request(body.to_json, "setWebhook")
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete_webhook(drop_pending_updates=true)
|
52
|
+
request(
|
53
|
+
{
|
54
|
+
drop_pending_updates: drop_pending_updates
|
55
|
+
}.to_json,
|
56
|
+
"deleteWebhook"
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
def send(recipient_id,message, type="sendMessage")
|
61
|
+
body = {
|
62
|
+
chat_id: recipient_id
|
63
|
+
}.merge(message).to_json
|
64
|
+
|
65
|
+
return(self.request(body,type))
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def answer_inline_query(inline_query_id, results, extra_params={})
|
70
|
+
body = {
|
71
|
+
inline_query_id: inline_query_id,
|
72
|
+
results: results
|
73
|
+
}.merge(extra_params)
|
74
|
+
logger.write_json body, :blue
|
75
|
+
return(self.request(body.to_json,"answerInlineQuery"))
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_commands(commands,scope, lang=nil)
|
80
|
+
valid_scopes = self.command_valid_scopes
|
81
|
+
raise "Error, invalid scope. Must be one of these: #{valid_scopes.join(",")}" unless valid_scopes.include?(scope)
|
82
|
+
body = {
|
83
|
+
commands: commands.map{|command, description| {command: command, description: description}},
|
84
|
+
scope: {
|
85
|
+
type: scope
|
86
|
+
}
|
87
|
+
}
|
88
|
+
body[:language_code] = lang unless lang.nil?
|
89
|
+
logger.write "SET COMMAND"
|
90
|
+
logger.write_json body, :blue
|
91
|
+
return(self.request(body.to_json, "setMyCommands"))
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_all_commands
|
95
|
+
Kogno::Application.config.telegram.commands.each do |conf|
|
96
|
+
set_commands(conf[:commands], conf[:scope], conf[:lang])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def set_scope_commands(scope)
|
101
|
+
Kogno::Application.config.telegram.commands.each do |conf|
|
102
|
+
set_commands(conf[:commands], conf[:scope], conf[:lang]) if scope == conf[:scope]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def delete_commands(scope, lang=nil)
|
107
|
+
body = {
|
108
|
+
scope: {
|
109
|
+
type: scope
|
110
|
+
}
|
111
|
+
}
|
112
|
+
body[:language_code] = lang unless lang.nil?
|
113
|
+
logger.write "DELETE COMMAND"
|
114
|
+
logger.write_json body, :blue
|
115
|
+
return(self.request(body.to_json, "deleteMyCommands"))
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def command_valid_scopes
|
120
|
+
[:default, :all_private_chats, :all_group_chats, :all_chat_administrators]
|
121
|
+
end
|
122
|
+
|
123
|
+
def answer_callback_query(callback_query_id, params={})
|
124
|
+
body = {
|
125
|
+
callback_query_id: callback_query_id
|
126
|
+
}.merge(params).to_json
|
127
|
+
return(self.request(body,"answerCallbackQuery"))
|
128
|
+
end
|
129
|
+
|
130
|
+
def text(text, settings={})
|
131
|
+
|
132
|
+
result = {
|
133
|
+
:text => text
|
134
|
+
}
|
135
|
+
|
136
|
+
result = result.merge(self.add_remove_keyboard_reply_markup) if settings[:remove_keyboard]
|
137
|
+
|
138
|
+
result
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
def inline_keyboard_markup(text,replies, update={})
|
143
|
+
|
144
|
+
result = {
|
145
|
+
text: text,
|
146
|
+
disable_web_page_preview: true,
|
147
|
+
reply_markup: {
|
148
|
+
inline_keyboard: replies.first.class == Array ? replies : [replies] # needs to be an array of arrays
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
result = result.merge(update) unless update.nil?
|
153
|
+
|
154
|
+
result
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
def add_inline_keyboard_markup(replies)
|
159
|
+
{
|
160
|
+
reply_markup: {
|
161
|
+
inline_keyboard: replies # needs to be an array of arrays
|
162
|
+
}
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
def keyboard(text, buttons, one_time_keyboard=true) #type can be: :contact or :location
|
167
|
+
{
|
168
|
+
text: text,
|
169
|
+
disable_web_page_preview: true,
|
170
|
+
reply_markup: {
|
171
|
+
keyboard: buttons.first.class == Array ? buttons : [buttons], # needs to be an array of arrays
|
172
|
+
one_time_keyboard: one_time_keyboard
|
173
|
+
}
|
174
|
+
}
|
175
|
+
end
|
176
|
+
|
177
|
+
protected
|
178
|
+
|
179
|
+
def add_remove_keyboard_reply_markup
|
180
|
+
{
|
181
|
+
reply_markup: {
|
182
|
+
remove_keyboard: true
|
183
|
+
}
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
def add_reply_markup(settings)
|
188
|
+
reply_markup = {}
|
189
|
+
reply_markup[:inline_keyboard] = settings[:inline_keyboard]
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Kogno
|
2
|
+
module Telegram
|
3
|
+
class ChatActivity
|
4
|
+
|
5
|
+
def initialize(data)
|
6
|
+
@data = data
|
7
|
+
end
|
8
|
+
|
9
|
+
def type
|
10
|
+
:chat_activity
|
11
|
+
end
|
12
|
+
|
13
|
+
def chat
|
14
|
+
@data[:chat]
|
15
|
+
end
|
16
|
+
|
17
|
+
def chat_id
|
18
|
+
@data[:chat][:id]
|
19
|
+
end
|
20
|
+
|
21
|
+
def chat_title
|
22
|
+
@data[:chat][:title]
|
23
|
+
end
|
24
|
+
|
25
|
+
def chat_type
|
26
|
+
@data[:chat][:type]
|
27
|
+
end
|
28
|
+
|
29
|
+
def inviter_user_id
|
30
|
+
@data[:from][:id]
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_kgn_id
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def chat_perms
|
38
|
+
perms = @data[:new_chat_member]
|
39
|
+
{
|
40
|
+
can_be_edited: perms[:can_be_edited],
|
41
|
+
can_manage_chat: perms[:can_be_edited],
|
42
|
+
can_change_info: perms[:can_be_edited],
|
43
|
+
can_post_messages: perms[:can_be_edited],
|
44
|
+
can_edit_messages: perms[:can_be_edited],
|
45
|
+
can_delete_messages: perms[:can_be_edited],
|
46
|
+
can_invite_users: perms[:can_be_edited],
|
47
|
+
can_restrict_members: perms[:can_be_edited],
|
48
|
+
can_promote_members: perms[:can_be_edited],
|
49
|
+
can_manage_voice_chats: perms[:can_be_edited]
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def chat_membership_status
|
54
|
+
if ["member","administrator"].include?(@data[:new_chat_member][:status])
|
55
|
+
return true
|
56
|
+
elsif ["left","kicked"].include?(@data[:new_chat_member][:status])
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_context(user,notification, notification_group,chat=nil)
|
62
|
+
# Here you can use different contexts by self.post_id
|
63
|
+
context_class = Context::router(Kogno::Application.config.routes.chat_activity)[:class]
|
64
|
+
context_route = :main
|
65
|
+
context = context_class.new(user,self,notification,context_route, notification_group, chat)
|
66
|
+
return(context)
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_event(debug=false)
|
70
|
+
|
71
|
+
begin
|
72
|
+
|
73
|
+
user = User.find_or_create_by_psid(self.inviter_user_id, :telegram)
|
74
|
+
self.set_nlp(user.locale)
|
75
|
+
I18n.locale = user.locale unless user.locale.nil?
|
76
|
+
notification = Notification.new(user,self)
|
77
|
+
chat = TelegramChatGroup.find_or_create({
|
78
|
+
chat_id: self.chat_id,
|
79
|
+
title: self.chat_title,
|
80
|
+
kind: self.chat_type,
|
81
|
+
inviter_user_id: user.id,
|
82
|
+
membership: self.chat_membership_status
|
83
|
+
})
|
84
|
+
|
85
|
+
notification = Notification.new(user,self)
|
86
|
+
notification_group = Notification.new(chat,self)
|
87
|
+
|
88
|
+
context = get_context(user,notification, notification_group, chat)
|
89
|
+
context.run_for_chat_activity_only
|
90
|
+
|
91
|
+
notification.send
|
92
|
+
notification_group.send
|
93
|
+
|
94
|
+
if Kogno::Application.config.store_log_in_database
|
95
|
+
user.log_message(self, :chat_activity_received)
|
96
|
+
user.log_response(notification)
|
97
|
+
end
|
98
|
+
|
99
|
+
rescue StandardError => e
|
100
|
+
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
|
101
|
+
logger.write e.message, :red
|
102
|
+
logger.write "Error Token: #{error_token}", :red
|
103
|
+
logger.write "Backtrace:\n\t#{e.backtrace.join("\n\t")}", :red
|
104
|
+
ErrorHandler.notify_by_slack(Kogno::Application.config.app_name,e, error_token) if Kogno::Application.config.error_notifier.slack[:enable] rescue false
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Kogno
|
2
|
+
module Telegram
|
3
|
+
class InlineQuery < Kogno::Message
|
4
|
+
|
5
|
+
attr_accessor :event
|
6
|
+
|
7
|
+
@overwritten_payload = nil
|
8
|
+
|
9
|
+
def initialize(data)
|
10
|
+
@data = data
|
11
|
+
end
|
12
|
+
|
13
|
+
def type
|
14
|
+
:inline_query
|
15
|
+
end
|
16
|
+
|
17
|
+
def platform
|
18
|
+
:telegram
|
19
|
+
end
|
20
|
+
|
21
|
+
def page_id
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def chat_type
|
26
|
+
@data[:chat_type]
|
27
|
+
end
|
28
|
+
|
29
|
+
def id
|
30
|
+
return @data[:id]
|
31
|
+
end
|
32
|
+
|
33
|
+
def sender_id
|
34
|
+
return @data[:from][:id]
|
35
|
+
end
|
36
|
+
|
37
|
+
def sender_first_name
|
38
|
+
return @data[:from][:first_name] rescue ""
|
39
|
+
end
|
40
|
+
|
41
|
+
def sender_last_name
|
42
|
+
return @data[:from][:last_name] rescue ""
|
43
|
+
end
|
44
|
+
|
45
|
+
def payload_action
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def empty?
|
50
|
+
self.text.to_s.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def text
|
55
|
+
return (@data[:query].to_s rescue "")
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_context(user,notification)
|
59
|
+
# Here you can use different contexts by self.post_id
|
60
|
+
context_class = Context::router(Kogno::Application.config.routes.inline_query)[:class]
|
61
|
+
context = context_class.new(user,self,notification,nil, nil, user)
|
62
|
+
return(context)
|
63
|
+
end
|
64
|
+
|
65
|
+
def handle_event(debug=false)
|
66
|
+
|
67
|
+
begin
|
68
|
+
|
69
|
+
user = User.find_or_create_by_psid(self.sender_id, :telegram)
|
70
|
+
user.first_name = self.sender_first_name
|
71
|
+
user.last_name = self.sender_last_name
|
72
|
+
user.save
|
73
|
+
|
74
|
+
self.set_nlp(user.locale)
|
75
|
+
I18n.locale = user.locale unless user.locale.nil?
|
76
|
+
|
77
|
+
notification = Notification.new(user,self)
|
78
|
+
|
79
|
+
logger.write "--------------------MESSAGE: #{self.text}--------------------------", :green
|
80
|
+
|
81
|
+
context = get_context(user,notification)
|
82
|
+
|
83
|
+
return({post_comment: self, user: user, notification: notification, context: context}) if debug
|
84
|
+
|
85
|
+
context.run_for_text_only
|
86
|
+
|
87
|
+
notification.answer_inline_query(self.id, self.sender_id)
|
88
|
+
|
89
|
+
recipient_psid = notification.get_psid_from_response_log
|
90
|
+
|
91
|
+
user = User.find_or_create_by_psid(self.sender_id, :telegram)
|
92
|
+
|
93
|
+
if Kogno::Application.config.store_log_in_database
|
94
|
+
user.log_message(self, :inline_query_received)
|
95
|
+
user.log_response(notification)
|
96
|
+
end
|
97
|
+
|
98
|
+
logger.write "**********************#{user.context}***********************", :green
|
99
|
+
|
100
|
+
rescue StandardError => e
|
101
|
+
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
|
102
|
+
logger.write e.message, :red
|
103
|
+
logger.write "Error Token: #{error_token}", :red
|
104
|
+
logger.write "Backtrace:\n\t#{e.backtrace.join("\n\t")}", :red
|
105
|
+
ErrorHandler.notify_by_slack(Kogno::Application.config.app_name,e, error_token) if Kogno::Application.config.error_notifier.slack[:enable] rescue false
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|