slack-smart-bot 1.13.1 → 1.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +100 -4
- data/lib/slack/smart-bot/ai/open_ai/connect.rb +61 -0
- data/lib/slack/smart-bot/ai/open_ai/models.rb +21 -0
- data/lib/slack/smart-bot/ai/open_ai/send_gpt_chat.rb +24 -0
- data/lib/slack/smart-bot/ai/open_ai/send_image_edit.rb +23 -0
- data/lib/slack/smart-bot/ai/open_ai/send_image_generation.rb +18 -0
- data/lib/slack/smart-bot/ai/open_ai/send_image_variation.rb +22 -0
- data/lib/slack/smart-bot/ai/open_ai/whisper_transcribe.rb +21 -0
- data/lib/slack/smart-bot/ai.rb +8 -0
- data/lib/slack/smart-bot/comm/get_channel_members.rb +15 -13
- data/lib/slack/smart-bot/comm/get_channels.rb +31 -29
- data/lib/slack/smart-bot/comm/respond_thread.rb +2 -2
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat.rb +40 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_edit_image.rb +66 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_generate_image.rb +65 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_models.rb +37 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_variations_image.rb +84 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_whisper.rb +51 -0
- data/lib/slack/smart-bot/commands/general/bot_help.rb +1 -0
- data/lib/slack/smart-bot/commands/general/personal_settings.rb +38 -0
- data/lib/slack/smart-bot/commands/general/poster.rb +107 -104
- data/lib/slack/smart-bot/commands/general/public_holidays.rb +116 -114
- data/lib/slack/smart-bot/commands/general/set_public_holidays.rb +6 -2
- data/lib/slack/smart-bot/commands/general/teams/add_team.rb +87 -0
- data/lib/slack/smart-bot/commands/general/teams/delete_team.rb +69 -0
- data/lib/slack/smart-bot/commands/general/teams/memos/add_memo_team.rb +136 -0
- data/lib/slack/smart-bot/commands/general/teams/memos/add_memo_team_comment.rb +37 -0
- data/lib/slack/smart-bot/commands/general/teams/memos/delete_memo_team.rb +83 -0
- data/lib/slack/smart-bot/commands/general/teams/memos/see_memo_team.rb +97 -0
- data/lib/slack/smart-bot/commands/general/teams/memos/see_memos_team.rb +304 -0
- data/lib/slack/smart-bot/commands/general/teams/memos/set_memo_status.rb +66 -0
- data/lib/slack/smart-bot/commands/general/teams/ping_team.rb +104 -0
- data/lib/slack/smart-bot/commands/general/teams/see_teams.rb +236 -0
- data/lib/slack/smart-bot/commands/general/teams/see_vacations_team.rb +183 -0
- data/lib/slack/smart-bot/commands/general/teams/update_team.rb +137 -0
- data/lib/slack/smart-bot/commands/general_bot_commands.rb +905 -741
- data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +379 -353
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +87 -189
- data/lib/slack/smart-bot/commands/on_bot/repl_client.rb +233 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +17 -4
- data/lib/slack/smart-bot/commands.rb +26 -10
- data/lib/slack/smart-bot/process.rb +14 -3
- data/lib/slack/smart-bot/process_first.rb +36 -2
- data/lib/slack/smart-bot/treat_message.rb +28 -0
- data/lib/slack/smart-bot/utils/check_vacations.rb +1 -0
- data/lib/slack/smart-bot/utils/create_routine_thread.rb +1 -1
- data/lib/slack/smart-bot/utils/display_calendar.rb +17 -10
- data/lib/slack/smart-bot/utils/encryption/decrypt.rb +23 -0
- data/lib/slack/smart-bot/utils/encryption/encrypt.rb +27 -0
- data/lib/slack/smart-bot/utils/{encryption_get_key_iv.rb → encryption/encryption_get_key_iv.rb} +12 -8
- data/lib/slack/smart-bot/utils/get_help.rb +3 -1
- data/lib/slack/smart-bot/utils/get_personal_settings.rb +14 -0
- data/lib/slack/smart-bot/utils/get_teams.rb +2 -2
- data/lib/slack/smart-bot/utils/get_vacations.rb +2 -2
- data/lib/slack/smart-bot/utils/save_stats.rb +3 -1
- data/lib/slack/smart-bot/utils/update_personal_settings.rb +18 -0
- data/lib/slack/smart-bot/utils/update_teams.rb +1 -1
- data/lib/slack/smart-bot/utils/update_vacations.rb +1 -1
- data/lib/slack/smart-bot/utils.rb +5 -3
- data/lib/slack-smart-bot.rb +12 -0
- data/whats_new.txt +13 -14
- metadata +63 -15
- data/lib/slack/smart-bot/commands/general/add_memo_team.rb +0 -117
- data/lib/slack/smart-bot/commands/general/add_team.rb +0 -81
- data/lib/slack/smart-bot/commands/general/delete_memo_team.rb +0 -69
- data/lib/slack/smart-bot/commands/general/delete_team.rb +0 -55
- data/lib/slack/smart-bot/commands/general/ping_team.rb +0 -100
- data/lib/slack/smart-bot/commands/general/see_memos_team.rb +0 -202
- data/lib/slack/smart-bot/commands/general/see_teams.rb +0 -230
- data/lib/slack/smart-bot/commands/general/see_vacations_team.rb +0 -136
- data/lib/slack/smart-bot/commands/general/set_memo_status.rb +0 -58
- data/lib/slack/smart-bot/commands/general/update_team.rb +0 -131
- data/lib/slack/smart-bot/utils/decrypt.rb +0 -15
- data/lib/slack/smart-bot/utils/encrypt.rb +0 -15
@@ -4,12 +4,13 @@ class SlackSmartBot
|
|
4
4
|
# helpadmin: `exit bot`
|
5
5
|
# helpadmin: `quit bot`
|
6
6
|
# helpadmin: `close bot`
|
7
|
+
# helpadmin: `exit bot silent`
|
7
8
|
# helpadmin: The bot stops running and also stops all the bots created from this master channel
|
8
9
|
# helpadmin: You can use this command only if you are an admin user and you are on the master channel
|
9
10
|
# helpadmin: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
|
10
11
|
# helpadmin: command_id: :exit_bot
|
11
12
|
# helpadmin:
|
12
|
-
def exit_bot(command, from, dest, display_name)
|
13
|
+
def exit_bot(command, from, dest, display_name, silent: false)
|
13
14
|
save_stats(__method__)
|
14
15
|
if config.on_master_bot
|
15
16
|
if config.masters.include?(from) #admin user
|
@@ -18,21 +19,33 @@ class SlackSmartBot
|
|
18
19
|
else
|
19
20
|
case answer
|
20
21
|
when /yes/i, /yep/i, /sure/i
|
21
|
-
|
22
|
-
respond "Ciao #{display_name}!", dest
|
22
|
+
react :runner
|
23
23
|
@bots_created.each { |key, value|
|
24
24
|
value[:thread] = ""
|
25
|
-
send_msg_channel(key, "Bot has been closed by #{from}")
|
25
|
+
send_msg_channel(key, "Bot has been closed by #{from}") unless silent
|
26
26
|
save_status :off, :exited, "The admin closed SmartBot on *##{value.channel_name}*"
|
27
27
|
sleep 0.5
|
28
28
|
}
|
29
29
|
update_bots_file()
|
30
30
|
sleep 0.5
|
31
|
+
file = File.open("#{config.path}/config_tmp.status", "w")
|
32
|
+
config.exit_bot = true
|
33
|
+
file.write config.inspect
|
34
|
+
file.close
|
35
|
+
@status = :exit
|
36
|
+
respond "Game over!", dest
|
31
37
|
if config.simulate
|
38
|
+
sleep 2
|
32
39
|
@status = :off
|
33
40
|
config.simulate = false
|
34
41
|
Thread.exit
|
35
42
|
else
|
43
|
+
respond 'Ok, It will take around 40s to close all the bots, all routines and the master bot.'
|
44
|
+
sleep 35
|
45
|
+
respond "Ciao #{display_name}!", dest
|
46
|
+
unreact :runner
|
47
|
+
react :beach_with_umbrella
|
48
|
+
sleep 1
|
36
49
|
exit!
|
37
50
|
end
|
38
51
|
when /no/i, /nope/i, /cancel/i
|
@@ -4,6 +4,7 @@ require_relative "commands/general/bot_help"
|
|
4
4
|
require_relative "commands/on_bot/general/suggest_command"
|
5
5
|
require_relative "commands/on_bot/ruby_code"
|
6
6
|
require_relative "commands/on_bot/repl"
|
7
|
+
require_relative "commands/on_bot/repl_client"
|
7
8
|
require_relative "commands/on_bot/get_repl"
|
8
9
|
require_relative "commands/on_bot/run_repl"
|
9
10
|
require_relative "commands/on_bot/kill_repl"
|
@@ -60,18 +61,33 @@ require_relative "commands/general/poster"
|
|
60
61
|
require_relative "commands/general/see_access"
|
61
62
|
require_relative "commands/general/allow_access"
|
62
63
|
require_relative "commands/general/deny_access"
|
63
|
-
require_relative "commands/general/add_team"
|
64
|
-
require_relative "commands/general/add_memo_team"
|
65
|
-
require_relative "commands/general/set_memo_status"
|
66
|
-
require_relative "commands/general/delete_memo_team"
|
67
|
-
require_relative "commands/general/see_memos_team"
|
68
|
-
require_relative "commands/general/see_teams"
|
69
|
-
require_relative "commands/general/update_team"
|
70
|
-
require_relative "commands/general/ping_team"
|
71
|
-
require_relative "commands/general/delete_team"
|
64
|
+
require_relative "commands/general/teams/add_team"
|
65
|
+
require_relative "commands/general/teams/memos/add_memo_team"
|
66
|
+
require_relative "commands/general/teams/memos/set_memo_status"
|
67
|
+
require_relative "commands/general/teams/memos/delete_memo_team"
|
68
|
+
require_relative "commands/general/teams/memos/see_memos_team"
|
69
|
+
require_relative "commands/general/teams/see_teams"
|
70
|
+
require_relative "commands/general/teams/update_team"
|
71
|
+
require_relative "commands/general/teams/ping_team"
|
72
|
+
require_relative "commands/general/teams/delete_team"
|
72
73
|
require_relative "commands/general/add_vacation"
|
73
74
|
require_relative "commands/general/remove_vacation"
|
74
75
|
require_relative "commands/general/see_vacations"
|
75
|
-
require_relative "commands/general/see_vacations_team"
|
76
|
+
require_relative "commands/general/teams/see_vacations_team"
|
76
77
|
require_relative "commands/general/public_holidays"
|
77
78
|
require_relative "commands/general/set_public_holidays"
|
79
|
+
require_relative "commands/general/personal_settings"
|
80
|
+
require_relative "commands/general/teams/memos/add_memo_team_comment"
|
81
|
+
require_relative "commands/general/teams/memos/see_memo_team"
|
82
|
+
require_relative 'commands/general/ai/open_ai/open_ai_chat'
|
83
|
+
require_relative 'commands/general/ai/open_ai/open_ai_generate_image'
|
84
|
+
require_relative 'commands/general/ai/open_ai/open_ai_variations_image'
|
85
|
+
require_relative 'commands/general/ai/open_ai/open_ai_edit_image'
|
86
|
+
require_relative 'commands/general/ai/open_ai/open_ai_models'
|
87
|
+
require_relative 'commands/general/ai/open_ai/open_ai_whisper'
|
88
|
+
|
89
|
+
class SlackSmartBot
|
90
|
+
include SlackSmartBot::Commands::General::AI::OpenAI
|
91
|
+
include SlackSmartBot::Commands::General::Teams
|
92
|
+
include SlackSmartBot::Commands::General::Teams::Memos
|
93
|
+
end
|
@@ -74,8 +74,9 @@ class SlackSmartBot
|
|
74
74
|
/\A\s*use\s+rules\s+(on\s+)(.+)/i
|
75
75
|
channel = $2
|
76
76
|
extend_rules(dest, user, from, channel, typem)
|
77
|
-
when /\A\s*exit\s+bot\s*$/i, /\A\s*quit\s+bot\s*$/i, /\A\s*close\s+bot\s*$/i
|
78
|
-
|
77
|
+
when /\A\s*exit\s+bot(\s+silent)?\s*$/i, /\A\s*quit\s+bot(\s+silent)?\s*$/i, /\A\s*close\s+bot(\s+silent)?\s*$/i
|
78
|
+
silent = $1.to_s != ''
|
79
|
+
exit_bot(command, from, dest, display_name, silent: silent)
|
79
80
|
when /\A\s*start\s+(this\s+)?bot$/i
|
80
81
|
start_bot(dest, from)
|
81
82
|
when /\A\s*pause\s+(this\s+)?bot$/i
|
@@ -327,13 +328,23 @@ class SlackSmartBot
|
|
327
328
|
opts.gsub!(/\s+routines$/,'')
|
328
329
|
opts.gsub!(/\s+routines\s+/,'')
|
329
330
|
end
|
331
|
+
only_graph = all_opts.include?('graph')
|
332
|
+
|
330
333
|
monthly = false
|
334
|
+
type_group = ''
|
331
335
|
if all_opts.include?('today')
|
332
336
|
st_from = st_to = "#{Time.now.strftime("%Y-%m-%d")}"
|
333
337
|
elsif all_opts.include?('yesterday')
|
334
338
|
st_from = st_to = "#{(Time.now-86400).strftime("%Y-%m-%d")}"
|
335
339
|
elsif all_opts.include?('monthly')
|
336
340
|
monthly = true
|
341
|
+
type_group = :monthly
|
342
|
+
elsif all_opts.include?('weekly')
|
343
|
+
type_group = :weekly
|
344
|
+
elsif all_opts.include?('daily')
|
345
|
+
type_group = :daily
|
346
|
+
elsif all_opts.include?('yearly')
|
347
|
+
type_group = :yearly
|
337
348
|
end
|
338
349
|
if this_month
|
339
350
|
st_from = "#{Date.today.strftime("%Y-%m-01")}"
|
@@ -379,7 +390,7 @@ class SlackSmartBot
|
|
379
390
|
header << r[0]
|
380
391
|
regexp << r[1]
|
381
392
|
end
|
382
|
-
bot_stats(dest, user, typem, st_channel, st_from, st_to, st_user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data, members_channel, exclude_members_channel, header, regexp)
|
393
|
+
bot_stats(dest, user, typem, st_channel, st_from, st_to, st_user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data, members_channel, exclude_members_channel, header, regexp, type_group: type_group, only_graph: only_graph)
|
383
394
|
when /\A(set|turn)\s+maintenance\s+(on|off)\s*()\z/im, /\A(set|turn)\s+maintenance\s+(on)\s*(.+)\s*\z/im
|
384
395
|
status = $2.downcase
|
385
396
|
message = $3.to_s
|
@@ -26,6 +26,15 @@ class SlackSmartBot
|
|
26
26
|
else
|
27
27
|
respond "Only the creator of the loop or an admin can stop the loop.", dest, thread_ts: thread_ts
|
28
28
|
end
|
29
|
+
if Thread.current.key?(:encrypted) and Thread.current[:encrypted].size > 0
|
30
|
+
found = false
|
31
|
+
Thread.current[:encrypted].each do |encdata|
|
32
|
+
found = true if !found and text.include?(encdata)
|
33
|
+
text.gsub!(encdata, "********")
|
34
|
+
end
|
35
|
+
text = "********" if !found
|
36
|
+
text+= " (encrypted #{Thread.current[:command_id]})"
|
37
|
+
end
|
29
38
|
@logger.info "command: #{nick}> #{text}"
|
30
39
|
return :next #jal
|
31
40
|
end
|
@@ -306,7 +315,20 @@ class SlackSmartBot
|
|
306
315
|
end
|
307
316
|
processed = (processed || general_bot_commands(user, command_thread, dest, files))
|
308
317
|
processed = (processed || general_commands(user, command_thread, dest, files)) if defined?(general_commands)
|
309
|
-
|
318
|
+
if processed
|
319
|
+
text_to_log = command_thread.dup
|
320
|
+
|
321
|
+
if Thread.current.key?(:encrypted) and Thread.current[:encrypted].size > 0
|
322
|
+
found = false
|
323
|
+
Thread.current[:encrypted].each do |encdata|
|
324
|
+
found = true if !found and text_to_log.include?(encdata)
|
325
|
+
text_to_log.gsub!(encdata, "********")
|
326
|
+
end
|
327
|
+
text_to_log = "********" if !found
|
328
|
+
text_to_log+= " (encrypted #{Thread.current[:command_id]})"
|
329
|
+
end
|
330
|
+
@logger.info "command: #{nick}> #{text_to_log}"
|
331
|
+
end
|
310
332
|
end
|
311
333
|
|
312
334
|
if !config.on_maintenance and !processed and typem != :on_pub and typem != :on_pg
|
@@ -319,7 +341,19 @@ class SlackSmartBot
|
|
319
341
|
((@listening[nick].key?(dest) and !Thread.current[:on_thread]) or
|
320
342
|
(@listening[nick].key?(thread_ts) and Thread.current[:on_thread]))) or
|
321
343
|
dest[0] == "D" or on_demand)
|
322
|
-
|
344
|
+
unless processed
|
345
|
+
text_to_log = command_thread.dup
|
346
|
+
found = false
|
347
|
+
if Thread.current.key?(:encrypted) and Thread.current[:encrypted].size > 0
|
348
|
+
Thread.current[:encrypted].each do |encdata|
|
349
|
+
found = true if !found and text_to_log.include?(encdata)
|
350
|
+
text_to_log.gsub!(encdata, "********")
|
351
|
+
end
|
352
|
+
text_to_log = "********" if !found
|
353
|
+
text_to_log+= " (encrypted #{Thread.current[:command_id]})"
|
354
|
+
end
|
355
|
+
@logger.info "command: #{nick}> #{text_to_log}"
|
356
|
+
end
|
323
357
|
#todo: verify this
|
324
358
|
|
325
359
|
if dest[0] == "C" or dest[0] == "G" or (dest[0] == "D" and typem == :on_call)
|
@@ -71,6 +71,16 @@ class SlackSmartBot
|
|
71
71
|
if !data.files.nil? and data.files.size == 1 and data.text.to_s == "" and data.files[0].filetype == "ruby"
|
72
72
|
data.text = "ruby"
|
73
73
|
end
|
74
|
+
|
75
|
+
#open ai chat gpt and shared messages as an input
|
76
|
+
if data.text.match?(/\A\s*(^|!!|!)?\s*(\?|\?\?)\s*/im) and !data.attachments.nil? and data.attachments.size > 0 and !data.attachments[0].text.nil? and data.attachments[0].text != ''
|
77
|
+
data.attachments.each_with_index do |att, i|
|
78
|
+
if !att.text.nil? and att.text != ''
|
79
|
+
data.text += "\n#{att.text}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
74
84
|
if !dest.nil? and config.on_master_bot and !data.text.nil? and data.text.match(/^ping from (.+)\s*$/) and data.user == config[:nick_id]
|
75
85
|
@pings << $1
|
76
86
|
end
|
@@ -355,6 +365,24 @@ class SlackSmartBot
|
|
355
365
|
if File.exist?("#{config.path}/shortcuts/shortcuts_global.yaml")
|
356
366
|
@shortcuts_global = YAML.load(File.read("#{config.path}/shortcuts/shortcuts_global.yaml"))
|
357
367
|
end
|
368
|
+
when /\AGame\s+over!\z/i
|
369
|
+
sleep 2
|
370
|
+
get_bots_created()
|
371
|
+
if File.exist?("#{config.path}/config_tmp.status")
|
372
|
+
file_cts = IO.readlines("#{config.path}/config_tmp.status").join
|
373
|
+
unless file_cts.to_s() == ""
|
374
|
+
file_cts = eval(file_cts)
|
375
|
+
if file_cts.is_a?(Hash) and file_cts.key?(:exit_bot)
|
376
|
+
config.exit_bot = file_cts.exit_bot
|
377
|
+
end
|
378
|
+
@status = :exit if config.exit_bot
|
379
|
+
end
|
380
|
+
end
|
381
|
+
if @status == :exit
|
382
|
+
@logger.info 'Game over!'
|
383
|
+
sleep 3
|
384
|
+
exit!
|
385
|
+
end
|
358
386
|
end
|
359
387
|
end
|
360
388
|
end
|
@@ -2,7 +2,7 @@ class SlackSmartBot
|
|
2
2
|
|
3
3
|
def create_routine_thread(name, hroutine)
|
4
4
|
t = Thread.new do
|
5
|
-
while @routines.key?(@channel_id) and @routines[@channel_id].key?(name)
|
5
|
+
while @routines.key?(@channel_id) and @routines[@channel_id].key?(name) and @status != :exit
|
6
6
|
@routines[@channel_id][name][:thread] = Thread.current
|
7
7
|
started = Time.now
|
8
8
|
if @status == :on and @routines[@channel_id][name][:status] == :on
|
@@ -1,15 +1,18 @@
|
|
1
1
|
class SlackSmartBot
|
2
|
-
def display_calendar(from_user_name, year)
|
2
|
+
def display_calendar(from_user_name, year, country_region: '')
|
3
3
|
if @vacations.key?(from_user_name) and @vacations[from_user_name][:public_holidays].to_s != ""
|
4
4
|
country_region = @vacations[from_user_name][:public_holidays].downcase
|
5
|
-
elsif config[:public_holidays].key?(:default_calendar)
|
5
|
+
elsif config[:public_holidays].key?(:default_calendar) and country_region.empty?
|
6
6
|
country_region = config[:public_holidays][:default_calendar].downcase
|
7
|
-
else
|
8
|
-
country_region = ""
|
9
7
|
end
|
8
|
+
|
10
9
|
country, location = country_region.split("/")
|
11
10
|
public_holidays(country.to_s, location.to_s, year, "", "", add_stats: false, publish_results: false)
|
12
|
-
|
11
|
+
if from_user_name.empty?
|
12
|
+
messages = ["*Calendar #{year} #{country_region}*"]
|
13
|
+
else
|
14
|
+
messages = ["*Time off #{year}*"]
|
15
|
+
end
|
13
16
|
days_of_vacations = 0
|
14
17
|
(1..12).each do |m|
|
15
18
|
date = Date.parse("#{year}/#{m}/1")
|
@@ -74,13 +77,17 @@ class SlackSmartBot
|
|
74
77
|
end
|
75
78
|
messages << "#{month_line} #{month_name}\n"
|
76
79
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
+
if !from_user_name.empty?
|
81
|
+
messages << "\n\n:large_yellow_square: weekend / :white_square: weekday / :white_small_square: not in month / :large_red_square: Public Holiday / :palm_tree: Vacation / :face_with_thermometer: Sick / :baby: Sick child"
|
82
|
+
if country_region != ""
|
83
|
+
messages << "Your public holidays are set for #{country_region.downcase}. Call `set public holidays to COUNTRY/REGION` if you want to change it.\n"
|
84
|
+
else
|
85
|
+
messages << "Your public holidays are not set. Call `set public holidays to COUNTRY/REGION` to set it.\n"
|
86
|
+
end
|
87
|
+
messages << "You have spent #{days_of_vacations} days of vacations in #{year} considering only weekdays.\n\n"
|
80
88
|
else
|
81
|
-
messages << "
|
89
|
+
messages << "\n\n:large_yellow_square: weekend / :white_square: weekday / :white_small_square: not in month / :large_red_square: Public Holiday"
|
82
90
|
end
|
83
|
-
messages << "You have spent #{days_of_vacations} days of vacations in #{year} considering only weekdays.\n\n"
|
84
91
|
respond messages.join("\n")
|
85
92
|
end
|
86
93
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
module Utils
|
3
|
+
module Encryption
|
4
|
+
def self.decrypt(data, config)
|
5
|
+
if config.encrypt
|
6
|
+
require "openssl"
|
7
|
+
require "base64"
|
8
|
+
|
9
|
+
key, iv = Utils::Encryption.encryption_get_key_iv(config)
|
10
|
+
encrypted = Base64.decode64(data)
|
11
|
+
cipher = OpenSSL::Cipher.new("AES-256-CBC")
|
12
|
+
cipher.decrypt
|
13
|
+
cipher.key = key
|
14
|
+
cipher.iv = iv
|
15
|
+
plain = cipher.update(encrypted) + cipher.final
|
16
|
+
return plain
|
17
|
+
else
|
18
|
+
return data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
module Utils
|
3
|
+
module Encryption
|
4
|
+
def self.encrypt(data, config)
|
5
|
+
if config.encrypt
|
6
|
+
require "openssl"
|
7
|
+
require "base64"
|
8
|
+
|
9
|
+
key, iv = Utils::Encryption.encryption_get_key_iv(config)
|
10
|
+
cipher = OpenSSL::Cipher::Cipher.new "AES-256-CBC"
|
11
|
+
cipher.encrypt
|
12
|
+
cipher.key = key
|
13
|
+
cipher.iv = iv
|
14
|
+
encrypted = cipher.update(data) + cipher.final
|
15
|
+
encrypted = Base64.encode64(encrypted)
|
16
|
+
if defined?(Thread.current)
|
17
|
+
Thread.current[:encrypted] ||= []
|
18
|
+
Thread.current[:encrypted] << data
|
19
|
+
end
|
20
|
+
return encrypted
|
21
|
+
else
|
22
|
+
return data
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/slack/smart-bot/utils/{encryption_get_key_iv.rb → encryption/encryption_get_key_iv.rb}
RENAMED
@@ -1,5 +1,7 @@
|
|
1
1
|
class SlackSmartBot
|
2
|
-
|
2
|
+
module Utils
|
3
|
+
module Encryption
|
4
|
+
def self.encryption_get_key_iv(config)
|
3
5
|
if defined?(@encryption_key_built)
|
4
6
|
key = @encryption_key_built
|
5
7
|
iv = @encryption_iv_built
|
@@ -11,19 +13,21 @@ class SlackSmartBot
|
|
11
13
|
key = (Socket.gethostname + config.token.reverse)[0..49]
|
12
14
|
iv = config.token[0..15]
|
13
15
|
end
|
14
|
-
|
16
|
+
|
15
17
|
#Convert from hex to raw bytes:
|
16
|
-
key = [key].pack(
|
18
|
+
key = [key].pack("H*")
|
17
19
|
#Pad with zero bytes to correct length:
|
18
20
|
key << ("\x00" * (32 - key.length))
|
19
|
-
|
21
|
+
|
20
22
|
#Convert from hex to raw bytes:
|
21
|
-
iv = [iv].pack(
|
23
|
+
iv = [iv].pack("H*")
|
22
24
|
#Pad with zero bytes to correct length:
|
23
|
-
iv << ("\x00" * (16 - iv.length))
|
25
|
+
iv << ("\x00" * (16 - iv.length))
|
24
26
|
@encryption_key_built = key
|
25
27
|
@encryption_iv_built = iv
|
26
28
|
end
|
27
29
|
return key, iv
|
28
|
-
|
29
|
-
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -4,7 +4,9 @@ class SlackSmartBot
|
|
4
4
|
general: [:bot_help, :hi_bot, :bye_bot, :add_admin, :remove_admin, :see_admins, :poster, :add_announcement, :delete_announcement,
|
5
5
|
:see_announcements, :see_command_ids, :share_messages, :see_shares, :delete_share, :see_favorite_commands, :see_statuses,
|
6
6
|
:allow_access, :see_access, :deny_access, :add_team, :add_memo_team, :delete_memo_team, :set_memo_status, :see_teams, :update_team, :ping_team, :delete_team,
|
7
|
-
:see_memos_team, :add_vacation, :remove_vacation, :see_vacations, :see_vacations_team, :public_holidays, :create_loop, :quit_loop
|
7
|
+
:see_memos_team, :add_vacation, :remove_vacation, :see_vacations, :see_vacations_team, :public_holidays, :set_public_holidays, :create_loop, :quit_loop,
|
8
|
+
:get_personal_settings, :delete_personal_settings, :set_personal_settings,
|
9
|
+
:open_ai_chat, :open_ai_generate_image, :open_ai_edit_image, :open_ai_variations_image, :open_ai_whisper, :open_ai_models ],
|
8
10
|
on_bot_general: [:whats_new, :suggest_command, :bot_status, :use_rules, :stop_using_rules, :bot_stats, :leaderboard],
|
9
11
|
on_bot: [:ruby_code, :repl, :get_repl, :run_repl, :delete_repl, :see_repls, :kill_repl, :add_shortcut, :delete_shortcut, :see_shortcuts],
|
10
12
|
on_bot_admin: [:extend_rules, :stop_using_rules_on, :start_bot, :pause_bot, :add_routine,
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def get_personal_settings
|
3
|
+
@personal_settings ||= {}
|
4
|
+
@datetime_personal_settings_file ||= {}
|
5
|
+
files = Dir.glob(File.join(config.path, "personal_settings", "ps_*.yaml"))
|
6
|
+
files.each do |file|
|
7
|
+
if !defined?(@datetime_personal_settings_file) or !@datetime_personal_settings_file.key?(file) or @datetime_personal_settings_file[file] != File.mtime(file)
|
8
|
+
user_personal_settings = YAML.load(Utils::Encryption.decrypt(File.read(file),config))
|
9
|
+
@personal_settings[File.basename(file).gsub("ps_","").gsub(".yaml","")] = user_personal_settings
|
10
|
+
@datetime_personal_settings_file[file] = File.mtime(file)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -8,7 +8,7 @@ class SlackSmartBot
|
|
8
8
|
teams = YAML.load(File.read(old_teams_file))
|
9
9
|
@logger.info "@teams: #{teams.inspect}}"
|
10
10
|
teams.each do |key, value|
|
11
|
-
File.write(File.join(config.path, "teams", "t_#{key}.yaml"), encrypt(value.to_yaml))
|
11
|
+
File.write(File.join(config.path, "teams", "t_#{key}.yaml"), Utils::Encryption.encrypt(value.to_yaml, config))
|
12
12
|
end
|
13
13
|
@logger.info "Deleting old_teams_file: #{old_teams_file}"
|
14
14
|
File.delete(old_teams_file)
|
@@ -17,7 +17,7 @@ class SlackSmartBot
|
|
17
17
|
@datetime_teams_file ||= {}
|
18
18
|
files.each do |file|
|
19
19
|
if !defined?(@datetime_teams_file) or !@datetime_teams_file.key?(file) or @datetime_teams_file[file] != File.mtime(file)
|
20
|
-
teams_team = YAML.load(decrypt(File.read(file)))
|
20
|
+
teams_team = YAML.load(Utils::Encryption.decrypt(File.read(file),config))
|
21
21
|
team_name = File.basename(file).gsub("t_","").gsub(".yaml","")
|
22
22
|
teams_team[:name] = team_name unless teams_team.key?(:name) #to be backward compatible
|
23
23
|
@teams[team_name.to_sym] = teams_team
|
@@ -9,7 +9,7 @@ class SlackSmartBot
|
|
9
9
|
vacations = YAML.load(File.read(old_vacations_file))
|
10
10
|
@vacations = vacations unless vacations.is_a?(FalseClass)
|
11
11
|
@vacations.each do |key, value|
|
12
|
-
File.write(File.join(config.path, "vacations", "v_#{key}.yaml"), encrypt(value.to_yaml))
|
12
|
+
File.write(File.join(config.path, "vacations", "v_#{key}.yaml"), Utils::Encryption.encrypt(value.to_yaml, config))
|
13
13
|
end
|
14
14
|
@logger.info "Deleting old_vacations_file: #{old_vacations_file}"
|
15
15
|
File.delete(old_vacations_file)
|
@@ -18,7 +18,7 @@ class SlackSmartBot
|
|
18
18
|
@datetime_vacations_file ||= {}
|
19
19
|
files.each do |file|
|
20
20
|
if !defined?(@datetime_vacations_file) or !@datetime_vacations_file.key?(file) or @datetime_vacations_file[file] != File.mtime(file)
|
21
|
-
vacations_user = YAML.load(decrypt(File.read(file)))
|
21
|
+
vacations_user = YAML.load(Utils::Encryption.decrypt(File.read(file), config))
|
22
22
|
@vacations[File.basename(file).gsub("v_","").gsub(".yaml","")] = vacations_user
|
23
23
|
@datetime_vacations_file[file] = File.mtime(file)
|
24
24
|
end
|
@@ -3,6 +3,8 @@ class SlackSmartBot
|
|
3
3
|
if has_access?(method, Thread.current[:user]) or forced
|
4
4
|
if config.stats
|
5
5
|
begin
|
6
|
+
command_ids_not_to_log = ['add_vacation', 'remove_vacation', 'add_memo_team', 'set_personal_settings']
|
7
|
+
Thread.current[:command_id] = method.to_s
|
6
8
|
require "csv"
|
7
9
|
if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
|
8
10
|
CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", "wb") do |csv|
|
@@ -42,7 +44,7 @@ class SlackSmartBot
|
|
42
44
|
time_zone = user_info.tz_label
|
43
45
|
job_title = user_info.profile.title
|
44
46
|
end
|
45
|
-
|
47
|
+
command_txt = "#{method} encrypted" if command_ids_not_to_log.include?(method.to_s)
|
46
48
|
CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", "a+") do |csv|
|
47
49
|
csv << [Time.now, config.channel, @channel_id, @channels_name[data.dest], data.dest, data.typem, user_name, user_id, command_txt, method, data.files, time_zone, job_title]
|
48
50
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def update_personal_settings(user_personal_settings=nil)
|
3
|
+
require 'yaml'
|
4
|
+
unless user_personal_settings.nil?
|
5
|
+
get_personal_settings()
|
6
|
+
@personal_settings.merge!(user_personal_settings)
|
7
|
+
end
|
8
|
+
user = Thread.current[:user]
|
9
|
+
personal_settings_file = File.join(config.path, "personal_settings", "ps_#{user.name}.yaml")
|
10
|
+
|
11
|
+
File.open(personal_settings_file, 'w') {|file|
|
12
|
+
file.flock(File::LOCK_EX)
|
13
|
+
file.write(Utils::Encryption.encrypt(@personal_settings[user.name].to_yaml, config))
|
14
|
+
file.flock(File::LOCK_UN)
|
15
|
+
}
|
16
|
+
@datetime_personal_settings_file[personal_settings_file] = File.mtime(personal_settings_file)
|
17
|
+
end
|
18
|
+
end
|
@@ -13,7 +13,7 @@ class SlackSmartBot
|
|
13
13
|
team_file = File.join(config.path, "teams", "t_#{team}.yaml")
|
14
14
|
File.open(team_file, 'w') {|file|
|
15
15
|
file.flock(File::LOCK_EX)
|
16
|
-
file.write(encrypt(@teams[team].to_yaml))
|
16
|
+
file.write(Utils::Encryption.encrypt(@teams[team].to_yaml, config))
|
17
17
|
file.flock(File::LOCK_UN)
|
18
18
|
}
|
19
19
|
@datetime_teams_file[team_file] = File.mtime(team_file)
|
@@ -10,7 +10,7 @@ class SlackSmartBot
|
|
10
10
|
|
11
11
|
File.open(vacations_file, 'w') {|file|
|
12
12
|
file.flock(File::LOCK_EX)
|
13
|
-
file.write(encrypt(@vacations[user.name].to_yaml))
|
13
|
+
file.write(Utils::Encryption.encrypt(@vacations[user.name].to_yaml, config))
|
14
14
|
file.flock(File::LOCK_UN)
|
15
15
|
}
|
16
16
|
@datetime_vacations_file[vacations_file] = File.mtime(vacations_file)
|
@@ -26,12 +26,14 @@ require_relative 'utils/update_access_channels'
|
|
26
26
|
require_relative 'utils/get_command_ids'
|
27
27
|
require_relative 'utils/get_teams'
|
28
28
|
require_relative 'utils/get_vacations'
|
29
|
+
require_relative 'utils/get_personal_settings'
|
30
|
+
require_relative 'utils/update_personal_settings'
|
29
31
|
require_relative 'utils/update_teams'
|
30
32
|
require_relative 'utils/update_vacations'
|
31
33
|
require_relative 'utils/check_vacations'
|
32
34
|
require_relative 'utils/display_calendar'
|
33
|
-
require_relative 'utils/encryption_get_key_iv'
|
34
|
-
require_relative 'utils/encrypt'
|
35
|
-
require_relative 'utils/decrypt'
|
35
|
+
require_relative 'utils/encryption/encryption_get_key_iv'
|
36
|
+
require_relative 'utils/encryption/encrypt'
|
37
|
+
require_relative 'utils/encryption/decrypt'
|
36
38
|
require_relative 'utils/get_team_members'
|
37
39
|
|
data/lib/slack-smart-bot.rb
CHANGED
@@ -18,6 +18,7 @@ require_relative "slack/smart-bot/process_first"
|
|
18
18
|
require_relative "slack/smart-bot/commands"
|
19
19
|
require_relative "slack/smart-bot/process"
|
20
20
|
require_relative "slack/smart-bot/utils"
|
21
|
+
require_relative "slack/smart-bot/ai"
|
21
22
|
|
22
23
|
ADMIN_USERS = MASTER_USERS if defined?(MASTER_USERS) # for bg compatibility
|
23
24
|
class SlackSmartBot
|
@@ -57,6 +58,15 @@ class SlackSmartBot
|
|
57
58
|
config[:public_holidays] = { api_key: '' } unless config.key?(:public_holidays) and config[:public_holidays].key?(:api_key)
|
58
59
|
config[:public_holidays][:host] ||= "https://calendarific.com"
|
59
60
|
config[:public_holidays][:host] = "https://#{config[:public_holidays][:host]}" unless config[:public_holidays][:host] == '' or config[:public_holidays][:host].match?(/^http/)
|
61
|
+
config[:encrypt] ||= true unless config.key?(:encrypt)
|
62
|
+
config[:ai] ||= {} unless config.key?(:ai)
|
63
|
+
config[:ai][:open_ai] ||= {
|
64
|
+
access_token: '',
|
65
|
+
organization_id: ''
|
66
|
+
} unless config[:ai].key?(:open_ai)
|
67
|
+
config[:ai][:open_ai][:whisper_model] ||= 'whisper-1'
|
68
|
+
config[:ai][:open_ai][:image_size] ||= '256x256'
|
69
|
+
config[:ai][:open_ai][:gpt_model] ||= 'gpt-3.5-turbo'
|
60
70
|
|
61
71
|
if config.path.to_s!='' and config.file.to_s==''
|
62
72
|
config.file = File.basename($0)
|
@@ -80,6 +90,7 @@ class SlackSmartBot
|
|
80
90
|
Dir.mkdir("#{config.path}/rules") unless Dir.exist?("#{config.path}/rules")
|
81
91
|
Dir.mkdir("#{config.path}/vacations") unless Dir.exist?("#{config.path}/vacations")
|
82
92
|
Dir.mkdir("#{config.path}/teams") unless Dir.exist?("#{config.path}/teams")
|
93
|
+
Dir.mkdir("#{config.path}/personal_settings") unless Dir.exist?("#{config.path}/personal_settings")
|
83
94
|
File.delete("#{config.path}/config_tmp.status") if File.exist?("#{config.path}/config_tmp.status")
|
84
95
|
|
85
96
|
config.masters = MASTER_USERS if config.masters.to_s=='' and defined?(MASTER_USERS)
|
@@ -326,6 +337,7 @@ class SlackSmartBot
|
|
326
337
|
get_admins_channels()
|
327
338
|
get_access_channels()
|
328
339
|
get_vacations()
|
340
|
+
get_personal_settings()
|
329
341
|
|
330
342
|
if @routines.key?(@channel_id)
|
331
343
|
@routines[@channel_id].each do |k, v|
|
data/whats_new.txt
CHANGED
@@ -1,21 +1,20 @@
|
|
1
|
-
*Version 1.
|
1
|
+
*Version 1.14.0* Released 2023-Apr-13
|
2
2
|
|
3
3
|
*For General users*
|
4
|
-
-
|
5
|
-
-
|
6
|
-
-
|
7
|
-
-
|
8
|
-
-
|
9
|
-
-
|
10
|
-
-
|
4
|
+
- `team TEAM_NAME memo ID MESSAGE`, `TEAM_NAME team memo ID MESSAGE` It will add a comment to the memo ID specified on the team specified. (<https://github.com/MarioRuiz/slack-smart-bot/issues/95|#95>).
|
5
|
+
- `team TEAM_NAME memo ID`, `TEAM_NAME team memo ID` It will show the memo ID specified on the team specified along with all the comments. (<https://github.com/MarioRuiz/slack-smart-bot/issues/96|#96>)
|
6
|
+
- When on a repl it is possible to get the documentation and source code of any method: `doc METHOD`, `source METHOD`, `code METHOD`. Examples: `doc Operations.list`, `code World::API::Time.get` (<https://github.com/MarioRuiz/slack-smart-bot/issues/98|#98>)
|
7
|
+
- Deleted memos will be accessible by the creator (<https://github.com/MarioRuiz/slack-smart-bot/issues/100|#100>)
|
8
|
+
- `calendar COUNTRY`, `calendar COUNTRY/STATE`, `calendar COUNTRY/STATE DATE` will display the calendar of public holidays. (<https://github.com/MarioRuiz/slack-smart-bot/issues/102|#102>)
|
9
|
+
- Display public holidays for every member on vacation team calendar (<https://github.com/MarioRuiz/slack-smart-bot/issues/103|#103>)
|
10
|
+
- OpenAI integration for personal results. ChatGPT, Whisper, Image generation, Image Variations and Image Edition (<https://github.com/MarioRuiz/slack-smart-bot/issues/101|#101>)
|
11
|
+
- New `set personal settings` command (<https://github.com/MarioRuiz/slack-smart-bot/issues/105|#105>)
|
11
12
|
|
12
13
|
*For Admin users*
|
13
|
-
-
|
14
|
-
-
|
15
|
-
-
|
16
|
-
- Routines now can create threads (<https://github.com/MarioRuiz/slack-smart-bot/issues/36|#36>)
|
17
|
-
- `add routine NAME on the DAY_OF_MONTH at TIME COMMAND` (<https://github.com/MarioRuiz/slack-smart-bot/issues/82|#82>)
|
14
|
+
- New 'silent' option for command `exit bot silent`. It won't notify the SmartBot channels. (<https://github.com/MarioRuiz/slack-smart-bot/issues/93|#93>).
|
15
|
+
- Show graph for `bot stats` when specifying option `graph` and grouping by daily, weekly, monthly or yearly. (<https://github.com/MarioRuiz/slack-smart-bot/issues/97|#97>).
|
16
|
+
- config.encrypt (Boolean) By default will be set to true. (<https://github.com/MarioRuiz/slack-smart-bot/issues/99|#99>)
|
18
17
|
|
19
18
|
------------------------------
|
20
19
|
|
21
|
-
*Previous*: <https://github.com/MarioRuiz/slack-smart-bot/blob/
|
20
|
+
*Previous*: <https://github.com/MarioRuiz/slack-smart-bot/blob/644c0882dec62281d5961d7565f6aba001be8d91/whats_new.txt|1.13.2>
|