diff --git a/lib/slack-smart-bot.rb b/lib/slack-smart-bot.rb index 19fdf16..24917c7 100644 --- a/lib/slack-smart-bot.rb +++ b/lib/slack-smart-bot.rb @@ -61,6 +61,7 @@ def initialize(config) Dir.mkdir("#{config.path}/logs") unless Dir.exist?("#{config.path}/logs") Dir.mkdir("#{config.path}/shortcuts") unless Dir.exist?("#{config.path}/shortcuts") Dir.mkdir("#{config.path}/routines") unless Dir.exist?("#{config.path}/routines") + File.delete("#{config.path}/config_tmp.status") if File.exist?("#{config.path}/config_tmp.status") config.masters = MASTER_USERS if config.masters.to_s=='' and defined?(MASTER_USERS) config.master_channel = MASTER_CHANNEL if config.master_channel.to_s=='' and defined?(MASTER_CHANNEL) diff --git a/lib/slack/smart-bot/comm/event_hello.rb b/lib/slack/smart-bot/comm/event_hello.rb index 04c52b2..3adad99 100644 --- a/lib/slack/smart-bot/comm/event_hello.rb +++ b/lib/slack/smart-bot/comm/event_hello.rb @@ -16,7 +16,7 @@ def event_hello() version_message = ". There is a new available version: #{version_remote}." end if (!config[:silent] or ENV['BOT_SILENT'].to_s == 'false') and !config.simulate - ENV['BOT_SILENT'] = 'true' if config[:silent] == 'true' and ENV['BOT_SILENT'].to_s != 'true' + ENV['BOT_SILENT'] = 'true' if config[:silent] and ENV['BOT_SILENT'].to_s != 'true' respond "Smart Bot started v#{VERSION}#{version_message}\nIf you want to know what I can do for you: `bot help`.\n`bot rules` if you want to display just the specific rules of this channel.\nYou can talk to me privately if you prefer it." end @routines.each do |ch, rout| diff --git a/lib/slack/smart-bot/comm/respond.rb b/lib/slack/smart-bot/comm/respond.rb index 5cbade0..ea5ab95 100644 --- a/lib/slack/smart-bot/comm/respond.rb +++ b/lib/slack/smart-bot/comm/respond.rb @@ -6,8 +6,11 @@ def respond(msg, dest = nil) dest = @channels_id[dest] if @channels_id.key?(dest) #it is a name of channel if !config.simulate #https://api.slack.com/docs/rate-limits msg.to_s.size > 500 ? wait = 0.5 : wait = 0.1 - sleep wait if Time.now <= (@last_respond+wait) + sleep wait if Time.now <= (@last_respond+wait) + else + wait = 0 end + msgs = msg.chars.each_slice(4000).map(&:join) # max of 4000 characters per message if dest.nil? if config[:simulate] open("#{config.path}/buffer_complete.log", "a") { |f| @@ -15,9 +18,15 @@ def respond(msg, dest = nil) } else if Thread.current[:on_thread] - client.message(channel: @channel_id, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts]) + msgs.each do |msg| + client.message(channel: @channel_id, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts]) + sleep wait + end else - client.message(channel: @channel_id, text: msg, as_user: true) + msgs.each do |msg| + client.message(channel: @channel_id, text: msg, as_user: true) + sleep wait + end end end if config[:testing] and config.on_master_bot @@ -32,9 +41,15 @@ def respond(msg, dest = nil) } else if Thread.current[:on_thread] - client.message(channel: dest, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts]) + msgs.each do |msg| + client.message(channel: dest, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts]) + sleep wait + end else - client.message(channel: dest, text: msg, as_user: true) + msgs.each do |msg| + client.message(channel: dest, text: msg, as_user: true) + sleep wait + end end end if config[:testing] and config.on_master_bot @@ -43,11 +58,17 @@ def respond(msg, dest = nil) } end elsif dest[0] == "D" or dest[0] == "U" or dest[0] == "W" # Direct message - send_msg_user(dest, msg) + msgs.each do |msg| + send_msg_user(dest, msg) + sleep wait + end elsif dest[0] == "@" begin user_info = get_user_info(dest) - send_msg_user(user_info.user.id, msg) + msgs.each do |msg| + send_msg_user(user_info.user.id, msg) + sleep wait + end rescue Exception => stack @logger.warn("user #{dest} not found.") @logger.warn stack diff --git a/lib/slack/smart-bot/commands/general/use_rules.rb b/lib/slack/smart-bot/commands/general/use_rules.rb index ec7364f..dc9243b 100644 --- a/lib/slack/smart-bot/commands/general/use_rules.rb +++ b/lib/slack/smart-bot/commands/general/use_rules.rb @@ -16,12 +16,13 @@ def use_rules(dest, channel, user, dchannel) else #todo: add pagination for case more than 1000 channels on the workspace channels = get_channels() - + channel.gsub!('#','') # for the case the channel name is in plain text including # channel_found = channels.detect { |c| c.name == channel } - members = get_channel_members(@channels_id[channel]) unless channel_found.nil? + get_channels_name_and_id() unless @channels_id.key?(channel) + members = get_channel_members(@channels_id[channel]) unless channel_found.nil? or !@channels_id.key?(channel) - if channel_found.nil? - respond "The channel you are trying to use doesn't exist", dest + if channel_found.nil? or !@channels_id.key?(channel) + respond "The channel you are trying to use doesn't exist or cannot be found.", dest elsif channel_found.name == config.master_channel respond "You cannot use the rules from Master Channel on any other channel.", dest elsif !@bots_created.key?(@channels_id[channel]) diff --git a/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb b/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb index d3e0e36..a5b0465 100644 --- a/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +++ b/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb @@ -99,12 +99,21 @@ def add_routine(dest, from, user, name, type, number_time, period, command_to_ru http.get(files[0].url_private_download, save_data: file_path) system("chmod +x #{file_path}") end - channel = dest if channel.to_s == '' + get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel) + channel_id = nil + if @channels_name.key?(channel) #it is an id + channel_id = channel + channel = @channels_name[channel_id] + elsif @channels_id.key?(channel) #it is a channel name + channel_id = @channels_id[channel] + end + + channel_id = dest if channel_id.to_s == '' @routines[@channel_id] = {} unless @routines.key?(@channel_id) @routines[@channel_id][name] = { channel_name: config.channel, creator: from, creator_id: user.id, status: :on, every: every, every_in_seconds: every_in_seconds, at: at, dayweek: dayweek, file_path: file_path, command: command_to_run.to_s.strip, silent: silent, - next_run: next_run.to_s, dest: channel, last_run: "", last_elapsed: "", + next_run: next_run.to_s, dest: channel_id, last_run: "", last_elapsed: "", running: false } update_routines respond "Added routine *`#{name}`* to the channel", dest diff --git a/lib/slack/smart-bot/process.rb b/lib/slack/smart-bot/process.rb index c1e33ca..8c275bb 100644 --- a/lib/slack/smart-bot/process.rb +++ b/lib/slack/smart-bot/process.rb @@ -27,7 +27,7 @@ def process(user, command, dest, dchannel, rules_file, typem, files, ts) command = command2 on_demand = true end - if (on_demand or + if (on_demand or typem == :on_dm or (@listening.key?(from) and (@listening[from].key?(dest) or @listening[from].key?(Thread.current[:thread_ts])) )) and config.on_maintenance and !command.match?(/\A(set|turn)\s+maintenance\s+off\s*\z/) respond config.on_maintenance_message, dest @@ -83,8 +83,11 @@ def process(user, command, dest, dchannel, rules_file, typem, files, ts) when /^\s*kill\s+bot\s+on\s+<#C\w+\|(.+)>\s*$/i, /^kill\s+bot\s+on\s+(.+)\s*$/i channel = $1 kill_bot_on_channel(dest, from, channel) - when /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(every)\s+(\d+)\s*(days|hours|minutes|seconds|mins|min|secs|sec|d|h|m|s)\s*(\s<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i, + when /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(every)\s+(\d+)\s*(days|hours|minutes|seconds|mins|min|secs|sec|d|h|m|s)\s*(\s#(\w+)\s*)(\s.+)?\s*$/i, + /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(every)\s+(\d+)\s*(days|hours|minutes|seconds|mins|min|secs|sec|d|h|m|s)\s*(\s<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i, + /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+on\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)s?\s+at\s+(\d+:\d+:?\d+?)\s*()(\s#(\w+)\s*)(\s.+)?\s*$/i, /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+on\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)s?\s+at\s+(\d+:\d+:?\d+?)\s*()(\s<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i, + /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s#(\w+)\s*)(\s.+)?\s*$/i, /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i silent = $2.to_s!='' name = $3.downcase diff --git a/lib/slack/smart-bot/treat_message.rb b/lib/slack/smart-bot/treat_message.rb index 55f452c..9953c78 100644 --- a/lib/slack/smart-bot/treat_message.rb +++ b/lib/slack/smart-bot/treat_message.rb @@ -69,14 +69,24 @@ def treat_message(data, remove_blocks = true) end typem = :dont_treat if !dest.nil? and !data.text.nil? and !data.text.to_s.match?(/\A\s*\z/) - #if data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?<#(\w+)\|([^>]+)>\s*:?\s*(.*)/im) - if data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?((<#\w+\|[^>]+>\s*)+)\s*:?\s*(.*)/im) + #todo: we need to add mixed channels: @smart-bot on private1 #bot1cm <#CXDDFRDDF|bot2cu>: echo A + if data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?((<#\w+\|[^>]+>\s*)+)\s*:?\s*(.*)/im) or + data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?((#[a-zA-Z0-9]+\s*)+)\s*:?\s*(.*)/im) or + data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?(([a-zA-Z0-9]+\s*)+)\s*:\s*(.*)/im) channels_rules = $2 #multiple channels @smart-bot on #channel1 #channel2 echo AAA data_text = $4 channel_rules_name = '' channel_rules = '' + channels_arr = channels_rules.scan(/<#(\w+)\|([^>]+)>/) + if channels_arr.size == 0 + channels_arr = [] + channels_rules.scan(/([^\s]+)/).each do |cn| + cna = cn.join.gsub('#','') + channels_arr << [@channels_id[cna], cna] + end + end # to be treated only on the bots of the requested channels - channels_rules.scan(/<#(\w+)\|([^>]+)>/).each do |tcid, tcname| + channels_arr.each do |tcid, tcname| if @channel_id == tcid data.text = data_text typem = :on_call @@ -234,6 +244,7 @@ def treat_message(data, remove_blocks = true) file_cts = eval(file_cts) if file_cts.is_a?(Hash) and file_cts.key?(:on_maintenance) config.on_maintenance = file_cts.on_maintenance + config.on_maintenance_message = file_cts.on_maintenance_message end end end @@ -245,6 +256,7 @@ def treat_message(data, remove_blocks = true) file_cts = eval(file_cts) if file_cts.is_a?(Hash) and file_cts.key?(:on_maintenance) config.on_maintenance = file_cts.on_maintenance + config.on_maintenance_message = file_cts.on_maintenance_message end end end diff --git a/slack-smart-bot.gemspec b/slack-smart-bot.gemspec index c84e67c..86d9814 100644 --- a/slack-smart-bot.gemspec +++ b/slack-smart-bot.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'slack-smart-bot' - s.version = '1.9.0' + s.version = '1.9.2' s.summary = "Create a Slack bot that is smart and so easy to expand, create new bots on demand, run ruby code on chat, create shortcuts..." s.description = "Create a Slack bot that is smart and so easy to expand, create new bots on demand, run ruby code on chat, create shortcuts... The main scope of this gem is to be used internally in the company so teams can create team channels with their own bot to help them on their daily work, almost everything is suitable to be automated!! diff --git a/spec/bot/rules/GNCU7JC6L/slack-smart-bot_rules_GNCU7JC6L_smartbotuser1.rb b/spec/bot/rules/GNCU7JC6L/slack-smart-bot_rules_GNCU7JC6L_smartbotuser1.rb deleted file mode 100644 index 664f9ad..0000000 --- a/spec/bot/rules/GNCU7JC6L/slack-smart-bot_rules_GNCU7JC6L_smartbotuser1.rb +++ /dev/null @@ -1,153 +0,0 @@ - -#path to the project folder -# for example "#{`eval echo ~$USER`.chop}/projects/the_project" -def project_folder() - "#{Dir.pwd}/" -end - -#link to the project -def git_project() - "" -end - -#for the case of testing, just run this file adding in the end a call to rules with the parameters you want -if defined?(respond) - @testing = false -else - @testing = true - @questions = Hash.new() - - def respond(message, dest) - puts message - end - - #context: previous message - #to: user that should answer - def ask(question, context, to, dest) - puts "Bot: #{question}" - @questions[to] = context - end -end - -# user: user slack object -# command: command to run -# processed: in case the command has been already processed on Bot class, by default false -# dest: channel_id -# files: files attached -# rules_file: rules_file name -# -# About the Help: -# Add as a comment starting by "help:" the help you need to add to the `bot help` and `bot rules` commands. -# The command logic needs to be added with ``, and the parameters to supply need to be in capital for example: `echo SOMETHING` -# -# help: =================================== -# help: -# help: *These are specific commands for this bot on this Channel.* -# help: They will be accessible only when the bot is listening to you just writing the command -# help: or the bot is not listening to you but requested on demand, or in a private conversation with the Smart Bot. -# help: To run a command on demand: -# help: `!THE_COMMAND` -# help: `@NAME_OF_BOT THE_COMMAND` -# help: `NAME_OF_BOT THE_COMMAND` -# help: To run a command on demand and add the respond on a thread: -# help: `^THE_COMMAND` -# help: `!!THE_COMMAND` -# help: -def rules(user, command, processed, dest, files = [], rules_file = "") - from = user.name - display_name = user.profile.display_name - - if @testing - puts "#{from}: #{command}" - if @questions.keys.include?(from) - context = @questions[from] - @questions[from] = command - command = context - end - end - load "#{config.path}/rules/general_rules.rb" - - unless general_rules(user, command, processed, dest, files, rules_file) - - begin - case command - - # help: ---------------------------------------------- - # help: `go to sleep` - # help: it will sleep the bot for 5 seconds - # help: - when /^go\sto\ssleep/i - unless @questions.keys.include?(from) - ask("do you want me to take a siesta?", command, from, dest) - else - case @questions[from] - when /yes/i, /yep/i, /sure/i - @questions.delete(from) - respond "I'll be sleeping for 5 secs... just for you", dest - respond "zZzzzzzZZZZZZzzzzzzz!", dest - sleep 5 - when /no/i, /nope/i, /cancel/i - @questions.delete(from) - respond "Thanks, I'm happy to be awake", dest - else - respond "I don't understand", dest - ask("are you sure you want me to sleep? (yes or no)", command, from, dest) - end - end - - # help: ---------------------------------------------- - # help: `run something` - # help: It will run the process and report the results when done - # help: - when /^run something/i - respond "Running", dest - - process_to_run = "ruby -v" - process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder) - stdout, stderr, status = Open3.capture3(process_to_run) - if stderr == "" - if stdout == "" - respond "#{display_name}: Nothing returned.", dest - else - respond "#{display_name}: #{stdout}", dest - end - else - respond "#{display_name}: #{stdout} #{stderr}", dest - end - - # Example downloading a file from slack - # if !files.nil? and files.size == 1 and files[0].filetype == 'yaml' - # require 'nice_http' - # http = NiceHttp.new(host: "https://files.slack.com", headers: { "Authorization" => "Bearer #{config[:token]}" }) - # http.get(files[0].url_private_download, save_data: './tmp/') - # end - - # Examples sending a file to slack: - # send_file(to, msg, filepath, title, format, type = "text") - # send_file(dest, 'the message', "#{project_folder}/temp/logs_ptBI.log", 'title', 'text/plain', "text") - # send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'title', 'image/jpeg', "jpg") - - else - unless processed - dont_understand(rules_file, command, user, dest) - end - end - rescue => exception - if defined?(@logger) - @logger.fatal exception - respond "Unexpected error!! Please contact an admin to solve it: <@#{config.admins.join(">, <@")}>", dest - else - puts exception - end - end - end -end - -#for the case of testing just running this file, write the dialogue in here: -if @testing - require "nice_hash" - user = { name: "Peter Johnson", id: "Uxxxxxx" } - - rules user, "go to sleep, you look tired", false, nil - rules user, "yes", false, nil -end diff --git a/whats_new.txt b/whats_new.txt index cf7bcda..5ec563c 100644 --- a/whats_new.txt +++ b/whats_new.txt @@ -1,3 +1,9 @@ +*Version 1.9.2* Released 2021-Apr-27 + +- Bugfixing and small improvements + +------------------------------ + *Version 1.9.0* Released 2021-Mar-18 *For General users*