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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +100 -4
  3. data/lib/slack/smart-bot/ai/open_ai/connect.rb +61 -0
  4. data/lib/slack/smart-bot/ai/open_ai/models.rb +21 -0
  5. data/lib/slack/smart-bot/ai/open_ai/send_gpt_chat.rb +24 -0
  6. data/lib/slack/smart-bot/ai/open_ai/send_image_edit.rb +23 -0
  7. data/lib/slack/smart-bot/ai/open_ai/send_image_generation.rb +18 -0
  8. data/lib/slack/smart-bot/ai/open_ai/send_image_variation.rb +22 -0
  9. data/lib/slack/smart-bot/ai/open_ai/whisper_transcribe.rb +21 -0
  10. data/lib/slack/smart-bot/ai.rb +8 -0
  11. data/lib/slack/smart-bot/comm/get_channel_members.rb +15 -13
  12. data/lib/slack/smart-bot/comm/get_channels.rb +31 -29
  13. data/lib/slack/smart-bot/comm/respond_thread.rb +2 -2
  14. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat.rb +40 -0
  15. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_edit_image.rb +66 -0
  16. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_generate_image.rb +65 -0
  17. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_models.rb +37 -0
  18. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_variations_image.rb +84 -0
  19. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_whisper.rb +51 -0
  20. data/lib/slack/smart-bot/commands/general/bot_help.rb +1 -0
  21. data/lib/slack/smart-bot/commands/general/personal_settings.rb +38 -0
  22. data/lib/slack/smart-bot/commands/general/poster.rb +107 -104
  23. data/lib/slack/smart-bot/commands/general/public_holidays.rb +116 -114
  24. data/lib/slack/smart-bot/commands/general/set_public_holidays.rb +6 -2
  25. data/lib/slack/smart-bot/commands/general/teams/add_team.rb +87 -0
  26. data/lib/slack/smart-bot/commands/general/teams/delete_team.rb +69 -0
  27. data/lib/slack/smart-bot/commands/general/teams/memos/add_memo_team.rb +136 -0
  28. data/lib/slack/smart-bot/commands/general/teams/memos/add_memo_team_comment.rb +37 -0
  29. data/lib/slack/smart-bot/commands/general/teams/memos/delete_memo_team.rb +83 -0
  30. data/lib/slack/smart-bot/commands/general/teams/memos/see_memo_team.rb +97 -0
  31. data/lib/slack/smart-bot/commands/general/teams/memos/see_memos_team.rb +304 -0
  32. data/lib/slack/smart-bot/commands/general/teams/memos/set_memo_status.rb +66 -0
  33. data/lib/slack/smart-bot/commands/general/teams/ping_team.rb +104 -0
  34. data/lib/slack/smart-bot/commands/general/teams/see_teams.rb +236 -0
  35. data/lib/slack/smart-bot/commands/general/teams/see_vacations_team.rb +183 -0
  36. data/lib/slack/smart-bot/commands/general/teams/update_team.rb +137 -0
  37. data/lib/slack/smart-bot/commands/general_bot_commands.rb +905 -741
  38. data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +379 -353
  39. data/lib/slack/smart-bot/commands/on_bot/repl.rb +87 -189
  40. data/lib/slack/smart-bot/commands/on_bot/repl_client.rb +233 -0
  41. data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +17 -4
  42. data/lib/slack/smart-bot/commands.rb +26 -10
  43. data/lib/slack/smart-bot/process.rb +14 -3
  44. data/lib/slack/smart-bot/process_first.rb +36 -2
  45. data/lib/slack/smart-bot/treat_message.rb +28 -0
  46. data/lib/slack/smart-bot/utils/check_vacations.rb +1 -0
  47. data/lib/slack/smart-bot/utils/create_routine_thread.rb +1 -1
  48. data/lib/slack/smart-bot/utils/display_calendar.rb +17 -10
  49. data/lib/slack/smart-bot/utils/encryption/decrypt.rb +23 -0
  50. data/lib/slack/smart-bot/utils/encryption/encrypt.rb +27 -0
  51. data/lib/slack/smart-bot/utils/{encryption_get_key_iv.rb → encryption/encryption_get_key_iv.rb} +12 -8
  52. data/lib/slack/smart-bot/utils/get_help.rb +3 -1
  53. data/lib/slack/smart-bot/utils/get_personal_settings.rb +14 -0
  54. data/lib/slack/smart-bot/utils/get_teams.rb +2 -2
  55. data/lib/slack/smart-bot/utils/get_vacations.rb +2 -2
  56. data/lib/slack/smart-bot/utils/save_stats.rb +3 -1
  57. data/lib/slack/smart-bot/utils/update_personal_settings.rb +18 -0
  58. data/lib/slack/smart-bot/utils/update_teams.rb +1 -1
  59. data/lib/slack/smart-bot/utils/update_vacations.rb +1 -1
  60. data/lib/slack/smart-bot/utils.rb +5 -3
  61. data/lib/slack-smart-bot.rb +12 -0
  62. data/whats_new.txt +13 -14
  63. metadata +63 -15
  64. data/lib/slack/smart-bot/commands/general/add_memo_team.rb +0 -117
  65. data/lib/slack/smart-bot/commands/general/add_team.rb +0 -81
  66. data/lib/slack/smart-bot/commands/general/delete_memo_team.rb +0 -69
  67. data/lib/slack/smart-bot/commands/general/delete_team.rb +0 -55
  68. data/lib/slack/smart-bot/commands/general/ping_team.rb +0 -100
  69. data/lib/slack/smart-bot/commands/general/see_memos_team.rb +0 -202
  70. data/lib/slack/smart-bot/commands/general/see_teams.rb +0 -230
  71. data/lib/slack/smart-bot/commands/general/see_vacations_team.rb +0 -136
  72. data/lib/slack/smart-bot/commands/general/set_memo_status.rb +0 -58
  73. data/lib/slack/smart-bot/commands/general/update_team.rb +0 -131
  74. data/lib/slack/smart-bot/utils/decrypt.rb +0 -15
  75. 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
- respond "Game over!", dest
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
- exit_bot(command, from, dest, display_name)
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
- @logger.info "command: #{nick}> #{command_thread}" if processed
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
- @logger.info "command: #{nick}> #{command_thread}" unless processed
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
@@ -10,6 +10,7 @@ class SlackSmartBot
10
10
  users.each do |user|
11
11
  type = nil
12
12
  expiration = nil
13
+ @vacations[user].periods ||= []
13
14
  @vacations[user].periods.each do |p|
14
15
  if only_first_day and p.from == date.strftime("%Y/%m/%d")
15
16
  type = p.type
@@ -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
- messages = ["*Time off #{year}*"]
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
- 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"
78
- if country_region != ""
79
- messages << "Your public holidays are set for #{country_region.downcase}. Call `set public holidays to COUNTRY/REGION` if you want to change it.\n"
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 << "Your public holidays are not set. Call `set public holidays to COUNTRY/REGION` to set it.\n"
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
@@ -1,5 +1,7 @@
1
1
  class SlackSmartBot
2
- def encryption_get_key_iv
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('H*')
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('H*')
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
- end
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
 
@@ -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.13.0* Released 2023-Mar-01
1
+ *Version 1.14.0* Released 2023-Apr-13
2
2
 
3
3
  *For General users*
4
- - It is possible to run any command on a loop: `for 3 times every 5 minutes !ruby puts Time.now` (<https://github.com/MarioRuiz/slack-smart-bot/issues/83|#83>).
5
- - You can add collaborators to your REPL by sending `add collaborator @USER` to the session. (<https://github.com/MarioRuiz/slack-smart-bot/issues/85|#85>).
6
- - If using the `monthly` option when calling `bot stats` it will show a graph (<https://github.com/MarioRuiz/slack-smart-bot/issues/86|#86>).
7
- - New `public holidays COUNTRY/REGION` command (<https://github.com/MarioRuiz/slack-smart-bot/issues/88|#88>)
8
- - When calling `see my vacations` on a DM will display a calendar of the year with the days off, including public holidays (<https://github.com/MarioRuiz/slack-smart-bot/issues/89|#89>)
9
- - `set public holidays to COUNTRY/REGION` will set the public holidays for the country and region specified. (<https://github.com/MarioRuiz/slack-smart-bot/issues/90|#90>)
10
- - `see MEMO_TYPE from TEAM_NAME team` will show the memos of the team. (<https://github.com/MarioRuiz/slack-smart-bot/issues/91|#91>)
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
- - It is possible to see routines filtering the HEADER supplied using the given REGEXP: `see routines HEADER /REGEXP/` (<https://github.com/MarioRuiz/slack-smart-bot/issues/84|#84>).
14
- - `send message to users from YYYY/MM/DD to YYYY/MM/DD #CHANNEL COMMAND_ID: MESSAGE` will send a DM to all users that have been using the SmartBot according to the SmartBot Stats. One message every 5sc. #CHANNEL and COMMAND are optional filters. (<https://github.com/MarioRuiz/slack-smart-bot/issues/87|#87>)
15
- - `update message URL TEXT` It will update the SmartBot message supplied. You can use this command only if you are a Master admin user and if you are in a private conversation with the bot. (<https://github.com/MarioRuiz/slack-smart-bot/issues/33|#33>)
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/2b93317d7556ceaeb724494f53cfa9e8907c3e52/whats_new.txt|1.12.9>
20
+ *Previous*: <https://github.com/MarioRuiz/slack-smart-bot/blob/644c0882dec62281d5961d7565f6aba001be8d91/whats_new.txt|1.13.2>