slack-smart-bot 1.13.2 → 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 +6 -107
  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
@@ -23,6 +23,8 @@ class SlackSmartBot
23
23
  # help: By default it will be automatically loaded the gems: string_pattern, nice_hash and nice_http
24
24
  # help: To pre-execute some ruby when starting the session add the code to .smart-bot-repl file on the project root folder defined on project_folder
25
25
  # help: If you want to see the methods of a class or module you created use _ls TheModuleOrClass_
26
+ # help: To see the code of a method: _code TheModuleOrClass.my_method_
27
+ # help: To see the documentation of a method: _doc TheModuleOrClass.my_method_
26
28
  # help: You can supply the Environmental Variables you need for the Session
27
29
  # help: You can add collaborators by sending _add collaborator @USER_ to the session.
28
30
  # help: Examples:
@@ -91,118 +93,14 @@ class SlackSmartBot
91
93
  end
92
94
  @ts_repl ||= {}
93
95
  @ts_repl[session_name] = ""
96
+ process_to_run = repl_client(from, session_name, type, serialt, env_vars)
94
97
 
95
- message = "Session name: *#{session_name}*
96
- From now on I will execute all you write as a Ruby command and I will keep the session open until you send `quit` or `bye` or `exit`.
97
- In case you need someone to help you with the session you can add collaborators by sending `add collaborator @USER` to the session.
98
- I will respond with the result so it is not necessary you send `print`, `puts`, `p` or `pp` unless you want it as the output when calling `run repl`.
99
- Use `p` to print a message raw, exacly like it is returned.
100
- If you want to avoid a message to be treated by me, start the message with '-'.
101
- After 30 minutes of no communication with the Smart Bot the session will be dismissed.
102
- If you want to see the methods of a class or module you created use _ls TheModuleOrClass_
103
- You can supply the Environmental Variables you need for the Session
104
- Example:
105
- _repl CreateCustomer LOCATION=spain HOST='https://10.30.40.50:8887'_
106
- "
107
- respond message, dest
108
-
109
- File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.input", "", mode: "a+")
110
- File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.output", "", mode: "a+")
111
- File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.run", "", mode: "a+")
112
-
113
- if type != :private_clean and type != :public_clean
114
- pre_execute = '
115
- if File.exist?(\"./.smart-bot-repl\")
116
- begin
117
- eval(File.read(\"./.smart-bot-repl\"), bindme' + serialt + ")
118
- rescue Exception => resp_repl
119
- end
120
- end
121
- "
122
- else
123
- pre_execute = ""
124
- end
125
-
126
- process_to_run = "
127
- " + env_vars.join("\n") + '
128
- require \"amazing_print\"
129
- require \"stringio\"
130
- bindme' + serialt + ' = binding
131
- eval(\"require \'nice_http\'\" , bindme' + serialt + ')
132
- def ls(obj)
133
- (obj.methods - Object.methods)
134
- end
135
- file_run_path = \"' + +File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.rb\"
136
- file_input_repl = File.open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.input\", \"r\")
137
- ' + pre_execute + '
138
- while true do
139
- sleep 0.2
140
- code_to_run_repl = file_input_repl.read
141
- if code_to_run_repl.to_s!=\"\"
142
- add_to_run_repl = true
143
- if code_to_run_repl.to_s.match?(/^quit$/i) or
144
- code_to_run_repl.to_s.match?(/^exit$/i) or
145
- code_to_run_repl.to_s.match?(/^bye bot$/i) or
146
- code_to_run_repl.to_s.match?(/^bye$/i)
147
- exit
148
- else
149
- if code_to_run_repl.match?(/^\s*ls\s+(.+)/)
150
- add_to_run_repl = false
151
- end
152
- error = false
153
- begin
154
- begin
155
- original_stdout = $stdout
156
- $stdout = StringIO.new
157
- resp_repl = eval(code_to_run_repl, bindme' + serialt + ')
158
- stdout_repl = $stdout.string
159
- ensure
160
- $stdout = original_stdout
161
- end
162
- rescue Exception => resp_repl
163
- error = true
164
- end
165
- if error
166
- open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.output\", \"a+\") {|f|
167
- f.puts \"\`\`\`\n#{resp_repl.to_s.gsub(/^.+' + session_name + '\.rb:\d+:/,\"\")}\`\`\`\"
168
- }
169
- else
170
- if code_to_run_repl.match?(/^\s*p\s+/i)
171
- resp_repl = stdout_repl unless stdout_repl.to_s == \'\'
172
- if stdout_repl.to_s == \'\'
173
- resp_repl = resp_repl.inspect
174
- else
175
- resp_repl = stdout_repl
176
- end
177
- open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.output\", \"a+\") {|f|
178
- f.puts \"\`\`\`\n#{resp_repl}\`\`\`\"
179
- }
180
- else
181
- if stdout_repl.to_s == \'\'
182
- resp_repl = resp_repl.ai
183
- else
184
- resp_repl = stdout_repl
185
- end
186
- open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.output\", \"a+\") {|f|
187
- f.puts \"\`\`\`\n#{resp_repl}\`\`\`\"
188
- }
189
- end
190
- unless !add_to_run_repl
191
- open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.run\", \"a+\") {|f|
192
- f.puts code_to_run_repl
193
- }
194
- end
195
- end
196
- end
197
- end
198
- end
199
- '
200
98
  unless rules_file.empty? # to get the project_folder
201
99
  begin
202
100
  eval(File.new(config.path + rules_file).read) if File.exist?(config.path + rules_file)
203
101
  end
204
102
  end
205
- process_to_run.gsub!('\"', '"')
103
+
206
104
  file_run_path = "./tmp/repl/#{@channel_id}/#{session_name}.rb"
207
105
  if defined?(project_folder)
208
106
  Dir.mkdir("#{project_folder}/tmp/") unless Dir.exist?("#{project_folder}/tmp/")
@@ -257,7 +155,8 @@ class SlackSmartBot
257
155
  unreact(:running, @ts_repl[@repl_sessions[from].name])
258
156
  @ts_repl[@repl_sessions[from].name] = ""
259
157
  end
260
- if resp_repl.to_s.lines.count < 60 and resp_repl.to_s.size < 3500
158
+ if (resp_repl.to_s.lines.count < 60 and resp_repl.to_s.size < 3500) or
159
+ resp_repl.match?(/^\s*[_\*]*`\w+`/im)
261
160
  respond resp_repl, dest
262
161
  else
263
162
  resp_repl.gsub!(/^\s*```/, "")
@@ -0,0 +1,233 @@
1
+ class SlackSmartBot
2
+ def repl_client(from, session_name, type, serialt, env_vars)
3
+ message = "Session name: *#{session_name}*
4
+ From now on I will execute all you write as a Ruby command and I will keep the session open until you send `quit` or `bye` or `exit`.
5
+ In case you need someone to help you with the session you can add collaborators by sending `add collaborator @USER` to the session.
6
+ I will respond with the result so it is not necessary you send `print`, `puts`, `p` or `pp` unless you want it as the output when calling `run repl`.
7
+ Use `p` to print a message raw, exacly like it is returned.
8
+ If you want to avoid a message to be treated by me, start the message with '-'.
9
+ After 30 minutes of no communication with the Smart Bot the session will be dismissed.
10
+ If you want to see the methods of a class or module you created use _ls TheModuleOrClass_
11
+ To see the code of a method: _code TheModuleOrClass.my_method_. To see the documentation of a method: _doc TheModuleOrClass.my_method_
12
+ You can supply the Environmental Variables you need for the Session
13
+ Example:
14
+ _repl CreateCustomer LOCATION=spain HOST='https://10.30.40.50:8887'_
15
+ "
16
+ respond message
17
+
18
+ File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.input", "", mode: "a+")
19
+ File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.output", "", mode: "a+")
20
+ File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.run", "", mode: "a+")
21
+
22
+ if type != :private_clean and type != :public_clean
23
+ pre_execute = '
24
+ if File.exist?(\"./.smart-bot-repl\")
25
+ begin
26
+ eval(File.read(\"./.smart-bot-repl\"), bindme' + serialt + ")
27
+ rescue Exception => resp_repl
28
+ end
29
+ end
30
+ "
31
+ else
32
+ pre_execute = ""
33
+ end
34
+
35
+ process_to_run = "
36
+ " + env_vars.join("\n") + '
37
+ require \"amazing_print\"
38
+ require \"stringio\"
39
+ require \"method_source\"
40
+ bindme' + serialt + ' = binding
41
+ eval(\"require \'nice_http\'\" , bindme' + serialt + ')
42
+ def get_met_params(obj, m=nil)
43
+ result = ""
44
+ if m.nil?
45
+ met = obj
46
+ else
47
+ met = obj.method(m)
48
+ end
49
+ met.source.split("\n").each { |line|
50
+ line.gsub!("def", "")
51
+ line.gsub!("self.", "")
52
+ line.strip!
53
+ line.gsub!(/\A(\w+)\(/, \'*`\1`* (\')
54
+ line.gsub!(/\A(\w+)$/, \'*`\1`*\')
55
+ if line.strip[-1] == ")" or (result.empty? and !line.include?("("))
56
+ line.gsub!(/\A(\w+)\s/, \'*`\1`* \') if !line.include?("(")
57
+ result << "#{line}"
58
+ result << " ..." if !line.include?("(") and !line.include?(")")
59
+ result << "\n"
60
+ break
61
+ else
62
+ result << "#{line}\n"
63
+ end
64
+ }
65
+ result
66
+ end
67
+ def ls(obj)
68
+ result = ""
69
+ (obj.methods - Object.methods).sort.each do |m|
70
+ result << get_met_params(obj, m)
71
+ result << "\n"
72
+ end
73
+ puts result
74
+ end
75
+ def get_object(obj_txt)
76
+ met = obj_txt.scan(/\.(\w+)/).flatten.last
77
+
78
+ if met.nil? and obj_txt[0].match(/[A-Z]/)
79
+ obj = Object
80
+ obj_txt.split("::").each do |cl|
81
+ if obj.const_defined?(cl.to_sym)
82
+ obj = obj.const_get(cl)
83
+ else
84
+ obj = nil
85
+ break
86
+ end
87
+ end
88
+ elsif met.nil? and obj_txt[0].match(/[a-z]/)
89
+ begin
90
+ obj = self.method(obj_txt)
91
+ rescue
92
+ obj = nil
93
+ end
94
+ else
95
+ cl = obj_txt.scan(/([\w\:]+)\./).flatten.first
96
+ obj = Object
97
+ cl.split("::").each do |cl|
98
+ if obj.const_defined?(cl.to_sym)
99
+ obj = obj.const_get(cl)
100
+ else
101
+ obj = nil
102
+ break
103
+ end
104
+ end
105
+ unless obj.nil?
106
+ if obj.respond_to?(met)
107
+ obj = obj.method(met)
108
+ elsif obj.instance_method(met)
109
+ obj = obj.instance_method(met)
110
+ else
111
+ obj = nil
112
+ end
113
+ end
114
+
115
+ end
116
+ end
117
+
118
+ def doc(obj_txt)
119
+ obj = get_object(obj_txt)
120
+ if !obj.nil? and obj.respond_to?(:source_location) and obj.respond_to?(:comment) and
121
+ !obj.source_location.nil? and !obj.comment.nil?
122
+ result = "_*#{obj.source_location.join(":").gsub(Dir.pwd,"").gsub(Dir.home,"")}*_\n\n"
123
+ comment = obj.comment.gsub(/^\s*\#/, "")
124
+ comment.gsub!(/^\s*#+\s*(\R|$)/, "")
125
+ comment.gsub!(/^\s(\w)([\w\s\-]*):/i, \'*\1\2*:\')
126
+ comment.gsub!(/^(\s+)(\w[\w\s\-]*):/i, \'\1*`\2`*:\')
127
+ result << "#{comment}"
128
+ result << "\n\n"
129
+ result << get_met_params(obj)
130
+ else
131
+ result = "No documentation found for #{obj_txt}. The object doesn\'t exist or it is not accessible."
132
+ end
133
+ puts result
134
+ end
135
+
136
+ def source(obj_txt)
137
+ obj = get_object(obj_txt)
138
+ if !obj.nil? and obj.respond_to?(:source_location) and obj.respond_to?(:comment) and
139
+ !obj.source_location.nil? and !obj.comment.nil?
140
+ result = "# #{obj.source_location.join(":").gsub(Dir.pwd,"").gsub(Dir.home,"")}\n\n"
141
+ result << "#{obj.source}"
142
+ else
143
+ result = "No source code found for #{obj_txt}. The object doesn\'t exist or it is not accessible."
144
+ end
145
+ puts result
146
+ end
147
+
148
+ def code(obj_txt)
149
+ source(obj_txt)
150
+ end
151
+
152
+ file_run_path = \"' + +File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.rb\"
153
+ file_input_repl = File.open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.input\", \"r\")
154
+ ' + pre_execute + '
155
+ while true do
156
+ sleep 0.2
157
+ code_to_run_repl = file_input_repl.read
158
+ if code_to_run_repl.to_s!=\"\"
159
+ add_to_run_repl = true
160
+ if code_to_run_repl.to_s.match?(/^quit$/i) or
161
+ code_to_run_repl.to_s.match?(/^exit$/i) or
162
+ code_to_run_repl.to_s.match?(/^bye bot$/i) or
163
+ code_to_run_repl.to_s.match?(/^bye$/i)
164
+ exit
165
+ else
166
+ error = false
167
+ as_it_is = false
168
+ begin
169
+ if code_to_run_repl.match?(/^\s*ls\s+(.+)/)
170
+ add_to_run_repl = false
171
+ as_it_is = true
172
+ elsif code_to_run_repl.match(/^\s*doc\s+(.+)/)
173
+ add_to_run_repl = false
174
+ code_to_run_repl = \"doc \\\"#{$1}\\\"\"
175
+ as_it_is = true
176
+ elsif code_to_run_repl.match(/^\s*(code|source|src)\s+(.+)/)
177
+ add_to_run_repl = false
178
+ code_to_run_repl = \"source \\\"#{$2}\\\"\"
179
+ end
180
+ begin
181
+ original_stdout = $stdout
182
+ $stdout = StringIO.new
183
+ resp_repl = eval(code_to_run_repl, bindme' + serialt + ')
184
+ stdout_repl = $stdout.string
185
+ ensure
186
+ $stdout = original_stdout
187
+ end
188
+ rescue Exception => resp_repl
189
+ error = true
190
+ end
191
+ if error
192
+ open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.output\", \"a+\") {|f|
193
+ f.puts \"\`\`\`\n#{resp_repl.to_s.gsub(/^.+' + session_name + '\.rb:\d+:/,\"\")}\`\`\`\"
194
+ }
195
+ else
196
+ if code_to_run_repl.match?(/^\s*p\s+/i)
197
+ resp_repl = stdout_repl unless stdout_repl.to_s == \'\'
198
+ if stdout_repl.to_s == \'\'
199
+ resp_repl = resp_repl.inspect
200
+ else
201
+ resp_repl = stdout_repl
202
+ end
203
+ open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.output\", \"a+\") {|f|
204
+ f.puts \"\`\`\`\n#{resp_repl}\`\`\`\"
205
+ }
206
+ else
207
+ if stdout_repl.to_s == \'\'
208
+ resp_repl = resp_repl.ai
209
+ else
210
+ resp_repl = stdout_repl
211
+ end
212
+ open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.output\", \"a+\") {|f|
213
+ if as_it_is
214
+ f.puts resp_repl
215
+ else
216
+ f.puts \"\`\`\`\n#{resp_repl}\`\`\`\"
217
+ end
218
+ }
219
+ end
220
+ unless !add_to_run_repl
221
+ open(\"' + File.expand_path(config.path) + "/repl/" + @channel_id + "/" + session_name + '.run\", \"a+\") {|f|
222
+ f.puts code_to_run_repl
223
+ }
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
229
+ '
230
+ process_to_run.gsub!('\"', '"')
231
+ return process_to_run
232
+ end
233
+ end
@@ -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